When using xml-rpc, server side will get the data from client with php://input method instead of $_POST. Hence today we will discuss php://input.
PHP official manual has below explanation to php://input:
“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”.
Here we understand the above statement from 3 aspects:
- Read POST data
- Cannot use multipart/form-data type
- php://input vs $HTTP_RAW_POST_DATA
Read POST data
PHPers should be familiar with $_POST, What are the differences between $_POST and php://input? GET can also be used to communicate between client and server, is php://input able to read GET data? Here we use some scripts to do some experiments.
@file 192.168.0.6:/phpinput_server.php --Print received data @file 192.168.0.8:/phpinput_post.php --Submit form data with POST @file 192.168.0.8:/phpinput_xmlrpc.php --Submit xml-rpc data with POST @file 192.168.0.8:/phpinput_get.php --Submit form data with GET
phpinput_server.php and phpinput_post.php
file_get_contents('php://input', 'r'); echo "-------\$_POST------------------\n"; echo var_dump($_POST) . "\n"; echo "-------php://input-------------\n"; echo $raw_post_data . "\n"; ?> urldecode('perfgeeks') . '&p=' . urldecode('7788'); $http_entity_type = 'application/x-www-form-urlencoded'; $http_entity_length = strlen($http_entity_body); $host = '192.168.0.6'; $port = 80; $path = '/phpinput_server.php'; $fp = fsockopen($host, $port, $error_no, $error_desc, 30); if ($fp) { fputs($fp, "POST {$path} HTTP/1.1\r\n"); fputs($fp, "Host: {$host}\r\n"); fputs($fp, "Content-Type: {$http_entity_type}\r\n"); fputs($fp, "Content-Length: {$http_entity_length}\r\n"); fputs($fp, "Connection: close\r\n\r\n"); fputs($fp, $http_entity_body . "\r\n\r\n"); while (!feof($fp)) { $d .= fgets($fp, 4096); } fclose($fp); echo $d; } ?>
We can use ngrep to capture the http request packet. Let's execute phpinput_post.php
@php /phpinput_post.php
HTTP/1.1 200 OK Date: Thu, 08 Apr 2010 03:23:36 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Content-Length: 160 Connection: close Content-Type: text/html; charset=UTF-8 -------$_POST------------------ array(2) { ["n"]=> string(9) "perfgeeks" ["p"]=> string(4) "7788" } -------php://input------------- n=perfgeeks&p=7788
The HTTP request looks like:
T 192.168.0.8:57846 -> 192.168.0.6:80 [AP] POST /phpinput_server.php HTTP/1.1.. Host: 192.168.0.6..Content-Type: application/x-www-form-urlencoded..Co ntent-Length: 18..Connection: close....n=perfgeeks&p=7788....
With close check, we can find:
- The data is the same in $_POST and php://input
- The Content-Type is application/x-www-form-urlencoded, it means the data in the HTTP body is submitted with POST method and urlencoded.
Now let's look at phpinput_xmlrpc.php:
After executing this script, we get:
@php /phpinput_xmlrcp.php
HTTP/1.1 200 OK Date: Thu, 08 Apr 2010 03:47:18 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Content-Length: 154 Connection: close Content-Type: text/html; charset=UTF-8 -------$_POST------------------ array(0) { } -------php://input------------- jt_userinfo
The HTTP request data packet:
T 192.168.0.8:45570 -> 192.168.0.6:80 [AP] POST /phpinput_server.php HTTP/1.1.. Host: 192.168.0.6..Content-Type: text/html..Content-Length: 75..Connec tion: close...... jt_userinfo< /name>.....
We can easily find:
- Content-Type is text/xml, it means the data in body of HTTP request is xml formmatted.
- $_POST is empty which is different from http_entity_body
- php://input is the same as http_entity_body, it means php://input is different from $_POST
Let's now look at the script using GET method. Here we need some small modifications to the phpinput_server.php script:
file_get_contents('php://input', 'r'); echo "-------\$_GET------------------\n"; echo var_dump($_GET) . "\n"; echo "-------php://input-------------\n"; echo $raw_post_data . "\n"; ?> urldecode('perfgeeks') . '&p=' . urldecode('7788'); $host = '192.168.0.6'; $port = 80; $path = '/phpinput_server.php'; $d = ''; $fp = fsockopen($host, $port, $error_no, $error_desc, 30); if ($fp) { fputs($fp, "GET {$path}?{$query_path} HTTP/1.1\r\n"); fputs($fp, "Host: {$host}\r\n"); fputs($fp, "Connection: close\r\n\r\n"); while (!feof($fp)) { $d .= fgets($fp, 4096); } fclose($fp); echo $d; } ?>
After executing above script, we get:
@php /phpinput_get.php
HTTP/1.1 200 OK Date: Thu, 08 Apr 2010 07:38:15 GMT Server: Apache/2.2.3 (CentOS) X-Powered-By: PHP/5.1.6 Content-Length: 141 Connection: close Content-Type: text/html; charset=UTF-8 -------$_GET------------------ array(2) { ["n"]=> string(9) "perfgeeks" ["p"]=> string(4) "7788" } -------php://input-------------
The HTTP request data packet is :
T 192.168.0.8:36775 -> 192.168.0.6:80 [AP] GET /phpinput_server.php?n=perfgeeks&p=7788 HTTP/1.1.. Host: 192.168.0.6..Connection: close....
We can summarize some points from above result:
- When Content-Type is application/x-www-form-urlencoded, PHP will fill the $_POST with the respective HTTP request data
- php://input data will be the same as the http entity body only if Content-Type is not multipart/form-data.
- php://input and $_POST data will be the same only if Content-type is application/x-www-form-urlencoded and submit method is POST.
- php://input cannot read GET data because $_GET data is appended to the PATH as a query string but not written into the http request body
php://input and multipart/form-data
<form enctype="multipart/form-data" action="phpinput_server.php" method="POST" > <input type="text" name="n" /> <input type="file" name="f" /> <input type="submit" value="upload now" /> form>
Using this enctype, it means the submitted data also contains the file to be uploaded. The data format will be different from the data using application/x-www-form-urlencoded. The result may look like:
-------$_POST------------------ array(1) { ["n"]=> string(9) "perfgeeks" } -------php://input-------------
The HTTP request data packet:
######## T 192.168.0.8:3981 -> 192.168.0.6:80 [AP] POST /phpinput_server.php HTTP/1.1..Host: 192.168.0.6..Connection: kee p-alive..User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) A ppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3 Safari/533.2..Re ferer: http://192.168.0.6/phpinput_server.php..Content-Length: 306..Ca che-Control: max-age=0..Origin: http://192.168.0.6..Content-Type: mult ipart/form-data; boundary=----WebKitFormBoundarybLQwkp4opIEZn1fA..Acce pt: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q =0.8,image/png,*/*;q=0.5..Accept-Encoding: gzip,deflate,sdch..Accept-L anguage: zh-CN,zh;q=0.8..Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3..Cook ie: SESS3b0e658f87cf58240de13ab43a399df6=lju6o5bg8u04lv1ojugm2ccic6... . ## T 192.168.0.8:3981 -> 192.168.0.6:80 [AP] ------WebKitFormBoundarybLQwkp4opIEZn1fA..Content-Disposition: form-da ta; name="n"....perfgeeks..------WebKitFormBoundarybLQwkp4opIEZn1fA..C ontent-Disposition: form-data; name="f"; filename="test.txt"..Content- Type: text/plain....i am file..multipart/form-data..------WebKitFormBo undarybLQwkp4opIEZn1fA--.. ##
php://input will always be empty when the enctype is multipart/form-data.
php://input vs $http_raw_post_data
What is $http_raw_post_data? It is an internal variable of PHP. It will be used when PHP cannot figure out the Content-Type, the POST data will be put into $http_raw_post_data. It cannot be used to read multipart/form-data as well. PHP will always put the data in $http_raw_post_data only if always_populate_raw_post_data is set to On in php.ini.
We modify the phpinput_server.php to:
And execute the below scripts:
@php phpinput_post.php @php phpinput_get.php @php phpinput_xmlrpc.php
The output is the same as using php://input.
Notes:
- PHP will fill data in $_POST only when Content-Type is application/x-www-data-urlencoded or multipart/form-data
- PHP will fill data in $HTTP_RAW_POST_DATA when it cannot figure out the Content-Type
- PHP will fill data in php://input if Content-Type is not multipart/form-data
- $_POST will be the same as php://input only when Content-type is application/x-www-data-urlencoded
- php://input will always has the same data as $HTTP_RAW_POST_DATA
References:
1,HTTP1.1 Protocols
2,Media Reference
3,Wiki MIME
4,PHP Stream Wrappers
Source : http://www.perfgeeks.com/?p=150