Skip to content

Validation error message is empty on array of file #12118

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

Closed
lino10 opened this issue Feb 2, 2016 · 38 comments
Closed

Validation error message is empty on array of file #12118

lino10 opened this issue Feb 2, 2016 · 38 comments
Labels

Comments

@lino10
Copy link

lino10 commented Feb 2, 2016

Hi, after doing some testing, I think this is a bug.

I have this html

<input type="file" name="images[]">
<input type="file" name="images[]">
.
.
<input type="file" name="images[]">

Form Request's rules

'images.*' => 'mimes:jpeg',
'name' => 'required',

When the file type is not jpeg, it redirects back to the input page. So the validation works, but there's no error message. When I checked the error message bag, it is empty.

Illuminate\Support\ViewErrorBag Object ( [bags:protected] => Array ( ) ) 

I'm using Laravel Framework version 5.2.12

Might be related: #6028

@GrahamCampbell
Copy link
Member

Thanks for reporting. Ping @taylorotwell.

@ctf0
Copy link

ctf0 commented Feb 2, 2016

same here, actually anything other than required wont trigger any error, same as on old 4.2
#6649

@lino10
Copy link
Author

lino10 commented Feb 2, 2016

I have more information.

if the file validation trigerred, the 'old' field form data will be gone too.

So if I input 'name' and got wrong validation on the file, the field name will not be filled the next redirect.

@ctf0
Copy link

ctf0 commented Feb 2, 2016

@lino10 i believe thats because the image validation bug doesn't treat this as a validation error rather its more of just redirect back.

@ctf0
Copy link

ctf0 commented Feb 2, 2016

@lino10 here is a solution i used back in 4.2, give it a try and see if u have any success

if (Input::file('thumb')->getError() != 0) {
                return Redirect::back()
                    ->withInput()
                    ->withErrors(Input::file('thumb')->getErrorMessage());
            }

@lino10
Copy link
Author

lino10 commented Feb 2, 2016

@ctf0 Hi, I use the Form Request Validation method, how to implement your code using it?
https://laravel.com/docs/5.2/validation#form-request-validation

@ctf0
Copy link

ctf0 commented Feb 2, 2016

@lino10 ah yes, unfortunately that method doesn't give much of choice to customize the pipeline as u want however u can make the validation along with the rules in another class and inject it into ur store method and work on it as usual.

EDIT:
the above will only work with single file upload as with multi, it will give error if no uploaded file found.

@kkiernan
Copy link

kkiernan commented Feb 3, 2016

I am not able to recreate this issue. Form request validation on an array of files seems to work fine for me on a clean install of Laravel 5.2.12. Has this been fixed already? Maybe something else is going on?

@ctf0
Copy link

ctf0 commented Feb 4, 2016

@kkiernan do u get an actual error message (anything other than required) when u get redirected back ?

@kkiernan
Copy link

kkiernan commented Feb 4, 2016

@ctf0 Yes I get all error messages as expected. For example, if I upload a gif for the first image, this is the message bag I receive:

ViewErrorBag {#150 ▼
  #bags: array:1 [▼
    "default" => MessageBag {#151 ▼
      #messages: array:2 [▼
        "images.0" => array:1 [▼
          0 => "The images.0 must be a file of type: jpeg."
        ]
        "name" => array:1 [▼
          0 => "The name field is required."
        ]
      ]
      #format: ":message"
    }
  ]
}

@ctf0
Copy link

ctf0 commented Feb 4, 2016

@kkiernan , Ping @GrahamCampbell

right now am on 5.2.14 and i have the rules as
'photo.*' => 'required|image|min:1|max:4000|mimes:jpeg,bmp,png'
and to test i've chose a gif file with size of 4.3mb,
so i should get 2 validation errors for both the type and size, however am only getting

Validator {#252 ▼
  #translator: Translator {#114 ▶}
  #presenceVerifier: DatabasePresenceVerifier {#141 ▶}
  #container: Application {#2 ▶}
  #failedRules: array:1 [▼
    "photo.0" => array:1 [▼
      "Required" => []
    ]
  ]
  #messages: MessageBag {#253 ▼
    #messages: array:1 [▼
      "photo.0" => array:1 [▼
        0 => "The photo.0 field is required."
      ]
    ]
    #format: ":message"
  }
  #data: array:14 [▶]
  #files: array:1 [▼
    "photo.0" => UploadedFile {#30 ▼
      -test: false
      -originalName: "3o85xpXcGqIX5ALSlG.gif"
      -mimeType: "application/octet-stream"
      -size: 0
      -error: 1
      path: ""
      filename: ""
      basename: ""
      pathname: ""
      extension: ""
      realPath: "/Users/Novo/Public/www/public"
      aTime: 1970-01-01 00:00:00
      mTime: 1970-01-01 00:00:00
      cTime: 1970-01-01 00:00:00
      inode: false
      size: false
      perms: 00
      owner: false
      group: false
      type: false
      writable: false
      readable: false
      executable: false
      file: false
      dir: false
      link: false
    }
  ]
  #rules: array:1 [▼
    "photo.0" => array:5 [▼
      0 => "required"
      1 => "image"
      2 => "min:1"
      3 => "max:4000"
      4 => "mimes:jpeg,bmp,png"
    ]
  ]
  #after: []
  #customMessages: []
  #fallbackMessages: array:2 [▶]
  #customAttributes: []
  #customValues: []
  #extensions: array:2 [▶]
  #replacers: []
  #sizeRules: array:4 [▶]
  #numericRules: array:2 [▶]
  #implicitRules: array:8 [▶]
}

