您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)php中怎么利用webuploader實現(xiàn)斷點續(xù)傳功能,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
webuploaderthinkphp5
斷點續(xù)傳的思路:
客戶端:
1.獲取文件md5(MD5是文件唯一標(biāo)識,用來判斷是否存在此文件,并且用作分片的文件夾名) 2.將文件分片 3.驗證分片是否上傳過,上傳過直接跳過當(dāng)前分片 3.上傳分片到md5的文件夾(保存文件名建議按分片序號來,因為分片的順序很重要) 4.最后一個分片上傳完成后發(fā)送合并分片請求并由服務(wù)器返回文件信息
服務(wù)端
1.獲取md5文件夾下的文件數(shù)量并返回用作分片驗證 2.接收文件分片并保存到文件md5的文件夾,文件名稱使用分片序號:如0.mp4,1.mp4 3.合并分片時將md5文件夾下的所有文件按文件名順序提取并寫入到最終的文件內(nèi) 4.寫入完成獲取最終文件hash并判斷是否存在,存在則返回已存在文件,刪除當(dāng)前文件,不存在則寫入數(shù)據(jù)庫并返回文件信息
大體思路是這樣,實際還要加入許多驗證,比客戶端獲取到md5后馬上要驗證文件是否存在,存在就不上傳,直接使用文件信息,不存在則上傳分片上傳前也要驗證,不過分片的跳過規(guī)則需要注意,服務(wù)器只需要返回已有的分片數(shù)量,客戶端根據(jù)已有的分片和當(dāng)前分片索引即可判斷是否應(yīng)該跳過,因為分片是按順序上傳的,如:,服務(wù)端需要注意合并的時候順序不能亂,順序亂了就無法還原源文件,所以建議用分片索引作為文件名,獲取的時候直接按0,1,2這樣獲取就行了.
并且保存時要注意保存在自定義的目錄下需要確保該目錄存在,不存在的目錄需要新建后才可以保存文件
完整代碼如下:
客戶端:
var uploader;var fileMd5;var is_upload;var totalFiles;function initWebUploader() { /***************************************************** 監(jiān)聽分塊上傳過程中的三個時間點 start ***********************************************************/ WebUploader.Uploader.register({ "before-send":"beforeSend", //每個分片上傳前 }, { //時間點2:如果有分塊上傳,則每個分塊上傳之前調(diào)用此函數(shù) beforeSend:function(block){ var deferred = WebUploader.Deferred(); if(is_upload)//跳過到開始上傳的哪一個分片時 { deferred.resolve(); }else if(totalFiles)//已經(jīng)獲取過文件數(shù)量則直接判斷是否跳過 { //當(dāng)前分片下標(biāo)小于等于目錄下的文件數(shù)量就認(rèn)為分塊存在,因為分塊上傳下標(biāo)是由小到大 if (block.chunk > totalFiles - 1) { is_upload = true; deferred.resolve(); } else { //分塊存在,跳過 deferred.reject(); } } else { $.post('/api.php/upload/checkUpload', {md5: fileMd5}, function (data) { if (data.code) { totalFiles = data.data; //當(dāng)前分片下標(biāo)小于等于目錄下的文件數(shù)量就認(rèn)為分塊存在,因為分塊上傳下標(biāo)是由小到大 if (block.chunk > data.data - 1) { is_upload = true; deferred.resolve(); } else { //分塊存在,跳過 deferred.reject(); } } else { is_upload = true; deferred.resolve(); } }); } return deferred.promise(); } }); /***************************************************** 監(jiān)聽分塊上傳過程中的三個時間點 end **************************************************************/ uploader = WebUploader.create({ // swf文件路徑 swf: '{$maccms.path}static/webupload/Uploader.swf', // 文件接收服務(wù)端。 server: '/api.php/upload/chunkUpload', // 選擇文件的按鈕??蛇x。 // 內(nèi)部根據(jù)當(dāng)前運行是創(chuàng)建,可能是input元素,也可能是flash. pick: '#name', accept: { title: 'Images', extensions: 'mp4', }, // 不壓縮image, 默認(rèn)如果是jpeg,文件上傳前會壓縮一把再上傳! resize: false, prepareNextFile:true, chunked : true, // 分片處理 chunkSize : 5 * 1024 * 1024, // 每片50M,經(jīng)過測試,發(fā)現(xiàn)上傳1G左右的視頻大概每片50M速度比較快的,太大或者太小都對上傳效率有影響 chunkRetry : false,// 如果失敗,則不重試 threads:1, formData:{guid:WebUploader.Base.guid()} }); uploader.on('fileQueued',function (file) { uploader.md5File( file,0,10*1024*1024 ) // 及時顯示進度 .progress(function(percentage) { console.log('Percentage:', percentage); $(".readFile").text("正在讀取視頻信息..."+(percentage * 100).toFixed(2) + '%'); }) // 完成 .then(function(val) { console.log('md5 result:', val); $(".readFile").text(''); fileMd5 = val; var formData = uploader.option('formData'); formData.md5 = val; uploader.option('formData',formData); //驗證文件是否存在 $.post('/api.php/upload/md5check',{md5:val},function (data) { if(data.code) { //選擇后直接上傳 uploader.upload(); $("#name .webuploader-pick").text(file.name); $(".up-state .file_name").text(file.name); var size; size = Math.round(file.size/(1024*1024),2); if(size > 1024) { size = Math.round(size/1024,2) + 'G'; }else{ size += 'M'; } $(".up-state .file_size").text(size); $('.up-in').width('0'); $('.bar').find('span').html('0%'); $('.up-con').hide(); $('.up-state').show(); $('#go').click(function () { $('.up-end').hide(); $('.up-con').show(); }) }else{ var msg = '該視頻已存在!'; alert(msg); uploader.reset(); $("#name .webuploader-pick").text(file.name); $(".up-state .file_name").text(file.name); $(".file-address input[name=vod_play_url]").val(data.data.path); $(".file-address input[name=url_id]").val(data.data.id); //獲取視頻時長,配合video標(biāo)簽 $("#duration").attr("src",data.data.path); } }); }); }); // 文件上傳過程中創(chuàng)建進度條實時顯示。 uploader.on( 'uploadProgress', function( file, percentage ) { $('.bar').find('span').html((percentage * 100).toFixed(2) + '%'); $('.up-in').width(percentage * 100 + '%'); }); uploader.on( 'uploadSuccess', function( file,res ) { //最后一塊完成時間 //全部上傳完成發(fā)送合并請求 $.post('/api.php/upload/videoUpload',{md5:fileMd5},function (data) { if(data.code) { $('.up-end').show(); $('.up-state').hide(); setTimeout(function () { $(".up-end").hide(); $('.up-con').show(); },2000); $(".file-address input[name=vod_play_url]").val(data.data.path); $(".file-address input[name=url_id]").val(data.data.id); $("#duration").attr("src",data.data.path); }else{ (".up-end h2").text('上傳出錯'); $('.up-end').show(); $('.up-state').hide(); setTimeout(function () { $(".up-end").hide(); $('.up-con').show(); },2000); } }); }); uploader.on( 'uploadError', function( file ) { $(".up-end h2").text('上傳出錯'); $('.up-end').show(); $('.up-state').hide(); setTimeout(function () { $(".up-end").hide(); $('.up-con').show(); },2000); });}
服務(wù)器:
//分片上傳function chunkUpload($name = 'file'){ $md5 = request()->param()['md5']; $object_info = request()->file($name); //保存文件的順序很重要! $object = $object_info->rule('uniqid')->move(PATH_FILE . $md5 . '/',request()->param()['chunk']); if($object) { return ['chunks'=>request()->param()['chunks'],'chunk'=>request()->param()['chunk']]; }else{ return false; }}//最終合并文件function videoUpload(){ $md5 = request()->param()['md5']; $dir = PATH_FILE . $md5; if(is_dir($dir)) { //獲取文件的順序很重要!!! $files = []; $chunk_id = 0; $chunk_file = PATH_FILE . $md5 . '/'; while (file_exists($chunk_file . $chunk_id . '.mp4')){ $files[] = $chunk_file . $chunk_id . '.mp4'; $chunk_id++; } $file_name = randomStr().'.mp4'; $path_file = date('Ymd') . SYS_DS_PROS . $file_name; //日期目錄不存在則創(chuàng)建目錄 if(!is_dir(PATH_FILE . date('Ymd'))) { mkdir(PATH_FILE . date('Ymd')); } $count = 0; foreach ($files as $v) { $_file = file_get_contents($v); $_res = file_put_contents(PATH_FILE . $path_file,$_file,FILE_APPEND); if($_res) { unlink($v); }else{ $count++; } } if($count == 0) { rmdir($dir); //檢查合并后的文件hash $_hash = hash_file('sha1', PATH_FILE . $path_file); //合并后的文件已存在則刪除已合并文件并返回已有文件信息 $file_info = $this->modelFile->getInfo(['sha1'=>$_hash],'id,name,path,sha1,guid,md5'); if(!empty($file_info)) { unlink(PATH_FILE . $path_file); return $file_info; } //合并后的文件入庫并返回 $_data = ['name' => $file_name, 'path' => $path_file, 'sha1' => $_hash,'guid'=>'','md5'=>request()->param()['md5']]; $result = $this->modelFile->addInfo($_data); $_data['id'] = $result; return $_data; }else{ $this->error = '合并文件失敗'; return false; } }else{ $this->error = '分片目錄不存在!'; return false; }}//分片驗證function checkChunk(){ $md5 = request()->param()['md5']; $dir = PATH_FILE . $md5; if(is_dir($dir)) { $files = $this->getFileByPath($dir); return count($files); }else{ return false; }}
=========================================================================最新更新:分片驗證存在bug,當(dāng)上傳分片不小心刪除了前面的分片時就導(dǎo)致無法合成文件(文件數(shù)量導(dǎo)致跳過了),因此,更新分片驗證前端:
//時間點2:如果有分塊上傳,則每個分塊上傳之前調(diào)用此函數(shù)beforeSend:function(block){ var deferred = WebUploader.Deferred(); if(is_upload)//跳過到開始上傳的哪一個分片時 { deferred.resolve(); }else if(totalFiles)//已經(jīng)獲取過文件數(shù)量則直接判斷是否跳過 { //當(dāng)前分片下標(biāo)小于等于目錄下的文件數(shù)量就認(rèn)為分塊存在,因為分塊上傳下標(biāo)是由小到大 if (!totalFiles.in_array(block.chunk)) { deferred.resolve(); } else { //分塊存在,跳過 deferred.reject(); } } else { $.post('/api.php/upload/checkUpload', {md5: fileMd5}, function (data) { if (data.code) { totalFiles = data.data; //當(dāng)前分片下標(biāo)小于等于目錄下的文件數(shù)量就認(rèn)為分塊存在,因為分塊上傳下標(biāo)是由小到大 if (!data.data.in_array(block.chunk)) { deferred.resolve(); } else { //分塊存在,跳過 deferred.reject(); } } else { is_upload = true; deferred.resolve(); } }); } return deferred.promise();
后端:
//分片驗證public function checkChunk(){ $md5 = request()->param()['md5']; $dir = PATH_FILE . $md5; if(is_dir($dir)) { $files = $this->getFileByPath($dir); foreach ($files as $k=>$v) { $file_name = explode('/',$v); $file_name = $file_name[count($file_name) - 1]; $file_index = explode('.',$file_name)[0]; $files[$k] = (int)$file_index; } return $files; }else{ return false; }}
利用文件名的有序性判斷當(dāng)前分片索引是否存在服務(wù)器判斷是否存在數(shù)組中的函數(shù):
Array.prototype.in_array = function (element) { for (var i = 0; i < this.length; i++) { if (this[i] == element) { return true; } } return false;};
以上就是php中怎么利用webuploader實現(xiàn)斷點續(xù)傳功能,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。