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

网站后台有一个上传视频文件的选项。我上传一个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,接近当前占用内存的两倍时,就可以上传了。
图片描述

阅读 3.5k
1 个回答

stripos($file_content, $value) 执行过程中会再生成一份 $file_content 变量放在内存中
假设你 $file_content 大小为 26M
在程序运行到 stripos()函数时,内存会瞬间增长到 52M,但是 memory_limit = 50M
这时候会出现内存超出问题
所以设置 memory_limit = 55M 超过 26M 大小的两倍才能正常执行

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

// 拷贝一份haystack
haystack_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);
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