首页 > 开发 > php > 正文

memory_limit的值为什么要设置大于上传视频文件值的两倍以上?

2017-09-06 13:35:05  来源:网友分享

网站后台有一个上传视频文件的选项。我上传一个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 大小的两倍才能正常执行

下面是底层实现,内容来源于网络

// 拷贝一份haystackhaystack_dup = estrndup(haystack, haystack_len);if (Z_TYPE_P(needle) == IS_STRING) {    char *orig_needle;    if (!Z_STRLEN_P(needle)) {        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");        efree(haystack_dup);        RETURN_FALSE;    }    orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));    // 调用php_stristr函数找出orig_needle的值。    found = php_stristr(haystack_dup, orig_needle,    haystack_len, Z_STRLEN_P(needle));    efree(orig_needle);} else {    if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {        efree(haystack_dup);        RETURN_FALSE;    }    needle_char[1] = 0;    found = php_stristr(haystack_dup, needle_char,    haystack_len, 1);}if (found) {    found_offset = found - haystack_dup;    if (part) {        RETVAL_STRINGL(haystack, found_offset, 1);    } else {        RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);    }} else {    RETVAL_FALSE;}// 释放变量efree(haystack_dup);