34

I was trying to make a file upload form and checked the PHP documentation to refresh my memory on the subject. Here is a link to the relevant article. All of a sudden I noticed this message:

The MAX_FILE_SIZE hidden field (measured in bytes) must precede the file input field, and its value is the maximum filesize accepted by PHP. This form element should always be used as it saves users the trouble of waiting for a big file being transferred only to find that it was too large and the transfer failed. Keep in mind: fooling this setting on the browser side is quite easy, so never rely on files with a greater size being blocked by this feature. It is merely a convenience feature for users on the client side of the application. The PHP settings (on the server side) for maximum-size, however, cannot be fooled.

OK... Say what? First it tells that it must precede the file upload field. Then it tells us that it is merely for convenience. And besides - it's on client side anyway so anyone can mess with it. After googling around I also found information that there are no known browsers that support it.

WTF? Why is it said that it must precede the file upload field if it seems to be (for all intents and purposes) absolutely pointless? Should I bother putting it in my HTML at all?

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • Vilx - it appears my assumptions about how it worked may be wrong. Could you test it and let me know if files larger than `max_file_size` are actually posted? I'd be interested to be found wrong! – Dominic Rodger Sep 04 '09 at 20:39
  • Sure are! At least on my WinXP SP3 + Apache 2.2 + PHP 5. PHP would have no way of stopping it either - the most it can do is close the connection (if even that much), but then it won't be able to provide any errors to the user at all. – Vilx- Sep 04 '09 at 20:48
  • @Vilx - thanks - most interesting! – Dominic Rodger Sep 04 '09 at 20:49
  • 3
    about the `must precede the file input field`, I think it just means that if you decide to include that field, it MUST be before the related input field. – Sebas Nov 16 '13 at 22:47
  • @Sebas, What an arbitrary restriction. And what if we are uploading multiple files? [**No wonder** browsers don't support it](http://stackoverflow.com/questions/1381364/max-file-size-in-php-whats-the-point/6273418#comment46711434_6273418), it's not even well-designed. – Pacerier Mar 25 '15 at 11:23

6 Answers6

40

After failed attempt to find any authoritative information about MAX_FILE_INFO i've decided to resort to drastic measures - and peeked at PHP's holy source.

I scanned entire PHP source recursively using grep:

grep -ri MAX_FILE_SIZE .

The only place that mentioned this variable was (excluding tests folder) - rfc1867.c file. Completely expectable since rfc1867 standard deals with file uploads.

Related C code:

......
if (!strcasecmp(param, "MAX_FILE_SIZE")) {                                                                                                                                                                              
   max_file_size = atol(value);
}
......
......
if (PG(upload_max_filesize) > 0 && (total_bytes+blen) > PG(upload_max_filesize)) {
    cancel_upload = UPLOAD_ERROR_A;
} else if (max_file_size && ((total_bytes+blen) > max_file_size)) {
    cancel_upload = UPLOAD_ERROR_B;
} else if
....

So - here's short explanation of above code:

1) first we get the value of MAX_FILE_SIZE into max_file_size variable.

2) Then we check if max_file_size value exists and if the sum of already accepted bytes (total_bytes) + the size of bytes in the buffer(blen) exceeds max_file_size.

3) If 2 is true - at this point we cancel upload with some error code that's been set by this constant: UPLOAD_ERROR_B

BUT - as you can see - right before checking max_file_size variable - PHP performs EXACTLY THE SAME CHECK for upload_max_filesize variable!!! So - there we have it.

Conclusion: IMHO - op is right - there is 0 point in including MAX_FILE_SIZE into your forms! Simply set upload_max_filesize in your php.ini file or dynamically via ini_set().

j08691
  • 204,283
  • 31
  • 260
  • 272
