PHP流/文件上传和max_input_vars

时间:2012-10-24 13:31:08

标签: php upload stream

当我从Java执行流上传到PHP时,我有时会收到PHP错误,指出输入变量超过了max_input_vars的限制。

起初,我没有意识到原因。我先解释一下:

使用与此类似的方法上传文件:

// get file data from input stream
$putdata = fopen("php://input", "r");
$tmp = tmpfile();
filesize = stream_copy_to_stream ($putdata, $tmp);
fclose ($putdata);

// copy temp stream into destination stream
$target = fopen('myfile.dwg', "w");        
fseek($tmp, 0, SEEK_SET);
stream_copy_to_stream($tmp, $target);
fclose($target);
fclose ($tmp);

为了了解为什么PHP会给我这样的警告,我收集了正在发送的数据:

file_put_contents ('input_vars.log', print_r ($_REQUEST, true));
file_put_contents ('php_input.log', file_get_contents ('php://input'));

这是有趣的部分: 上传的文件是1,8兆字节。生成的日志是:

  • input_vars.log => 5兆字节,90,000行
  • php_input.log => 20兆字节,283,000行

现在错误消息突然变得合法了。 php_input.log只包含字节码,但input_vars.log的格式如下:

Array
(
    [filename] => 0018-101-001_67.dwg
    [versionId] => 11253
    [filetype] => dwg
    [‘á‹Úê-8øFj–sÙ/ghÔ÷JJÐWhvPV] => ...
    ....
)

前三个键是通过GET发送的,其余的都是文件数据。如果我搜索并计算=>的匹配项,我会得到25,954个匹配项。然后我假设REQUEST拥有26,000个密钥。

现在,我的问题: 我已多次触发max_input_vars值,现在它保持30000的值。我应该忽略这个安全设置,并设置它尽可能高吗? 我担心的是,如果REQUEST数组大于30000,它会从REQUEST数组中删除部分,从而使文件损坏。

将此值设置得太高会有任何安全问题吗?是否有更好的方法可以将文件上传到PHP?

6 个答案:

答案 0 :(得分:2)

也许尝试将 enable_post_data_reading 指令设置为“false”(或“关闭”)以防止PHP解析文件正文?

顺便说一句,如果你使用的是PHP 5.3.9,你应该修补max_input_vars vulnerability

答案 1 :(得分:2)

你想做什么,是PUT upload,你不应该把它作为POST来处理;或者 - 至少 - 将Content-Type HTTP标头设置为application/octet-stream

答案 2 :(得分:1)

本身“php.net”(PHP.NET - max_input_vars),他们报告说你增加这个设置的值没有问题,但是,这是一种“使用这个指令减轻了可能性使用哈希冲突的拒绝服务攻击。“。

要解决此僵局,您可以尝试使用以下函数在运行时设置变量值:

ini_set("max_input_vars", 30000);

我最近遇到了这个问题以及调用是如何远程调用的,没有给出配置运行时,所以很遗憾我们不得不增加值。

到目前为止我们没有问题,但想法是未来,修改代码以按部件发送数据,从而将代码保持在标准当前配置的语言中。

答案 3 :(得分:0)

您没有展示如何使用Java上传文件。 PHP将普通的POST请求视为来自表单,并尝试从中解析字段 - 如果数据是二进制的,这是一个坏主意。您最好模仿HTML文件上传表单所做的事情并发送“多部分帖子”(example)。然后使用PHP's standard file upload handling functionality,就像从表单接收一样。

答案 4 :(得分:0)

接受的答案有效,但您必须注意,关闭enable_post_data_reading也意味着关闭自动填充$_POST$_GET$_REQUEST阵列。当我广泛使用这些数组时,我决定将enable_post_data_reading限制为专用于文件上传的特定文件:

<Files "UploadFile.php">
    php_value enable_post_data_reading Off
</Files>

因为我使用ajax请求上传,所以我可以这样设置用户定义的标题:

oXhr.setRequestHeader("X-File-Name", I_sFileName);
oXhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

通过这样做,您无需使用$_REQUEST$_POST,因为您在php中获取信息:

$fileName = $_SERVER['HTTP_X_FILE_NAME'];

答案 5 :(得分:-1)

尝试在php.ini中增加post_max_size,upload_max_filesize和max_file_uploads的大小