file_save_upload() not notifying user when PHP upload limit is exceeded.
rgladwell - September 6, 2005 - 18:41
| Project: | Drupal |
| Version: | 6.x-dev |
| Component: | file system |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs work |
| Issue tags: | File API |
Description
The upload.module returns without error when it fails to upload a file that exceeds the php.ini upload size limit. The upload.module should report an error on the attachment screen that upload failed.

#1
Confirmed. It's still a bug.
#2
Still a bug in the latest 4.7. I was just looking at php.net and saw that...
I think the upload creates an invisible IFRAME or something to that effect. So maybe we should check to see if a $_GET var is set, if not we should return an error saying the file exceeded the PHP configuration limits.
Regardless, what is happening now is users are uploading files that are too large and the upload form is just returning blank. Meaning if you have a file uploaded already, and try to upload another that is too large, it will fail and remove the existing file from the list.
#3
Confirmed.
1. when uploads a file larger than PHP limit it fails without a message
2. when uploads a file larger than PHP limit, it removes the already uploaded files
#4
I can confirm this bug in 5.1
This has been open since 4.6, could somebody please look into it.
#5
Moving to 6.x-dev. Hope I get some time to work on my old issues before the freeze...Anyone have any ideas on this?
#6
Check out related issue: http://drupal.org/node/104220.
#7
it looks like the problem goes back to the 4.7 days and the problem is that we check that is_uploaded_file() is true before checking for errors one of the comments on the patch alludes to the problem.
i've reworked the test so that it only checks that the file is_uploaded_file() when there's no error.
#8
Tested the patch - I'm not seeing any change though, large files still fail silently.
There is a notice though: 'notice: Undefined property: stdClass::$vid in /modules/upload/upload.module on line 536.'
#9
I can confirm this, so i change the status.
#10
here's a slightly improved version. it gives better errors.
i think the problem you guys are running into trying to test this is that it depends on php's max post and file upload sizes. if you upload a file bigger than the post max size you won't see any error because php silently discards the submission. so for example with:
post_max_size = 32Mupload_max_filesize = 4M
uploading a 1mb file would work. uploading an 8mb file would fail with an error. but if you upload a 38mb file you'd loose everything submitted with the form. there's not much we can do about this.
also when you're testing this, use the preview button rather than the attach button. there's some issues with the javascript that are separate from this.
#11
i want to clarify that this patch only fixes one thing: if you submit a file that's larger than php's max file size and less than the max post size you will now get an error. we can't do anything about uploads that are larger than the post size.
#12
Because of the unique error it drops on reaching the POST size limit I thought it is possible to filter out the conditions when this occurs. This is a try. This patch gives correct error messages when on node/add/story, but removes the previous attachments when editing an existing node and encountering the POST size limit. Maybe someone finds this useful.
#13
I've rerolled the patch:
- Fixed an incomplete comment.
- Removed the separate error messages since they weren't actually being used (if the file is larger than the user roles maximum file size, but less than the PHP maximum, the file uploads properly and the error is thrown later)
#14
i tested out snufkin's patch on #12 and it didn't seem to report an error for a file larger than the max post size.
webernet, i think your patch on #13 is a step backwards. you remerged distinct error messages. in one case it's larger than the max upload size in another someone put a constant on the form specifying a maximum upload size. totally different... a misleading error message is worse than none at all. i was trying to separate them out to make it clearer what had happened.
#15
#16
This patch once again splits the messages for the two cases.
#17
i tried to improve the error messages a bit and used webernet's suggestion on IRC of using the filename rather than $source in the error messages.
#18
#19
php.net suggests (as quoted above) that we also pass a GET parameter, which signals that we should have files, and if we have no files, that means we have gone over the POST max size. We can easily use both POST and GET data, so we can detect the case when a file was expected but not uploaded at all.
#20
Gabor, the attached patch would catch a single file that's oversize, the problem is when the whole request is larger than the max post size. in that case then entire request is discarded and you get a blank node upload form... should we be passing a default ?posted=1 to all pages?
#21
@drewish: It sounds like that's what PHP recommends doing, I think that's a good idea.
#22
RobRoy, I agree it's a good idea but I've got no idea where to start hacking the Forms API so that we pass a GET when submitting all the forms with '#type'=>'file' element on them.
Considering that at this point there's two errors that aren't handled correctly, it seems to me that fixing one would be a good start.
#23
I came in late to this so probably don't grasp the whole situation, but just want to jot down some quick ideas that may inspire a real solution.
I was thinking we'd just do it manually somehow. Like in upload_form_alter() we would do a $form['#file_upload'] = TRUE; when adding the attachments fieldset. Then, when FAPI is gonna submit the form...it takes whatever $form['#action'] is set to and adds a file_upload=1 to the query string. Then, the submit handler could check for that.
But that isn't too well thought out, because I guess we only set file_upload=1 when a file upload is attempted, not just when a 'file' field is included in the form. So maybe all file FAPI elements have their own generic '#submit' handler called 'file_validate_form_upload' or something that does some magic based on data submitted.
Ehhh, ya those are some pretty worthless suggestions but might get the balls rolling. :P
#24
bump.
Can we agree this is a problem, and that having the problem continue to exist since late 2005 is pretty sad?
How about a fix that deals with some of the above, rather than leave the entire issue outstanding?
#25
bumping to HEAD, hopefully we can backport something once this gets committed.
#26
marked #282605: New Audio content never created if file exceeds max upload (no warning given) as a duplicate of this.
#27
also marked #248185: Wrong error management in file_save_upload as a duplicate. improving the title to make it easier to find
#28
Looks like the patch is not specific to upload.module.
#29
I tried the last patch and it worked for me on drupal 5.
This patch is for drupal 5 (the check was in a function called file_check_upload).
#30
If The file size exceeds the post_max_size what about calling error_get_last() ?
The php generate this warning :
PHP Warning: POST Content-Length of (failed uploaded size) bytes exceeds the limit of (post_max_size) bytes
#31
Marked #289518: No error message for attachment larger than PHP settings limit as a duplicate.
#32
here's a reroll against HEAD.
#33
Patch failed to apply. More information can be found at http://testing.drupal.org/node/14286. If you need help with creating patches please look at http://drupal.org/patch/create
#34
Patch failed to apply. More information can be found at http://testing.drupal.org/node/14286. If you need help with creating patches please look at http://drupal.org/patch/create
#35
DrupalTestbedBot is a wrong, looks like it grabbed the previous patch that yassin.mohii posted.
Update: Reported an issue for the test bot #307197: Testing the incorrect patch posting multiple comments.
#36
re-rolled for HEAD. if you want unit tests take a look at #310358: Add a test for file_save_upload and clean up file.test
#37
Patch failed to apply. More information can be found at http://testing.drupal.org/node/14535. If you need help with creating patches please look at http://drupal.org/patch/create
#38
i'm going to drag the DrupalTestbedBot out back and shoot it: http://drupal.org/node/307197
#39
last patch was rolled from /includes... re-rolled.
#40
The last submitted patch failed testing.
#41
I have drupal 5.12 and I could only apply the patch attached to comment #29, the rest fail for my system.
Anyway the patch only solves the problem of submitting a file greater than php upload_max_filesize AND smaller than post_max_size
If post_max_size is exceeded the problem continues.
#42
here's a re-roll that restructures this a bit so that if there's no upload we hurry up and just return FALSE rather than indenting the rest of the code. all file and upload tests pass.
#43
re-rolled.
#44
Excellent! This has bitten me in the past and I'm very happy to see a working patch!
Tested by setting my max_post_size to 32M and max_upload_filesize to 1M and uploading a 3M file. Without the patch, nothing happens, leaving me scratching my head and feeling lost and alone. With the patch, I get a nice error message to tell me what happened.
Code looks good (it's basically just a re-shuffling) and file tests continue to pass. I asked drewish if we could supplement this with unit tests, but unfortunately we cannot; both of these INI values are not settable at run-time.
Committed to HEAD. Marking for porting to 6.x/5.x.
#45
Humm... not quite yet. I just noticed one other test case, submitting the form at admin/build/themes/settings with no files incorrectly gave the following errors:
* The file logo_upload could not be saved, because the upload did not complete.* The file favicon_upload could not be saved, because the upload did not complete.
I'm working on another patch right now but I'll pick this up when I'm finished.
FileSaveUploadTest really needs to add tests for submitting an empty upload to an optional and required fields.
#46
This doesn't address the test yet but now it returns NULL if no upload was attempted.
#47
Marked #357382: Error message shown when no upload file provided as a duplicate of this bug. The patch in #46 is contains unwanted debugging statement so posting a revised patch.
#48
much better looking. i'd like to get tests but it might be worth holding off on for them for now and getting this fixed.
#49
just double checked and this patch fixes the problem in all the file elements that are currently in core (theme logo/favicon, user pictures, upload.modue).
#50
Tested, works, RTBC.
#51
Oh my...trying to write tests for this is just horrible. Can't use drupalPost() with an empty file field.
#52
Looks like dagnabbed artwork... works for me... and if it can't be tested I see no reason to hold it up.
#53
I think I finally figured out a test for this. Before the change to file_save_upload(), this new test will fail. With the change, it passes.
#54
Cleaned out the unrelated whitespace changes and documentation revision for the test.
#55
thanks, #54 looks good and tests pass. RTBC.
#56
Yay! :) Really glad to have this fixed AND tested so we don't break it again. :D
Committed to HEAD.
#57
From #44/#45, it looks like we need this backported.
#58
Here's the backport for #43 and #54 combined. I tested uploading a new user picture on my 6.x patched install and it worked successfully. The only API change is that the function returns FALSE/NULL instead of 0, which all == FALSE.
#59
Revised patch that includes the more helpful error messages in #361514: Error messages in file_save_upload should use the actual file name without changing any actual strings for translation.
#60
Is there any way to backport this to 5.x ?? I just found this error on my site today, and I won't be changing to 6.x for quite awhile. Thanks!
#61
+1 on the backport please! I also just found this issue.
#62
Feel free to review the patch and if it works for you, mark as "reviewed and tested by the community"
#63
Confirmed this patch fixes problems with both Upload module and FileField in Drupal 6. The patch looks large but doesn't change nearly as many lines as it appears to. A huge improvement to prevent upload.module from silently failing without giving the user any indication of an error whatsoever.
Tested by:
- Setting post_max_size to 10M and upload_max_filesize to 1M. Restart Apache.
- Uploaded a 2M file in upload module and in FileField. FileField reports unhelpfully "The file in the field was unable to be uploaded.", Upload doesn't report anything at all. After patching, both report "The file IMG_1208.JPG could not be saved, because it exceeds 1 MB, the maximum allowed size for uploads."
- Uploaded a 500K file to ensure files are still accepted.
Both modules still fail pretty spectacularly when an upload exceeds the post_max_size (the form element disappears entirely, preventing any uploads), but that's a different issue. Great work on solving this one.
#64
Pretty big patch indeed, so I'd welcome if more people would test it before RTBC. I for example found a function called which does not even exist in Drupal 6: file_load_multiple(). This function is also used in a passage of code which is not in the Drupal 6 version currently and is not related to fixing this bug either.
#65
Gabor's right this whole block of code in D7 only:
+ // If we are replacing an existing file re-use its database record.+ if ($replace == FILE_EXISTS_REPLACE) {
+ $existing_files = file_load_multiple(array(), array('filepath' => $file->filepath));
+ if (count($existing_files)) {
+ $existing = reset($existing_files);
+ $file->fid = $existing->fid;
+ }
+ }
#66
I'm have also had issues with this, but checks on anything after the max size of $_POST is exceeded is almost pointless as the entire reference to the form build id is lost. The only solution that I have found so far is to change theme_form to append the action with the build id. This ensures that this is never lost and a failed POST can be detected.
Rather than pushing in a patch, I just post the code to get feedback on the idea.
<?php
// Original
function theme_form($element) {
// Anonymous div to satisfy XHTML compliance.
$action = $element['#action'] ? 'action="' . check_url($element['#action']) . '" ' : '';
return '<form ' . $action . ' accept-charset="UTF-8" method="' . $element['#method'] . '" id="' . $element['#id'] . '"' . drupal_attributes($element['#attributes']) . ">\n<div>" . $element['#children'] . "\n</div></form>\n";
}
// Modified
function theme_form($element) {
// PHP drops the $_POST array if this exceeds the PHP setting post_max_size.
$action = '';
if ($element['#action']) {
$action = 'action="' . check_url($element['#action']) . (strpos($element['#action'], '?') !== FALSE ? '&' : '?') . 'form-id=' . check_plain($element['#build_id']) . '"';
}
// Anonymous div to satisfy XHTML compliance.
return '<form ' . $action . ' accept-charset="UTF-8" method="' . $element['#method'] . '" id="' . $element['#id'] . '"' . drupal_attributes($element['#attributes']) . ">\n<div>" . $element['#children'] . "\n</div></form>\n";
}
?>
So with the modifications, a var_dump on $_GET and $_POST normally will result in something like:
<?phpvar_dump($_GET);
/*
Outputs
array(2) {
["q"]=>
string(31) "admin/settings/site-information"
["form-id"]=>
string(37) "form-f3b2569b7299435726c96c962dab3d89"
}
*/
var_dump($_POST);
/*
array(11) {
["site_name"]=>
string(5) "d7dev"
["site_mail"]=>
....
}
*/
?>
But if max_post_size is exceeded:
<?phpvar_dump($_GET);
/*
Outputs
array(2) {
["q"]=>
string(31) "admin/settings/site-information"
["form-id"]=>
string(37) "form-f3b2569b7299435726c96c962dab3d89"
}
*/
var_dump($_POST);
/*
array(0) {
}
*/
?>
In both cases, we can still retain the actual form that was originally posted and also detect if the form data has been dropped.
#67
Alan D., I think that's an interesting approach but it should really be in a follow up issue since it seems a bit too big to get backported for D6.
#68
Followup on #66, see Issue: Enabling handling of errors related to max_post_size.
#69
+1 to backport to 5.x
flashvideo module needs this fix (http://drupal.org/node/463126)