@lino10
Copy link
Author

lino10 commented Feb 4, 2016

I just tested using the fresh 5.2.14, there's still no error messages. So why is this issue closed?

Here's the app and resources folder, you just need to replace them to test. Just empty the name field and upload image other than gif.
http://s000.tinyupload.com/index.php?file_id=71431977644503943832

Tested using xampp and homestead

@lino10
Copy link
Author

lino10 commented Feb 4, 2016

I think I know why the error displayed for kkiernan. If you don't use enctype="multipart/form-data" on the form, the error will display.

@kkiernan
Copy link

kkiernan commented Feb 4, 2016

@lino10 No, my form does have the enctype set.

@kkiernan
Copy link

kkiernan commented Feb 4, 2016

@lino10 I just downloaded your files and they work fine for me. Hmm.

image

@kkiernan
Copy link

kkiernan commented Feb 4, 2016

@lino10 @ctf0 Ok, I am able to recreate this issue now. I had to create a new Homestead VM, and on that box I see the same thing you guys see. Weird. The Illuminate\Support\ViewErrorBag just comes back with an empty bags array. If I run the same example using php artisan serve on my host machine it works fine. How about you guys?

@ctf0
Copy link

ctf0 commented Feb 4, 2016

am having this issue through php artisan serve on local server not the vm, and i don't know what exactly should i be looking for or how to exactly debug that :(

@kkiernan
Copy link

kkiernan commented Feb 4, 2016

@ctf0 The MessageBag seems ok all the way through the failedValidation method of the Illuminate\Foundation\Http\FormRequest class. Below is the error that is logged. Do you get a similar error in your storage/logs directory?

[2016-02-04 21:40:45] local.ERROR: Exception: Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed in /home/vagrant/Code/testing/vendor/laravel/framework/src/Illuminate/Session/Store.php:262
Stack trace:
#0 /home/vagrant/Code/testing/vendor/laravel/framework/src/Illuminate/Session/Store.php(262): serialize(Array)
#1 /home/vagrant/Code/testing/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(88): Illuminate\Session\Store->save()
#2 /home/vagrant/Code/testing/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(155): Illuminate\Session\Middleware\StartSession->terminate(Object(Illuminate\Http\Request), Object(Illuminate\Http\RedirectResponse))
#3 /home/vagrant/Code/testing/public/index.php(65): Illuminate\Foundation\Http\Kernel->terminate(Object(Illuminate\Http\Request), Object(Illuminate\Http\RedirectResponse))
#4 {main}  

Update
On my setups that don't have this issue, the UploadedFile is not included in the session's old input. Curious. It seems like the withInput method of the RedirectResponse class is adding the UploadedFile to the session data even though it shouldn't.

@kkiernan
Copy link

kkiernan commented Feb 4, 2016

Potrential fix: Try replacing the withInputmethod in the Illuminate\Http\RedirectResponse class with the one below. I only added a return statement inside the conditional that checks if $value is an array. This should prevent it from executing the following line and adding the array that contains the UploadedFile object to the session which causes the eventual serialization error.

    /**
     * Flash an array of input to the session.
     *
     * @param  array  $input
     * @return $this
     */
    public function withInput(array $input = null)
    {
        $input = $input ?: $this->request->input();

        $this->session->flashInput($data = array_filter($input, $callback = function (&$value) use (&$callback) {
            if (is_array($value)) {
                $value = array_filter($value, $callback);
                return false;
            }

            return ! $value instanceof UploadedFile;
        }));

        return $this;
    }

Update
I just realized adding that return statement breaks other arrays in the form, for example, an array of text inputs. The old data for those inputs wont be added to the session. We'd need to add a bit more logic to the withInput statement or figure something else out.

@ctf0
Copy link

ctf0 commented Feb 4, 2016

@kkiernan good find, let me test and come back to u asap.

@lino10
Copy link
Author

lino10 commented Feb 5, 2016

@kkiernan Wow! That fix is working! The 'old' data is also returned successfully!
Thank you :D

Regarding your comment above I don't know if this help or not, I'm using windows 10 64 bit and tested using xampp 3.2.2, also with homestead but not using artisan serve(serving website by editing yaml file)

@kkiernan
Copy link

kkiernan commented Feb 5, 2016

@lino10 Nice! It's odd that it happens on homestead but not my host machine. I am also on Windows 10 64-bit.

I just noticed adding that return statements breaks other arrays, for example, an array of text inputs. The old data for those inputs wont be added to the session. We'd need to add a bit more logic to the withInput statement.

