php tp5大文件分片上传,切片上传,结合layui上传插件,可上传4G文件

php 大文件分片上传,结合layui上传插件

原理是将文件切成小文件,ajax递归上传,然后在后台再拼接成一个整的文件

  1. html 页面

    <div class="layui-upload">
    
       <input type="file" style="display: none;" id="fileElem" ></input>
       <button type="button" class="btn btn-primary radius layui-btn-normal" id="fileSelect">选择文件</button>&emsp;<span style="color: #FF5722">每次只能上传1个文件,文件大小“小于等于150M”</span>
       <div class="layui-upload-list">
            <table class="layui-table">
            <thead>
                <tr style="width: 15%"><th>文件名</th>
                <th style="width: 10%">大小</th>
                <th style="width: 65%">进度</th>
                <th style="width: 10%">状态</th>
            </thead>
            <tbody id="demoList"></tbody>
            </table>
        </div>
        <button type="button" class="btn btn-success radius" id="upstart">开始上传</button>
    
    </div> 
    
  2. jq代码(js jq 都用上了,哈哈)

       var fileSelect = document.getElementById("fileSelect"),
           fileElem = document.getElementById("fileElem");
     
           fileSelect.addEventListener("click", function (e) {
     
           if (fileElem) {
               fileElem.click();
               fileElem.addEventListener("change", handleFiles, false); 
             }
             e.preventDefault(); // prevent navigation to "#"
           }, false);
      
     
       var fileList = "";
       function handleFiles(){
     
           fileList = this.files; 
     
           var filecontent = "";
     
           for( var i = 0 ; i < fileList.length ; i++ ){  
     
             // 定义允许上传文件的大小
             var filesize = (fileList[i].size/1024/1024).toFixed(1);
     
             if(filesize >= file_size){
     
               layer.msg('* 文件大小超出限制',{icon:2,time:3000});
               fileList = "";
               return false;
             }
     
             filecontent += '<tr>'+
                             '<td>'+ fileList[i].name +'</td>'+
                             '<td>'+ (fileList[i].size/1024/1024).toFixed(1) +'MB</td>'+
                             '<td>'+
                               '<div class="layui-progress" lay-filter="'+fileList[i].lastModified+'_'+i+'" lay-showPercent="true" lay-filter="progress_'+i+'">'+
                                 '<div class="layui-progress-bar" lay-percent="0%"></div>'+
                               '</div>'+
                             '</td>'+
                             '<td id="'+fileList[i].lastModified+'_'+i+'">等待上传</td>'+
                             '<td style="display:none" id="filepath"></td>'+
                           '</tr>';  
           }
           $("#demoList").append(filecontent); 
       } 
     
       
       //---------------
       var upstartBtn = document.getElementById('upstart');
       //---------------
       const LENGTH = 512 * 1024 * 1;
       var start = 0;
       var end = start + LENGTH;
       var blob;
       var blob_num = 1;
       var is_stop = 0
       var file = null;
       var loading;
       //-----------------------------
       var upload_instance = new Upload();
     
       var fileid = 0;
       upstartBtn.onclick = function () {
           for( var i = 0 ; i < fileList.length ; i++ ){ 
             fileid = fileList[i].lastModified+'_'+i;
             upload_instance.addFileAndSend(fileList[i]);
           }
           return false;
       }
     
       function Upload() {
         //对外方法,传入文件对象
         this.addFileAndSend = function (that) {
             // loading
             loading = layer.load(1, {shade: [0.3,'#fff']}); 
     
             file = that;
             blob = cutFile(file);
             sendData(blob, file);
             blob_num += 1;
         }
         //切割文件
         function cutFile(file) {
             var file_blob = file.slice(start, end);
             start = end;
             end = start + LENGTH;
             return file_blob;
         };
         //发送文件
         function sendData(blob, file){
     
             var form_data = new FormData();
             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);
             console.log(blob_num);
             console.log(total_blob_num);
             $.ajax({
               url:upload_url,
               type:'post',
               async:true,
               dataType:"json",
               data:form_data,
               contentType:false,
               processData:false,
               success:function(data){
                 console.log(data);
                 if(data['code'] == 1){
     
                   // 进度条和状态设置
                   if (total_blob_num == 1) {
                       progress = '100%';
                   } else {
                       progress = (Math.min(100, (blob_num / total_blob_num) * 100)).toFixed(2) + '%';
                   }
     
                   // 进度条
                   layui.element.progress(fileid, progress);
     
                   // 状态
                   var type = document.getElementById(fileid);
                       type.innerText = progress;
                   console.log('progress-----' + progress);
     
                   //继续上传
                   if (start < file.size && is_stop === 0) {
                       blob = cutFile(file);
                       sendData(blob, file);
                       blob_num += 1;
                   }
                   //每次清空
                   form_data = "";
     
                 }else if(data['code'] == 2){
     
                   // 进度条
                   progress = '100%';
                   layui.element.progress(fileid, progress);
     
                   // loading end 
                   layer.close(loading);
     
                   // 上传成功
                   var type = document.getElementById(fileid);
                       type.innerText = "上传成功";
                   var text = '<span class="filePath" style="display:none">'+data.file_path+'</span><span class="fileExtension" style="display:none">'+data.file_extension+'</span><span class="fileName" style="display:none">'+data.file_name+'</span>';
                   $("#filepath").append(text); 
                   
                   //每次清空
                   form_data = "";
     
                 }
               },error:function(data){
                 // loading end 
                 layer.close(loading);
     
                 layer.msg('* 未知错误',{icon:2,time:2000});
                 return;
               }
             })
         }
     }
    
  3. php 后台代码,我用的是tp5.0

    • upload.php 封装了一个上传,拼接的方法

        <?php
        	namespace app\admin\controller;
        	use think\Controller;
        	
        	ini_set('memory_limit',-1); //要有足够大的内存来允许处理上传的文件
        	set_time_limit(0); //防止超时
        	
        	class Upload extends Controller
        	{	
        		private $filepath; //上传目录
        		private $tmpPath; //PHP文件临时目录
        		private $blobNum; //第几个文件块
        		private $totalBlobNum; //文件块总数
        		private $fileName; //文件名
        	
        		public function __construct($tmpPath,$blobNum,$totalBlobNum,$fileName,$filepath){
        		    $this->tmpPath = $tmpPath;
        		    $this->blobNum = $blobNum;
        		    $this->totalBlobNum = $totalBlobNum;
        		    $this->fileName = $fileName;
        		    $this->filepath = $filepath;
        		    $this->moveFile();
        		    $this->fileMerge();
        		}
        	
        	  	private function fileMerge(){
        		    if($this->blobNum == $this->totalBlobNum){
        		      // 此处文件不应该拼接,应该是追加入内
        		      // 实测修改后php占用很少的内存也可以实现大文件的上传和拼接操作
        		      for($i=1; $i<= $this->totalBlobNum; $i++){
        		        $blob = '';
        		        $blob = file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);
        		        file_put_contents($this->filepath.'/'. $this->fileName, $blob, FILE_APPEND );
        		        unset($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'] = $this->fileName;
        		          $data['file_name'] = substr($this->fileName,0,strrpos($this->fileName, '.'));
        		          $data['file_extension'] = substr(strrchr($this->fileName, '.'), 1);
        		        }
        		    }else{
        		        if(file_exists($this->filepath.'/'. $this->fileName.'__'.$this->blobNum)){
        		          $data['code'] = 1;
        		          $data['msg'] = 'waiting';
        		          $data['file_path'] = '';
        		        }
        		    }
        		    header('Content-type: application/json');
        		    echo json_encode($data);
        	  	}
        	   
        	  
        	  	private function touchDir(){
        		    if(!file_exists($this->filepath)){
        		      return mkdir($this->filepath);
        		    }
        		}
        	  
        	}
      
  4. 控制器调用上传方法

     // 上传文件
     public function uploadhandle(){
         // 定义存储路径
         $uploadDir = ROOT_PATH . 'public' . DS . 'assets' . DS . 'zip';
    
         $upload = new Upload($_FILES['file']['tmp_name'],$_POST['blob_num'],$_POST['total_blob_num'],$_POST['file_name'],$uploadDir);
         
         $upload->apiReturn();
     }
    

