Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 5.3, check if uploaded file is bigger than upload_max_filesize (optional upload)

In Laravel 5.3, I'm trying to catch if an uploaded file has a bigger file size than upload_max_filesize. The upload field is not required.

I tried this method, but it doesn't work

public function checkFile($field)
{
    if (request()->hasFile($field)){ // check if field is present
        $file = request()->file($field);
        if (!$file->isValid()){ // now check if it's valid
            return back()->with('error', $file->getErrorMessage());
        }
    }
}

I can't use just if (!$file->isValid()) because file field is optional and i get a Call to a member function isValid() on null if field is empty.

So I have to check if field is present using if (request()->hasFile($field)), but this doesn't work for big files, since dd(request()->hasFile('picture')) returns false.

Of course I can rely on default Laravel Validator messages, but I get a dummy The picture failed to upload. that doesn't give any clue to the user.

like image 649
Ivan Avatar asked Nov 16 '16 16:11

Ivan


4 Answers

Laravel Validation will work only if the filesize you are uploading is less than the limit set in php.ini.

If you try to upload a file larger than the limit, PHP will not forward the request to Laravel, and will error straight away. Hence, Laravel cannot do anything in this scenario.

One way to fix this is to set a much larger limit in php.ini and then validating the file size in Laravel.

like image 58
Manan Avatar answered Oct 04 '22 19:10

Manan


You should consider using the built in Laravel form request validation system. There is a built in validation rule which lets you specify a max file size, you can check out the docs here:

https://laravel.com/docs/5.3/validation#rule-max

Your rule would look something like this:

[
    'video' => 'max:256'
]

This would fail if the file uploaded was a greater size than 256kb.

You mentioned that you didn't like Laravel's built in validation error messages. No problem! You can change them in the resources/lang/en/validation.php language file, this is the line you'd need to change:

https://github.com/laravel/laravel/blob/master/resources/lang/en/validation.php#L51

like image 35
edcs Avatar answered Oct 04 '22 21:10

edcs


My previous answer handled the case where an uploaded file was bigger than the upload_max_filesize setting in php.ini. But failed when the size of the file made the Request be larger than the post_max_size (another php.ini setting). This case is harder to handle because the inputs (the $_POST global, if we handled plain PHP) get cleared.

I think a Middleware is a good place to do this "validation":

public function handle(Request $request, Closure $next)
{
    $post_max_size = ini_get('post_max_size') * 1024 * 1024;
    $content_length = $request->server('HTTP_CONTENT_LENGTH') ?: $request->server('CONTENT_LENGTH') ?: 0;

    $response = $next($request);

    if ($content_length > $post_max_size)
    {
        return redirect()->back()->with('errors', collect([trans('validation.max.file', ['max' => 2000])]));
    }

    return $response;
}

(As I said, this won't preserve the input.)

like image 29
alepeino Avatar answered Oct 04 '22 20:10

alepeino


Server side code(In Controller):

Below function is taken from drupal by meustrus author at his stack answer and I taken here as example. Start with post_max_size

// Returns a file size limit in bytes based on the PHP upload_max_filesize
// and post_max_size
$max_size = parse_size(ini_get('post_max_size'));

// If upload_max_size is less, then reduce. Except if upload_max_size is
// zero, which indicates no limit.
$upload_max = parse_size(ini_get('upload_max_filesize'));
if ($upload_max > 0 && $upload_max < $max_size) {
  $max_size = $upload_max;
}

//Get max upload file size limit...
$file_upload_max_size = $max_size;

Public function to parse size

public function parse_size($size) {
  $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
  $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
  if ($unit) {
    // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
    return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
  }
  else {
    return round($size);
  }
}

Set compact for send 'file_upload_max_size' value to blade

return view('YOURBLADEPATH',compact('file_upload_max_size'));

JS Validation(In Blade):

<script type="text/javascript">
document.forms[0].addEventListener('submit', function( evt ) {
    var file = document.getElementById('file').files[0];

    if(file && file.size < '{$file_upload_max_size}') { // 10 MB (this size is in bytes)
        //Submit form        
    } else {
        //Prevent default and display error
        evt.preventDefault();
    }
}, false);
like image 43
AddWeb Solution Pvt Ltd Avatar answered Oct 04 '22 19:10

AddWeb Solution Pvt Ltd