webupload 实现分片上传视频

前端代码,不一定适合你的项目要求,可以做一定量修改!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
var fileMd5;
//监听分块上传过程中的三个时间点
WebUploader.Uploader.register({
"before-send-file":"beforeSendFile",
"before-send":"beforeSend",
"after-send-file":"afterSendFile",
},{
//时间点1:所有分块进行上传之前调用此函数
beforeSendFile:function(file){
var deferred = WebUploader.Deferred();
//1、计算文件的唯一标记,用于断点续传
(new WebUploader.Uploader()).md5File(file)
.progress(function(percentage){
$('#item1').find("p.state").text("正在读取文件信息...");
})
.then(function(val){
fileMd5=val;
$('#item1').find("p.state").text("成功获取文件信息...");
//获取文件信息后进入下一步
deferred.resolve();
});
return deferred.promise();
},
//时间点2:如果有分块上传,则每个分块上传之前调用此函数
beforeSend:function(block){
var deferred = WebUploader.Deferred();

$.ajax({
type:"POST",
url:"uploadVideo.php",
data:{
//文件唯一标记
fileMd5:fileMd5,
//当前分块下标
chunk:block.chunk,
//当前分块大小
chunkSize:block.end-block.start ,
'option':'checkChunk',
},
dataType:"json",
success:function(response){
if(response.status == 'error'){
//分块存在,跳过
deferred.reject();
}else{
//分块不存在或不完整,重新发送该分块内容
deferred.resolve();
}
}
});

this.owner.options.formData.fileMd5 = fileMd5;
deferred.resolve();
return deferred.promise();
},
//时间点3:所有分块上传成功后调用此函数
afterSendFile:function(block){
//如果分块上传成功,则通知后台合并分块
$.ajax({
type:"POST",
url:"uploadVideo.php",
data:{
fileMd5:fileMd5,
'option':'merge',
},
success:function(response){
if (response.status == 'success') {
$('input[name=url]').val(response.data.video_path);
$('.webuploader-pick').html('视频上传成功');
$('#item1').html(' ');
} else {
layui.msg(response.msg);
}
}
});
}
});

var uploader = WebUploader.create({
// swf文件路径
swf: '/Public/webuploader/Uploader.swf',
// 文件接收服务端。
server:"uploadVideo.php",
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: {id: '#filePicker',multiple:true},
// 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
resize: true,
auto:true,
//开启分片上传
chunked: true,
chunkSize: 2 * 1024 * 1024,

accept: {
//限制上传文件为MP4
extensions:'mp4',
mimeTypes: 'video/mp4',
},
});

// 文件上传过程中创建进度条实时显示。
uploader.on( 'uploadProgress', function( file, percentage ) {
$('.webuploader-pick').html('视频正在上传中...'+Math.round(percentage * 100) + '%');
});

uploader.on( 'uploadError', function( file ) {
$('.webuploader-pick').html('视频出错了');
$('#item1').html('');

});

后端利用的是php,不一定适合你的项目,可以做修改这里只是提供思路,可到github看官方的列子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
class uploadVideo
{
//视频块的大小
//设置上传的目录
private $upload_path = './VideoTemp/';
//文件格式
private $exts = ['mp4'];
private $tem_path;
private $allow_host = '';
//视频地址
private $host = '';
//资源大小
private $size = 2;

public function __construct() {
// header('Access-Control-Allow-Origin:' . $this->allow_host);
header('Access-Control-Allow-Origin:*');//项目要求跨域,解决跨域请求
}

public function upload()
{
$data = $_POST;
//检查块是否上传
if ($data['option'] == 'checkChunk') {
$this->checkChunk();
//合并视频块
} else if ($data['option'] == 'merge') {
$this->merge();
//上传资源
} else {
$this->uploadFile();
}

}

protected function uploadFile()
{
$data = $_POST;

$file = $_FILES['file'];
//临时目录,以上传文件md5加密
$tem_path = $this->upload_path.$data['fileMd5'].'/';

//检测上传视频的格式
if (!$ext = $this->checkExt($file['name'])) {
$this->ajaxError('视频格式只能mp4');
}

//创建临时目录
if (!is_dir($tem_path)) {
mkdir($tem_path,0777,true);
}

//组装块名
$file_name = $data['fileMd5'] . '_' . $data['chunk'];
$file_name = $file_name.'.' .$ext;

//上传块
$result =move_uploaded_file($file['tmp_name'], $tem_path.$file_name);

return $result == false ? $this->ajaxError('文件上传失败') : $this->ajaxSuccess('文件上传成功');

}


private function checkExt($filename)
{
$ext = array_pop(explode('.',$filename));

return in_array($ext, $this->exts) ? $ext : false;
}

protected function checkChunk()
{
$data = $_POST;

$file_name = $data['fileMd5'] . '_' . $data['chunk'] . '.mp4';

//视频块路径
$blocks_path = $this->upload_path.$data['fileMd5'].'/';
return file_exists($blocks_path.$file_name) ? $this->ajaxError('该块已经上传过') : $this->ajaxSuccess('上传成功');
}

protected function ajaxError($msg='', $fields=array())
{
header('Content-Type:application/json; charset=utf-8');
$data = array('status'=>'error', 'msg'=>$msg, 'fields'=>$fields);
echo json_encode($data);
exit;
}
protected function ajaxSuccess($msg, $_data=array())
{
header('Content-Type:application/json; charset=utf-8');
$data = array('status'=>'success', 'msg' => $msg ,'data'=>$_data);
echo json_encode($data);
exit;
}

protected function merge()
{
$data = $_POST;

//视频块临时目录
$block_path = $this->upload_path.$data['fileMd5'].'/';

//chunks数量
$chunksArray = glob($block_path.'*.mp4');
$numbers = count($chunksArray);

//合并视频地址
$mergeFileName = $this->upload_path . $data['fileMd5'] .'.mp4';

//每次读取资源大小2M
$filezie = $this->size * 1024 * 1024;

//处理视频块地址
$fp2 = fopen($mergeFileName,"wb+");//二进制方法打开

if ( flock($fp2, LOCK_EX) ) {
for($key = 0 ; $key < $numbers ; $key++)
{
$path = $block_path . $data['fileMd5'] . '_' . $key . '.mp4';

$fp = fopen($path, "rb");

while ($buff = fread($fp, $filezie)) {
fwrite($fp2, $buff);
}

unset($buff);

fclose($fp);

}

flock($fp2, LOCK_UN);
}

fclose($fp2);

//验证视频的散列值是否一致
if (md5_file($mergeFileName) == $data['fileMd5']) {
foreach ($chunksArray as $vo) {
//删除视频块
unlink($vo);
}
//删除临时文件夹
rmdir($block_path);

$this->ajaxSuccess('视频上传成功',['video_path' => $this->host . ltrim($mergeFileName,'.')]);
} else {
$this->ajaxError('视频上传失败');
}

}
}

$uploadVideo = new uploadVideo2();

$uploadVideo->upload();