laravel 大文件分片上传

9 篇文章 0 订阅

一、PHP实现大文件上传的办法

1、因为默认会有上传大小限制,所有可以通过修改nginx和PHP的配置,来扩大限制,但是只能治标不治本,换一个环境还需要重新配置,而且很容易因为上传超时而中断

2、通过将大文件进行分片,每一片都是一个小文件,每次上传一部分到服务器,通过多次上传来完成大文件的上传功能,不会出现超时中断的问题

大文件分片上传解决的是大文件上传容易出现超时中断的问题,并不是解决上传速度的问题

该篇文章是我在已有的可以正常运行的laravel项目中新增的几个文件来实现的,如果不想自己做也可以使用laravel的开源扩展包 AetherUpload - 让 Laravel 支持超大文件断点上传

二、具体实现
1、前端代码,通过前端js代码,实现每次只上传指定大小的文件

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ajax上传文件进度条显示</title>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
    </script>
    <script type="text/javascript">
        function sendfile(){
            const LENGTH = 2*1024*1024;
            var sta=0;
            var end=sta+LENGTH;
            var blob=new Blob();

            var fd=null;

            var xhr=null;

            var pic=document.getElementsByTagName('input')[0].files[0];
            console.log(pic,1);
            var name=pic.name;
            var  totalsize=pic.size;

            var precent=null;
            while(sta<totalsize){
                blob = pic.slice(sta,end);

                fd = new FormData();
                fd.append('part',blob);
                fd.append('name',name);

                xhr=new XMLHttpRequest();
                xhr.open('POST','{{route('upload.store')}}',false);

                xhr.send(fd);
                var response = JSON.parse(xhr.responseText);
                if (response.code == '-1'){
                    alert(response.error);
                    break;
                }


                precent=100 * (end/totalsize);
                if(precent>100){
                    precent=100;
                }
                console.log(Math.round(precent)+'%');
                document.getElementById('nei').style.width=precent+'%';
                document.getElementById('precent').innerHTML=Math.floor(precent)+'%';
                sta = end;
                end = end + LENGTH;
            }
        }
    </script>
    <style>
        #wai{
            width:500px;
            height:30px;
            border:1px solid green;
        }
        #nei{
            width:0px;
            height:30px;
            background:green;
        }
    </style>
</head>
<body>
<div id="wai">
    <div id="nei"></div>
</div>
<span id="precent"></span><br/>
<input type="file" name="pic" onchange="sendfile();"/>
</body>
</html>

2、后端代码
2.1创建一个UploadContracts契约,用来约定一下接口

<?php


namespace App\Contracts;

use Illuminate\Http\Request;

interface UploadContracts
{
    /**
     * @param Request $request
     * @return mixed
     * 接收文件
     */
    public function requestFile(Request $request);

    /**
     * @return mixed
     *  文件校验的方法
     */
    public function FileCheck();

    /**
     * @return mixed
     * 判断目录是否存在
     */
    public function ExistsDir();

    /**
     * @return mixed
     * 上传文件
     */
    public function UploadFIle();
}

2.2创建一个UploadSupport,实现这个契约接口

<?php


namespace App\Support;

use App\Contracts\UploadContracts;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class UploadSupport implements UploadContracts
{
    protected $file;

    protected $fileName;

    protected $fileSize;

    protected $fileExtension;

    protected $image = [
        'png','jpeg','jpg','gif'
    ];

    protected $txt = [
        'docx','doc'.'txt','csv','pdf'
    ];

    protected $url = 'default';

    /**
     * @var 本次文件上传地址
     */
    protected $pathUrl;

    public function requestFile(Request $request)
    {
        $this->file = $request->file('part');

        $this->fileName = $request->input('name');


        $this->fileSize = $this->file->getSize();

//        $this->fileExtension = $this->file->extension();

        $this->fileExtension = substr($this->fileName,strripos($this->fileName,'.') + 1);



        return $this;
    }

    public function FileCheck()
    {
        if (in_array($this->fileExtension,$this->image)){
            $this->url = 'images';
        }

        if (in_array($this->fileExtension,$this->txt)){
            $this->url = 'document';
        }

        $this->ExistsDir();

        $this->pathUrl = Storage::path('public').'/'.$this->url.'/'.$this->fileName;

        return $this;
    }

    public function ExistsDir()
    {
        if (!is_dir(Storage::path('public').'/'.$this->url)){
            mkdir(Storage::path('public').'/'.$this->url);
        }

        return true;
    }

    public function UploadFIle()
    {
		//分片文件第一次上传,创建文件
        if (!file_exists($this->pathUrl)){

            return move_uploaded_file($this->file->path(),$this->pathUrl);
        }
		//追加分片文件到之前的文件中
        return file_put_contents($this->pathUrl,file_get_contents($this->file->path()),FILE_APPEND);

    }
}

3.3在AppServiceProvider服务提供者中注册
在这里插入图片描述
3.4创建控制器,配置路由

<?php

namespace App\Http\Controllers\Admin\V1;

use App\Contracts\UploadContracts;
use Illuminate\Http\Request;

class UploadController extends BaseAdminController
{
    public function store(Request $request,UploadContracts $uploadContracts)
    {
        $upload = $uploadContracts->requestFile($request);
        $upload->FileCheck();
        $upload->UploadFIle();

        return response()->json([
            'code' => 200,
            'info' => '上传成功'
        ]);
    }
}

路由
Route::view(‘upload’,‘upload’);

Route::post(‘UploadFile’,[\App\Http\Controllers\Admin\V1\UploadController::class,‘store’])->name(‘upload.store’)->middleware(‘upload.check’);
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值