我正在处理一个将文件附加到电子邮件的PHP表单,并试图妥善处理上传的文件太大的情况。
我了解到,其中有两个设置php.ini
会影响文件上传的最大大小:upload_max_filesize
和post_max_size
。
如果文件的大小超过upload_max_filesize
,PHP会将文件的大小返回为0。我可以检查一下。
但是如果超过post_max_size
,我的脚本会静默失败并返回空白表格。
有什么办法可以捕捉到此错误?
我正在处理一个将文件附加到电子邮件的PHP表单,并试图妥善处理上传的文件太大的情况。
我了解到,其中有两个设置php.ini
会影响文件上传的最大大小:upload_max_filesize
和post_max_size
。
如果文件的大小超过upload_max_filesize
,PHP会将文件的大小返回为0。我可以检查一下。
但是如果超过post_max_size
,我的脚本会静默失败并返回空白表格。
有什么办法可以捕捉到此错误?
Answers:
从文档中:
如果发布数据的大小大于post_max_size,则$ _POST和$ _FILES超全局变量为空。这可以通过各种方式进行跟踪,例如,将$ _GET变量传递给处理数据的脚本,即<form action =“ edit.php?processed = 1”>,然后检查$ _GET ['processed']是否为组。
因此,不幸的是,PHP似乎没有发送错误。并且由于它发送了一个空的$ _POST数组,这就是为什么脚本返回空白格式的原因-它不认为它是POST。(恕我直言,糟糕的设计决策)
这个评论者也有一个有趣的想法。
似乎更优雅的方法是在post_max_size和$ _SERVER ['CONTENT_LENGTH']之间进行比较。请注意,后者不仅包括上传文件的大小加上帖子数据,还包括多部分序列。
有一种方法可以捕获/处理超出最大发布大小的文件,这是我的首选,因为它可以告诉最终用户发生了什么以及谁有过错;)
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...
}
$_SERVER['CONTENT_LENGTH']
和upload_max_filesize
考虑。
对于SOAP请求,我们遇到了一个问题,其中对$ _POST和$ _FILES的空度检查不起作用,因为它们在有效请求中也为空。
因此,我们比较了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;
}
以@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>';
}
}
这是解决此问题的简单方法:
只需在代码开头调用“ 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;
}