Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue With Validating Multiple File Uploads #15044

Closed
KayTokyo opened this issue Aug 25, 2016 · 49 comments
Closed

Issue With Validating Multiple File Uploads #15044

KayTokyo opened this issue Aug 25, 2016 · 49 comments

Comments

@KayTokyo
Copy link

Hi,

I have a single input field for multiple uploads.

<input type="file" name="attachments[]" multiple>

I am trying to validate each file with the same set of rules.

'attachments.*'     => 'mimes:pdf,xls,doc,docx,pptx,pps,jpeg,bmp,png|max:20000',

I am having some issues with this, i hope someone could address.

  1. Although i have not set a required attribute to the validation, the input field is now required.
  2. Although i have added .xls to the acceptable mime types, im still unable to upload a .xls file (excel)
  3. I do not see any error messages for this input.

Thank you.

@fernandobandeira
Copy link
Contributor

Wich version of laravel and php are you using(excatly)?

I guess that you are on PHP7, since thats the most common one when this error occurs.

@KayTokyo
Copy link
Author

I am but actually i just updated to php 7 on this machine. I was having the same issue on an older version of php.

@ctf0
Copy link

ctf0 commented Aug 25, 2016

how do u display the error for this validation ?

@KayTokyo
Copy link
Author

Ye there maybe something wrong here?

    <div class="form-group {{ $errors->has('attachments.*') ? ' has-error' : '' }}">
                        @include('errors.validation-message', ['inputName' => 'attachments'])
                        {{$errors->first('attachments.*')}}
                        <input type="file" name="attachments[]">
                    </div>

errors.validation-message

@if ($errors->has($inputName))
    <span class="help-block">
        <strong>{{ $errors->first($inputName) }}</strong>
    </span>
@endif

But i can see them when i use

                @if($errors->any())
                    @foreach($errors->getMessages() as $this_error)
                        <p style="color: red;">{{$this_error[0]}}</p>
                    @endforeach
                @endif

@themsaid
Copy link
Member

old office documents are uploaded as application/vnd.ms-office (.doc, .xls, .ppt, etc...) based on the server configurations, to validate for an xls extension symfony expects a application/vnd.ms-excel instead, that's why your xls files won't pass.

Are you running on nginx?

@KayTokyo
Copy link
Author

Im running apache. So what mine type do i need to add to my validation rule to get .xls files working and the older ones.

@ctf0
Copy link

ctf0 commented Aug 25, 2016

@KayTokyo
Copy link
Author

KayTokyo commented Aug 25, 2016

I will try that, but any ideas why the field still throws the error The attachments.0 must be of type: pdf, xls, doc, docx, pptx, pps, jpeg, bmp, png. when the field is not required.

@ctf0
Copy link

ctf0 commented Aug 25, 2016

for validation array error msg, still no sign of how exactly to display it https://laravel.com/docs/5.3/validation#validating-arrays which already have like a couple of issues which got closed for no reason and mostly to get the error u cant use $errors->has('attachments.*') because the error array comes in numbers attachments.0, attachments.1, etc.. so u have to use ``$errors->has('attachments.0')` to get it work but again it will fail if the error is related to another index.

@KayTokyo
Copy link
Author

Yeah i saw those issues closed thats why i decided to open this.

@KayTokyo
Copy link
Author

KayTokyo commented Aug 25, 2016

@ctfo Because theres so many issues with uploading multiple files with a single input field. Do you think it could work if i dynamically add a single file input field for each upload using js and then validate each one individually ? Is that possible

@ctf0
Copy link

ctf0 commented Aug 25, 2016

u can ofcourse do so but i have also came up with a solution for displaying the array errors #13779 (comment)

@ctf0
Copy link

ctf0 commented Aug 25, 2016

as for why u r always getting the error for the upload even when its not required , maybe u can try with a single file and see if u r still getting the same or is it only related to the multi file, showing us the whole form code would be better.

@KayTokyo
Copy link
Author

I tried with a single file input, it works this issue is only with multiple file upload

@ctf0
Copy link

ctf0 commented Aug 25, 2016

r u on v5.2 or v5.3 ? if on latest downgrade to v5.2 and re-test

@KayTokyo
Copy link
Author

