基于php+webuploader的大檔案分片上傳,帶進度條,支持斷點續傳(重繪、關閉頁面、重新上傳、網路中斷等情況),檔案上傳前先檢測該檔案是否已上傳,如果已上傳提示“檔案已存在”,如果未上傳則直接上傳,視頻上傳時會根據設定的引數(分片大小、分片數量)進行上傳,上傳程序中會在目標檔案夾中生成一個臨時檔案夾,用于存盤臨時分片,等所有分片上傳完畢后,會根據序號重新組合成一個完整的視頻,臨時檔案被洗掉,
如果檔案上傳至七牛云,可參看基于php大檔案分片上傳至七牛云,帶進度條
首先下載webuploader
效果圖:


臨時檔案,用于存盤分片

html代碼
<title>webuploader分片上傳</title> <meta charset="utf8"> <!--引入CSS--> <link rel="stylesheet" type="text/css" href="/static/webupload/webuploader.css"> <script type="text/javascript" src="/static/index/js/jquery.js"></script> <script type="text/javascript" src="/static/index/js/jquery.md5.js"></script> <!--引入JS--> <script type="text/javascript" src="/static/webupload/webuploader.js"></script> <div id="uploader" class="wu-example"> <!--用來存放檔案資訊--> <div id="thelist" class="uploader-list"></div> <div class="btns"> <div id="picker">選擇檔案</div> <button id="ctlBtn" class="btn btn-default">開始上傳</button> </div> </div> <style> .progress{ height: 20px; width: 300px; background: #ccc; } .progress-bar{ height: 20px; background: #0a3536;} </style> <script> var uploadswf = '/static/webupload/Uploader.swf'; var chunkSize = 2*1024*1024; var server_url='uploadVedio'; var GUID = WebUploader.Base.guid();//一個GUID var chunkObj = {}; //用來記錄檔案的狀態、上傳中斷的位置 var seq=1; var msg=''; $(function () { var $ = jQuery; var $list = $('#thelist'); WebUploader.Uploader.register({ "before-send-file":"beforeSendFile", "before-send": "beforeSend" }, { "beforeSendFile": function (file) { //上傳前校驗檔案是否已經上傳過 var deferred = WebUploader.Deferred(); $.ajax({ type:"POST", //上傳前校驗檔案上傳到第幾片 url: "checkFile", data: { seq: seq, fileMd5: $.md5(file.name + file.size + file.ext), fileName:file.name }, dataType: "json", success: function (data) { console.log(data); chunkObj = data; chunkObj.type = data.type; chunkObj.chunk == data.chunk; msg = data.msg; if(data.type==404){ deferred.reject(); $("#" + file.id).find(".state").text(data.msg); }else if (data.type == 0) { deferred.reject(); $("#" + file.id).find(".state").text("檔案已上傳"); } else if (data.type == 1) { if (data.chunk) { deferred.resolve(); } } else { deferred.resolve(); } }, error: function () { deferred.resolve(); } }) //deferred.resolve(); return deferred.promise(); }, "beforeSend": function (block) { var deferred = WebUploader.Deferred(); var curChunk = block.chunk; var totalChunk = block.chunks; console.log(chunkObj) if (chunkObj.type == "1") { if (curChunk < chunkObj.chunk) { deferred.reject(); } else { deferred.resolve(); } } else { deferred.resolve(); } return deferred.promise(); } }); var uploader = WebUploader.create({ // 選完檔案后,是否自動上傳, auto: false, // swf檔案路徑 swf: uploadswf, // 檔案接收服務端, server: server_url, // 內部根據當前運行是創建,可能是input元素,也可能是flash. pick: '#picker', chunked: true,//開始分片上傳 chunkSize:1 * 1024 * 1024,//每一片的大小 threads: 1, formData: { }, // 不壓縮image, 默認如果是jpeg,檔案上傳前會壓縮一把再上傳! resize: false }); // 當有檔案被添加進佇列的時候 uploader.on('fileQueued', function (file) { $list.append('<div id="' + file.id + '" >' + '<div ><div ></div>' + '<div ><h4 >' + file.name + '</h4>' + '<p >等待上傳...</p>' + '</div></div></div>'); }); // 檔案上傳程序中創建進度條實時顯示, uploader.on('uploadProgress', function (file, percentage) { var $li = $('#' + file.id), $percent = $li.find('.progress .progress-bar'); // 避免重復創建 if (!$percent.length) { $percent = $('<div >' + '<div role="progressbar" style="width: 0%">' + '</div>' + '</div>').appendTo($li).find('.progress-bar'); } $li.find('p.state').text('上傳中'); $percent.css('width', percentage * 100 + '%'); }); uploader.on("uploadBeforeSend", function (obj, data, headers) { var file = obj.cuted.file; data.test = 1; data.fileMd5 = $.md5(file.name + file.size + file.ext); }) // 檔案上傳成功,給item添加成功class, 用樣式標記上傳成功, uploader.on('uploadSuccess', function (file, response) { if(response.status==299){ $('#' + file.id).find('p.state').text('檔案已存在'); }else{ $('#' + file.id).find('p.state').text('已上傳'); } }); // 檔案上傳失敗,顯示上傳出錯, uploader.on('uploadError', function (file) { $('#' + file.id).find('p.state').text(msg); }); // 完成上傳完了,成功或者失敗,先洗掉進度條, uploader.on('uploadComplete', function (file) { $('#' + file.id).find('.progress').fadeOut(); }); //所有檔案上傳完畢 uploader.on("uploadFinished", function () { //提交表單 }); //開始上傳 $("#ctlBtn").click(function () { uploader.upload(); }); }); </script>
php請求后端
use app\index\controller\Upload;
public function uploadVedio() { $model =new Upload(); $res = $model->doUpload(); $model->ajaxReturn($res); }
封裝上傳類
<?php namespace app\index\controller; use think\Controller; /** * 大檔案分片上傳 */ class Upload extends Controller { private $filepath = 'uploads/'; //上傳目錄 private $blobNum; //第幾個檔案塊 private $totalBlobNum; //檔案塊總數 private $fileName; //檔案名 #允許上傳的檔案 private $allowExtension = ['mp4','avi','wmv']; #檔案后綴 private $fileExtension =''; #當前塊內容 private $nowFile = ''; #檔案大小 private $totalSize = 0; #檔案總大小只允許1G private $allowFileSize = 0; #檔案md5 前端傳過來的 用于創建臨時檔案夾 上傳完后洗掉 private $fileMd5=''; public function __construct($savePath =''){ $postData = $_POST; #測驗斷點上傳 if(isset($postData['test'])){ sleep(1); } if($savePath){ $this->filepath = $this->filepath.$savePath; } # #檔案名稱 # var_dump($postData); $postData['name'] =isset($postData['name'])?$postData['name']:''; $this->fileName =$postData['name']; if($this->isHaveFile()){ $this->ajaxReturn(['status'=>299,'msg'=>'檔案已存在!']); } $this->fileMd5 =$postData['fileMd5']; #允許檔案的大小 1G $this->allowFileSize =(1*1024*1024*1024); if((int)$postData['size']>$this->allowFileSize){ $this->ajaxReturn(['status'=>204,'msg'=>"檔案大小超1G限制!"]); } #檔案大小 $this->totalSize=$postData['size']; $postData['chunks']=isset($postData['chunks'])?(int)$postData['chunks']:1; $postData['chunk']=isset($postData['chunk'])?(int)$postData['chunk']:0; if(!(int)$postData['chunks']){ $this->ajaxReturn(['status'=>208,'msg'=>'chunks引數錯誤']); } #當前塊 $this->blobNum =$postData['chunk']+1; #總共塊 $this->totalBlobNum =$postData['chunks']; #獲取后綴 $fileExtension =explode(".",basename( $this->fileName)); $this->fileExtension=array_pop($fileExtension); #檢測后綴是否在允許范圍 $this->checkFileExtension(); $this->nowFile = $_FILES['file']; if( $this->nowFile['error'] > 0) { $msg['status'] = 502; $msg['msg'] = "檔案錯誤!"; $this->ajaxReturn($msg); } } public function doUpload(){ #臨時檔案移動到指定目錄下 $res = $this->moveFile(); if($res['status']==999){ return $this->fileMerge(); }else{ return $res; } } #創建md5 檔案名 public function createFileName(){ return $this->filepath.$this->fileName; } #檢測檔案是否重復 public function isHaveFile(){ if(file_exists($this->filepath.$this->fileName)){ return true; } return false; } #檔案合并 public function fileMerge(){ if ($this->blobNum == $this->totalBlobNum) { $fileName = $this->createFileName(); @unlink($fileName); #洗掉舊檔案 #檔案合并 檔案名以 $handle=fopen($fileName,"a+"); for($i=1; $i<= $this->totalBlobNum; $i++){ #當前分片數 $this->blobNum = $i; #吧每個塊的檔案追加到 上傳的檔案中 fwrite($handle,file_get_contents($this->createBlockFileName())); } fclose($handle); #洗掉分片 for($i=1; $i<= $this->totalBlobNum; $i++){ $this->blobNum = $i; @unlink($this->createBlockFileName()); } #洗掉臨時目錄 @rmdir($this->filepath.$this->fileMd5); if(filesize($fileName) == $this->totalSize){ $msg['status'] = 200; $msg['msg'] = '上傳成功!'; $msg['size'] = $this->totalSize; $msg['filename'] = "http://".$_SERVER['HTTP_HOST']."/".$this->createFileName(); $msg['name'] = $this->fileName; }else{ $msg['status'] = 501; $msg['msg'] = '上傳檔案大小和總大小有誤!'; @unlink($this->createFileName()); } return $msg; # $this->ajaxReturn($msg); } } #檢測上傳型別 public function checkFileExtension(){ if(!in_array(strtolower($this->fileExtension),$this->allowExtension)){ $this->ajaxReturn(['status'=>203,'msg'=>"檔案型別不允許"]); } } #將臨時檔案移動到指定目錄 public function moveFile(){ try{ #每個塊的檔案名 以檔案名的MD5作為命名 $filename=$this->createBlockFileName(); #分片檔案寫入 $handle=fopen($filename,"w+"); fwrite($handle,file_get_contents($this->nowFile ['tmp_name'])); fclose($handle); #不是最后一塊就回傳當前資訊 是最后一塊往下執行合并操作 if($this->blobNum != $this->totalBlobNum) { $msg['status'] = 201; $msg['msg'] = "上傳成功!"; $msg['blobNum'] = $this->blobNum; return $msg; #$this->ajaxReturn($msg); }else{ $msg['status'] = 999; $msg['msg'] = "上傳成功!"; $msg['blobNum'] = $this->blobNum; return $msg; } }catch (Exception $e){ $msg['status'] = 501; $msg['error'] = $e->getMessage(); return $msg; #$this->ajaxReturn($msg); } } #創建分片檔案名 public function createBlockFileName(){ $dirName = $this->filepath.$this->fileMd5."/"; if (!is_dir($dirName) ) { @mkdir($dirName, 0700); }; return $dirName.$this->blobNum.".part"; } #json格式放回處理 public function ajaxReturn($msg){ exit(json_encode($msg)); } }
——現在的努力,只為小時候吹過的牛逼! ——
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542929.html
標籤:其他
上一篇:Java微服務隨機掉線排查思路
