上传前验证文件扩展名和大小

Posted

技术标签:

【中文标题】上传前验证文件扩展名和大小【英文标题】:Validate file's extension & size before uploading 【发布时间】:2021-03-09 06:01:37 【问题描述】:

我尝试制作一个文件上传器,它应该能够上传 mimes,即:.jpg, .jpeg, .pdf, .bmp, .png, .doc & .docx。我还提出了一个请求规则如下:

StoreFileRequest.php

public function rules()

    'files.*' => [
        'mimes:jpg,jpeg,pdf,bmp,png,doc,docx',
        'max:20000',
    ],

控制器

use App\Http\Requests\Backend\StoreFileRequest;

public function store(StoreFileRequest $request)

    if($request->hasFile('files'))
    
        foreach ($files as $file) 
            //file Mime type
            $fileMimeType=$file->getClientMimeType();

            //change filename to laravel generated name using above extention
            $filename=$file->hashName();

            //upload file
            $path=$file->storeAs('public/user-existing-health-reports/'.auth()->user()->uuid,$filename);
        
    

刀片

!! Form::file('files[]',
    array('class' => 'form-control btn btn-file ',
    'accept'=>'.jpg, .jpeg, .pdf, .bmp, .png, .doc, .docx',
    'multiple',
    'required',
    )) !!

尽管有上述验证规则,假设我尝试上传 .zip.rar 文件,这些文件位于 1GB。该文件首先被上传,这需要相当长的时间,然后在验证后抛出错误。

我的问题:我需要在用户单击提交按钮时验证文件扩展名和大小,然后再上传文件以通过验证器进行验证。

【问题讨论】:

【参考方案1】:

一旦收到请求数据,验证规则和请求数据验证就会在服务器上进行。

因此,即使您尝试上传 2GB 文件或 zip 文件,它也必须先到达服务器,然后才能根据验证规则进行验证。

您还必须在前端实现一些验证以防止此类问题。

例如,您可以在前端(通过 javascript)检查正在上传的文件的 mime 类型和大小,并且只有当它在前端通过验证时才允许使用上传的文件向服务器发出请求。

但是,永远不要只依赖前端的验证。必须在服务器级别进行验证。

例如验证上传的文件大小不超过 20MB

function isValidSize(file) 
    const errors = [];

    const maxUploadSizeInBytes = 20 * 1024 * 1024;

    let valid = true;

    if (file.size > maxUploadSizeInBytes) 

        valid = false;

        let sizeInKb = maxUploadSizeInBytes / 1024;

        let sizeForHumans = sizeInKb < 1024
            ? `$sizeInKb KB`
            : `$sizeInKb / 1024 MB`;

        this.errors.push(
            `The file exceeds the maximum allowed size of $sizeForHumans`
         );
    

    return valid;

根据允许的 mime 类型验证上传文件的 mime 类型的功能

isValidType(file) 
    const errors = [];

    let acceptedMimes = "jpg,jpeg,png,webp"
        .trim()
        .split(",")
        .map(type => `image/$type`);

    let valid = true;

    if (!acceptedMimes.includes(file.type)) 
        valid = false;

        let phrase = acceptedMimes.replace(/,/g, " or ");

        this.errors.push(
            `The file type is not allowed. Please upload $phrase file.`
        );
     

     return valid;

必须在服务器(后端)上进行验证

前端验证是为了更好的用户体验和节省一些不必要的网络请求

【讨论】:

我的想法是一样的,我可能必须使用 Javascript 来验证,但是在 Laravel 中没有其他方法可以在文件到达服务器之前在前端不使用 Javascript 来验证文件扩展名和大小? 或者无论如何我们只能先发送文件的扩展名和大小进行验证,一旦服务器响应为真,文件就会上传? 如果您不在前端进行验证,那么只有在 Laravel 可以根据规则进行验证后,包含大文件在内的数据的请求才需要到达服务器。前端验证可以节省一些网络请求并为访问者/用户提供更好的体验【参考方案2】:

为什么不在控制器中使用 Request 并调用 Request。

'files.*' => 'mimes:jpeg,jpg,png,pdf|max:1024',

不要使用逗号使用 OR 运算符来使用文件类型

PS:1024 KB,即 1MB

【讨论】:

我给出的代码是在请求中编写的,并在控制器中作为参数调用,但是每当我在选择文件后点击上传按钮时,它首先上传整个文件不在存储中,但它显示了它上传整个文件需要时间,然后验证并抛出错误 那你为什么不试试我的回答。我已经尝试过在发送请求之前验证用户。你能提供我完整的请求代码,以便我可以帮助你【参考方案3】:

使用这样的东西:

if(isset($_FILES['uploaded_file'])) 
    $errors     = array();
    $maxsize    = 2097152;
    $acceptable = array(
        'application/pdf',
        'image/jpeg',
        'image/jpg',
        'image/gif',
        'image/png'
    );

    if(($_FILES['uploaded_file']['size'] >= $maxsize) || ($_FILES["uploaded_file"]["size"] == 0)) 
        $errors[] = 'File too large. File must be less than 2 megabytes.';
    

    if((!in_array($_FILES['uploaded_file']['type'], $acceptable)) && (!empty($_FILES["uploaded_file"]["type"]))) 
        $errors[] = 'Invalid file type. Only PDF, JPG, GIF and PNG types are accepted.';
    

    if(count($errors) === 0) 
        move_uploaded_file($_FILES['uploaded_file']['tmpname'], '/store/to/location.file');
     else 
        foreach($errors as $error) 
            echo '<script>alert("'.$error.'");</script>';
        

        die(); //Ensure no more processing is done
    

使用此 html 代码甚至不允许上传文件:

<input type="file"
       id="avatar" name="avatar"
       accept="image/png, image/jpeg">

参考:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

【讨论】:

即使在这种情况下,整个 .zip 文件也会先上传,然后再验证哪个文件需要同样的时间来上传 1gb 文件 先生再次检查我的答案,我添加了一个 html 属性,甚至不允许文件上传

以上是关于上传前验证文件扩展名和大小的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在上传前同时验证文件大小和扩展名?

使用 javascript/jquery 验证文件上传 [重复]

文件上传-1

PHP 带有扩展名和大小检查的PHP文件上传

如何 Laravel 中验证 zip 压缩包里的文件?

如何 Laravel 中验证 zip 压缩包里的文件?