【问题标题】:$_POST data returns empty when headers are > POST_MAX_SIZE当标头大于 POST_MAX_SIZE 时,$_POST 数据返回空
【发布时间】:2011-02-13 13:33:33
【问题描述】:

希望这里有人能回答我的问题。

我有一个包含简单字段的基本表单,例如姓名、号码、电子邮件地址等和 1 个文件上传字段。

我正在尝试在我的脚本中添加一些验证,以检测文件是否太大,然后拒绝用户返回表单以选择/上传较小的文件。

我的问题是,如果用户选择的文件大于我的验证文件大小规则且大于 php.ini POST_MAX_SIZE/UPLOAD_MAX_FILESIZE 并推送提交,那么 PHP 似乎尝试处理表单只是在 POST_MAX_SIZE 设置上失败然后清除整个 $_POST 数组并且不返回任何内容。

有没有办法解决这个问题?当然,如果有人上传的内容 > 超过 php.ini 中配置的最大大小,那么您仍然可以获得其余的 $_POST 数据???

这是我的代码。

<?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 在日志中返回此错误: [2010 年 4 月 29 日 10:32:47] PHP 警告:57885895 字节的 POST 内容长度超过第 0 行未知中 10485760 字节的限制

请原谅所有的调试问题:)

FTR,我在 IIS 上运行 PHP 5.1.2。

【问题讨论】:

  • 这听起来不对,所有的 POST 变量都应该保持不变。您可能必须发布该代码。
  • 现在将其添加到原始帖子中。
  • @Jared:应该在我的第一条评论中提到,但您可能还想查看php.net/manual/en/features.file-upload.common-pitfalls.php
  • 不是很相关,但只是作为至少升级到 PHP 5.2.0 的激励——您可以利用 PHP 的数据过滤将 validEmail() 函数缩短为 function validEmail($email) { return (bool)filter_var($email, FILTER_VALIDATE_EMAIL); }(参见: us2.php.net/manual/en/book.filter.php)
  • 有点相关,您是否尝试过使用$_POST 而不是$_REQUEST 来查看这些值是否仍然填充在那里?当$_FILE 处理失败时,$_REQUEST 处理可能会被取消。

标签: php


【解决方案1】:

其中一个技巧是使用这样的东西:

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

【讨论】:

    【解决方案2】:

    "尝试将文件字段移动到 表格底部,看看什么 发生。 – 马克 B"

    不幸的是,同样的事情发生了:$_POST 数组被清除了。 所以 iFrame 诡计似乎是最好的解决方案之一。谢谢你,取消发布!

    【讨论】:

      【解决方案3】:

      Erisco 是对的,这需要分解为多个步骤。但是,我认为没有必要向用户公开此后端描述,因此我建议采取以下行动方案之一:

      将文件上传拆分为单独的&lt;form&gt; 元素。当对任一表单执行提交操作时,取消默认操作,而是执行以下两项操作之一:

      1. 通过 AJAX 提交常规表单数据,完成后通过标准流程提交上传的文件(包括页面重新加载等)
      2. 检查this example of iFrame trickery先上传文件,确保文件不要太大,如果不通过,防止页面甚至重新加载。如果文件确实通过了,则将其标识符存储在隐藏的输入元素中并正常提交表单。如果文件没有正确上传,请采取任何适当的措施。请注意,此解决方案不需要您使用 PHP 会话,只需要一点响应技巧。

      【讨论】:

      • 我同意尽可能使用 JavaScript 来减轻用户的麻烦。
      【解决方案4】:

      PHP 会丢弃所有 POST 数据,因为没有空间放置它们。仅从部分数据中没有任何可靠的信息。

      我会通过在一个单独的步骤中上传必要的文件来解决这个问题,一种不同的形式。您可以将已经获得的值存储在会话中,确保它们不会因为过多的 POST 数据而丢失。

      【讨论】:

      • 我开始认为这是唯一的方法 :( 感谢大家提供的提示/解决方案。
      • 如果有人遇到这个很有帮助的问题......我最终做的是将文件上传与主表单分开,因此构建了一个多阶段表单,因此当用户上传了文件并且文件大于 POST_MAXSIZE 是否清除标题无关紧要,因为表单详细信息已保存到会话中,我使用if($_SERVER['REQUEST_METHOD'] == 'POST' &amp;&amp; empty($_POST) &amp;&amp; $_SERVER['CONTENT_LENGTH'] &gt; 0) 来检测标题是否已满。
      【解决方案5】:

      在您发现 _POST 数组已被 nuked 后,您可以尝试查看是否可以从 php://input 或 php://stdin 读取任何内容。您也许可以从那里检索 POST 数据并手动处理它,但是如果您的表单使用 enctype=multipart/form-data,手动 also says 将不适用于 //input

      【讨论】:

      • 我给了你一个聪明的主意。但由于这不适用于 enctype=multipart/form-data,因此并不是我正在寻找的答案。不过谢谢!我不敢相信这么简单的事情竟然需要一个复杂的解决方案。为什么 PHP 无论如何都要清除 $_POST 数组,我猜是因为大文件上传的标头已满???
      • 嗯,PHP 确实按照从客户端发送的顺序处理表单字段。如果文件字段是表单中的第一件事,并且文件超出了大小限制,则处理将在处理任何其他字段之前中止。尝试将文件字段移动到表单底部,看看会发生什么。
      • Removing "Content-Type": "application/json" from my js fetch 解决了上传大文件时 $_POST 为空的问题
      猜你喜欢
      • 1970-01-01
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多