简体   繁体   中英

PHP stream/file upload and max_input_vars

When I perform stream upload from Java to PHP, I sometimes get a PHP error saying input vars exceeds the limit of max_input_vars .

At first, I did not realize why. Let me first explain:

The files are being uploaded with an approach similar to this:

// 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);

To get a picture why PHP would give me such a warning, I took a dump of the data being sent:

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

Here's the funny part: The file being uploaded is 1,8 megabytes. The resulting logs are:

  • input_vars.log => 5 megabytes, 90,000 lines
  • php_input.log => 20 megabytes, 283,000 lines

Now the error message suddenly seems legit. The php_input.log just contains bytecode, but the input_vars.log is formatted as such:

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

The first three keys are sent via GET, and all the rest would then be the file data. If I search and count for matches of => , I get 25,954 matches. I then assume that REQUEST holds 26,000 keys.

Now, over to my question: I have rased the max_input_vars value several times, and it now holds the value of 30000 . Should I just ignore this security setting, and set it has high as possible? My concern is that PHP removes parts from the REQUEST array if it is larger than 30000 , making the file corrupt.

Is there any security problems with setting this value too high? Is there perhaps a better way of uploading files to PHP?

Maybe try setting enable_post_data_reading directive to "false" (or "Off") to prevent PHP from parsing the file body?

BTW if you are using PHP 5.3.9, you should patch the max_input_vars vulnerability .

What you want to do, is a PUT upload , you shouldn't handle it as a POST; or - at least - set the Content-Type HTTP header to application/octet-stream

In itself "php.net" ( PHP.NET - max_input_vars ), they report that there is no problem in you increase the value of this setting, however, this is a form of "use of this directive mitigates the possibility of denial of service attacks which use hash collisions.".

To resolve this impasse, you can try to set the variable value at runtime, using the function below:

ini_set("max_input_vars", 30000);

I recently went through this problem and how the call was remote, not given to configure runtime, so unfortunately we had to increase the value.

Until now we had no problem, but the idea is the future, modify the code to send the data by parts and thus keep the code within the standards current configuration of the language.

You didn't show how you upload the file in Java. PHP treats ordinary POST requests as if they came from a form and tries to parse fields from them - a bad idea if the data is binary. You'd be better off emulating what HTML file upload forms do and send a "multipart post" (an example ). Then use PHP's standard file upload handling functionality as if receiving from a form.

The accepted answer is valid, but you have to be aware of the fact that turning enable_post_data_reading off also means turning off auto-populating $_POST , $_GET and $_REQUEST arrays. As I am using these arrays extensively, I decided to limit enable_post_data_reading to a specific file dedicated to file uploads:

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

Because I am uploading using an ajax request, I can set user defined headers this way:

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

By doing so, you bypass the need of using $_REQUEST or $_POST , because you get the information in php doing:

$fileName = $_SERVER['HTTP_X_FILE_NAME'];

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM