PHP大文件分割分片上传实现代码

吾爱主题 阅读:223 2021-11-01 15:00:00 评论:0

服务端为什么不能直接传大文件?跟php.ini里面的几个配置有关

upload_max_filesize = 2M //PHP最大能接受的文件大小
post_max_size = 8M //PHP能收到的最大POST值'
memory_limit = 128M //内存上限
max_execution_time = 30 //最大执行时间

当然不能简单粗暴的把上面几个值调大,否则服务器内存资源吃光是迟早的问题。

解决思路

好在HTML5开放了新的FILE API,也可以直接操作二进制对象,我们可以直接在浏览器端实现文件切割,按照以前的做法就得用Flash的方案,实现起来会麻烦很多。

JS思路

1.监听上传按钮的onchange事件

2.获取文件的FILE对象

3.把文件的FILE对象进行切割,并且附加到FORMDATA对象中

4.把FORMDATA对象通过AJAX发送到服务器

5.重复3、4步骤,直到文件发送完。

PHP思路

1.建立上传文件夹

2.把文件从上传临时目录移动到上传文件夹

3.所有的文件块上传完成后,进行文件合成

4.删除文件夹

5.返回上传后的文件路径

DEMO代码

前端部分代码

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 <!doctype html> < html lang = "en" > < head >    < meta charset = "UTF-8" >    < meta name = "viewport"       content = "width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" >    < meta http-equiv = "X-UA-Compatible" content = "ie=edge" >    < title >Document</ title >    < style >      #progress{        width: 300px;        height: 20px;        background-color:#f7f7f7;        box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);        border-radius:4px;        background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);      }        #finish{        background-color: #149bdf;        background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);        background-size:40px 40px;        height: 100%;      }      form{        margin-top: 50px;      }    </ style > </ head > < body > < div id = "progress" >    < div id = "finish" style = "width: 0%;" progress = "0" ></ div > </ div > < form action = "./upload.php" >    < input type = "file" name = "file" id = "file" >    < input type = "button" value = "停止" id = "stop" > </ form > < script >    var fileForm = document.getElementById("file");    var stopBtn = document.getElementById('stop');    var upload = new Upload();      fileForm.onchange = function(){      upload.addFileAndSend(this);    }      stopBtn.onclick = function(){      this.value = "停止中";      upload.stop();      this.value = "已停止";    }      function Upload(){      var xhr = new XMLHttpRequest();      var form_data = new FormData();      const LENGTH = 1024 * 1024;      var start = 0;      var end = start + LENGTH;      var blob;      var blob_num = 1;      var is_stop = 0      //对外方法,传入文件对象      this.addFileAndSend = function(that){        var file = that.files[0];        blob = cutFile(file);        sendFile(blob,file);        blob_num += 1;      }      //停止文件上传      this.stop = function(){        xhr.abort();        is_stop = 1;      }      //切割文件      function cutFile(file){        var file_blob = file.slice(start,end);        start = end;        end = start + LENGTH;        return file_blob;      };      //发送文件      function sendFile(blob,file){        var total_blob_num = Math.ceil(file.size / LENGTH);        form_data.append('file',blob);        form_data.append('blob_num',blob_num);        form_data.append('total_blob_num',total_blob_num);        form_data.append('file_name',file.name);          xhr.open('POST','./upload.php',false);        xhr.onreadystatechange = function () {          var progress;          var progressObj = document.getElementById('finish');          if(total_blob_num == 1){            progress = '100%';          }else{            progress = Math.min(100,(blob_num/total_blob_num)* 100 ) +'%';          }          progressObj.style.width = progress;          var t = setTimeout(function(){            if(start < file.size && is_stop === 0){              blob = cutFile (file);              sendFile(blob,file);              blob_num += 1;            }else{              setTimeout(t);            }          },1000);        }        xhr.send(form_data);      }    }   </script> </ body > </ html >

PHP部分代码

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 <?php class Upload{    private $filepath = './upload' ; //上传目录    private $tmpPath ; //PHP文件临时目录    private $blobNum ; //第几个文件块    private $totalBlobNum ; //文件块总数    private $fileName ; //文件名      public function __construct( $tmpPath , $blobNum , $totalBlobNum , $fileName ){      $this ->tmpPath = $tmpPath ;      $this ->blobNum = $blobNum ;      $this ->totalBlobNum = $totalBlobNum ;      $this ->fileName = $fileName ;           $this ->moveFile();      $this ->fileMerge();    }       //判断是否是最后一块,如果是则进行文件合成并且删除文件块    private function fileMerge(){      if ( $this ->blobNum == $this ->totalBlobNum){        $blob = '' ;        for ( $i =1; $i <= $this ->totalBlobNum; $i ++){          $blob .= file_get_contents ( $this ->filepath. '/' . $this ->fileName. '__' . $i );        }        file_put_contents ( $this ->filepath. '/' . $this ->fileName, $blob );        $this ->deleteFileBlob();      }    }       //删除文件块    private function deleteFileBlob(){      for ( $i =1; $i <= $this ->totalBlobNum; $i ++){        @unlink( $this ->filepath. '/' . $this ->fileName. '__' . $i );      }    }       //移动文件    private function moveFile(){      $this ->touchDir();      $filename = $this ->filepath. '/' . $this ->fileName. '__' . $this ->blobNum;      move_uploaded_file( $this ->tmpPath, $filename );    }       //API返回数据    public function apiReturn(){      if ( $this ->blobNum == $this ->totalBlobNum){          if ( file_exists ( $this ->filepath. '/' . $this ->fileName)){            $data [ 'code' ] = 2;            $data [ 'msg' ] = 'success' ;            $data [ 'file_path' ] = 'http://' . $_SERVER [ 'HTTP_HOST' ].dirname( $_SERVER [ 'DOCUMENT_URI' ]). str_replace ( '.' , '' , $this ->filepath). '/' . $this ->fileName;          }      } else {          if ( file_exists ( $this ->filepath. '/' . $this ->fileName. '__' . $this ->blobNum)){            $data [ 'code' ] = 1;            $data [ 'msg' ] = 'waiting for all' ;            $data [ 'file_path' ] = '' ;          }      }      header( 'Content-type: application/json' );      echo json_encode( $data );    }       //建立上传文件夹    private function touchDir(){      if (! file_exists ( $this ->filepath)){        return mkdir ( $this ->filepath);      }    } }   //实例化并获取系统变量传参 $upload = new Upload( $_FILES [ 'file' ][ 'tmp_name' ], $_POST [ 'blob_num' ], $_POST [ 'total_blob_num' ], $_POST [ 'file_name' ]); //调用方法,返回结果 $upload ->apiReturn();

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://www.cnblogs.com/ghjbk/p/7443765.html

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

【腾讯云】云服务器产品特惠热卖中
搜索
标签列表
    关注我们

    了解等多精彩内容