$_POST data returns empty when headers are > POST_MAX_SIZE

Hopefully someone here might have an answer to my question.

I have a basic form that contains simple fields, like name, number, email address etc and 1 file upload field.

I am trying to add some validation into my script that detects if the file is too large and then rejects the user back to the form to select/upload a smaller file.

My problem is, if a user selects a file that is bigger than my validation file size rule and larger than php.ini POST_MAX_SIZE/UPLOAD_MAX_FILESIZE and pushes submit, then PHP seems to try process the form only to fail on the POST_MAX_SIZE settings and then clears the entire $_POST array and returns nothing back to the form.

Is there a way around this? Surely if someone uploads something > than the max size configured in the php.ini then you can still get the rest of the $_POST data???

Here is my code.

<?php

   function validEmail($email)
    {
       $isValid = true;
       $atIndex = strrpos($email, "@");
       if (is_bool($atIndex) && !$atIndex)
       {
          $isValid = false;
       } else {
          $domain = substr($email, $atIndex+1);
          $local = substr($email, 0, $atIndex);
          $localLen = strlen($local);
          $domainLen = strlen($domain);

          if ($localLen < 1 || $localLen > 64)
          {
             // local part length exceeded
             $isValid = false;
          }
          else if ($domainLen < 1 || $domainLen > 255)
          {
             // domain part length exceeded
             $isValid = false;
          }
          else if ($local[0] == '.' || $local[$localLen-1] == '.')
          {
             // local part starts or ends with '.'
             $isValid = false;
          }
          else if (preg_match('/\\.\\./', $local))
          {
             // local part has two consecutive dots
             $isValid = false;
          }
          else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
          {
             // character not valid in domain part
             $isValid = false;
          }
          else if (preg_match('/\\.\\./', $domain))
          {
             // domain part has two consecutive dots
             $isValid = false;
          }
          else if
          (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local)))
          {
             // character not valid in local part unless 
             // local part is quoted
             if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local)))
             {
                $isValid = false;
             }
          }

       }
       return $isValid;
    }

        //setup post variables
        @$name = htmlspecialchars(trim($_REQUEST['name'])); 
        @$emailCheck = htmlspecialchars(trim($_REQUEST['email']));
        @$organisation = htmlspecialchars(trim($_REQUEST['organisation']));
        @$title = htmlspecialchars(trim($_REQUEST['title']));
        @$phone = htmlspecialchars(trim($_REQUEST['phone']));
        @$location = htmlspecialchars(trim($_REQUEST['location']));
        @$description = htmlspecialchars(trim($_REQUEST['description']));
        @$fileError = 0;
        @$phoneError = "";

        //setup file upload handler
        $target_path = 'uploads/';
        $filename =  basename( @$_FILES['uploadedfile']['name']);
        $max_size = 8000000; // maximum file size (8mb in bytes) NB: php.ini max filesize upload is 10MB on test environment.
        $allowed_filetypes = Array(".pdf", ".doc", ".zip", ".txt", ".xls", ".docx", ".csv", ".rtf"); //put extensions in here that should be uploaded only.
        $ext = substr($filename, strpos($filename,'.'), strlen($filename)-1); // Get the extension from the filename.

        if(!is_writable($target_path)) die('You cannot upload to the specified directory, please CHMOD it to 777.'); //Check if we can upload to the specified upload folder.


        //display form function
        function displayForm($name, $emailCheck, $organisation, $phone, $title, $location, $description, $phoneError, $allowed_filetypes, $ext, $filename, $fileError)
        {
          //make $emailCheck global so function can get value from global scope.
          global $emailCheck;
          global $max_size;



          echo  '<form action="geodetic_form.php" method="post" name="contact" id="contact" enctype="multipart/form-data">'."\n".
                '<fieldset>'."\n".'<div>'."\n";

          //name        
          echo '<label for="name"><span class="mandatory">*</span>Your name:</label>'."\n".
                '<input type="text" name="name" id="name" class="inputText required" value="'. $name .'" />'."\n";

                //check if name field is filled out
                if (isset($_REQUEST['submit']) && empty($name)) 
                {        
                  echo '<label for="name" class="error">Please enter your name.</label>'."\n";
                }

           echo '</div>'."\n". '<div>'."\n";

           //Email     
           echo '<label for="email"><span class="mandatory">*</span>Your email:</label>'."\n".
                '<input type="text" name="email" id="email" class="inputText required email" value="'. $emailCheck .'" />'."\n";

               // check if email field is filled out and proper format   
                if (isset($_REQUEST['submit']) && validEmail($emailCheck) == false)
                {
                  echo '<label for="email" class="error">Invalid email address entered.</label>'."\n";
                }

           echo '</div>'."\n". '<div>'."\n";

           //organisation     
           echo '<label for="phone">Organisation:</label>'."\n".
                '<input type="text" name="organisation" id="organisation" class="inputText" value="'. $organisation .'" />'."\n";
           echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n";

           //title     
           echo '<label for="phone">Title:</label>'."\n".
                '<input type="text" name="title" id="title" class="inputText" value="'. $title .'" />'."\n";        
           echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n";

          //phone     
           echo '<label for="phone"><span class="mandatory">*</span>Phone <br /><span class="small">(include area code)</span>:</label>'."\n".
                '<input type="text" name="phone" id="phone" class="inputText required" value="'. $phone .'" />'."\n";       

           // check if phone field is filled out that it has numbers and not characters
           if (isset($_REQUEST['submit']) && $phoneError == "true" && empty($phone)) echo '<label for="email" class="error">Please enter a valid phone number.</label>'."\n";       

           echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n";

            //Location     
            echo '<label class="location" for="location"><span class="mandatory">*</span>Location:</label>'."\n".
                 '<textarea name="location" id="location" class="required">'. $location .'</textarea>'."\n";

            //check if message field is filled out
            if (isset($_REQUEST['submit']) && empty($_REQUEST['location'])) echo '<label for="location" class="error">This field is required.</label>'."\n";

            echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n";

           //description     
           echo '<label class="description" for="description">Description:</label>'."\n".
                '<textarea name="description" id="queryComments">'. $description .'</textarea>'."\n";               
           echo '</div>'."\n". '</fieldset>'."\n".'<fieldset>'. "\n" . '<div>'."\n";

          //file upload
           echo '<label class="uploadedfile" for="uploadedfile">File:</label>'."\n".
                '<input type="file" name="uploadedfile" id="uploadedfile" value="'. $filename .'" />'."\n";

           // Check if the filetype is allowed, if not DIE and inform the user.   
           switch ($fileError)
           {
            case "1":
                echo '<label for="uploadedfile" class="error">The file you attempted to upload is not allowed.</label>';
            break;

            case "2":
                echo '<label for="uploadedfile" class="error">The file you attempted to upload is too large.</label>';
            break;
           }   
           echo '</div>'."\n". '</fieldset>';

            //end of form
            echo '<div class="submit"><input type="submit" name="submit" value="Submit" id="submit"  /></div>'.
                 '<div class="clear"><p><br /></p></div>';
        } //end function

        //setup error validations
        if (isset($_REQUEST['submit']) && !empty($_REQUEST['phone']) && !is_numeric($_REQUEST['phone'])) $phoneError = "true";
        if (isset($_REQUEST['submit']) && $_FILES['uploadedfile']['error'] != 4 && !in_array($ext, $allowed_filetypes)) $fileError = 1;
        if (isset($_REQUEST['submit']) && $_FILES["uploadedfile"]["size"] > $max_size) $fileError = 2; echo "this condition " . $fileError; 

        $POST_MAX_SIZE = ini_get('post_max_size');
        $mul = substr($POST_MAX_SIZE, -1);

        $mul = ($mul == 'M' ? 1048576 : ($mul == 'K' ? 1024 : ($mul == 'G' ? 1073741824 : 1)));
        if ($_SERVER['CONTENT_LENGTH'] > $mul*(int)$POST_MAX_SIZE && $POST_MAX_SIZE) echo "too big!!";
        echo $POST_MAX_SIZE;


        if(empty($name) || empty($phone) || empty($location) || validEmail($emailCheck) == false || $phoneError == "true" || $fileError != 0)
        {
            displayForm($name, $emailCheck, $organisation, $phone, $title, $location, $description, $phoneError, $allowed_filetypes, $ext, $filename, $fileError);
          echo $fileError;
          echo "max size is: " .$max_size;
          echo "and file size is: " .  $_FILES["uploadedfile"]["size"];
          exit;
        } else {

            //copy file from temp to upload directory
            $path_of_uploaded_file = $target_path . $filename;
            $tmp_path = $_FILES["uploadedfile"]["tmp_name"];
            echo $tmp_path;
            echo "and file size is: " .  filesize($_FILES["uploadedfile"]["tmp_name"]);
            exit;
            if(is_uploaded_file($tmp_path))
            {
              if(!copy($tmp_path,$path_of_uploaded_file))
              {
                echo 'error while copying the uploaded file';
              }
            }

        //test debug stuff
            echo "sending email...";
            exit;


        }
        ?>

PHP is returning this error in the log:
[29-Apr-2010 10:32:47] PHP Warning: POST Content-Length of 57885895 bytes exceeds the limit of 10485760 bytes in Unknown on line 0

Excuse all the debug stuff 🙂

FTR, I am running PHP 5.1.2 on IIS.

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

PHP throws all the POST data away because there was no room to put it. There is nothing reliable to be had from only part of the data.

I would work around this problem by uploading the necessary files in a separate step, a different form. You can store the values already obtained in session, ensuring they are not lost because of excessive POST data.

Solution 2

Erisco is right, this will need to be broken down into multiple steps. I do not believe, however, that there is any need to expose this back-end delineation to the user, so I would recommend one of the following courses of action:

Break the file upload into a separate <form> element. When the submit action is taken on either form, cancel the default action, and instead do one of the two things:

  1. Submit the regular form data via AJAX, and when that is complete submit the uploaded file via the standard process (involving the page reloading and what-not)
  2. Check out this example of iFrame trickery to upload the file first, ensure it is not too large, and prevent the page from even reloading if it would not otherwise pass. If the file does pass, store its identifier in a hidden input element and submit the form normally. Take whatever action is appropriate if the file does not upload correctly. Note that this solution does not require you to use the PHP session, just a little bit of response trickery.

Solution 3

You might try seeing if you can read anything from php://input or php://stdin after you find the _POST array has been nuked. You may be able to retrieve the POST data from there and process it manually, but the manual also says that this will not work for //input if your form is using enctype=multipart/form-data

Solution 4

“Try moving the file field to the
bottom of the form and see what
happens. – Marc B”

Unfortunately the same happens: the $_POST array is cleared.
So the iFrame trickery seems to be one of the best solutions. Thanks for that, Dereleased!

Solution 5

one of the tricks is to use something like this:

$lE = error_get_last();
if (  !empty($lE) &&  strpos($lE['message'] , 'POST Content-Length' ) !== false)
{
 die ('Naughty naughty.  you can only upload xxxxx bytes');
}

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply