webuploader實現大檔案上傳
阿新 • • 發佈:2019-01-25
目前在公司專案裡遇到了需要上傳大檔案(視訊、音訊)的情況,特此記錄。
此次專案引用了一款名為Webuploader的外掛。官網:http://fex.baidu.com/webuploader/getting-started.html
html程式碼:
<html> <head> <meta charset="utf-8"> <script src="jquery-2.1.1.js"></script> <link rel="stylesheet" type="text/css" href="webuploader.css"> <script type="text/javascript" src="webuploader.js"></script> </head> <body> <style> .progress-bar{background-color:red} </style> <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> <script> $(function(){ var uploader = WebUploader.create({ swf: 'Uploader.swf', server: 'http://www.test.loc/webuploader/upload.php', pick: '#picker', resize: false, chunked: true //是否切片 }); var $list = $('#thelist'), state = 'pending'; uploader.on( 'fileQueued', function( file ) { $list.append( '<div id="' + file.id + '" class="item">' + '<h4 class="info">' + file.name + '</h4>' + '<p class="state">已新增...</p>' + '</div>' ); }); uploader.on( 'uploadProgress', function( file, percentage ) { var $li = $( '#'+file.id ), $percent = $li.find('.progress .progress-bar'); if ( !$percent.length ) { $percent = $('<div class="progress progress-striped active">' + '<div class="progress-bar" role="progressbar" style="width: 0%;height:30px;">' + '</div>' + '</div>').appendTo( $li ).find('.progress-bar'); } $li.find('p.state').text('上傳中'); $percent.css( 'width', percentage * 100 + '%' ); }); uploader.on( 'uploadSuccess', function( file ) { $( '#'+file.id ).find('p.state').text('已上傳'); }); uploader.on( 'uploadError', function( file ) { $( '#'+file.id ).find('p.state').text('上傳出錯'); }); uploader.on( 'uploadComplete', function( file ) { $( '#'+file.id ).find('.progress').fadeOut(); }); $('#ctlBtn').on( 'click', function() { if ( state === 'uploading' ) { uploader.stop(true); state = "pending"; } else { uploader.upload(); state = "uploading"; } }); }) </script> </body> </html>
後臺upload.php
<?php header('Access-Control-Allow-Origin:*'); header('Access-Control-Allow-Headers: X-Requested-With,X_Requested_With'); $aFiles = getUploadFiles(); saveMultiFiles($aFiles[0]); function getUploadFiles() { $aFiles = $_FILES; $aMultiFiles = array(); // 判斷是否是分片上傳 $iChunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0; $iChunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 0; foreach ($aFiles as $sKey => $mFiles) { if (is_array($mFiles['name'])) { $iCnt = count($mFiles['name']); for ($i = 0; $i < $iCnt; ++$i) { $aMultiFiles[] = array( 'key' => $sKey . '_' . $i, 'name' => $mFiles['name'][$i], 'tmp_name' => $mFiles['tmp_name'][$i], 'error' => $mFiles['error'][$i], 'size' => $mFiles['size'][$i], 'chunk' => $iChunk, 'chunks' => $iChunks, ); } } else { $aMultiFiles[] = array( 'key' => $sKey, 'name' => $mFiles['name'], 'tmp_name' => $mFiles['tmp_name'], 'error' => $mFiles['error'], 'size' => $mFiles['size'], 'chunk' => $iChunk, 'chunks' => $iChunks, ); } } return $aMultiFiles; } /** * 將臨時檔案合併成正式檔案 */ function saveMultiFiles($aFile) { $tmp_file_path = './tmp'; $p_sName = $aFile['name']; $p_sNameFilename = pathinfo($p_sName, PATHINFO_FILENAME); $p_sFilePath = $tmp_file_path.DIRECTORY_SEPARATOR.$p_sNameFilename; $p_sFilenamePath = $tmp_file_path.DIRECTORY_SEPARATOR.$p_sName; if (!file_exists($p_sFilenamePath)) { fopen($p_sFilenamePath, "w"); } $p_sTmpName = $aFile['tmp_name']; $p_iError = $aFile['error']; $p_iSize = $aFile['size']; $iChunk = $aFile['chunk'] ; $iChunks = $aFile['chunks']; $iError = 0; if ($p_iError > 0) { // 檔案上傳出錯 $iError = 1; $mReturn = '檔案上傳出錯'; break; } if (!is_uploaded_file($p_sTmpName)) { $iError = 2; $mReturn = 'upload error, use http post to upload'; break; } $oFInfo = finfo_open(); $sMimeType = finfo_file($oFInfo, $p_sTmpName, FILEINFO_MIME_TYPE); finfo_close($oFInfo); $sExtension = pathinfo($p_sName, PATHINFO_EXTENSION); if (empty($sExtension)) { $iError = 2; $mReturn = 'upload error, The file does not have an extension '; break; } if (!$in = @fopen($p_sTmpName, "rb")) { $iError = 1; $mReturn = "Failed to open input stream."; break; } if (!$out = @fopen("{$p_sFilePath}_{$iChunk}.parttmp", "wb")) { $iError = 1; $mReturn = "Failed to open output stream."; break; } while ($buff = fread($in, 4096)) { fwrite($out, $buff); } @fclose($out); @fclose($in); rename("{$p_sFilePath}_{$iChunk}.parttmp", "{$p_sFilePath}_{$iChunk}.part"); $done = true; for ($index = 0; $index < $iChunks; $index++) { if (!file_exists("{$p_sFilePath}_{$index}.part")) { $done = false; break; } } if ($done) { $sDestFile = './upload/'.time().'.'.$sExtension; //合併檔案地址 if (!$out = @fopen($sDestFile, "wb")) { $iError = 1; $mReturn = "1Failed to open output stream."; break; } $sFileSize = 0; if (flock($out, LOCK_EX)) { for ($index = 0; $index < $iChunks; $index++) { if (!$in = @fopen("{$p_sFilePath}_{$index}.part", "rb")) { break; } while ($buff = fread($in, 4096)) { fwrite($out, $buff); } @fclose($in); @unlink("{$p_sFilePath}_{$index}.part"); } flock($out, LOCK_UN); } @fclose($out); // 刪除臨時檔案 @unlink($p_sFilenamePath); } return true; }
PS:事先需設定好伺服器(nginx)和PHP的最大上傳檔案大小限制,不然會報錯