Failed to submit form when no file selected #180

Closed
alexius opened this Issue Mar 21, 2012 · 18 comments

Comments

Projects
None yet
7 participants
@alexius

alexius commented Mar 21, 2012

Version 2.87 worked fine until upgraded to 3.02.

Getting error "file exceeds the defined ini size" when submitting a form without file selected.
If force to use iframe than everything works fine, but thats not a solution.

I analyzed the all version until 3.02 and find out than changes in 2.90 made this error.

just commented:

//  causing errors
//  var fileAPI = feature.fileapi && feature.formdata;
var fileAPI = false;

for temporary solution

@malsup

This comment has been minimized.

Show comment
Hide comment
@malsup

malsup Mar 21, 2012

Collaborator

Which browser?

Collaborator

malsup commented Mar 21, 2012

Which browser?

@alexius

This comment has been minimized.

Show comment
Hide comment
@alexius

alexius Mar 21, 2012

last version of chrome and firefox

alexius commented Mar 21, 2012

last version of chrome and firefox

@alexius

This comment has been minimized.

Show comment
Hide comment
@alexius

alexius Mar 22, 2012

well, I've analyzed a problem a little more.
I'm using Zend Framework and zend_form for uploading files.
Zend_Validate_File_Upload throws ini error because there is no <input type="file" name="file"> submitted that is present in form object witch validates the post request.

Maybe this is more Zend Framework problem than that of jquery.form but it is much more simplier to change jquery.form than dig in Zend Framework jungle.

:)

Maybe you can offer some solution instead of

// var fileAPI = feature.fileapi && feature.formdata;
var fileAPI = false;

alexius commented Mar 22, 2012

well, I've analyzed a problem a little more.
I'm using Zend Framework and zend_form for uploading files.
Zend_Validate_File_Upload throws ini error because there is no <input type="file" name="file"> submitted that is present in form object witch validates the post request.

Maybe this is more Zend Framework problem than that of jquery.form but it is much more simplier to change jquery.form than dig in Zend Framework jungle.

:)

Maybe you can offer some solution instead of

// var fileAPI = feature.fileapi && feature.formdata;
var fileAPI = false;
@OndraM

This comment has been minimized.

Show comment
Hide comment
@OndraM

OndraM Apr 12, 2012

I'm also experiencing this issue with the new version of Form plugin (3.03), with previously used 2.82 it was OK.

When no file is selected, the plugin now don't send the form as multipart/form-data even when specified in <form>, and the $_FILES is empty in PHP, thus causing mentioned error in Zend Framework.

IMO the behavior of plugin is now not correct.

OndraM commented Apr 12, 2012

I'm also experiencing this issue with the new version of Form plugin (3.03), with previously used 2.82 it was OK.

When no file is selected, the plugin now don't send the form as multipart/form-data even when specified in <form>, and the $_FILES is empty in PHP, thus causing mentioned error in Zend Framework.

IMO the behavior of plugin is now not correct.

@malsup

This comment has been minimized.

Show comment
Hide comment
@malsup

malsup Apr 12, 2012

Collaborator

v3.08 is the latest. Can you test with that?

Collaborator

malsup commented Apr 12, 2012

v3.08 is the latest. Can you test with that?

@OndraM

This comment has been minimized.

Show comment
Hide comment
@OndraM

OndraM Apr 12, 2012

Yep, tried just now, the issue is still present there.

OndraM commented Apr 12, 2012

Yep, tried just now, the issue is still present there.

@OndraM

This comment has been minimized.

Show comment
Hide comment
@OndraM

OndraM Apr 16, 2012

Are you able to reproduce the issue? If no, I may prepare some demo to demonstrate it - if you'd like to.

OndraM commented Apr 16, 2012

Are you able to reproduce the issue? If no, I may prepare some demo to demonstrate it - if you'd like to.

malsup added a commit that referenced this issue Apr 16, 2012

@malsup

This comment has been minimized.

Show comment
Hide comment
@malsup

malsup Apr 16, 2012

Collaborator

Fixed in 3.09.

Collaborator

malsup commented Apr 16, 2012

Fixed in 3.09.

@malsup malsup closed this Apr 16, 2012

@OndraM

This comment has been minimized.

Show comment
Hide comment
@OndraM

OndraM Apr 16, 2012

I'm sorry, but the new version makes no difference with this issue.

I created a simple gist demonstrating the different behavior on ajax form and standard form with file upload: https://gist.github.com/2401014

And here is screenshot of current result: http://dl.dropbox.com/u/15226372/screenshots/jquery-form-180.png

OndraM commented Apr 16, 2012

I'm sorry, but the new version makes no difference with this issue.

I created a simple gist demonstrating the different behavior on ajax form and standard form with file upload: https://gist.github.com/2401014

And here is screenshot of current result: http://dl.dropbox.com/u/15226372/screenshots/jquery-form-180.png

@malsup

This comment has been minimized.

Show comment
Hide comment
@malsup

