32

According to php manual nor php://input neither $HTTP_RAW_POST_DATA work with multipart/form-data POST-requests.

"php://input allows you to read raw POST data. It is a less memory intensive alternative to $HTTP_RAW_POST_DATA and does not need any special php.ini directives. php://input is not available with enctype="multipart/form-data"."

How can I get raw data for multipart/form-data forms?

Andrey M.
  • 3,688
  • 3
  • 33
  • 36

4 Answers4

35

Direct answer: you can not do that. PHP insists on parsing it itself, whenever it sees the multipart/form-data Content-Type. The raw data will not be available to you. Sadly. But you can hack around it.

I hit a similar problem, a partner was sending incorrectly formatted data as multipart/form-data, PHP could not parse it and was not giving it out so I could parse it myself.

The solution? I added this to my apache conf:

<Location "/backend/XXX.php">
    SetEnvIf Content-Type ^(multipart/form-data)(.*) NEW_CONTENT_TYPE=multipart/form-data-alternate$2 OLD_CONTENT_TYPE=$1$2
    RequestHeader set Content-Type %{NEW_CONTENT_TYPE}e env=NEW_CONTENT_TYPE
</Location> 

This will change the Content-Type of incoming request to XXX.php from multipart/form-data to multipart/form-data-alternate, which is enough to block PHP from trying to parse it

After this you can finally read the whole raw data from php://input and parse it yourself.

It is ugly, but I have not found a better or in fact any other solution - short of asking the partner to fix their side.

NB! When you do what I described here, $_FILES will be empty.

Anti Veeranna
  • 11,485
  • 4
  • 42
  • 63
  • If I replace the Content-type header this way, i get back the php source in my browser. It seems that the php engine will not process this request. What is the trick? I used different header replacements, none of them worked. –  Mar 14 '11 at 17:21
  • Seems like it's **possible** to do this with [`enable_post_data_reading`](http://stackoverflow.com/a/19710850/632951). – Pacerier Feb 05 '15 at 12:12
  • @Pacerier - possible, my answer was written before php 5.4 – Anti Veeranna Feb 06 '15 at 06:23
12

You can set enable_post_data_reading = Off and PHP won't intercept multipart/form-data data.

Requires: PHP 5.4

Pacerier
  • 86,231
  • 106
  • 366
  • 634
gerard
  • 755
  • 6
  • 12
  • 1
    Interesting. Especially when the PHP Manual elsewhere insists it is impossible to get raw body in case of `multipart/form-data`. – Anshul May 28 '14 at 11:16
  • @Anshul, Does the manual still state that? There's no coherent version of the manual. Some pages are version X while others are at version Z. – Pacerier Feb 05 '15 at 12:06
  • @Pacerier, I still believe its not possible to get the raw multipart/form-data. All of the following links suggest that: http://php.net/manual/en/ini.core.php#ini.always-populate-raw-post-data http://php.net/manual/en/ini.core.php#ini.enable-post-data-reading http://php.net/manual/en/wrappers.php.php http://php.net/manual/en/reserved.variables.httprawpostdata.php – Anshul Feb 06 '15 at 11:52
  • @Anshul, `enable_post_data_reading = Off` gives you the raw multipart/form-data doesn't it? – Pacerier Feb 08 '15 at 15:44
  • @Pacerier, you were right. I was able to read post data of any kind with php://input when enable_post_data_reading was set to off. Tested with Apache as well as PHP's inbuilt web server. The documentation needs to be updated for this. Unfortunately my previous attempts to get small changes in there went futile. :( – Anshul Feb 13 '15 at 18:23
  • @Anshul, Which "previous attempts" are you talking about? Do you have a link? – Pacerier Feb 17 '15 at 03:16
  • @Pacerier, not related to this but here it goes. I submitted a user note http://news.php.net/php.notes/183258 for page http://php.net/manual/en/gearman.examples-reverse-task.php. There was too much friction to get the stuff in and eventually I left it. Moreover, for another bug report, it ended up with status not a bug: https://bugs.php.net/bug.php?id=49322 finally I found my peace in making best of the PHP I know of :) – Anshul Feb 18 '15 at 15:30
5

I didn't implement this fully, but it looks like it should work. In Apache conf:

SetEnvIf Content-Type ^(multipart/form-data)(.*) MULTIPART_CTYPE=$1$2
RequestHeader set Content-Type application/x-httpd-php env=MULTIPART_CTYPE
RequestHeader set X-Real-Content-Type %{MULTIPART_CTYPE}e env=MULTIPART_CTYPE

Setting the Content-Type to application/x-httpd-php appears to solve the original problem of PHP parsing the body, and the problem Norbert Farkas reported: "Apache sends back PHP source code". The body is then available on php://input, and the real content type in the X-Real-Content-Type header. (That header may not be necessary for you -- the MULTIPART_CTYPE variable didn't seem to be showing up in my $_ENV, but the new header did.) All other requests should be handled as usual.

Thanks to Anti Veeranna for most of it! :)

EDIT: P.S. Obviously it's Apache-specific, but in some of the other configurations of PHP there may very well be easier ways.

mrjimoy_05
  • 3,452
  • 9
  • 58
  • 95
Joey Hewitt
  • 120
  • 1
  • 7
-2
//Get the raw POST data
$postBody = file_get_contents("php://input");