如何优雅地处理超过 PHP 的 `post_max_size` 的文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2133652/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to gracefully handle files that exceed PHP's `post_max_size`?
提问by Nathan Long
I'm working on a PHP form that attaches a file to an email, and trying to gracefully handle cases where the uploaded file is too large.
我正在处理一个将文件附加到电子邮件的 PHP 表单,并尝试优雅地处理上传文件太大的情况。
I've learned that there are two settings in php.inithat affect the maxiumum size of a file upload: upload_max_filesizeand post_max_size.
我了解到有两个设置php.ini会影响文件上传的最大大小:upload_max_filesize和post_max_size.
If a file's size exceeds upload_max_filesize, PHP returns the file's size as 0. That's fine; I can check for that.
如果文件大小超过upload_max_filesize,PHP 返回文件大小为 0。我可以检查一下。
But if it exceeds post_max_size, my script fails silently and goes back to the blank form.
但是如果超过post_max_size,我的脚本会默默地失败并返回到空白表单。
Is there any way to catch this error?
有没有办法捕捉这个错误?
采纳答案by Matt McCormick
From the documentation:
从文档:
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.
如果 post 数据的大小大于 post_max_size,则$_POST 和 $_FILES 超全局变量为空。这可以通过多种方式进行跟踪,例如通过将 $_GET 变量传递给处理数据的脚本,即 <form action="edit.php?processed=1">,然后检查 $_GET['processed'] 是否为放。
So unfortunately, it doesn't look like PHP sends an error. And since it sends am empty $_POST array, that is why your script is going back to the blank form - it doesn't think it is a POST. (Quite a poor design decision IMHO)
所以不幸的是,它看起来不像 PHP 发送错误。并且由于它发送的是空的 $_POST 数组,这就是为什么您的脚本返回空白表单的原因 - 它不认为它是 POST。(恕我直言,相当糟糕的设计决定)
This commenteralso has an interesting idea.
这位评论者也有一个有趣的想法。
It seems that a more elegant way is comparison between post_max_size and $_SERVER['CONTENT_LENGTH']. Please note that the latter includes not only size of uploaded file plus post data but also multipart sequences.
似乎更优雅的方法是在 post_max_size 和 $_SERVER['CONTENT_LENGTH'] 之间进行比较。请注意,后者不仅包括上传文件的大小和发布数据,还包括多部分序列。
回答by AbdullahAJM
there is a way to catch / handle files exceeding max post size, this is my preferred on, as it tells the end user what has happened and who is at fault ;)
有一种方法可以捕获/处理超过最大帖子大小的文件,这是我的首选,因为它告诉最终用户发生了什么以及谁有错;)
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.
}
else {
// continue on with processing of the page...
}
回答by staabm
We got the problem for SOAP requests where a check for emptiness of $_POST and $_FILES doesn't work, because they are also empty on valid requests.
我们遇到了 SOAP 请求的问题,其中检查 $_POST 和 $_FILES 的空性不起作用,因为它们在有效请求上也是空的。
Therefore we implemented a check, comparing CONTENT_LENGTH and post_max_size. The thrown Exception is later on transformed into a XML-SOAP-FAULT by our registered exception handler.
因此,我们实施了一项检查,比较 CONTENT_LENGTH 和 post_max_size。抛出的异常稍后由我们注册的异常处理程序转换为 XML-SOAP-FAULT。
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;
}
回答by Lance Cleveland
Building on @Matt McCormick's and @AbdullahAJM's answers, here is a PHP test case that checks the variables used in the test are set and then checks if the $_SERVER['CONTENT_LENGTH'] exceeds the php_max_filesize setting:
基于@Matt McCormick 和@AbdullahAJM 的回答,这里是一个 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>';
}
}
回答by Doglas
That is a simple way to fix this problem:
这是解决此问题的简单方法:
Just call "checkPostSizeExceeded" on begin of your code
只需在代码开头调用“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.'
);
}
}
Remember copy this auxiliar function:
记住复制这个辅助函数:
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;
}

