How to get body of a POST in php?
This is the body of the request (a POST request).
In php, what do I have to do to extract that value?
This is a helpful question for people looking to create RESTful APIs. Most don’t know how to access the raw input data submitted to their scripts as it’s not available via the $_POST superglobal. This is also (especially) true in the case of PUT requests, as PHP has no corresponding superglobal.
It’s worth noting that the name $_POST is misleading, as not any type of data from a POST request will be there, but only when the content type is application/x-www-form-urlencoded or multipart/form-data
9 Answers 9
To access the entity body of a POST or PUT request (or any other HTTP method):
$entityBody = file_get_contents('php://input');
Also, the STDIN constant is an already-open stream to php://input , so you can alternatively do:
$entityBody = stream_get_contents(STDIN);
php://input is a read-only stream that allows you to read raw data from the request body. In the case of POST requests, it is preferable to use php://input instead of $HTTP_RAW_POST_DATA as it does not depend on special php.ini directives. Moreover, for those cases where $HTTP_RAW_POST_DATA is not populated by default, it is a potentially less memory intensive alternative to activating always_populate_raw_post_data. php://input is not available with enctype=»multipart/form-data».
Specifically you’ll want to note that the php://input stream, regardless of how you access it in a web SAPI, is not seekable. This means that it can only be read once. If you’re working in an environment where large HTTP entity bodies are routinely uploaded you may wish to maintain the input in its stream form (rather than buffering it like the first example above).
To maintain the stream resource something like this can be helpful:
php://temp allows you to manage memory consumption because it will transparently switch to filesystem storage after a certain amount of data is stored (2M by default). This size can be manipulated in the php.ini file or by appending /maxmemory:NN , where NN is the maximum amount of data to keep in memory before using a temporary file, in bytes.
Of course, unless you have a really good reason for seeking on the input stream, you shouldn’t need this functionality in a web application. Reading the HTTP request entity body once is usually enough — don’t keep clients waiting all day while your app figures out what to do.
Note that php://input is not available for requests specifying a Content-Type: multipart/form-data header ( enctype=»multipart/form-data» in HTML forms). This results from PHP already having parsed the form data into the $_POST superglobal.
How to capture full HTTP request data (headers and body) with PHP?
I have a problem implementing an API that works with Java, but fails to work with cURL. We’ve gone through everything so far and there must be something that is different between the requests that Java makes and what we make. In PHP we can get header data by looking at $_SERVER[‘HTTP_*’] variables and we can get request body from file_get_contents(‘php://input’); But we cannot get the exact data sent from user agent to client. Is it possible to get the full request, that user agent sends, with PHP? Headers and body included? If so, then how? The only example I found is here, but this one gets the body the way I mentioned, while it gets headers by parsing through $_SERVER , which seems like a hack since it’s never 100% of what was actually sent. All help and tips are appreciated!
3 Answers 3
for headers you can try apache_request_headers() and for body I dont know other method than file_get_contents(‘php://input’);
These are fine, but we were looking for more of a byte-level comparison. Anyways, this is the best we have I suppose.
since headers comes from apache server in php you can’t do a thing maybe apache have something.. maybe in logs then read with php but that’s hack for hack 😀
Old question, but for anyone needing to do this in the future. The best (probably only) way would be to take full control of the server by being the server.
Set up a socket server listening on port 80 (if this is all you need the server to do), or any other port if 80 is not available.
That way you can capture the request completely unmodified. Examples of basic socket servers are plentiful, here is a simplified version of the latest one I implemented, which will print the full request:
//Create socket while (($sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) < dlog("socket_create() failed: reason: " . socket_strerror(socket_last_error())); sleep(1); >//Reduce blocking if previous connections weren't ended correctly if (!socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1)) < dlog("socket_set_option() failed: reason: " . socket_strerror(socket_last_error($sock))); exit; >//Bind to port $tries = 0; while (@socket_bind($sock, 0, $port) === false) < dlog("socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock))); sleep(1); $tries++; if ($tries>30) < dlog("socket_bind() failed 30 times giving up. "); exit; >> //Start listening while (@socket_listen($sock, 5) === false) < dlog("socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock))); sleep(1); >//Makes it possible to accept several simultaneous connections socket_set_nonblock($sock); //Keeps track of active connections $clients = array(); dlog("server started. "); while(true) < //Accept new connections while (($msgsock = @socket_accept($sock)) !== false) < //Prevent blocking socket_set_nonblock($msgsock); //Get IP - just for logging socket_getpeername($msgsock, $remote_address); //Add new client to array $clients[] = array('sock' =>$msgsock, 'timeout' => time()+30, 'ip' => $remote_address); dlog("$remote_address connected, client count: ".count($clients)); > //Loop existing clients and read input foreach($clients as $key => $client) < $rec = ''; $buf = ''; while (true) < //Read 2 kb into buffer $buf = socket_read($clients[$key]['sock'], 2048, PHP_BINARY_READ); //Break if error reading if ($buf === false) break; //Append buffer to input $rec .= $buf; //If no more data is available socket read returns an empty string - break if ($buf === '') break; >if ($rec=='') < //If nothing was received from this client for 30 seconds then end the connection if ($clients[$key]['timeout']
To start the server on port 8080 just run php filename.php 8080 from a shell.
Getting content body from http post using php CURL
I am trying to debug an http post the I am trying to send from list application. I have been able to send the correct post from php CURL which corectly interfaces with my drupal 7 website and uploads an image. In order to get this to work in my lisp application I really need to see the content body of my http post I have been able to see the headers using a call like this:
curl_setopt($curl, CURLOPT_STDERR, $fp); curl_setopt($curl, CURLOPT_VERBOSE, 1);
and the headers look the same in my lisp application but I have been unable to examine the body of the post. I have searched online and other people have asked this question but no one posted a response. The content type of my http post is:
application/x-www-form-urlencoded
I have also tried many http proxy debuging tools but they only ever the http GET to get my php page but never capture the get sent from server once the php code is executed. EDIT: I have added a code snipet showing where I actually upload the image file.
// file $file = array( 'filesize' => filesize($filename), 'filename' => basename($filename), 'file' => base64_encode(file_get_contents($filename)), 'uid' => $logged_user->user->uid, ); $file = http_build_query($file); // REST Server URL for file upload $request_url = $services_url . '/file'; // cURL $curl = curl_init($request_url); curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); curl_setopt($curl, CURLOPT_STDERR, $fp); curl_setopt($curl, CURLOPT_VERBOSE, 1); curl_setopt($curl, CURLOPT_POST, 1); // Do a regular HTTP POST curl_setopt($curl, CURLOPT_POSTFIELDS, $file); // Set POST data curl_setopt($curl, CURLOPT_HEADER, FALSE); // Ask to not return Header curl_setopt($curl, CURLOPT_COOKIE, "$cookie_session"); // use the previously saved session curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($curl, CURLOPT_FAILONERROR, TRUE); curl_setopt_array($curl, array(CURLINFO_HEADER_OUT => true) ); $response = curl_exec($curl);