Hardik Sisodia
Hardik Sisodia

Reputation: 635

Validate file's extension & size before uploading

I tried to make a file uploader which can should be able to upload mimes viz.: .jpg, .jpeg, .pdf, .bmp, .png, .doc & .docx. I also make a request rule given below:

StoreFileRequest.php

public function rules()
{
    'files.*' => [
        'mimes:jpg,jpeg,pdf,bmp,png,doc,docx',
        'max:20000',
    ],
}

Controller

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);
        }
    }
}

blade

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

Inspite of the validation rule above let's suppose if I try to upload a .zip & also .rar file which are around 1GB. The file gets uploaded first which takes quite a very good time and then throws an error after validating.

My issue: I need to validate the file extension and size when the user clicks the submit button before it uploads the file to validate via validator.

Upvotes: 0

Views: 3332

Answers (3)

Donkarnash
Donkarnash

Reputation: 12835

The validation rules and and request data validation against it happens on the server once the Request data is received.

So naturally even if you try to upload 2GB file or a zip file, it will have to reach the server before it gets validated against the validation rules.

You must also implement some validation in the frontend to prevent such issues.

Say for example you can check the mime type and size of the file being uploaded on the frontend (via javascript) and only if it passes the validation here on frontend allow request to be made to the server with the uploaded file.

However never rely only on validation on the frontend. Validation at server level is must.

For example to validate file being uploaded does not exceed 20MB in size

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;
}

Function to validate mime type of the file being uploaded against allowed mime types

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;
}

Validation on Server (backend) is a MUST

Frontend validation is for better user experience and to save some unnecessary network requests

Upvotes: 1

Hammad Ahmed khan
Hammad Ahmed khan

Reputation: 1671

use something like this:

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
    }
}

use this html code to dont allow to even upload file :

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

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

Upvotes: 0

Purushottam Tiwari
Purushottam Tiwari

Reputation: 53

Why do not you use Request and call Request in controller.

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

do not use comma use OR operator to use file type

PS: 1024 in KB which is 1MB

Upvotes: 0

Related Questions