2010-01-25 53 views
74

我正在處理一個將文件附加到電子郵件的PHP表單,並試圖正常處理上傳文件太大的情況。如何正常處理超過PHP的`post_max_size`的文件?

我知道php.ini中有兩個設置會影響文件上傳的最大文件大小:upload_max_filesizepost_max_size

如果一個文件的大小超過upload_max-filesize,PHP會將該文件的大小返回爲0。我可以檢查。

但是,如果它超過post_max_size,我的腳本會自動失敗並返回空白表單。

有什麼辦法可以捕捉到這個錯誤嗎?

+1

你有機會爲php.ini? post_max_size應設置爲大於upload_max_filesize。您還應該在表單中使用,如http://ca2.php.net/manual/en/features.file-upload.post -method.php – 2010-01-25 16:43:58

+0

@Matt McCormick - MAX_FILE_SIZE輸入效果很好 - 如果文件大小超過了,文件大小現在顯示爲0,這是我已經處理的情況。即使這可以被惡意用戶繞過,它也可以在這裏達到我的目的,因爲我只是想爲普通用戶優雅地失敗。 – 2010-01-25 16:53:44

回答

47

the documentation

如果POST數據的大小大於 比post_max_size要的$ _ POST和 $ _FILES superglobals便會爲空。這個 可以以各種方式跟蹤,例如,如果$ _GET [「處理」]是 集 由$ _GET變量傳遞到 腳本處理數據,即<形式 行動=「edit.php?加工= 1」>和 然後檢查。

因此,不幸的是,它看起來不像PHP發送錯誤。而且由於它發送的是空的$ _POST數組,這就是爲什麼你的腳本回到空白表單 - 它不認爲它是一個POST。 (相當差的設計決定恕我直言)

This commenter也有一個有趣的想法。

似乎更優雅的方式是upload_tmp_dirpost_max_size以及 $ _ SERVER [「CONTENT_LENGTH」]之間 比較。請注意,後者不僅包括 上傳文件的大小加上發佈數據 ,還包括多部分序列。

+3

請閱讀粗體部分。即如果文件大小超過upload_max_filesize,則用戶詢問表單超過post_max_size時會發生什麼。 post_max_size應設置爲高於upload_max_filesize以嘗試避免此問題,但OP可能有保持相同的原因。 – 2010-01-25 16:29:43

+1

對不起,我混淆了post_max_size和upload_max_filesize。 +1 – 2010-01-25 16:40:43

+0

@Matt - post_max_size被設置爲高於upload_max_filesize,但如果上傳超過兩者,仍然會失敗。如果它介於兩者之間,我看到文件大小顯示爲0. – 2010-01-25 16:45:42

36

沒有趕上/處理文件超過最大投遞大小的方式,這是我的首選上,因爲它告訴最終用戶發生了什麼,誰是過錯;)

