How to detect if a user uploaded a file larger than post_max_size?
How should I go about handling http uploads that exceeds the post_max_size
in a sane manner?
In my configuration post_max_size
is a few MB larger than upload_max_filesize
The problems I'm having are:
post_max_size
- The _POST array is empty
- The _FILES array is empty, and of course any error codes therein are not present.
- No other info what kind of form post it is is accessible through theses means.
Part of the problem is that the receiving script takes different actions depending on the contents of the POST.
I do have access to the _SERVER
variables and can get clues as to what happened, i.e. CONTENT_TYPE
,开发者_JAVA百科 CONTENT_LENGTH
and REQUEST_METHOD
. It does however seem very problematic to make guesses based on those contents.
MEMORY_LIMIT (set to 10 times the relevant sizes) and Apaches LimitRequestBody (set to unlimited) are found to not be at fault.
As it stands now I have a hard time even providing any meaningful messages to the user.
Is there any way to retain some form data to get better clues as to what has gone wrong? I'm very reluctant to move away from php.
For a simple fix that would require no server side changes, I would use the HTML5 File API to check the size of the file before uploading. If it exceeds the known limit, then cancel the upload. I believe something like this would work:
function on_submit()
{
if (document.getElementById("upload").files[0].size > 666)
{
alert("File is too big.");
return false;
}
return true;
}
<form onsubmit="return on_submit()">
<input id="upload" type="file" />
</form>
Obviously it's just a skeleton of an example, and not every browser supports this. But it wouldn't hurt to use this, as it could be implemented in such a way that it gracefully degrades into nothing for older browsers.
Of course this doesn't solve the issue, but it will at least keep a number of your users happy with minimal effort required. (And they won't even have to wait for the upload to fail.)
--
As an aside, checking $_SERVER['CONTENT_LENGTH']
vs the size of the post and file data might help detect if something failed. I think it when there is an error it will be non zero, while the $_POST
and $_FILES
would both be empty.
Per the PHP documentation:
If the size of post data is greater than post_max_size, the $_POST and $_FILES superglobals are empty. This can be tracked in various ways, e.g. by passing the $_GET variable to the script processing the data, i.e. <form action="edit.php?processed=1">, and then checking if $_GET['processed'] is set.
If you need the limit increased for a specific script, you can try ini_set('post-max-size', $size_needed);. I'm not sure if it can be overridden within a script, though; that limit is probably there to specifically keep you from doing what you're trying to do.
I liked @Matthew answer, but needed a version that checked for multiple upload files.
This was my solution:
function checkAttachmentsSize() {
var total = 0;
var count = 0;
jQuery('input[type="file"]').each(
function() {
if (typeof this.files[0] != 'undefined') {
total+= this.files[0].size;
count++;
}
}
);
var word = (count > 1) ? 's are' : ' is';
if (total > (uploadMax * 1000 * 1000)) {
alert("The attachment file" + word + " too large to upload.");
return false;
}
return true;
}
And, for completeness, here's the binding of the function to the form being submitted:
jQuery(function($) {
$("form").submit(
function() {
return checkAttachmentsSize();
}
});
);
NOTE:
uploadMax is a variable that I set via php after calculating the maximum size of the allowable upload.
You can solve this on the server side without resorting to a query string. Just compare the *post_max_size* setting to the expected content length of the request. The following code is how Kohana does it.
public static function post_max_size_exceeded()
{
// Make sure the request method is POST
if (Request::$initial->method() !== HTTP_Request::POST)
return FALSE;
// Get the post_max_size in bytes
$max_bytes = Num::bytes(ini_get('post_max_size'));
// Error occurred if method is POST, and content length is too long
return (Arr::get($_SERVER, 'CONTENT_LENGTH') > $max_bytes);
}
You may need to revert to something that uses flash/silverlight etc. such as: http://www.plupload.com/
Or look at a Java-based solution...
Basically something that will break the upload into more managable (and resumable) chunks, and then re-assemble them on the server side.
Unless your upload form has fields other than the file input field, then $_POST should be empty - files are handled exclusively through the $_FILES. It's very odd that $_FILES would be empty if the post size is exceeded - the upload handlers have a specific error code (1/UPLOAD_ERR_INI_SIZE) to report such a condition. Also check that memory_limit
is larger than the upload_max_filesize.
Your webserver may be blocking the upload as well, which would occur before PHP is invoked. On Apache, it's controlled by LimitRequestBody
.
精彩评论