网站后台有一个上传视频文件的选项。我上传一个25M的视频,结果报Fatal error
php.ini中的配置:
file_uploads = On
max_execution_time =90
max_input_time = 90
memory_limit = 50M
post_max_size =40M
upload_max_filesize =40M
default_socket_timeout = 80
关键代码:
public function checkContent($uploadInfo) {
$file_content = $this->readover(BASE_ROOT.$uploadInfo['source']);
if (empty($file_content)) {
@unlink(BASE_ROOT.$uploadInfo['source']);
return 'upload_content_error';
}
else {
$forbid_chars = array(
'0'=>"?php",
'1'=>"cmd.exe",
'2'=>"mysql_connect",
'3'=>"phpinfo()",
'4'=>"get_current_user",
'5'=>"zend",
'6'=>"_GET",
'7'=>"_POST",
'8'=>"_REQUEST",
'9'=>"base64_decode",
'10'=>"echo",
'11'=>"?PHP",
);
foreach ($forbid_chars as $key=>$value) {
printf('memory usage: %01.2f MB | ', memory_get_usage()/1024/1024);
if (stripos($file_content, $value)) {//程序走到这个位置报错!
@unlink(BASE_ROOT.$uploadInfo['source']);
return 'upload_content_error';
break;
}
}
}
if (in_array(strtolower($uploadInfo['ext']), array('gif','jpg','jpeg','png'))) {
if (!$this->getFileSize($uploadInfo['source'])) {
@unlink(BASE_ROOT.$uploadInfo['source']);
return 'input_max_file_size';
}
}
return true;
}
private function readover($fileName, $method = 'rb') {
$data = '';
if ($handle = @fopen($fileName, $method)) {
flock($handle, LOCK_SH);
$data = @fread($handle, filesize($fileName));
fclose($handle);
}
return $data;
}
后来设置memory_limit = 55M,接近当前占用内存的两倍时,就可以上传了。
stripos($file_content, $value) 执行过程中会再生成一份 $file_content 变量放在内存中
假设你 $file_content 大小为 26M
在程序运行到 stripos()函数时,内存会瞬间增长到 52M,但是 memory_limit = 50M
这时候会出现内存超出问题
所以设置 memory_limit = 55M 超过 26M 大小的两倍才能正常执行
下面是底层实现,内容来源于网络