您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關php中怎么利用webuploader實現斷點續傳功能,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
webuploaderthinkphp5
斷點續傳的思路:
客戶端:
1.獲取文件md5(MD5是文件唯一標識,用來判斷是否存在此文件,并且用作分片的文件夾名) 2.將文件分片 3.驗證分片是否上傳過,上傳過直接跳過當前分片 3.上傳分片到md5的文件夾(保存文件名建議按分片序號來,因為分片的順序很重要) 4.最后一個分片上傳完成后發送合并分片請求并由服務器返回文件信息
服務端
1.獲取md5文件夾下的文件數量并返回用作分片驗證 2.接收文件分片并保存到文件md5的文件夾,文件名稱使用分片序號:如0.mp4,1.mp4 3.合并分片時將md5文件夾下的所有文件按文件名順序提取并寫入到最終的文件內 4.寫入完成獲取最終文件hash并判斷是否存在,存在則返回已存在文件,刪除當前文件,不存在則寫入數據庫并返回文件信息
大體思路是這樣,實際還要加入許多驗證,比客戶端獲取到md5后馬上要驗證文件是否存在,存在就不上傳,直接使用文件信息,不存在則上傳分片上傳前也要驗證,不過分片的跳過規則需要注意,服務器只需要返回已有的分片數量,客戶端根據已有的分片和當前分片索引即可判斷是否應該跳過,因為分片是按順序上傳的,如:,服務端需要注意合并的時候順序不能亂,順序亂了就無法還原源文件,所以建議用分片索引作為文件名,獲取的時候直接按0,1,2這樣獲取就行了.
并且保存時要注意保存在自定義的目錄下需要確保該目錄存在,不存在的目錄需要新建后才可以保存文件
完整代碼如下:
客戶端:
var uploader;var fileMd5;var is_upload;var totalFiles;function initWebUploader() { /***************************************************** 監聽分塊上傳過程中的三個時間點 start ***********************************************************/ WebUploader.Uploader.register({ "before-send":"beforeSend", //每個分片上傳前 }, { //時間點2:如果有分塊上傳,則每個分塊上傳之前調用此函數 beforeSend:function(block){ var deferred = WebUploader.Deferred(); if(is_upload)//跳過到開始上傳的哪一個分片時 { deferred.resolve(); }else if(totalFiles)//已經獲取過文件數量則直接判斷是否跳過 { //當前分片下標小于等于目錄下的文件數量就認為分塊存在,因為分塊上傳下標是由小到大 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; //當前分片下標小于等于目錄下的文件數量就認為分塊存在,因為分塊上傳下標是由小到大 if (block.chunk > data.data - 1) { is_upload = true; deferred.resolve(); } else { //分塊存在,跳過 deferred.reject(); } } else { is_upload = true; deferred.resolve(); } }); } return deferred.promise(); } }); /***************************************************** 監聽分塊上傳過程中的三個時間點 end **************************************************************/ uploader = WebUploader.create({ // swf文件路徑 swf: '{$maccms.path}static/webupload/Uploader.swf', // 文件接收服務端。 server: '/api.php/upload/chunkUpload', // 選擇文件的按鈕。可選。 // 內部根據當前運行是創建,可能是input元素,也可能是flash. pick: '#name', accept: { title: 'Images', extensions: 'mp4', }, // 不壓縮image, 默認如果是jpeg,文件上傳前會壓縮一把再上傳! resize: false, prepareNextFile:true, chunked : true, // 分片處理 chunkSize : 5 * 1024 * 1024, // 每片50M,經過測試,發現上傳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標簽 $("#duration").attr("src",data.data.path); } }); }); }); // 文件上傳過程中創建進度條實時顯示。 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 ) { //最后一塊完成時間 //全部上傳完成發送合并請求 $.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); });}
服務器:
//分片上傳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; //日期目錄不存在則創建目錄 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,當上傳分片不小心刪除了前面的分片時就導致無法合成文件(文件數量導致跳過了),因此,更新分片驗證前端:
//時間點2:如果有分塊上傳,則每個分塊上傳之前調用此函數beforeSend:function(block){ var deferred = WebUploader.Deferred(); if(is_upload)//跳過到開始上傳的哪一個分片時 { deferred.resolve(); }else if(totalFiles)//已經獲取過文件數量則直接判斷是否跳過 { //當前分片下標小于等于目錄下的文件數量就認為分塊存在,因為分塊上傳下標是由小到大 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; //當前分片下標小于等于目錄下的文件數量就認為分塊存在,因為分塊上傳下標是由小到大 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; }}
利用文件名的有序性判斷當前分片索引是否存在服務器判斷是否存在數組中的函數:
Array.prototype.in_array = function (element) { for (var i = 0; i < this.length; i++) { if (this[i] == element) { return true; } } return false;};
以上就是php中怎么利用webuploader實現斷點續傳功能,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。