Today's Question:  What does your personal desk look like?        GIVE A SHOUT

php://input in PHP

  sonic0002        2013-02-25 20:43:00       34,868        0    

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:

  1. Read POST data
  2. Cannot use multipart/form-data type
  3. 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:

  1. The data is the same in $_POST and php://input
  2. 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:

  1. Content-Type is text/xml, it means the data in body of HTTP request is xml formmatted.
  2. $_POST is empty which is different from http_entity_body
  3. 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:

  1. When Content-Type is application/x-www-form-urlencoded, PHP will fill the $_POST with the respective HTTP request data
  2. php://input data will be the same as the http entity body only if Content-Type is not multipart/form-data.
  3. php://input and $_POST data will be the same only if Content-type is application/x-www-form-urlencoded and submit method is POST.
  4. 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:

  1. PHP will fill data in $_POST only when Content-Type is application/x-www-data-urlencoded or multipart/form-data
  2. PHP will fill data in $HTTP_RAW_POST_DATA when it cannot figure out the Content-Type
  3. PHP will fill data in php://input if Content-Type is not multipart/form-data
  4. $_POST will be the same as php://input only when Content-type is application/x-www-data-urlencoded
  5. 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

PHP://INPUT  IO  INPUT 

Share on Facebook  Share on Twitter  Share on Weibo  Share on Reddit 

  RELATED


  0 COMMENT


No comment for this article.