malsup Apr 16, 2012

Collaborator

It appears that an ajax post doesn't send the same headers for an empty file input. If you have a pull request to fix this I'd be happy to apply it.

Collaborator

malsup commented Apr 16, 2012

It appears that an ajax post doesn't send the same headers for an empty file input. If you have a pull request to fix this I'd be happy to apply it.

@OndraM

This comment has been minimized.

Show comment
Hide comment
@OndraM

OndraM Apr 16, 2012

I made a deeper investigation of the issue, and found this as some kind of limitation (or maybe feature?) of XHR level 2.

  • This problem only appear when browser is capable of fileAPI
  • When files are appended to the FormData object (formdata.append(a[i].name, a[i].value);), the value is empty string.
  • According to .append() specs: set its type to "text" if value is a string.
  • So the item is treated as a string, which causes that Content-Type: application/octet-stream is not added to the POST request as in the standard form, making the $_FILES empty in PHP.

I tried to use empty BlobBuilder object to pass the append a BLOB object, but this actually causes an upload of an empty file. Also the third parameter of FormData.append (filename), which may allow to pass "empty" file name, seems to be unimplemented in browsers yet (https://bugzilla.mozilla.org/show_bug.cgi?id=736324, https://bugzilla.mozilla.org/show_bug.cgi?id=690659...).

From my point of view, it appears as a glitch in the specification, which the browsers implements. Or maybe in the PHP, which is then unable to recognize that empty file field was send. The only workarounds I see is fallback to the iframe method (fileUploadIframe), or hack the validator in Zend From...

OndraM commented Apr 16, 2012

I made a deeper investigation of the issue, and found this as some kind of limitation (or maybe feature?) of XHR level 2.

  • This problem only appear when browser is capable of fileAPI
  • When files are appended to the FormData object (formdata.append(a[i].name, a[i].value);), the value is empty string.
  • According to .append() specs: set its type to "text" if value is a string.
  • So the item is treated as a string, which causes that Content-Type: application/octet-stream is not added to the POST request as in the standard form, making the $_FILES empty in PHP.

I tried to use empty BlobBuilder object to pass the append a BLOB object, but this actually causes an upload of an empty file. Also the third parameter of FormData.append (filename), which may allow to pass "empty" file name, seems to be unimplemented in browsers yet (https://bugzilla.mozilla.org/show_bug.cgi?id=736324, https://bugzilla.mozilla.org/show_bug.cgi?id=690659...).

From my point of view, it appears as a glitch in the specification, which the browsers implements. Or maybe in the PHP, which is then unable to recognize that empty file field was send. The only workarounds I see is fallback to the iframe method (fileUploadIframe), or hack the validator in Zend From...

OndraM added a commit to OndraM/form that referenced this issue Apr 16, 2012

@OndraM

This comment has been minimized.

Show comment
Hide comment
@OndraM

OndraM Apr 16, 2012

I've created the fallback handling and reverted the previous change in 3.09. For me it works fine now, but I'm not creating a pull request, since this may not be the cleanest solution (at least until the behavior is changed in ZF). You may of course use the commit, if you want to.

For the record, I've also created ZF issue: http://framework.zend.com/issues/browse/ZF-12159

OndraM commented Apr 16, 2012

I've created the fallback handling and reverted the previous change in 3.09. For me it works fine now, but I'm not creating a pull request, since this may not be the cleanest solution (at least until the behavior is changed in ZF). You may of course use the commit, if you want to.

For the record, I've also created ZF issue: http://framework.zend.com/issues/browse/ZF-12159

@ybart

This comment has been minimized.

Show comment
Hide comment
@ybart

ybart Dec 11, 2012

Unfortunately, this broke a form of mine 💔

When I don't upload using AJAX, the file inputs are not sent to the server. I think that the ajaxform behavior should match the browser one.

ybart commented Dec 11, 2012

Unfortunately, this broke a form of mine 💔

When I don't upload using AJAX, the file inputs are not sent to the server. I think that the ajaxform behavior should match the browser one.

@zgmnkv

This comment has been minimized.

Show comment
Hide comment
@zgmnkv

zgmnkv Mar 4, 2013

It seems that this issue is still not fully fixed.
Wrong behavior is in the line 862 (there's also a comment related to this issue on line 861)
a.push({ name: n, value: '', type: el.type });
So, jquery.form tries to send empty string when no file is selected, while native behavior is to send empty file.
As an example here's what jquery.form sends if no file was selected (from Google Chrome):

------WebKitFormBoundary5dOYNbbxTmBGyyVP
Content-Disposition: form-data; name="photo"
------WebKitFormBoundary5dOYNbbxTmBGyyVP

And what Google Chrome sends without jquery.form:

------WebKitFormBoundaryWNFAubVszG9aWqrI
Content-Disposition: form-data; name="photo"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundaryWNFAubVszG9aWqrI

So, the fix seems to be easy: set the value to empty file instead of empty string in lint 862.
But the problem is that javascript does not allow you to create a File instance, it could be only created when user selects a file with .

Instead of File object we can use Blob object, as File extends Blob with some extra fields.
See details at http://www.w3.org/TR/FileAPI/#dfn-file

I tried to simply set value to new Blob() in line 862. But behavior is still not like native:

------WebKitFormBoundaryq97MUrwUErZRon9b
Content-Disposition: form-data; name="photo"; filename="blob"
Content-Type: application/octet-stream
------WebKitFormBoundaryq97MUrwUErZRon9b

Browser sends filename="blob" when Blob object is passed to FormData.
Find details here: http://www.w3.org/TR/XMLHttpRequest/#interface-formdata

I also tried to send empty string as filename parameter to formData.append but filename in request was still 'blob'. Maybe this is browser-specific.

As a result, I still can't make ajax request be exactly the same as native browser request. But I think sending new Blob() is better than sending empty string, as it has proper Content-Type in request.

On server-side I have Java Servlet with Spring Framework, and it works wrong with empty string sended if no file selected. It works fine with new Blob(), even if filename is 'blob' instead of ''. I have a manual check if file size equals 0 and I don't process file in this case, so it doesn't matter what filename was sended.

zgmnkv commented Mar 4, 2013

It seems that this issue is still not fully fixed.
Wrong behavior is in the line 862 (there's also a comment related to this issue on line 861)
a.push({ name: n, value: '', type: el.type });
So, jquery.form tries to send empty string when no file is selected, while native behavior is to send empty file.
As an example here's what jquery.form sends if no file was selected (from Google Chrome):

------WebKitFormBoundary5dOYNbbxTmBGyyVP
Content-Disposition: form-data; name="photo"
------WebKitFormBoundary5dOYNbbxTmBGyyVP

And what Google Chrome sends without jquery.form:

------WebKitFormBoundaryWNFAubVszG9aWqrI
Content-Disposition: form-data; name="photo"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundaryWNFAubVszG9aWqrI

So, the fix seems to be easy: set the value to empty file instead of empty string in lint 862.
But the problem is that javascript does not allow you to create a File instance, it could be only created when user selects a file with .

Instead of File object we can use Blob object, as File extends Blob with some extra fields.
See details at http://www.w3.org/TR/FileAPI/#dfn-file

I tried to simply set value to new Blob() in line 862. But behavior is still not like native:

------WebKitFormBoundaryq97MUrwUErZRon9b
Content-Disposition: form-data; name="photo"; filename="blob"
Content-Type: application/octet-stream
------WebKitFormBoundaryq97MUrwUErZRon9b

Browser sends filename="blob" when Blob object is passed to FormData.
Find details here: http://www.w3.org/TR/XMLHttpRequest/#interface-formdata

I also tried to send empty string as filename parameter to formData.append but filename in request was still 'blob'. Maybe this is browser-specific.

As a result, I still can't make ajax request be exactly the same as native browser request. But I think sending new Blob() is better than sending empty string, as it has proper Content-Type in request.

On server-side I have Java Servlet with Spring Framework, and it works wrong with empty string sended if no file selected. It works fine with new Blob(), even if filename is 'blob' instead of ''. I have a manual check if file size equals 0 and I don't process file in this case, so it doesn't matter what filename was sended.

@malsup

This comment has been minimized.

Show comment
Hide comment
@malsup

malsup Mar 8, 2013

Collaborator

To work around this issue you can use the iframe: true option.

Collaborator

malsup commented Mar 8, 2013

To work around this issue you can use the iframe: true option.

@tsantos84

This comment has been minimized.

Show comment
Hide comment
@tsantos84

tsantos84 Apr 2, 2013

Just to let you know that I'm using jQuery Form 3.20 and I'm getting the same error as zagumennikov has described. I've setted the option iframe to true and worked to me, but I think this is not the best solution.

Just to let you know that I'm using jQuery Form 3.20 and I'm getting the same error as zagumennikov has described. I've setted the option iframe to true and worked to me, but I think this is not the best solution.

@ar-dia

This comment has been minimized.

Show comment
Hide comment
@ar-dia

ar-dia Dec 1, 2016

@zgmnkv actually using

    var emptyFile = new File([""], "", {type:"application/octet-stream"});
    a.push({ name: n, value: emptyFile, type: el.type });

instead of

    a.push({ name: n, value: '', type: el.type });

as suggested in malsup#449 works now in Chrome and Firefox, but does not work in IE11.
It results in filename="" on Chrome and filename="blob" on Firefox.

ar-dia commented Dec 1, 2016

@zgmnkv actually using

    var emptyFile = new File([""], "", {type:"application/octet-stream"});
    a.push({ name: n, value: emptyFile, type: el.type });

instead of

    a.push({ name: n, value: '', type: el.type });

as suggested in malsup#449 works now in Chrome and Firefox, but does not work in IE11.
It results in filename="" on Chrome and filename="blob" on Firefox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment