不少项目中会遇到上传视频等大文件的业务场景;
此类业务共同点 : 传输慢 , 占用带宽;
由此就需要用另一种解决方法 分片上传;
带大家用php实现一下;
本次用到的是php框架laravel;
各种语言和框架同时适用;
语言和实现的思路是一样的;
使用laravel 还可以使用这个扩展包(AetherUpload-Laravel);
有条件的可以使用第三方七牛云,阿里云等大公司分片上传服务;
分片上传原理 :
服务端接收上传的文件片,并判断当前文件夹下的文件数据是否等于客户端分片数,如果是就合并文件,删除上传的文件块
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* @author zhouwang
* @description 分片上传
*/
public function sliceUploadMedia(Request $request)
{
try {
set_time_limit(0);
ini_set('memory_limit', '800M');
// 文件流
$file = $request->file('file');
// 当前是第几片
$blob_num = $request->post('chunkNumber', 1);
// 总共多少片
$total_blob_num = $request->post('totalChunks', 1);
// 文件名称不带文件后缀
$file_name = $request->post('filename', '');
// 上传文件唯一标识
$identifier = $request->post('identifier', '');
// 文件大小
$size = $request->post('totalSize', '');
// 获取路径信息
$pathInfo = pathinfo($file_name);
// 获取文件扩展名称
$extension = $pathInfo['extension'] ?? '';
// 获取文件名称
$file_name = $pathInfo['filename'] ?? '';
// 获取文件MD5,时间戳,时长
list($signature, $time, $video_second, $extend_name) = explode('-', $identifier);
// 校验参数
if ($blob_num <= 0)
return self::fail('请上传正确的当前片数');
if ($total_blob_num <= 0)
return self::fail('请上传分片总片数');
if (empty($file_name))
return self::fail('无效的文件名称');
if (empty($extension))
return self::fail('无效的文件后缀');
// 下载文件的本地
$directory = env('MATERIAL_ROOT') . "/file/$signature/$time/";
// 是否存在该目录 , 不存在创建目录
if (!is_dir($directory))
mkdir($directory, 0775, true);
// 判断文件在上传过程中是否出错
if (!$file->isValid())
return self::fail('上传文件错误');
// 拼接文件名称 + 文件第几片
$file_name_path = $file_name . '_' . $blob_num;
// 年月目录
$savePath = date('Ym') . '/' . date('d');
// 移动文件目录
$saveDir = getenv('MATERIAL_ROOT') . "/{$savePath}/";
// 是否存在该目录 , 不存在创建目录
if (!is_dir($saveDir))
mkdir($saveDir, 0777, true);
// 判断是否存在文件名称
$path = env('MATERIAL_ROOT') . "/{$savePath}/" . $file_name . '.' . $extend_name;
// 移动文件
$result = move_uploaded_file($file->getRealPath(), $directory . $file_name_path);
// 并发请求判断文件夹下面的文件数量是否等于分片数量
if (getFileNumber($directory) == $total_blob_num) {
$dirName = $directory . $file_name;
// 循环合并
for ($i = 1; $i <= $total_blob_num; $i++) {
// 读取文件流
$blob = file_get_contents($dirName . '_' . $i);
// 文件合并
file_put_contents($path, $blob, FILE_APPEND);
}
// 删除文件
for($i=1;$i<=$total_blob_num;$i++){
// 合并完删除文件块
@unlink($directory . $file_name . '_' .$i);
}
// 远程路径
$url = strtr($path, [env('MATERIAL_ROOT') => env('MATERIAL_URL')]);
// 返回成功
return self::success(compact('size', 'extend_name', 'path', 'video_second', 'width', 'height', 'file_name', 'url', 'signature'));
}
// 判断返回值
if ($result)
return self::success([], '上传成功');
return self::fail('上传失败');
} catch (\Exception $exception) {
return self::fail('服务器正在开小差');
}
}
至此关于分片上传简单实现Demo已经说完;
大致应该了解怎么实现分片上传了吧;
希望对大家有帮助;
因为大文件上传现实中经常遇到的事情;
本文为史大坨原创文章,转载无需和我联系,但请注明来自史大坨博客https://www.shidatuos.cn