php.ini里面的几个配置:
upload_max_filesize = 2M //PHP最大能接受的文件大小
post_max_size = 8M //PHP能收到的最大POST值'
memory_limit = 128M //内存上限
max_execution_time = 30 //最大执行时间
看出,如果想上传几百兆甚至几个G的文件势必会造成服务器内存资源吃光的问题,
所以我们使用webuploader,实现分片与并发结合,将一个大文件分割成多块,并发上传,也能极大提高大文件的上传速度。
1.页面中引入必要资源文件
webuploader需要的资源文件下载地址:http://fex.baidu.com/webuploader/download.html (官方站点还包括文档、API、Demo等)
video.js下载地址:https://github.com/videojs/video.js 下载后取src文件夹下的css、js即可
2.html
上传按钮及进度条部分
选择文件
视频展示部分(默认不显示),上传成功后jquery修改为display:block
form表单,上传成功后jquery将文件地址赋给input[name='videourl']的value
3.关键代码
getting-started.js
// 文件上传
jQuery(function() {
var $ = jQuery,
$list = $('#thelist'),
$btn = $('#ctlBtn'),
state = 'pending',
uploader;
var server = $('input#action').val();
var froot = $('input#froot').val();
var Uroot = $('input#Uroot').val();
uploader = WebUploader.create({
// 不压缩image
resize: false,
// swf文件路径
swf: froot + '/Admin/webuploader/Uploader.swf',
// 文件接收服务端。
server: server,
chunked:true,
// 分片大小
chunkSize:20 *1024 * 1024, //20M
//最大上传的文件数量, 总文件大小,单个文件大小(单位字节);
fileNumLimit:1,
fileSizeLimit:1000 * 1024 * 1024, //1G
fileSingleSizeLimit:1000 * 1024 * 1024, //1G
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#picker',
//只允许选择图片
accept: {
title: 'Video',
extensions: 'mp4',
mimeTypes: 'video/mp4'
},
duplicate :false //防止多次上传
});
// 当有文件添加进来的时候
uploader.on( 'fileQueued', function( file ) {
$list.append( '' +
'' + file.name + '
' +
'等待上传...
' +
'' );
});
// 文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
var $li = $( '#'+file.id ),
$percent = $li.find('.progress .progress-bar');
// 避免重复创建
if ( !$percent.length ) {
$percent = $('' +
'').appendTo( $li ).find('.progress-bar');
}
$li.find('p.state').text('上传中');
$percent.css( 'width', percentage * 100 + '%' );
$percent.css( 'height', '10px' );
$percent.css( 'margin-bottom', '20px' );
});
uploader.on( 'uploadSuccess', function( file , response) {
var fileinfojson =response._raw;//上传图片路径
var obj = new Function("return" + fileinfojson)();//转换后的JSON对象
var fileurl = obj.oldName;
$('input#videourl').val(fileurl);
$('#videobox').css('display','block');
$('video#example_video_1_html5_api').attr('src',Uroot + fileurl);
$('#sourse').attr('src',Uroot+fileurl);
$( '#'+file.id ).find('p.state').text('已上传');
$('input.webuploader-element-invisible').click(function(){
$( '#'+file.id ).find('p.state').text('');
uploader.removeFile(file);
for(var i=0;i<100;i++){
$('#' + 'WU_FILE_' + i).css('display','none');
}
})
});
uploader.on( 'uploadError', function( file ) {
$( '#'+file.id ).find('p.state').text('上传出错');
});
uploader.on( 'uploadComplete', function( file ) {
$( '#'+file.id ).find('.progress').fadeOut();
});
uploader.on( 'all', function( type ) {
if ( type === 'startUpload' ) {
state = 'uploading';
} else if ( type === 'stopUpload' ) {
state = 'paused';
} else if ( type === 'uploadFinished' ) {
state = 'done';
}
if ( state === 'uploading' ) {
$btn.text('等待上传...');
} else {
$btn.text('开始上传');
}
});
$btn.on( 'click', function() {
if ( state === 'uploading' ) {
uploader.stop();
} else {
uploader.upload();
}
});
// // 所有文件上传成功后调用
// uploader.on('uploadFinished', function () {
// //清空队列
// uploader.reset();
// });
});
' +
'
VideoUpload.class.php(官网下载已提供,仅对路径做稍作修改即可)
/**
* 大文件切片上传
*/
public function VideoUpload(){
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit; // finish preflight CORS requests here
}
if ( !empty($_REQUEST[ 'debug' ]) ) {
$random = rand(0, intval($_REQUEST[ 'debug' ]) );
if ( $random === 0 ) {
header("HTTP/1.0 500 Internal Server Error");
exit;
}
}
$dot="/";
$path=1;
$setFolder = 'Video/';
$setUserPath = makeFolderName($path) ;
$uploadDir = UPLOAD_PATH.$dot.$setFolder.$setUserPath;
$targetDir = $uploadDir.'/upload_tmp';
$cleanupTargetDir = true; // Remove old files
$maxFileAge = 5 * 3600; // Temp file age in seconds
// header("HTTP/1.0 500 Internal Server Error");
// exit;
// 5 minutes execution time
@set_time_limit(5 * 60);
// Uncomment this one to fake upload time
// usleep(5000);
// Settings
// $targetDir = ini_get("upload_tmp_dir") . DIRECTORY_SEPARATOR . "plupload";
// 验证缓存目录是否存在不存在创建
if (!file_exists($targetDir)) {
@mkdir($targetDir);
}
// 验证缓存目录是否存在不存在创建
if (!file_exists($uploadDir)) {
@mkdir($uploadDir);
}
// Get 或 file 方式获取文件名
if (isset($_REQUEST["name"])) {
$fileName = $_REQUEST["name"];
} elseif (!empty($_FILES)) {
$fileName = $_FILES["file"]["name"];
} else {
$fileName = uniqid("file_");
}
$oldName = $fileName;//记录文件原始名字
$filePath = $targetDir . $fileName;
// $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
// Chunking might be enabled
$chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
$chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
// 删除缓存校验
if ($cleanupTargetDir) {
if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory."}, "id" : "id"}');
}
while (($file = readdir($dir)) !== false) {
$tmpfilePath = $targetDir . $file;
// If temp file is current file proceed to the next
if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
continue;
}
// Remove temp file if it is older than the max age and is not the current file
if (preg_match('/\.(part|parttmp|mp4)$/', $file) && (@filemtime($tmpfilePath) < time() - $maxFileAge)) {
@unlink($tmpfilePath);
}
}
closedir($dir);
}
// 打开并写入缓存文件
if (!$out = @fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
}
if (!empty($_FILES)) {
if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file."}, "id" : "id"}');
}
// Read binary input stream and append it to temp file
if (!$in = @fopen($_FILES["file"]["tmp_name"], "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
}
} else {
if (!$in = @fopen("php://input", "rb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream."}, "id" : "id"}');
}
}
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}
@fclose($out);
@fclose($in);
rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
$index = 0;
$done = true;
for( $index = 0; $index < $chunks; $index++ ) {
if ( !file_exists("{$filePath}_{$index}.part") ) {
$done = false;
break;
}
}
//文件全部上传 执行合并文件
if ( $done ) {
$pathInfo = pathinfo($fileName);
$hashStr = substr(md5($pathInfo['basename']),8,16);
$hashName = time() . $hashStr . '.' .$pathInfo['extension'];
$uploadPath = $uploadDir .$hashName;
if (!$out = @fopen($uploadPath, "wb")) {
die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream."}, "id" : "id"}');
}
if ( flock($out, LOCK_EX) ) {
for( $index = 0; $index < $chunks; $index++ ) {
if (!$in = @fopen("{$filePath}_{$index}.part", "rb")) {
break;
}
while ($buff = fread($in, 4096)) {
fwrite($out, $buff);
}
@fclose($in);
@unlink("{$filePath}_{$index}.part");
}
flock($out, LOCK_UN);
}
@fclose($out);
/*/腾讯云--对象存储
vendor('TencentYun/TencentYunSendFile');
$Yun = new \TencentYunSendFile();
$res = $Yun->uploadYun(array('tmp_name'=>$uploadPath,'name'=>$hashName),'video');
var_dump($res);*/
//引用第三方类库
/*vendor('getid3.getid3');
$getID3 = new \getID3(); //实例化类
$ThisFileInfo = $getID3->analyze($uploadPath);//分析文件*/
$response = array(
'success'=>true,
'oldName'=>$setFolder.$setUserPath.$hashName,
//'filePaht'=>$hashName,
//'filePaht'=>substr($uploadPath,1),
'fileSuffixes'=>$pathInfo['extension'],
'time' =>$ThisFileInfo['playtime_string'],
);
//删除源文件
/*unlink($uploadPath);*/
die(json_encode($response));
}
// Return Success JSON-RPC response
die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
}
1.上传中
2.上传完成
注:
1.进度条显示加载完毕上传过程结束实际上上传失败
请检查上传的文件目录是否正确(是否存在,是否有权限),分片上传的过程中会把大文件按照定义的大小如500M文件,定义分片大小为128M,会分成4个分片文件分布上传,上传过程中可在目录中查看这些文件是否全部上传完毕。如代码正确,上传完毕后子文件会合并为大文件。
2.视频播放失败
路径路径路径,还是路径的问题,f12定位到source标签中查看src文件地址是否正确,变量是否解析等,不妨先手动写出正确地址查看视频能否正确播放再进行调试。
每日吃超过十块的盖饭都会考虑好久
却心系宇宙从哪来到哪去的普普通程序员
2018.10.11