if(empty($_FILES) && empty($_POST) && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) == 'post'){ //catch file overload error... 
     $postMax = ini_get('post_max_size'); //grab the size limits... 
     echo "<p style=\"color: #F00;\">\nPlease note files larger than {$postMax} will result in this error!<br>Please be advised this is not a limitation in the CMS, This is a limitation of the hosting server.<br>For various reasons they limit the max size of uploaded files, if you have access to the php ini file you can fix this by changing the post_max_size setting.<br> If you can't then please ask your host to increase the size limits, or use the FTP uploaded form</p>"; // echo out error and solutions... 
     addForm(); //bounce back to the just filled out form. 
} 
elseif(// continue on with processing of the page... 
+2

這適用於track_errors = Off時,也可能在php.ini中顯示display_errors = Off和display_startup_errors = Off。否則PHP甚至不會得到那麼多,併發送警告,就像問題標題中一樣。但是在生產系統中,這應該是php.ini設置,所以這很好。 – raoulsson 2013-12-15 20:43:09

+2

這個整潔的想法在我的測試(PHP/5.5.8)中工作正常。考慮到'$ _SERVER ['CONTENT_LENGTH']'和'upload_max_filesize',它也可以得到增強。 – 2014-01-20 11:05:09

+1

這是正確的答案。 – Zulakis 2014-03-05 10:03:24

6

我們在檢查$ _POST和$ _FILES空白的SOAP請求時無法正常工作,因爲它們在有效請求中也是空的。

因此我們實施了一個檢查,比較CONTENT_LENGTH和post_max_size。拋出的異常後來通過我們註冊的異常處理程序轉換爲XML-SOAP-FAULT。在@馬特·麥考密克的和@ AbdullahAJM的答案

private function checkPostSizeExceeded() { 
    $maxPostSize = $this->iniGetBytes('post_max_size'); 

    if ($_SERVER['CONTENT_LENGTH'] > $maxPostSize) { 
     throw new Exception(
      sprintf('Max post size exceeded! Got %s bytes, but limit is %s bytes.', 
       $_SERVER['CONTENT_LENGTH'], 
       $maxPostSize 
      ) 
     ); 
    } 
} 

private function iniGetBytes($val) 
{ 
    $val = trim(ini_get($val)); 
    if ($val != '') { 
     $last = strtolower(
      $val{strlen($val) - 1} 
     ); 
    } else { 
     $last = ''; 
    } 
    switch ($last) { 
     // The 'G' modifier is available since PHP 5.1.0 
     case 'g': 
      $val *= 1024; 
      // fall through 
     case 'm': 
      $val *= 1024; 
      // fall through 
     case 'k': 
      $val *= 1024; 
      // fall through 
    } 

    return $val; 
} 
+0

@曼努埃爾 - 阿扎爾:增加的「休息」階段不正確。那些不屬於那裏..見https://3v4l.org/ABfGs – staabm 2017-02-23 09:01:23

2

大廈,這裏是檢查在測試中使用的變量的設置,然後一個PHP測試用例檢查是否$ _ SERVER [「CONTENT_LENGTH」]超過php_max_filesize設置:

  if (
       isset($_SERVER['REQUEST_METHOD'])  && 
       ($_SERVER['REQUEST_METHOD'] === 'POST') && 
       isset($_SERVER['CONTENT_LENGTH'])  && 
       (empty($_POST)) 
      ) { 
       $max_post_size = ini_get('post_max_size'); 
       $content_length = $_SERVER['CONTENT_LENGTH']/1024/1024; 
       if ($content_length > $max_post_size) { 
        print "<div class='updated fade'>" . 
         sprintf(
          __('It appears you tried to upload %d MiB of data but the PHP post_max_size is %d MiB.', 'csa-slplus'), 
          $content_length, 
          $max_post_size 
         ) . 
         '<br/>' . 
         __('Try increasing the post_max_size setting in your php.ini file.' , 'csa-slplus') . 
         '</div>'; 
       } 
      } 
1

這是一個簡單的方法來解決這個問題:

就叫 「checkPostSizeExceeded」 在你的代碼的開始

function checkPostSizeExceeded() { 
     if (isset($_SERVER['REQUEST_METHOD']) and $_SERVER['REQUEST_METHOD'] == 'POST' and 
      isset($_SERVER['CONTENT_LENGTH']) and empty($_POST)//if is a post request and $_POST variable is empty(a symptom of "post max size error") 
     ) { 
      $max = get_ini_bytes('post_max_size');//get the limit of post size 
      $send = $_SERVER['CONTENT_LENGTH'];//get the sent post size 

      if($max < $_SERVER['CONTENT_LENGTH'])//compare 
       throw new Exception(
        'Max size exceeded! Were sent ' . 
         number_format($send/(1024*1024), 2) . 'MB, but ' . number_format($max/(1024*1024), 2) . 'MB is the application limit.' 
        ); 
     } 
    } 

記住複製此附配功能:

function get_ini_bytes($attr){ 
    $attr_value = trim(ini_get($attr)); 

    if ($attr_value != '') { 
     $type_byte = strtolower(
      $attr_value{strlen($attr_value) - 1} 
     ); 
    } else 
     return $attr_value; 

    switch ($type_byte) { 
     case 'g': $attr_value *= 1024*1024*1024; break; 
     case 'm': $attr_value *= 1024*1024; break; 
     case 'k': $attr_value *= 1024; break; 
    } 

    return $attr_value; 
}