KayTokyo commented Aug 25, 2016

Validation

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;
use Illuminate\Support\Facades\Auth;

class CreateEventRequest extends Request
{

    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {

        return Auth::user()->role_id == 1;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {

        $rules = [
            'title'             => 'required',
            'live_link'         => 'required',
            'hero_image'        => 'required|image|mimes:jpeg,bmp,png|max:5000',
            'overview'          => 'required',
            'type'              => 'required|',
            'status'            => 'required|',
            'address_name'      => 'required_if:type,conference,',
            'address_line_1'    => 'required_if:type,conference,',
            'address_line_2'    => 'required_if:type,conference,',
            'address_city'      => 'required_if:type,conference,',
            'address_country'   => 'required_if:type,conference,',
            'address_postcode'  => 'required_if:type,conference,',
            'start_date'        => 'required|date',
            'max_users'         => 'numeric',
            'contact_telephone' => 'required',
            'contact_email'     => 'required|email',
            'attachments.*'     => 'mimes:pdf,xls,doc,docx,pptx,pps,jpeg,bmp,png|max:20000',
        ];

        return $rules;
    }

    /**
     * Get the error messages that should be displayed if validation fails.
     *
     * @return array
     */
    public function messages()
    {

        return [
            'hero_image.max' => 'The hero image cannot be greater than 5mb.',
        ];

    }
}

Html

    <div class="form-group {{ $errors->has('attachments') ? ' has-error' : '' }}">
                        @include('errors.validation-message', ['inputName' => 'attachments'])
                        <input type="file" name="attachments[]" multiple>
                    </div>
@if ($errors->has($inputName))
    <span class="help-block">
        <strong>{{ $errors->first($inputName) }}</strong>
    </span>
@endif

@KayTokyo
Copy link
Author

This issue was happening on 5.2 and is still happening on 5.3 after i upgraded

@ctf0
Copy link

ctf0 commented Aug 25, 2016

mmmmm, try to make the validation manually https://laravel.com/docs/5.3/validation#manually-creating-validators and only add the attachment to the rules array and see if the error still display.

@themsaid
Copy link
Member

We're discussing multiple issues here:

Although i have not set a required attribute to the validation, the input field is now required.

Symfony Request creates a [0 => null] as a value of an empty file input that allows multiple files, this causes the validator to fail the check of a valid file even though no files exist, but internally it thinks theres a file with value null

Although i have added .xls to the acceptable mime types, im still unable to upload a .xls file

old office documents are uploaded as application/vnd.ms-office (.doc, .xls, .ppt, etc...) based on the server configurations, to validate for an xls extension symfony expects a application/vnd.ms-excel instead, that's why your xls files won't pass.

I do not see any error messages for this input.

That's not related to multiple files in specific actually, it's related to array validation in general, which I think should be solved.

I'm going to check also on how to solve the first matter with symfony returning a null and see how this can be dealt with in laravel.

@ctf0
Copy link

ctf0 commented Aug 25, 2016

@themsaid

Symfony Request creates a [0 => null] as a value of an empty file input that allows multiple files, this causes the validator to fail the check of a valid file even though no files exist, but internally it thinks theres a file with value null

maybe u r right but i have 'photo.*' => 'sometimes|image|max:3072', which works as expected and doesn't give errors like the previously mentiond

@themsaid
Copy link
Member

That's in Laravel 5.2 yes, because null would make the field not validatable and thus pass validation. In 5.3 this behaviour has changed. Using nullable|image would make the same effect as in 5.2.

@ctf0
Copy link

ctf0 commented Aug 25, 2016

is this documented somewhere ?

EDIT:
found it , actually sometimes and nullable does the same thing, i wonder why it was even added❓

on another note, if the input is required, laravel will make this input = null if it doesn't have a value "anything that != false" so the validation stops the form which makes sense,

but sometimes means that the input will only be present in the input array if and only if its != null "or falsy value" otherwise it will be ignored so again i don't know what exactly is nullable for.

@themsaid
Copy link
Member

Check https://laravel.com/docs/5.3/upgrade under Nullable Primitives, it doesn't cover this specific case though, just a general notice that null isn't considered a valid value anymore.

@themsaid
Copy link
Member

sometimes checks for presence, nullable checks for null.

@KayTokyo
Copy link
Author

KayTokyo commented Aug 25, 2016

@themsaid

Symfony Request creates a [0 => null] as a value of an empty file input that allows multiple files, this causes the validator to fail the check of a valid file even though no files exist, but internally it thinks theres a file with value null

So this is a known bug then, i assume its being looked into? Im not sure whether i should completely change the way i upload multiple files or wait for the fix...

old office documents are uploaded as application/vnd.ms-office (.doc, .xls, .ppt, etc...) based on the server configurations, to validate for an xls extension symfony expects a application/vnd.ms-excel instead, that's why your xls files won't pass.

So here i need to use the full mimetypes instead of mimes. So application/vnd.ms-excel instead of xls, Is that right?

That's not related to multiple files in specific actually, it's related to array validation in general, which I think should be solved.

What do you mean by this, is there a fix being released? or am i outputting the error messages wrong, if so how do i properly output it.

thank you

@themsaid
Copy link
Member

  1. Use nullable|mimes:... that'll fix your issue.
  2. Use application/vnd.ms-office as the type, that'll validate it's a .xls, or .doc, or .ppt.
  3. I personally believe this needs a fix yes, will look into that sometime soon. For now you can use this workaround or similar.

@KayTokyo
Copy link
Author

KayTokyo commented Aug 26, 2016

@themsaid

Hi thank you, 1. and 2. are now fixed for me.

Number 3. My final problem is here displaying the error messages. I dont want to declare my validation in my controller just because there is so much going on. How can i integrate @ctf0 solution into my form request class.

thank you.

@themsaid
Copy link
Member

@KayTokyo please check #15063 and let me know your feedback.

@KayTokyo
Copy link
Author

KayTokyo commented Aug 26, 2016

@themsaid

Looks good and it would solve this issue for me. thank you again for your help on this.

@ctf0
Copy link

ctf0 commented Aug 26, 2016

@themsaid can u also update the docs on how to retrieve the array errors so everyone can party ?

@ctf0
Copy link

ctf0 commented Aug 26, 2016

@KayTokyo u dont need to include the validation logic in ur controller https://gist.github.com/ctf0/bb137c135b6d9383184d4deec0b24d56

@themsaid
Copy link
Member

@ctf0 working on that.

@KayTokyo
Copy link
Author

KayTokyo commented Aug 27, 2016

@themsaid

Hey i was 100% that "application/vnd.ms-office" had fixed the issue for me. But ive tested it again today and i can't seem to pass validation on any office files. Ive tried .doc and .xls. Can someone else check this for me pls

Heres my validation once again

'attachments.*'     => 'nullable|mimes:application/vnd.ms-office,pdf,jpeg,bmp,png|max:20000'

@themsaid
Copy link
Member

You need to use mimetypes instead of mimes, mimes is used with extensions.

@KayTokyo
Copy link
Author

Is it possible to use mimetypes validation alongside mime validation?

For example

'attachments.*' => 'nullable|mimetypes:application/vnd.ms-office|mimes:pdf,jpeg,bmp,png|max:20000'

Though this is returning the error.

validation.mimetypes
The attachments.0 must be a file of type: pdf, jpeg, bmp, png.

If i remove mimes and just try the validation below i still get the error validation.mimetypes. Still doesn't seem to work.

'attachments.*'     => 'nullable|mimetypes:application/vnd.ms-office|max:20000'

@themsaid
Copy link
Member

So office files won't pass with this rule?

'attachments.*'     => 'nullable|mimetypes:application/vnd.ms-office|max:20000'

@KayTokyo
Copy link
Author

KayTokyo commented Aug 27, 2016

I just double checked to make sure and with those rules, office files don't pass validation. returning the error validation.mimetypes in the view.

@KayTokyo
Copy link
Author

KayTokyo commented Aug 27, 2016

Oh weird, .xls actually passes validation but not .doc.

Edit:
Its really not consistent, i downloaded some samples and they all dont pass.

Samples i used. From google.

www.columbia.edu/~dj114/excel-examples.xls

www.ezconf.net/docs/SOLI%202008/sample.doc

www.unm.edu/~unmvclib/powerpoint/pptexamples.ppt

@KayTokyo
Copy link
Author

KayTokyo commented Aug 27, 2016

If i want to validate legacy and new Microsoft extensions i need to write them out fully like below. This will validate ppt/pptx, doc/docx, xls/xlsx.

'attachments.*'     => 'nullable|mimetypes:application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet|max:20000'

https://en.wikipedia.org/wiki/List_of_Microsoft_Office_filename_extensions
http://stackoverflow.com/questions/4212861/what-is-a-correct-mime-type-for-docx-pptx-etc

Now as much as its a pain to list those (not even included mimetypes which contain office macros/scripts). Along side this how do i add validation for mimes such as pdf/jpg/png. As its returning the error "validation.mimetypes" (this is not descriptive as to know which mimetypes are available) when selecting a pdf.

Edit: i decided to stick with just using mimetypes as i don't think you can use both mimetypes and mimes.