Stann
  • 13,518
  • 19
  • 65
  • 73
  • 1
    just a note: you can't set upload_max_filesize with ini_set! –  Feb 01 '13 at 09:25
  • 3
    I read it as, "This extension to HTML form processing was added to limit attempts to upload oversized files. The idea is that the **browser** won't even _start_ to upload if the file is too large. Unfortunately, few (if any) browsers obey this extension/directive at this time, but more may do so in the future. Finally, it's easy to spoof, so don't count on it (check on the server side)." Accurate reading? – Phil Perry Jan 09 '14 at 15:15
  • @PhilPerry, Except **browsers don't** have any plans to support this feature at all. I don't see [RFC1867](https://www.ietf.org/rfc/rfc1867.txt) mentioning `MAX_FILE_SIZE` anywhere. **Is this just a PHP invention?** – Pacerier Mar 25 '15 at 11:19
  • The only real answer. – CoR May 16 '15 at 08:35
  • Thanks for providing a solid answer to this question. I have wasted over an hour today reading people's fantasies about how this feature works. – Mnebuerquo Jun 23 '15 at 17:46
16

At the moment there are no browsers that actually care about the MAX_FILE_SIZE directive so it is pretty pointless. I suppose it does give you more granular control over max sizes on upload (as the poster above stated) rather than going with php.ini's, but personally I just ignore it, and you probably should too. It will certainly not stop a user uploading a larger than required file - the manual is fairly misleading in this regard.

Meep3D
  • 3,803
  • 4
  • 36
  • 55
  • 5
    It is not intended for security -- **it is intended for user experience**. "it saves users the trouble of waiting for a big file being transferred only to find that it was too large and the transfer failed." Nor is it intended for browsers -- see PHP souce where it [stops reading from the buffer](https://github.com/php/php-src/blob/1c295d4a9ac78fcc2f77d6695987598bb7abcb83/main/rfc1867.c#L1028) if [cancel_upload](https://github.com/php/php-src/blob/1c295d4a9ac78fcc2f77d6695987598bb7abcb83/main/rfc1867.c#L1053) is set after checking max_file_size. – Pocketsand May 17 '16 at 11:52
12

Until we find browsers that support it, there's no point on the client side.

However, on the server side, MAX_FILE_SIZE does affect the values you get from $_FILES['your_file'].

Assuming the browser's request actually made it through post_max_size, usually this is what PHP gives:

array(5) {
    ["name"]=> string(11) "my_upload.dll"
    ["type"]=> string(24) "application/x-msdownload"
    ["tmp_name"]=> string(26) "C:\WINDOWS\Temp\php86A.tmp"
    ["error"]=> int(0) // UPLOAD_ERR_OK
    ["size"]=> int(238592)
}

But if uploaded file size exceeds MAX_FILE_SIZE, you'd see:

array(5) {
    ["name"]=> string(11) "my_upload.dll"
    ["type"]=> string(0) ""
    ["tmp_name"]=> string(0) ""
    ["error"]=> int(2) // UPLOAD_ERR_FORM_SIZE
    ["size"]=> int(0)
} 

And the part on "MAX_FILE_SIZE must precede the file input field" is not a joke. It actually works because PHP will interpret the browser's POST request payload sequentially:

<input name=F1 type=file> 
<input name=F2 type=file>
F1 and F2 will not be affected by MAX_FILE_SIZE

<input name=MAX_FILE_SIZE value=1024 type=hidden>
<input name=F3 type=file>
<input name=F4 type=file>
F3 and F4 will have MAX_FILE_SIZE = 1024 bytes

<input name=MAX_FILE_SIZE value=0 type=hidden>
<input name=F5 type=file>
<input name=F6 type=file>
F5 and F6 will have MAX_FILE_SIZE = 0 (infinite)

<input name=MAX_FILE_SIZE value=1 type=hidden>
<input name=F7 type=file> 
<input name=F8 type=file>
F7 and F8 will have MAX_FILE_SIZE = 1 byte

Also note that PHP interprets MAX_FILE_SIZE case insensitively, so maX_fILe_sIZE and Max_File_SIZE would work too.

Pacerier
  • 86,231
  • 106
  • 366
  • 634
2

I believe the point is that conformant browsers would prevent form submission in the case where the user selected a file that was too large, which would save them having to perform at least a partial upload (which could take a while) of a file that was going to be rejected.

On the server side, PHP still checks and enforces the various limits set in PHP.ini, and will reference the fact that an upload was too large in the normal manner, i.e. an error code set in $_FILES. You might think of the field as an analogy to JavaScript validation - we might do a quick client-side check for the user's convenience, but we still do a proper server-side test and enforce it for all requests.

As others have stated, there don't appear to be any browsers that actually bother to perform this check, making it relatively useless.

Rob
  • 47,999
  • 5
  • 74
  • 91
  • 1
    Actually, it's not even in any standards besides PHP's own documentation, so no wonder there are no browsers or even plugins that implement this. Check here: http://bugs.php.net/bug.php?id=40387 – Vilx- Sep 04 '09 at 20:45
  • Indeed. I use the term "conformant" scoped against that documentation. – Rob Sep 04 '09 at 20:54
1

What follows is me being wrong, please read the other answers which are better-informed, and accurate (AFAIK).

I think the point is exactly as it states:

This form element should always be used as it saves users the trouble of waiting for a big file being transferred only to find that it was too large and the transfer failed

Yes, it can be fooled, and so shouldn't be relied on to prevent larger files from being uploaded, but for non-malicious users if the uploaded file is bigger than the integer in this field, PHP disallows this upload and presents an error code in the $_FILES array (source - comments on php.net).

Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
  • 1
    How will this warn users if the browsers ignore it? – Vilx- Sep 04 '09 at 20:26
  • @Vilx - I've hopefully clarified my answer. I think PHP somehow checks for the existence of the `max_file_size` field before processing the post data, but I'm not sure quite how that works. – Dominic Rodger Sep 04 '09 at 20:32
  • Funny then, because it sure doesn't do it on my WinXP + Apache 2.2 + PHP 5. And google reveals that I'm not alone in this. – Vilx- Sep 04 '09 at 20:40
  • 1
    Users who've +1ed me, it appears I'm wrong, could you un+1 me. Then references in comments and other answers to the question will make sense, but no one will listen to what I wrote! – Dominic Rodger Sep 04 '09 at 20:50
1

I use it to set file size limit when a particular application needs smaller files than the limit in php.ini. My php scripts check it, but it is set in the HTML form. Different forms have different file size limits. I am not sure if this has much to do with the intended use, but it makes it easier to reuse my scripts. It would be good if it could be checked at the browser level, but it's not the only reason it is useful.

konsolenfreddy
  • 9,551
  • 1
  • 25
  • 36
cls
  • 11
  • 1