|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2009-11-17 22:46 UTC] tyler dot thackray at gmail dot com
Description:
------------
When POSTing multipart/form-data to a PHP script, PHP will automatically parse the data into $_FILES and $_POST super globals. In this case, php://stdio will be empty.
Apache 2 supports chunked encoded requests. When sending multipart/form-data with "transfer-encoding: chunked" Apache 2 will dechunk the request and pass it onto PHP. However, in this case PHP will NOT parse the multipart/form-data and the RAW data can be seen at php://stdio. I've examined the headers and the only difference between the working and not working is the "transfer-encoding: chunked"; the "content-type: multipart/form-data, boundry=XXXX" is still present.
Perhaps this is an issue with mod_php? Perhaps the chunked header is confusing PHP? In any case, I would expect PHP to parse the multipart/form-data regardless if it was originally chunked or not, as Apache should take care of the chunks.
It's interesting to note that the headers can be combined with php://stdio and resent to the same script (not chunked but still multipart/form-data encoded) and PHP will actually parse it.
There's no easy way to provide sample code for this issue, suffice it to say that if you send multipart/form-data using chunked encoding to any PHP script, you will find that $_FILES and $_POST are empty and the raw data is present at php://stdio.
Reproduce code:
---------------
<?php
print_r($_FILES);
print_r($_POST);
?>
Expected result:
----------------
"Array() Array()"
Actual result:
--------------
The $_FILES and $_POST super global should contain parsed data.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Mon Nov 03 23:00:01 2025 UTC |
Here is the test code, please excuse its length but this is not a simple scenario. The test involves two scripts "sender.php" and "receiver.php". RECEIVER.PHP: <?php $input = file_get_contents('php://input'); $stdin = file_get_contents('php://stdin'); print "FILES: "; print_r($_FILES); print("<br>POST: "); print_r($_POST); print("<br>input: ".$input); print("<br>stdin: ".$stdin); ?> SENDER.PHP <?php // when 'true' multipart data is NOT parsed, but is present at php://stdio // when 'false' multipart is parsed into $_FILES and $_POST $chunked = false; $body1 = "--AaB03x\r\n". "Content-Disposition: form-data; name=\"forPOST\"\r\n". "\r\n". "1257880790\r\n". "--AaB03x\r\n"; $body2 = "Content-Disposition: form-data; name=\"test_file\"; filename=\"test.file\"\r\n". "Content-Type: application/octet-stream\r\n". "\r\n". "binary data\r\n". "--AaB03x--"; // change the POST to the location of your "receiver.php" $header = "POST /test/receiver.php HTTP/1.1\r\n". "Connection: close\r\n". "Host: ".$_SERVER['HTTP_HOST']."\r\n". "Content-Type: multipart/form-data, boundary=AaB03x\r\n"; if ($chunked){ $body = dechex(strlen($body1))."\r\n".$body1."\r\n". dechex(strlen($body2))."\r\n".$body2."\r\n0\r\n\r\n"; $header .= "Transfer-Encoding: chunked\r\n"; } else{ $body = $body1 . $body2; $header .= "Content-Length: ".strlen($body)."\r\n"; } $header .= "\r\n"; $final = $header . $body; print "<pre>".$final."<br><br>"; $fp = fsockopen($_SERVER['HTTP_HOST'], 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { fwrite($fp, $final); while (!feof($fp)) { print fgets($fp, 128); } fclose($fp); } print "</pre>"; ?>I am using apache2 with mod_php. Sender script: <?php $response = [ "POST /api/responses HTTP/1.1", "Host: 1vsig-test01.dev.aorti.tech:8080", "Authorization: Explicit kraken@domain.ru", "Accept: */*", "Accept-Encoding: gzip, deflate", "User-Agent: Python/3.5 aiohttp/3.6.2", "Content-Type: multipart/form-data; boundary=48d383065e754030ae01de21a3269bd5", "Transfer-Encoding: chunked", "", "24", "--48d383065e754030ae01de21a3269bd5", "", "62", "Content-Type: application/json", "Content-Length: 2", "Content-Disposition: form-data; name=\"meta\"", "", "", "2", "{}", "2", "", "", "26", "--48d383065e754030ae01de21a3269bd5--", "", "0", "" ]; $fp = stream_socket_client("tcp://1vsig-test01.dev.aorti.tech:8080", $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { foreach($response as $responseLine){ fwrite($fp, $responseLine."\r\n"); } while (!feof($fp)) { echo fgets($fp, 1024); } fclose($fp); } If I use the "Content-Type: multipart/form-data; boundary=48d383065e754030ae01de21a3269bd5" header, I completely lose the request body. $input = file_get_contents('php://input'); $stdin = file_get_contents('php://stdin'); $input and $stdin - empty If I remove "boundary=48d383065e754030ae01de21a3269bd5" and I have a "Content-Type: multipart/form-data". then the request body exists, although not in a structured form