【问题标题】:How to detect if a user uploaded a file larger than post_max_size?如何检测用户是否上传了大于 post_max_size 的文件?
【发布时间】:2011-09-05 15:37:24
【问题描述】:

我应该如何以理智的方式处理超过 post_max_size 的 http 上传?

在我的配置中,post_max_sizeupload_max_filesize 大几 MB 我遇到的问题是:
如果用户上传的文件超过post_max_size

  • _POST 数组为空
  • _FILES 数组为空,当然其中不存在任何错误代码。
  • 没有其他信息可以通过这些方式访问它是哪种形式的帖子。

部分问题在于接收脚本会根据 POST 的内容采取不同的操作。

我确实可以访问_SERVER 变量,并且可以获得关于发生了什么的线索,即CONTENT_TYPECONTENT_LENGTHREQUEST_METHOD。然而,根据这些内容进行猜测似乎非常有问题。

MEMORY_LIMIT(设置为相关大小的 10 倍)和 Apaches LimitRequestBody(设置为无限制)被发现没有问题。

就目前而言,我什至很难向用户提供任何有意义的消息。

有什么方法可以保留一些表单数据,以便更好地了解哪里出了问题?我非常不愿意离开 php。

【问题讨论】:

    标签: php file-upload php-5.3


    【解决方案1】:

    您可能需要恢复到使用闪光灯/银光等的东西,例如: http://www.plupload.com/

    或者看看基于 Java 的解决方案...

    基本上是将上传分成更易于管理(和可恢复)的块,然后在服务器端重新组装它们。

    【讨论】:

      【解决方案2】:

      除非您的上传表单包含文件输入字段以外的字段,否则 $_POST 应该为空 - 文件仅通过 $_FILES 处理。如果超过帖子大小,$_FILES 会为空,这很奇怪——上传处理程序有一个特定的错误代码 (1/UPLOAD_ERR_INI_SIZE) 来报告这种情况。还要检查memory_limit 是否大于upload_max_filesize。

      您的网络服务器也可能会阻止上传,这会在调用 PHP 之前发生。在 Apache 上,它由 LimitRequestBody 控制。

      【讨论】:

      • 是的,还有一些其他的字段,在正常情况下是用来识别是什么类型的上传。在这种情况下,LimitRequestBody 设置在 php 设置之上并且没有干扰。
      • 是的,我也很惊讶地发现 _FILES 是空的。
      【解决方案3】:

      根据PHP documentation

      如果 post 数据的大小大于 post_max_size,则 $_POST 和 $_FILES 超全局变量为空。这可以通过各种方式进行跟踪,例如通过将 $_GET 变量传递给处理数据的脚本,即

      ,然后检查是否设置了 $_GET['processed']。

      如果您需要为特定脚本增加限制,您可以尝试ini_set('post-max-size', $size_needed);。不过,我不确定它是否可以在脚本中被覆盖;这个限制可能是为了特别阻止你做你想做的事情。

      【讨论】:

      • 我对自己的限制感到满意,但不是 php 在超出这些限制时的反应方式。 GET 想法也是一个有用的想法,但我希望它对用户透明,并且感觉“hackish”。
      【解决方案4】:

      对于不需要更改服务器端的简单修复,我将使用 HTML5 文件 API 在上传之前检查文件的大小。如果超过已知限制,则取消上传。我相信这样的事情会奏效:

      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>
      

      显然这只是一个示例的骨架,并不是每个浏览器都支持这一点。但是使用它并没有什么坏处,因为它可以以这样的方式实现,它可以优雅地降级为旧浏览器的任何内容。

      当然,这并不能解决问题,但它至少可以让您的一些用户以最少的努力感到满意。 (而且他们甚至不必等待上传失败。)

      --

      顺便说一句,检查$_SERVER['CONTENT_LENGTH'] 与帖子和文件数据的大小可能有助于检测是否有故障。我认为当出现错误时它不会为零,而$_POST$_FILES 都将为空。

      【讨论】:

      • 为了清楚起见,我将与@King Skippus 回答中的引用一起实现这一点。即,用这个客户端解决方案让人们开心,然后在服务器端寻找空帖子并采取相应的行动。
      • 这很有用。我主要担心的是无法以适当的方式通知我的用户。对当前浏览器的支持有任何想法吗?
      • @Captain Giraffe,我认为每个常用的非 IE 浏览器都允许您像这样通过 JavaScript 检查文件大小,但我不确定。 (同样,它会优雅地降级,因此将其用作您的解决方案的一部分并没有什么害处。)另外,请参阅我的编辑以检查是否发生上传问题的潜在方法。
      • gracefully degrade 一种方式还是enhance progressively 另一种方式? HTML 给我们带来了很多不错的营销术语耶
      【解决方案5】:

      我喜欢@Matthew 的回答,但需要一个可以检查多个上传文件的版本。

      这是我的解决方案:

      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;
      }
      

      并且,为了完整起见,这里是函数与要提交的表单的绑定:

      jQuery(function($) {
          $("form").submit(
              function() {
                  return checkAttachmentsSize();
              }   
          });
      );
      

      注意:
      uploadMax 是我在计算允许上传的最大大小后通过 php 设置的变量。

      【讨论】:

        【解决方案6】:

        您可以在服务器端解决此问题,而无需求助于查询字符串。只需将 *post_max_size* 设置与请求的预期内容长度进行比较。以下代码是 Kohana 是如何做到的。

        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);
        }
        

        【讨论】:

        • 我自己不处理上传。 php 可以。如果我可以从浏览器中截取“content_length”,那一切都是粉红色的独角兽和蝴蝶。不过,我很感谢您的意见。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-26
        • 2011-04-04
        • 2011-09-20
        • 2016-02-15
        • 1970-01-01
        相关资源
        最近更新 更多