@ctf0
Copy link

ctf0 commented Feb 5, 2016

@kkiernan sorry to tell u that nothing changed here, still getting the same old required msg.

also i found another bug which if i uploaded a big file like a 12mb file, i get redirected back with all the inputs are gone and validation errors are showin up for all the fields except the file upload errors.

@lino10
Copy link
Author

lino10 commented Feb 5, 2016

@GrahamCampbell @taylorotwell
So is this a confirmed bug or not?
I hope that this can be reopen so it can be fixed..

@kkiernan
Maybe you can check the array using this?

instanceof UploadedFile

I'm not expert of laravel framework, just a suggestion

@kkiernan
Copy link

kkiernan commented Feb 5, 2016

@lino10 Well the array will never be an instance of UploadedFile. It's more that the array has an UploadedFile object in it that should not be included. At least that is what is happening for me on the Homestead VM.

@ctf0 Do you have any errors in your logs that you can share?

@ctf0
Copy link

ctf0 commented Feb 5, 2016

@kkiernan right now am downloading the vm to see if this is related to my machine or not, about the logging is there something like the dd() i can use to get directly to this issue ?

@kkiernan
Copy link

kkiernan commented Feb 5, 2016

@ctf0 Can you take a look in storage/logs and see if anything has been logged?

@ctf0
Copy link

ctf0 commented Feb 8, 2016

@kkiernan sorry for the long delay, let me do some tests and will come back to u with the results

@kkiernan
Copy link

kkiernan commented Feb 9, 2016

@ctf0 No problem. It's such a weird bug. I took another look with fresh eyes and the existing Laravel code seems like it should work totally fine. Really odd.

@ctf0
Copy link

ctf0 commented Feb 10, 2016

@kkiernan believe it or not actually this bug is there since 4.2 😢

@lino10
Copy link
Author

lino10 commented Feb 12, 2016

@kkiernan @ctf0
OK, I know how to 100% reproduce this.
Is there any way for @GrahamCampbell @taylorotwell to notice? It seems that after the issue is closed, the notification will not come to them? Do I need to create new issue?


So here's to reproduce:

  1. Install https://box.scotch.io/
  2. Install Laravel
  3. Replace the laravel files with http://s000.tinyupload.com/index.php?file_id=71431977644503943832
  4. Try uploading the a jpeg/png file. The error will will show that it needs gif image. So that means the bug is not there yet
  5. Update to php 7.0 -> https://www.digitalocean.com/community/tutorials/how-to-upgrade-to-php-7-on-ubuntu-14-04
  6. Try to do step Update src/Illuminate/Events/Dispatcher.php #4 again, now it will not show error

So my conclusion is, something in php 7.0 break the validation logic

@lino10
Copy link
Author

lino10 commented Feb 12, 2016

@kkiernan
I just did a bit tinkering, I think this code should fix for the empty array text.

    public function withInput(array $input = null)
    {
        $input = $input ?: $this->request->input();

        $this->session->flashInput($data = array_filter($input, $callback = function (&$value) use (&$callback) {
            if (is_array($value)) {
                $value = array_filter($value, $callback);

                if (empty($value))
                return false;
            }

            return ! $value instanceof UploadedFile;
        }));

        return $this;
    }

@ctf0
Copy link

ctf0 commented Feb 16, 2016

@lino10 @kkiernan
okay, i found a solution , it need some cleaning but it finally works, nothing changed to the withInput method though.

$validate = Validator::make($request->all(), ['photo.*'=> 'required|image|max:2048']);
$photos   = $request->file('photo');

// to make sure that we have at least one file in the photo array
if ($photos[0] != null) {
    $validate->after(function ($validate) use ($photos) {
        foreach ($photos as $photo) {
            if ($photo->getError() != 0) {
                $validate->errors()->add('photo_err', $photo->getErrorMessage());
            }
        }

    });
}

if ($validate->fails()) {
    return back()
        ->withInput()
        ->withErrors($validate);
}
now keep in mind 2 things
  • if the file failed , u will get the required error + the other error "the one that make sense"
  • if u uploaded more than one file and one of them failed, u will get the same thing as above,
    and as the file upload api doesn't hold a history of the uploaded file,
    u will have to select all the files again except the one that gave error :(.
    in that case its up to u to decide whether to cancel the whole thing as the above code does or make a condition and finish the upload.

@loursbourg
Copy link

Validator works fine for strings and other stuff, but not for files.
I use the following rules:
required|max:855|mimes:jpeg,bmp,png
I'm still facing this issue, please fix it.

@ctf0
Copy link

ctf0 commented Aug 9, 2016

@loursbourg validation works fine for single file, the issue is when u try to validate an array

@KayTokyo
Copy link

Was this issue fixed? Im still having this problem

@ctf0
Copy link

ctf0 commented Aug 25, 2016

@KayTokyo open a new issue as this is closed and no one will look into it.

@vinaysaini89
Copy link

#16113

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

No branches or pull requests

7 participants