Detecting file size overflow in PHP

One of the things that separates a good web application from a great one is how gracefully they handle failures. One of the often overlooked cases is when a user attempts to upload a file that exceeds the set PHP upload file size. This article shows how to detect when the user tries to upload a file that is too large and display an appropriate message.

This article assumes that you have already set upload_max_filesize, post_max_size, and memory_limit in your php.ini file to appropriate values. It also assumes that you already have a working file upload form. There are plenty of tutorials out there already to get you started.

If you can, you may want to set post_max_size to a low value (say “1M”) to make testing easier.

First test to see how your script behaves. Try uploading a file that is larger than post_max_size. If you do you will get a message like this in your error log:

[09-Jun-2010 19:28:01] PHP Warning:  POST Content-Length of 30980857 bytes exceeds the limit of 2097152 bytes in Unknown on line 0

If you’re not careful this can lead to unexpected behavior in your application. The end result can range from silent failure all the way to lost customers.

Solving the problem

The PHP documentation provides a hack to solve this problem:

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.
Source: PHP manual

To be clear, it is suggesting that you pass a value in the query string along with your form. If the value is in the $_GET superglobal and both $_FILE and $_POST are empty then the maximum upload size is exceeded. There are two problems with this approach: it adds extra complexity on the front-end and it can potential give a false positive.

Extra complexity on the front-end means extra documentation and more room for mistakes. And if there is a mistake it may not be caught for a long time (does your QA team routinely upload large files?). In this case we already have all the data that we need to determine if the maximum file size was exceeded without adding extra complexity and headache for developers.

We know what type of request is being processed, we have the $_POST and $_FILES arrays, and we have the content length as it was passed to the HTTP server from the client. From that we get this code:

if ( $_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST) &&
     empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0 )
{       
  $displayMaxSize = ini_get('post_max_size');

  switch ( substr($displayMaxSize,-1) )
  {
    case 'G':
      $displayMaxSize = $displayMaxSize * 1024;
    case 'M':
      $displayMaxSize = $displayMaxSize * 1024;
    case 'K':
       $displayMaxSize = $displayMaxSize * 1024;
  }

  $error = 'Posted data is too large. '.
           $_SERVER[CONTENT_LENGTH].
           ' bytes exceeds the maximum size of '.
           $displayMaxSize.' bytes.";
}

The important thing to notice is the “if” statement on lines one and two. The example code just sets an error string. Production code might display a message to the user, execute some Javascript (for asynchronous uploads), or pass back a XML or Json object for Flash clients.

I’ve tested this code with Apache as both a module and as CGI. As far as I know it should work fine with IIS as well.

Tagged with: ,
Posted in Code
9 comments on “Detecting file size overflow in PHP
  1. okjiko says:

    I may use the condition in a wrong way, but as far as I am concerned, I’ve added && isset($_SERVER['CONTENT_LENGTH']) to the condition :

    if (
    $_SERVER['REQUEST_METHOD'] == ‘POST’
    && empty($_POST)
    && empty($_FILES)
    && isset($_SERVER['CONTENT_LENGTH'])//here
    && $_SERVER['CONTENT_LENGTH'] > 0 )

    because the index CONTENT_LENGTH doesn’t exist when the page is loaded in the first place.

    Hope that helps

  2. Hi okjiko,

    Because we are first checking to see if REQUEST_METHOD is POST: the CONTENT_LENGTH value should always be set.

    However, it is up to the web server to set CONTENT_LENGTH and it is notable that old versions of Apache (and possible other web servers) do not set it. For these servers, the code in this article will not work (that code in the previous comment will produce a false positive) and it may be a good idea to fall back to the “processed=1″ method mentioned in the PHP documentation for those browsers.

  3. huarong says:

    Should I also check “upload_max_filesize” in php.ini?

  4. Hi huarong, this post deals explicitly with the error that occurs when post_max_size is exceeded (which is difficult to detect because it wipes out the $_POST and $_FILE arrays).

    When upload_max_filesize is exceeded it is actually treated as a normal upload error. So you can detect it by checking $_FILES['form_field_name']['error'] value after the upload and comparing it to UPLOAD_ERR_INI_SIZE. And yes, you should be checking this as well. See also: http://php.net/manual/en/features.file-upload.errors.php

  5. darren says:

    this method does not work for me using php 5.4 with mod apache, still get the same error.

  6. Brayan says:

    me too

    “..this method does not work for me using php 5.4 with mod apache, still get the same error..”

  7. Manuel Nieto says:

    This helped me a lot!! Thank you!

  8. Thanks designed for sharing such a pleasant thought, article is fastidious, thats why i have read it entirely

    my blog … web based file sharing

  9. Jamil says:

    While this works, it doesn’t suppress the warning from PHP about the length, which is really what I was looking for. I don’t want to suppress all warnings because that could potentially lead to some problems down the road. Just this one because I can handle it in my code. Is there a way to do that?

    Also, you have some errors in your posted code:
    Line 17: The index CONTENT_LENGTH should be enclosed in quotes or it will be interpreted as a constant.
    Line 19: The word bytes has a single quote on the left and double quote on the right. I think you meant just a pair of single quotes.

3 Pings/Trackbacks for "Detecting file size overflow in PHP"
  1. [...] 0 Times in 0 Posts For a solution that may work for you, see Detecting upload file size overflow in PHP | Andrew's Tech Musings Reply With [...]

  2. [...] detect if the uploaded POST data is to large (>post_max_size) according to http://andrewcurioso.com/2010/06/detecting-file-size-overflow-in-php/ and try to send an appropriate JSON-encoded error [...]

  3. […] Found an alternative solution that does not deal with the error directly. The following code is written by a software engineer Andrew Curioso in his blog: […]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>