How to change Laravel Validation message for max file size in MB instead of KB?
Asked Answered
C

8

11

Laravel comes with this validation message that shows file size in kilobytes:

file' => 'The :attribute may not be greater than :max kilobytes.',

I want to customize it in a way that it shows megabytes instead of kilobytes. So for the user it would look like:

"The document may not be greater than 10 megabytes."

How can I do that?

Coverdale answered 22/12, 2015 at 10:58 Comment(4)
Keep the rule as :max kilobytes and add custom message for the control displaying the size in MB.Spancake
@PratikKaje but for 10 MB my :max is 10240. So the message will say "The document may not be greater than 10240 megabytes."Coverdale
Your rule is going to take care of max size limit which you will mention in KB. Your custom message related to the rule will be a simple text saying "attribute may not be greater than 20 MB"Spancake
Not sure I understand completely. Are you saying to hard code the size in MB within the message itself?Coverdale
K
3

You can create your own rule, and use the same logic as existing rule, but without the conversion to KB.

To do that, add a call to Validator::extend method in your AppServiceProvider.php file, like:

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('max_mb', function($attribute, $value, $parameters, $validator) {
            $this->requireParameterCount(1, $parameters, 'max_mb');

            if ($value instanceof UploadedFile && ! $value->isValid()) {
                return false;
            }

            // If call getSize()/1024/1024 on $value here it'll be numeric and not
            // get divided by 1024 once in the Validator::getSize() method.

            $megabytes = $value->getSize() / 1024 / 1024;

            return $this->getSize($attribute, $megabytes) <= $parameters[0];
        });
    }
}

Then to change the error message, you can just edit your validation lang file.

See also the section on custom validation rules in the manual

Kursk answered 22/12, 2015 at 11:30 Comment(10)
Yeah I guess extending the validator is the only right way to goCoverdale
nope... i would recommend to use the built in validation rule 'file' and just create a custom replacer for that ruleSnort
I guess that's up to the OP. Adding a rule doesn't change the functionality others may come to expect with using the framework if working in teams. That said, the above is easily changed to Validator::replacer('max', ... if that's what OP is afterKursk
You are right, that's really up to the OP's intention. The question itself states that he just wants to have the output to be shown in MB. But if the intention is to provide the max limits as MB inside the validation rules a validator extension is the only way to handle this. Maybe you could add a short hint to that in your answer ;)Snort
Hi @BenSwinburne. I've tried your solution and in my lang file i've 'custom' => [ 'file' => [ 'max' => 'The :attribute may not be greater than :max megabytes.', ], ],. But laravel doesn't convert the value to megabite. I get 10240 megabytes.Jovitta
@FokwaBest are you using Validator::extend() or Validator::replace()? If you're using extend, the rule is entitled max_mb, not max so your array key in your lang file should be max_mb, not maxKursk
Thanks @BenSwinburne. I am using Validator::extend(). I'm now getting the error Call to undefined method [requireParameterCount]. I am using laravel 5.1Jovitta
My answer is probably actually not quite right. Both references to $this in the example should likely be $validator but I can't test for you. Give it a try and let me know. I'll update my answer if that's what it should be.Kursk
@FokwaBest Validator::requireParameterCount is a protected method so you can't call it from there. Validator::getSize is protected method too. You can see my answer below for sample.Hy
Hi @BenSwinburne using $validator doesn't work either.Jovitta
S
5

We might be on different page, here is what I am trying to say. I hope this helps. Cheers!

public function rules()
{
    return [
        'file' => 'max:10240',
     ];
}

public function messages()
{
    return [
        'file.max' => 'The document may not be greater than 10 megabytes'
    ];
}
Spancake answered 22/12, 2015 at 11:22 Comment(2)
But then the message forces you to have 10 MB limit accross the entire application because it is hard coded in the string (has no :max inside). What if for Word files the limit is 5MB and for Image files the limit is 10MB?Coverdale
@PratikKaje, I don't think hardcoding limit into a custom error message is flexible. Especially when you configure maximum from configuration file.Farahfarand
H
4

File: app/Providers/AppServiceProvider.php

