Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kingarthur86's avatar

Multiple file upload validation

Hi guys,

I struggle with validation of my multiple file upload fields.

I have a form:

<form action="{{ route('entry-form-submit') }}" method="post" enctype="multipart/form-data">
	<input class="fileUpload @error('image.0') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.0') }}">
<input class="fileUpload @error('image.1') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.1') }}">
<input class="fileUpload @error('image.2') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.2') }}">
<input class="fileUpload @error('image.3') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.3') }}">
</form>

And validation rules within Request validation file:

$rules = [
            'image.*' => 'required|image|mimes:jpeg,png,jpg|max:10000'
];

Unfortuantely, validation always passes. Also, I noticed that 'files' are not in request's input array, but in files (which makes sense), so how Laravel validates them?

On the other hand, If I leave only one file input field and name it 'image.0' then it always fails validation (even if the file was selected):

$rules = [
            'image.0' => 'required|image|mimes:jpeg,png,jpg|max:10000'
        ];

What am I doing wrong?

0 likes
4 replies
Nakov's avatar

@kingarthur86 it will help if you share how are you validating it, not just the rules. Do you validate using the Validator Facade, or directly on the request.

Because if you use the facade you should always manually check if the validation failed or succeeded.

kingarthur86's avatar

@Nakov I validate directly in the request file:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class EntryFormRequest extends FormRequest
{
   /**
    * 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()
   {
       $parentEmail = request('parent_email');

       $rules = [
           'child_image' => 'required',
           'child_image.*' => 'image|mimes:jpeg,png,jpg|max:10000'
       ];

       return $rules;
   }

   /**
    * Get custom attributes for validator errors.
    *
    * @return array
    */
   public function attributes()
   {
   }
}

As you can see I amended the rules since I started discussion:

$rules = [
            'child_image' => 'required',
            'child_image.*' => 'image|mimes:jpeg,png,jpg|max:10000'
        ];

And it seems to partially validate now, so validation fails if no image is chosen in any of the fields. But as soon as I choose image in one of the fields then it does not fail, which is wrong, because I want to make all the file fields required, not only one.

Nakov's avatar
Nakov
Best Answer
Level 73

I believe the issue here is that the size of the array is unknown, hence you don't get any validation errors for the rest of the images.

You might be good if you send the total number of images that needs to be validated in a hidden field or something, and then iterate in your request validator and add a rule for each index.

This is what worked for me:

<form action="/testing-upload" method="post" enctype="multipart/form-data">
                    @csrf
                    <input class="fileUpload @error('image.0') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.0') }}">
                    <input class="fileUpload @error('image.1') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.1') }}">
                    <input class="fileUpload @error('image.2') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.2') }}">
                    <input class="fileUpload @error('image.3') is-invalid @enderror" name="image[]" type="file" value="{{ old('image.3') }}">

    <input type="hidden" name="images" value="4">
 <button type="submit">Submit</button>
</form>

NOTE the hidden field with total number of images expected, you can also get that dynamically if you need to.

Then in the controller:

$images = $request->input('images');

$rules = [];
for ($i = 0; $i < $images; $i++) {
    $rules['image.' . $i] = 'required|image|mimes:jpeg,png,jpg|max:10000';
}

$validate = Validator::make($request->all(), $rules);

dd($validate->fails(), $validate->errors());

You can do the same in the form request as well, instead of $request->input it will be $this->input()

And this is the result that I got from selecting only the first image:

Illuminate\Support\MessageBag {#1249 ▼
  #messages: array:3 [▼
    "image.1" => array:1 [▼
      0 => "The image.1 field is required."
    ]
    "image.2" => array:1 [▼
      0 => "The image.2 field is required."
    ]
    "image.3" => array:1 [▼
      0 => "The image.3 field is required."
    ]
  ]
  #format: ":message"
}

3 other error messages which is expected.

Please or to participate in this conversation.