        'attachments.*'     => 'nullable|mimetypes:application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/pdf,image/jpeg,image/png|max:20000'

And because the error message when validating mimetypes is not descriptive ive added a custom error message.

    public function rules()
    {

        $rules = [
            'attachments.*'     => 'nullable|mimetypes:application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/pdf,image/jpeg,image/png|max:20000'
        ];

        return $rules;
    }

    /**
     * Get the error messages that should be displayed if validation fails.
     *
     * @return array
     */
    public function messages()
    {

        $messages = [
            'attachments.*.max'   => 'The attachment cannot be greater than 20mb',
            'attachments.*.mimetypes'   => 'File type must only be of type: doc,docx,ppt,pptx,xls,xlsx,pdf,jpeg,png',

        ];

        return $messages;

    }

@themsaid
Copy link
Member

@themsaid
Copy link
Member

themsaid commented Aug 27, 2016

You can write a custom validation rule to hide all this behind it, also to be able to use these rules anywhere else.

@KayTokyo
Copy link
Author

Right, also has the fix the #15063 been released?

@timgavin
Copy link

timgavin commented Sep 2, 2016

I'm having a similar problem with the upload field being required when no file is present. In my case I have a form which consists of title, body and photo[] fields. The user must fill in at least one field in order to submit the form, so using nullable doesn't work for me, as it allows for an empty form to be submitted.

If the user fills in the title or body fields they still receive the mime validation error because [0 => null]. I'm using L5.3.6

return [
    'title' => 'required_without_all:body,photo',
    'body' => 'required_without_all:title,photo',
    'price' => 'numeric',
    'photo' => 'array',
    'photo.*' => 'required_without_all:title,body|mimetypes:image/jpeg,image/png,image/gif',
];

@ctf0
Copy link

ctf0 commented Sep 2, 2016

@timgavin u should have the photo rule as

'photo.*' => 'required_without_all:title,body|mimetypes:image/jpeg,image/png,image/gif',

without the photo array one

@timgavin
Copy link

timgavin commented Sep 2, 2016

@ctfo Removing it makes no difference; still receiving the error. Plus, having 'photo' => 'array', was the only way I could get it to work with required_without_all.

@ctf0
Copy link

ctf0 commented Sep 2, 2016

if then u should put ur rules as

'photo' => 'required_without_all:title,body|array|mimetypes:image/jpeg,image/png,image/gif',

however this is just another newly introduced issue with the array validation in the 5.3. maybe @themsaid can help

@timgavin
Copy link

timgavin commented Sep 2, 2016

@ctfo Actually, doing that breaks my custom validation messages.

public function rules()
{
    return [
        ...
        'photo' => 'array',
        'photo.*' => 'required_without_all:title,body|mimetypes:image/jpeg,image/png,image/gif',
    ];
}

returns my custom error message

File can only be JPEG, GIF or PNG.

But

public function rules()
{
    return [
        ...
        'photo.*' => 'required_without_all:title,body|array|mimetypes:image/jpeg,image/png,image/gif',
    ];
}

returns

The photo.0 must be an array.

@themsaid
Copy link
Member

themsaid commented Sep 2, 2016

@timgavin proposed a fix to the issue: #15250

@timgavin
Copy link

@themsaid Confirmed; working as expected. Thanks! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants