Search code examples
phpapachehttp-headers

PHP: How to read POST body with Transfer-Encoding: chunked, no Content-Length


I am writing a service to receive data from an energy monitoring device in my house. The only way the device can push data is by using an HTTP POST, with Transfer-Encoding: chunked, and no Content-Length, and the data as XML in the request body.

I would like to be able to read this data in a PHP script (behind Apache) and store it in my database.

It appears that the most correct way to read the HTTP request body in PHP these days is to open and read php://input. However, comments from users on PHP's website indicate (and my testing confirms), that if no Content-Length header is specified by the client, php://input returns no data (even if there is data being sent by the client in chunked encoding).

Is there an alternate way to get access to the request body? Can I configure Apache (with .htaccess) to decode the chunked data and call my script once it gets it all, and include Content-Length? Or configure PHP so it will be able to handle this?

Thanks!


Solution

  • Might as well write this as an answer I suppose.

    The issue you describe is documented here: https://bugs.php.net/bug.php?id=60826

    Highlights from the thread:

    So here is what I found. If you send chunked http request but do not send the content-length (as we should do using HTTP 1.1 protocol) the body part of the request is empty (php://input returns nothing). This result remains valid for the following configuration where PHP runs via FastCGI :

    The same configuration with PHP running as mod_php is fine, the body request is available through php://input.

    And

    Essentially, PHP is following the spec, and not reading beyond the FastCGI CONTENT_LENGTH header value - so correct fixes are necessarily above PHP, in the FastCGI or web server implementation.

    Possible Workarounds:

    0) Use httpd with mod_php

    1) Use a different web server.

    2) Look at patches for mod_fcgid

    3) Maybe (not recommended) flip always_populate_raw_post_data and see if there is anything in $HTTP_RAW_POST_DATA