public function boot()
{
    Validator::extend('max_mb', function ($attribute, $value, $parameters, $validator) {

        if ($value instanceof UploadedFile && ! $value->isValid()) {
            return false;
        }

        // SplFileInfo::getSize returns filesize in bytes
        $size = $value->getSize() / 1024 / 1024;

        return $size <= $parameters[0];

    });

    Validator::replacer('max_mb', function ($message, $attribute, $rule, $parameters) {
        return str_replace(':' . $rule, $parameters[0], $message);
    });
}

Don't forget to import proper class.


File: resources/lang/en/validation.php

'max_mb' => 'The :attribute may not be greater than :max_mb MB.',

'accepted'             => 'The :attribute must be accepted.',
'active_url'           => 'The :attribute is not a valid URL.',
...

Change config('upload.max_size') accordingly.

Hy answered 22/8, 2016 at 20:4 Comment(2)
Hi @Fahmi. Your solution doesn't work either. I don't get any error but the validation in general doesn't work. Files greater than 10MB are not blocked. Besides where is upload.max_size located. The function config is used to access config values in laravel. Files in config directory and upload isn't one of those files.Jovitta
@FokwaBest upload.max_size is my custom config file so either you create the file like me, or you can just hardcode the value. Can you give your php.ini value for upload_max_filesize ? I suspect that's the culprit because Laravel will basically giving silent error if the file size is greater than upload_max_filesizeHy
K
3

You can create your own rule, and use the same logic as existing rule, but without the conversion to KB.

To do that, add a call to Validator::extend method in your AppServiceProvider.php file, like:

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('max_mb', function($attribute, $value, $parameters, $validator) {
            $this->requireParameterCount(1, $parameters, 'max_mb');

            if ($value instanceof UploadedFile && ! $value->isValid()) {
                return false;
            }

            // If call getSize()/1024/1024 on $value here it'll be numeric and not
            // get divided by 1024 once in the Validator::getSize() method.

            $megabytes = $value->getSize() / 1024 / 1024;

            return $this->getSize($attribute, $megabytes) <= $parameters[0];
        });
    }
}

Then to change the error message, you can just edit your validation lang file.

See also the section on custom validation rules in the manual

Kursk answered 22/12, 2015 at 11:30 Comment(10)
Yeah I guess extending the validator is the only right way to goCoverdale
nope... i would recommend to use the built in validation rule 'file' and just create a custom replacer for that ruleSnort
I guess that's up to the OP. Adding a rule doesn't change the functionality others may come to expect with using the framework if working in teams. That said, the above is easily changed to Validator::replacer('max', ... if that's what OP is afterKursk
You are right, that's really up to the OP's intention. The question itself states that he just wants to have the output to be shown in MB. But if the intention is to provide the max limits as MB inside the validation rules a validator extension is the only way to handle this. Maybe you could add a short hint to that in your answer ;)Snort
Hi @BenSwinburne. I've tried your solution and in my lang file i've 'custom' => [ 'file' => [ 'max' => 'The :attribute may not be greater than :max megabytes.', ], ],. But laravel doesn't convert the value to megabite. I get 10240 megabytes.Jovitta
@FokwaBest are you using Validator::extend() or Validator::replace()? If you're using extend, the rule is entitled max_mb, not max so your array key in your lang file should be max_mb, not maxKursk
Thanks @BenSwinburne. I am using Validator::extend(). I'm now getting the error Call to undefined method [requireParameterCount]. I am using laravel 5.1Jovitta
My answer is probably actually not quite right. Both references to $this in the example should likely be $validator but I can't test for you. Give it a try and let me know. I'll update my answer if that's what it should be.Kursk
@FokwaBest Validator::requireParameterCount is a protected method so you can't call it from there. Validator::getSize is protected method too. You can see my answer below for sample.Hy
Hi @BenSwinburne using $validator doesn't work either.Jovitta
F
1

This function works

public function getSize()
{
    $kb = 1024;
    $mb = $kb * 1024;
    
    if ($this->size > $mb)
        return @round($this->size / $mb, 2) . ' MB';
    return @round($this->size / $kb, 2) . ' KB';
}
Froehlich answered 23/5, 2019 at 12:7 Comment(0)
C
0