最后再强调一下啊,分片上传的文件先上传到一个缓存文件夹,等着合并完之后再保存到要保存的文件夹下,防止上传失败后文件夹里面多了很多小文件,很头痛 ,这样即使失败了也没关系,清一下文件就行#

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在ThinkPHP5 (TP5) 框架结合Layui库进行文件上传时,处理视频文件通常会稍微复杂一些,因为视频文件通常比图片大得多。以下是使用TP5Layui进行视频上传的基本步骤: 1. 引入依赖:首先,在项目中引入layui的表单组件和文件上传插件`layui.upload`。 ```html <script src="__STATIC__/layui/layui.js"></script> ``` 2. 配置上传规则:在前端HTML中设置一个表单,配置`layui.upload`的属性,例如设置允许上传文件类型和最大大小。 ```html <form id="videoForm" lay-filter="uploadVideo"> <input type="hidden" name="token" value="<your-token>"> <input type="file" name="videoFile" lay-choose="layfiles" accept="video/*"> <button type="submit">上传</button> </form> <script> layui.use(['form', 'layer', 'upload'], function () { var form = layui.form(); }); </script> ``` 3. JavaScript处理:在layui.js文件加载完成后,初始化上传函数并监听表单提交事件。 ```javascript layui.upload({ url: '<your-api-url>', // 后端接收视频的URL field: 'videoFile', // 表单字段名 before: async function (obj, file) { /* 在这里添加文件验证和限制 */ if (!file.type.match('video/*')) { layer.msg('只支持上传视频文件'); return false; } // 检查文件大小 if (file.size > 10 * 1024 * 1024) { layer.msg('视频文件过大,请小于10MB'); return false; } }, done: function (res, file) { console.log(res); // 成功回调 // 这里可以将上传结果返回给服务器或显示给用户 } }, '#videoForm') ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值