techn0guy's avatar

Array validation does not work if they are files

Hello,

Here is my scenario:

There is an array of file upload fields that are POST'd via the array 'color'. When there is no validation in place and I dump the request, the array is present:

  "color" => array:2 [▼
    1 => UploadedFile {#242 ▶}
    2 => UploadedFile {#259 ▶}
  ]
]

However, if I try and make the array required as seen here:

'size' => ['required'],

The validation always fails. The page always redirects and says the field is required even though it is filled. If I change the array fields to textfields the validation works perfectly. But because they are type="file" fields, for some reason the array isn't working at all. Why is this?

0 likes
21 replies
liumbiwe's avatar

I have similar validation on multiple files in my project.

'documents.*' => 'mimes:doc,pdf,txt,html,htm',

The * represents that there are one or more elements (in this case files).

Basicly you do this (for example):

'files.*' => 'file',

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

1 like
techn0guy's avatar

@liumbiwe

Doesn't that perform validation on each item in the array? I just want to validate that the array is present in the first place

prasinoulhs's avatar

You say you have a field color but you have a rule for the field size, is it a copy-paste error?

techn0guy's avatar

@prasinoulhs My mistake I didn't paste the correct part, but it is still there:

        $rules = [
            'title' => 'required|string',
            'style_id' => 'required|integer',
            'size' => ['required'],
            'size.*' => 'required|integer',
            'color' => ['required']
        ];
prasinoulhs's avatar

Strange i can validate the array correctly using your rules. Take a look at validateRequired in vendor/laravel/framework/src/Illuminate/Validation/Validator.php and see what $value is for color.

techn0guy's avatar

@prasinoulhs Is the array comprised of file upload fields? That's the issue I'm running into, if they are just plain old text fields the array validates correctly.

prasinoulhs's avatar

Yes it is.

array:4 [
  "_token" => "QJGTR3Y9kNV13IpF2sucA3YiJBSuSVVyB3C9fAwT"
  "_method" => "POST"
  "title" => "something"
  "color" => array:1 [
    0 => UploadedFile {#294 }
  ]
]
1 like
rmeza's avatar

You could try on Form Request, through each of the fields and stored in the array $rules.


foreach (range(0, count(Request::file('color')) - 1) as $index) 
{
    $rules['size.' . $index] = 'required';
}
            
return $rules;  

PD: I'm not sure if count(Request::file('color')) it's the right way to count the number of images in the Request

techn0guy's avatar

@prasinoulhs That's very odd, I'm trying with an isolated array now called "test" here is my HTML for the fields:

    <div class="form-group">
        {!! Form::label('test[1]','Test 1:', ['class' => 'control-label']) !!}
        {!! Form::file('test[1]',null,['class'=>'form-control']) !!}
    </div>
    <div class="form-group">
        {!! Form::label('test[2]','Test 2:', ['class' => 'control-label']) !!}
        {!! Form::file('test[2]',null,['class'=>'form-control']) !!}
    </div>
    public function rules()
    {
        $rules = [
            'title' => 'required|string',
            'style_id' => 'required|integer',
            'size' => ['required'],
            'size.*' => 'required|integer',
            'test' => ['required']
        ];


        return $rules;
    }

Whenever I submit it, even if I add two different files in the 'choose file' fields it still returns with 'The test field is required.'

prasinoulhs's avatar

Are you using Laravel 5.3?

Go to vendor/laravel/framework/src/Illuminate/Validation/Validator.php find the method validateRequired, put this at the top and then submit the form with a file.

if($attribute == 'test'){
    dd($attribute, $value);
}
1 like
techn0guy's avatar

@prasinoulhs

It returned

"test" null

Does that mean that there is a bigger issue at hand and my files are not even POST'ing in the first place?

prasinoulhs's avatar

Yes, something is wrong it should return an array of uploaded files.

What i would do is

  1. make sure the generated html is valid,
  2. try and save the file without validation,
  3. follow the flow of the controller and see where the input data changes, since you said you can see the uploaded files in the request.

If you can create a new Laravel installation, replicate the problem there and upload it i can take a look.

techn0guy's avatar

@prasinoulhs

The odd thing is, if I remove the validation and within my Store method try the code:

foreach($request->color as $color)
        {
            $path = $color->store('tempath');
            dd($path);
        }

The file successfully uploads and provides a path. It is as if the request completely disregards the array because it is comprised of files.

techn0guy's avatar

@prasinoulhs

And furthermore, if I change the inputs to textfields instead of files and place:

if($attribute == 'test'){
    dd($attribute, $value);
}

Inside of validateRequired just like earlier, it successfully return an array. Could this be an issue with Laravel itself?

themsaid's avatar

Hello everyone :)

Would like to help with the issue but I can't replicate, can you please share the exact laravel version along with the actual input, because I see you're validating size but the output you shared doesn't include any:

array:4 [
  "_token" => "QJGTR3Y9kNV13IpF2sucA3YiJBSuSVVyB3C9fAwT"
  "_method" => "POST"
  "title" => "something"
  "color" => array:1 [
    0 => UploadedFile {#294 }
  ]
]

Can you also share the validation error you receive?

techn0guy's avatar

@themsaid

No problem, here is my Request file:

    public function rules()
    {
        $rules = [
            'color' => ['required']
        ];
}

Here is my form, I simplified it for this example and removed all other fields.

{!! Form::open([
        'method'=>'POST', 
        'action'=>['ProductDisplaysController@store',$subdomain],
        'id' => 'product_display_form',
        'enctype' => 'multipart/form-data'
      ]) !!}
    <div class="form-group">
        {!! Form::label('color[1]','Color:', ['class' => 'control-label']) !!}
        {!! Form::file('color[1]',null,['class'=>'form-control']) !!}
    </div>
    <div class="form-group">
        {!! Form::label('color[2]','Color:', ['class' => 'control-label']) !!}
        {!! Form::file('color[2]',null,['class'=>'form-control']) !!}
    </div>

    {!! Form::submit($submitButtonText,[
        'class'=>'btn btn-success',
    ]) !!}
{!! Form::close() !!}

If I try and submit the form, it returns: 'The color field is required'. Which is essentially saying that it never received the color array in the request.

However, if I remove the validation and dump the request it displays the array:

array:2 [▼
  "_token" => "uMA0yrpog4MrtjGUhwQQFP2VNO1HZbNeqrutE3yL"
  "color" => array:2 [▼
    1 => UploadedFile {#252 ▶}
    2 => UploadedFile {#269 ▶}
  ]
]

And the crazy thing is: if I change the fields to text fields instead of file fields and submit the form it successfully validates. AKA, if I delete the fields, it returns 'The color field is required' (Stating that the array was not present) and if I fill out the textfields and submit, it dumps the request (Stating that the array field was present).

All-in-all, for some reason laravel is ignoring the array if it is comprised of file fields.

techn0guy's avatar

@prasinoulhs

Success! I cannot believe that that was the issue and I didn't figure it out sooner! Regardless, thank you for all the help. There is only one more issue I have with this:

'color' => ['required'],
'color.*' => ['required']

When there are text fields as the color array and I leave one blank, it returns an error that the second field needs to be populated. However, if there are two file fields, and there is no file uploaded on the second field it still passes validation because the array didn't include the second field as blank in the array, it excluded it completely. So what I'm saying is, how can I have the second blank file upload field pass into the array?

themsaid's avatar

That was a bug during files hydration by the validator, it's now fixed by entirely removing the hydration process and interact with both files and other input in the same manner.

Please or to participate in this conversation.