学无先后,达者为师

网站首页 PHP其他 正文

前端Jquery搭配PHP Laravel8版本实现分片上传大文件,使用Ajax异步上传

作者:小洪帽i 更新时间: 2022-02-06 PHP其他

一、编写前端简单上传的 html 与 jquery

在 Laravel 框架的 resources/views 目录下创建:upload.blade.php 文件,下面介绍该文件的内容。

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ajax上传文件进度条显示</title>
    <script type="text/javascript">

        function sendfile(){

            const LENGTH=5*1024*1024;//定义一次上传多少 这里是 5M 一次
            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);
            var name=pic.name;
            var  totalsize=pic.size;

            var precent=null;
            while(sta<totalsize){

                blob=pic.slice(sta,end);
                xhr=new XMLHttpRequest();
                xhr.open('POST','{{ route('upload.store') }}',false);//上传的路由地址 upload.store 在下面路由创建有说明
                fd=new FormData();
                fd.append('part',blob);
                fd.append('name',name);
                xhr.send(fd);

                var response = JSON.parse(xhr.responseText);
                if (response.code == 422){
                    alert(response.error);
                    break;
                }
                precent=100 * (end/totalsize);//进度
                if(precent>=100){
                    precent=100;

                }

                console.log(Math.round(precent)+'%');//在console看进度完成率

                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" /><br/><br/>
<input type="submit" value="提交" onclick="sendfile();"/>
</body>
</html>

二、创建接口,进行约束

在 laravel 框架 app 的目录下创建:Contracts 目录以及 UploadContracts.php 接口文件;以下是接口文件内容。

<?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();

}

三、创建工具类进行接口的使用

在 laravel 框架 app 的目录下创建:Support 目录以及 UploadSupport.php 文件,下面是该文件内容。

<?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 $fileImage = [ //图片的限制
        'png','jpg','jpeg','gif'
    ];

    protected $fileTxt = [ //文件的限制
        'docx','doc','txt','csv','pdf','xlsx','xls','ppt','pptx','rtf'
    ];

    protected $url = 'default'; //如果匹配不到上面的图片后缀和文件后缀,就上传到这个目录

    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();//获取文件的拓展名

        return $this;

    }


    public function FileCheck()
    {

        //判断是否为图片
        if(in_array($this->fileExtension,$this->fileImage)){
            $this->url = 'images';
        }

        //判断是否为txt类文件
        if(in_array($this->fileExtension,$this->fileTxt)){
            $this->url = 'document';
        }

        //检测文件目录是否存在
        $this->ExistsDir();

        //上传的路径
        $this->pathUrl = Storage::path('public').'\\'.$this->url.'\\'.$this->fileName;

        //返回当前内容
        return $this;
    }


    public function ExistsDir()
    {
        //Storage 是laravel框架自带的目录类,Storage::path('public')它的目录是在:storage/app/public
        //判断目录是否存在
        if(!is_dir(Storage::path('public').'\\'.$this->url)){
            //不存在就创建
            mkdir(Storage::path('public').'\\'.$this->url);
        }
        //返回true
        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);
    }
}

四、创建 Controller 进行使用文件上传接口的功能

在 laravel 框架的 app/Http/Controllers 的目录下创建 UploadController.php 文件,下面是该文件内容。

<?php

namespace App\Http\Controllers;

use App\Contracts\UploadContracts;//引用接口文件
use Illuminate\Http\Request;//引用Request功能

class UploadController extends Controller
{
    public function store(Request $request,UploadContracts $uploadContracts){

        //把上传的文件传送到接口类里面,然后工具类里面进行校验
        $upload = $uploadContracts->requestFile($request);
        
        //文件校验
        $upload->FileCheck();
        
        //文件上传
        $upload->UploadFile();
        
        //上传后返回信息
        return response()->json([
            'code' => 200,
            'info' => '上传成功'
        ]);

    }
}

五、定义路由

laravel 框架里面不定义路由是不能访问的。路由文件:routes/web.php

<?php

use Illuminate\Support\Facades\Route;


/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

//默认路由
Route::get('/', function () {
    return view('welcome');
});

//定义的前端路由
Route::view('upload','upload');

//定义文件上传的路由 这是8版本以上的写法  any代表允许任何方式访问
Route::any('UploadFile',[ App\Http\Controllers\UploadController::class,'store'])->name('upload.store');

//name 前端使用的路由名,实则访问的路由是 UploadFile


六、跳过路由校验

为什么要跳过路由的校验呢?

因为,不跳过校验的话,会报出一个 419 的错误。

419错误解释:服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突。

跟多状态码请看这个:HTTP状态码 | 菜鸟教程

回到正题;跳过路由的中间件在:app/Http/Middleware/VerifyCsrfToken.php

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'UploadFile' //将刚才定义的路由名称加入进来,跳过检测
    ];
}

七、注册契约

如果没有注册的接口或契约的话,是无法使用的;会报出 500 的状态码。

注册文件:app/Providers/AppServiceProvider.php 

<?php

namespace App\Providers;

use App\Contracts\UploadContracts;//引入接口类
use App\Support\UploadSupport;//引入工具类
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //注册接口类
        $this->app->singleton(UploadContracts::class,UploadSupport::class);
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

到此就结束了,访问前端路径,上传一下即可。

原文链接:https://blog.csdn.net/qq_39408664/article/details/120505734

栏目分类
最近更新