前端部分:
切割文件,然后递归上传,开始使用循环,但是循环时 不可以异步上传,分片的顺序会乱,只能同步,但是同步的时候,进度条那里就不好使了,最后改成递归异步,问题都解决了,开心;
<input id="video" type="file" name="video">
<input id="video_url" type="hidden" name="video_url" value="">
//视频分段
$("#video").change(function(){
videupload();
})
var bytesPerPiece = 1024 * 1024 * 3; // 每个文件切片大小定为3MB
var nub = 0; //进度条
var n = 0;
var start = 0; //切割 起始下标
var end = 0; //切割 结束下标
function videupload() {
var blob = document.getElementById("video").files[0];
var filesize = blob.size;
var filename = blob.name;
var totalPieces = Math.ceil(filesize / bytesPerPiece); //切片份数
var pian_num = Math.round(100 / totalPieces); //计算每片视频 进度条走的百分比
if (n < totalPieces) {
end = start + bytesPerPiece;
var chunk = blob.slice(start,end);//切割文件
start = end;
} else {
return false;
}
var formData = new FormData();
formData.append("file", chunk, filename);
formData.append("totalPieces", totalPieces);
formData.append("num", n+1);
formData.append('filename',filename);
$.ajax({
url: '/assessment/Video/fenduanUpload',
type: 'POST',
dataType: 'json',
// async:false,
data: formData,
processData: false,
contentType: false,
success:function(data){
// console.log(data)
if (data.st == "success") {
$("#video_url").val(data.data['video_url'])
$("#videochoose").addClass("selected").html(filename);
nub = 100;
} else {
nub += pian_num;
}
//进度条
$("#tiao").css('width',nub+'%');
n++;
videupload();
}
});
}
后端PHP 代码:
使用的CI4框架,先将文件上传到服务器,在进行合并,最终删除掉分片文件,
框架其实无所谓,就是上传文件那里,每个框架都封装的都不太一样 其他都没啥区别;
/*
* [视频分片上传]
*/
public function fenduanUpload() {
$video = $this->request->getFile('file');
$num = $this->request->getPost('num' , FILTER_SANITIZE_STRING); //第几个视频片段
$totalPieces = $this->request->getPost('totalPieces' , FILTER_SANITIZE_STRING); //视频片段总数
$filename = $this->request->getPost('filename' , FILTER_SANITIZE_STRING); //视频名
if ($video) {
//视频片段存放路径,没有就创建
$video_path = FCPATH . '/uploads/admin/training/video';
if (!is_dir($video_path)) {
mkdir($video_path , '0777' ,true);
}
$videoPath = 'uploads/admin/training/video/'.date('Y').'/'.date('m').'/'.date('d').'/';
//视频片段 文件名
$video_name = $filename.'_'.$num;
//异动文件到指定目录
$video->move($videoPath, $video_name);
//判断是否最后一个分片 合并分片
$path = $this->fileMerge($num,$totalPieces,$videoPath,$filename);
if ($path) {
$data['video_url'] = $path;
//删除分片文件
$this->deleteFileBlob($totalPieces,$videoPath,$filename);
return $this->showJsonMsg('success', '视频上传成功' , '' , $data);
} else {
return $this->showJsonMsg('error', '视频分片上传中');
}
}
}
/*
* [合并分片文件]
* $num 第几个文件分片
* $totalPieces 文件分片总数
* $videoPath 文件分片存放路径
* $fileName 文件分片名
* return $path 返回合并后文件路径
*/
Public function fileMerge($num , $totalPieces , $videoPath , $fileName) {
//判断是否最后一个分片文件 是就合并
if($num == $totalPieces) {
$blob = '';
//循环读取视频 分片文件
for($i=1; $i<= $totalPieces; $i++){
$blob .= file_get_contents($videoPath.$fileName.'_'.$i);
}
//将循环出的视频文件字符串 写入文件中,生成最终视频文件 LOCK_EX 标记可以防止多人同时写入
$path = $videoPath.time().$fileName;
$result = file_put_contents($path, $blob, FILE_APPEND | LOCK_EX);
if ($result) {
return $path;
}else {
return false;
}
}else{
return false;
}
}
/*
* [删除分片文件]
* $totalPieces 文件分片总数
* $videoPath 文件分片存放路径
* $fileName 文件分片名
*/
public function deleteFileBlob($totalPieces , $videoPath , $fileName) {
for($i=1; $i<= $totalPieces; $i++){
unlink($videoPath.$fileName.'_'.$i);
}
}