简单的Hyperf实现大文件分片上传,php+js

原理:简单来说,就是将前端需要上传的大文件拆分成为无数个小文件进行循环上传,后端接受的时候进行判断,往同一个文件里面添加,代码如下:

前端 经测试原生Ajax 有上传限制44次得限制,使用Vue的axios组件时没有异常情况

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="file" onchange="addAnnex('uploadAnnex-2')"  id="uploadAnnex-2"/>
</body>
</html>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
    //上传附件,监听input框onchange时间
    function addAnnex(id) {
        var file = document.getElementById(id).files[0];
           //调用分片上传方法
        PostFile(file,0,id);
    }
    
    //执行分片上传
    function PostFile(file,i,domId,json){
        //获取上传参数
        var name = file.name,//文件名
            size = file.size,//文件大小                           
            shardSize = 1024 * 1024 * 7,//设置每个分片大小,我这是7M一个
            shardCount = Math.ceil(size / shardSize);//计算总片数
    
        //容错
        if(i >= shardCount){
            return;
        }
    
        //计算文件截取起始位置
        var start = i * shardSize;
        var end = start + shardSize;
        
        //将文件进行切片
        var packet = file.slice(start, end);
    
        //组织post表单数据
        var form = new FormData();
    
        form.append("name", name);
        form.append("file", packet); //slice方法用于切出文件的一部分
        form.append("total", shardCount); //总片数
        form.append("index", i + 1); //当前是第几片
    
        //我这用这个变量标记当前传入的是否为第一片,存在值不是第一片,需要将之前的保存的文件名及需要的信息添加之表单数据中
        if(json){
            form.append('shard_name',json.name);
            form.append('id',json.id);
        }
    
        //开始上传
        $.ajax({
            url: baseUrl,//你的url
            type: "POST",
            data: form,
            async:false,
            timeout: 10000,
            processData: false,
            contentType: false,
            success: function (json) {
                //等于200,全部上传完成
                if(json.code == 200){
                    //此处实现你上传完成的逻辑
                }else if(json.code == 201){
                    //继续上传下一片,并将返回的结果加入到数据中
                    form = '';
                    i++;
                    PostFile(file, i,domId,json.data);
                }else{
                    //出现错误
                    jqtoast(json.msg);
                }
            },
            error: function (){
            }
        });
    }
    </script>
    

后端 我使用了hyperf框架,其实原理都一样

//获取上传的文件数据
$request = $this->request;
$file = $request->file('file');

//获取post删除
$data = $request->post();

if (!$request->hasFile('file')) {
    return ['code'=>400,'msg'=>'文件不存在'];
}
if (!$request->file('file')->isValid()) {
    return ['code'=>400,'msg'=>'文件上传失败'];
}
//限制文件大小,大于100M的不允许上传
$size = $file -> getSize();
if($size / (1024*1024) > 100){
    return ['code' => 401,'msg'=>'文件太大了'];
}
// 创建上传文件夹路径
$file_path = '/mnt/Static/UploadFile/'.date('Ymd') . '/';

//判断是否传入分片文件名,不存在则表示上传第一片
if(!isset($data['shard_name'])){
    //获取文件后缀
    $ext = explode('.',$data['name']);
    $ext = array_pop($ext);

    //定义新的文件名
    $name = md5('product'.time());
    $name = substr($name,5,10).'.'.$ext;
    @mkdir($file_path,0775,true);

    //定义文件保存路径
    $path = $file_path.$name;
    $file->moveTo($path);
    //保存文件
    if(!($file->isMoved())){
        return ['code' => 400,'msg'=>'文件保存失败'];
    }

    //组织保存数据
    $result = [
        'name'          => $name,
        'src_name'      => $data['name'],
        'index'         => $data['index'],
        'total'         => $data['total'],
    ];

    $upStatus = '初次上传';
}else{
    //定义文件保存路径
    $path = $file_path.$data['shard_name'];
    // 将文件流追加写入文件
    file_put_contents($path,$file->getStream(),FILE_APPEND);
    //组织返回数据
    $result = [
        'name'      => $data['shard_name'],
        'src_name'  => $data['name'],
    ];

    $upStatus = '分片上传';
}

$arr = [
    'name'       => $data['name'],
    'size'       => $data['total'] * $file->getSize(),
    'created_at' => date('Y-m-d H:i:s'),
];

if ($data['total'] == $data['index']){
    $upStatus = '上传结束';
}

$msg = [
    '总次数' => $data['total'],
    '上传状态' => $upStatus,
    '当前次数' => '第'.$data['index'].'次',
    'time' => $arr['created_at'],
];
var_dump($msg);
//判断是否上传完毕
if($data['total'] == $data['index']){
    //上传完毕
    return ['code'=>200,'msg'=>'成功','data'=>['arr'=>$arr]];
}else{
    return ['code'=>201,'msg'=>'成功','data'=>$result];
}

上传超过2MB的文件时需要修改Hyperf框架的config/autoload/server.php的settings选项,修改限制,如下下面,将上传限制修改为10MB

Constant::OPTION_SOCKET_BUFFER_SIZE => 10 * 1024 * 1024,
Constant::OPTION_BUFFER_OUTPUT_SIZE => 10 * 1024 * 1024,
Constant::OPTION_PACKAGE_MAX_LENGTH => 10 * 1024 * 1024,
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