This is how I would do validation using Request with custom validation messages in MB instead of KB:

  1. Create a Request file called StoreTrackRequest.php in App\HTTP\Requests folder with the following content

    <?php
    
    namespace App\Http\Requests;
    
    use App\Http\Requests\Request;
    
    class StoreTrackRequest extends Request
    {
        /**
         * Determine if the user is authorized to make this request.
         *
         * @return bool
         */
        public function authorize()
        {
            return true;
        }
    
        /**
         * Get the validation rules that apply to the request.
         *
         * @return array
         */
        public function rules()
        {
            return [
                "name" => "required",
                "preview_file" => "required|max:10240",
                "download_file" => "required|max:10240"
            ];
        }
    
        /**
         * Get the error messages that should be displayed if validation fails.
         *
         * @return array
         */
        public function messages()
        {
            return [
                'preview_file.max' => 'The preview file may not be greater than 10 megabytes.',
                'download_file.max' => 'The download file may not be greater than 10 megabytes.'
            ];
        }
    }
    
  2. Inside the controller make sure the validation is performed through StoreTrackRequest request:

    public function store($artist_id, StoreTrackRequest $request)
    {
         // Your controller code
    }
    
Celia answered 11/3, 2016 at 23:35 Comment(1)
Sorry dear, this solution did not work for me. Thanks.Brutalize
P
0

In Laravel 8

To generate a new validation rule.

php artisan make:rule MaxSizeRule

Edit your rule as follows.

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class MaxSizeRule implements Rule
{
    private $maxSizeMb;

    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct($maxSizeMb = 8)
    {
        $this->maxSizeMb = $maxSizeMb;
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $megabytes = $value->getSize() / 1024 / 1024;

        return $megabytes < $this->maxSizeMb;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The :attribute may not be greater than ' . $this->maxSizeMb . ' MB.';
    }
}

Use in your validation request as follow

return [
    ...
    'banner_image' => ['required', 'file', 'mimes:jpeg,png,jpg,svg', new MaxSizeRule(10)],
    ...
];
Peritoneum answered 7/5, 2022 at 16:5 Comment(0)
B
0

In Laravel 11

Generate a new validation rule:

php artisan make:rule ValidateMaxFileSize

app/Rules/ValidateMaxFileSize.php

<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class ValidateMaxFileSize implements ValidationRule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct($maximumFileSize = 10)
    {
        $this->maximumFileSize = $maximumFileSize;
    }

    /**
     * Validates if file exceeds $maximumFileSize in MB
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $megabytes = $value->getSize() / 1024 / 1024;

        if($megabytes > $this->maximumFileSize) {
            $fail('validation.custom.max_file_size')->translate([
                'max' => $this->maximumFileSize
            ]);
        }
    }
}

The translation is set in lang/en/validation.php

'custom' => [
    'max_file_size' => 'The :attribute must not be greater than :max megabytes.',
]

Used in FormRequest

public function rules()
    {
        $rules['file'] = ['required', 'file', new \App\Rules\ValidateMaxFileSize(10)];
        return $rules;
    }
Baggott answered 27/6 at 14:44 Comment(0)
A
-1

Change the string in resources\lang\en\validation.php to

'file' => 'The :attribute may not be greater than 10 Megabytes.',

and define the $rule as

$rules = array(
   'file'=>'max:10000',
);
Adlar answered 22/12, 2015 at 11:6 Comment(5)
But the laravel validator for "max" calculates size in KB not in MB. laravel.com/docs/5.1/validation#rule-max laravel.com/docs/5.1/validation#rule-sizeCoverdale
@GladToHelp Ok, then you can leave the rule to 10000 kilobytes, and hardcode the error message to 10 MbAdlar
But then file upload limit hardcoded in your message that does not correspond to the value you put in :maxCoverdale
@GladToHelp The rule will be activated when file is over 10000 kb. And it will trigger the message saying that your file is over 10 Megabytes, which is true. 10 Megabytes = 10000 KilobytesAdlar
What happens if I have a different file upload control for which the max is 5MB? Will then be true?Coverdale

© 2022 - 2024 — McMap. All rights reserved.