I'm using a form in Laravel 5.1 to post some text and to upload a file. It looks like this (simplified version):
{!! Form::open(array('url' => 'foo/bar')) !!}
{!! Form::text('image_name') !!}
{!! Form::file('image') !!}
{!! Form::submit('Submit!') !!}
{!! Form::close() !!}
The textfield is required, so I added a $validator
in my controller. If validation fails, the user is redirected back to the form. I use the withInput()
method to repopulate the form so that the user doesn't have to fill it in again:
if ($validator->fails()) {
return redirect()->back()->withInput();
}
This will get the old input back for textfields, dropdowns etc. But if the user has uploaded a file, the file selection is gone when validation fails and has to be selected again. Is there any way in Laravel to remember file selection as old input?
Thanks!
No, the file
input can't be prepopulated by Laravel or by any software. Your website (and any website) doesn't and shouldn't know the local path to the file. Imagine the security risks if they did! You could trick a user into uploading their SSH private key or something.
What you need to do is process the uploaded file regardless, even if there are validation errors.
Then you could either store it in your database with a pending
status, or have some unique hash
assigned to it, with a matching hash
stored in the user's session. The point is to be able to identify incomplete uploads that belong to this specific user.
Then when you display the form, retrieve those incomplete files either from the session or database, and display the thumbnail next to the file upload. This tells the user that they don't need to re-upload that file. Just make sure that they have a way to remove it as well in case they changed their mind.
Once the form is submitted correctly then clear the session hash
or update the database status to complete
; whatever you need to do.
There seems to be a lot of questions around for the same issue (Form::file: How to repopulate with Input::old After Validation Errors and/or on Update?) and everyone with apparent knowledge says that is not possible.
I would proppose a workaround that covers the following goals:
- Keep form data and file input in case of failed Laravel validation
- Use server side validation only. You
don't need SHOULD NEVER USE javascript validation.
The keyword of it all is AJAX. I would do the following:
December 2017 update: Send all fields and attached files by a single AJAX POST
- Create an AJAX form (method
GET POST) that contains everything except including file input. Remember that it requires to send the Laravel CSRF token.
- In the controller validation you need to make your responses (failed or success) to make a JSON output, so your AJAX send code can get the response in any case, and then you can show it in your browser
This way you avoid to have files in any temporal state in your server.
A more complex but improved version of this process, if you are worried about used bandwidth and you expect having errors in your input fields will be very common, you may do two (or more) AJAX POST validations: The first one with the input fields only, and if it's ok, send all fields (input fields again, now including the attached files) to attempt validation again and do actions with all data in case of success.