PHP输入流php://input
PHP输入流php://input
在使用xml-rpc的时候,server端获取client数据,主要是通过php输入流input,而不是$_POST数组。所以,这里主要探讨php输入流php://input
对一php://input介绍,PHP官方手册文档有一段话对它进行了很明确地概述。
“php://input allows you to read raw POST data. It is a less memoryintensive alternative to $HTTP_RAW_POST_DATA and does not need any specialphp.ini directives. php://input is not available withenctype=”multipart/form-data”.
翻译过来,是这样:
“php://input可以读取没有处理过的POST数据。相较于$HTTP_RAW_POST_DATA而言,它给内存带来的压力较小,并且不需要特殊的php.ini设置。php://input不能用于enctype=multipart/form-data”
我们应该怎么去理解这段概述呢?!
我把它划分为三部分,逐步去理解。
1) 读取POST数据
2) 不能用于multipart/form-data类型
3) php://input VS $HTTP_RAW_POST_DATA
1 . 读取POST数据
PHPer们一定很熟悉$_POST这个内置变量。$_POST与php://input存在哪些关联与区别呢?另外,客户端向服务端交互数据,最常用的方法除了POST之外,还有GET。既然php://input作为PHP输入流,它能读取GET数据吗?这二个问题正是我们这节需要探讨的主要内容。
经验告诉我们,从测试与观察中总结,会是一个很凑效的方法。这里,我写了几个脚本来帮助我们测试。
@file 192.168.0.6:/phpinput_server.php 打印出接收到的数据
@file 192.168.0.8:/phpinput_post.php 模拟以POST方法提交表单数据
@file 192.168.0.8:/phpinput_xmlrpc.php模拟以POST方法发出xmlrpc请求.
@file 192.168.0.8:/phpinput_get.php 模拟以GET方法提交表单表数
phpinput_server.php
1. <?php
2. //@file phpinput_server.php
3. $raw_post_data = file_get_contents('php://input', 'r');
4. echo "-------\$_POST------------------\n";
5. echo var_dump($_POST) . "\n";
6. echo "-------php://input-------------\n";
7. echo $raw_post_data . "\n";
8. ?
phpinput_post.php:
1. <?php
2. //@file phpinput_post.php
3. $http_entity_body = 'n=' .urldecode('perfgeeks') . '&p=' . urldecode('7788');
4. $http_entity_type ='application/x-www-form-urlencoded';
5. $http_entity_length =strlen($http_entity_body);
6. $host = '192.168.0.6';
7. $port = 80;
8. $path = '/phpinput_server.php';
9. $fp = fsockopen($host, $port, $error_no,$error_desc, 30);
10. if ($fp) {
11. fputs($fp, "POST {$path} HTTP/1.1\r\n");
12. fputs($fp, "Host: {$host}\r\n");
13.
14. fputs($fp, "Content-Type: {$http_entity_type}\r\n");
15. fputs($fp, "Content-Length: {$http_entity_length}\r\n");
16. fputs($fp, "Connection: close\r\n\r\n");
17. fputs($fp, $http_entity_body . "\r\n\r\n");
18.
19. while (!feof($fp)) {
20. $d .= fgets($fp, 4096);
21. }
22. fclose($fp);
23. echo $d;
24. }
25. ?>
我们可以通过使用工具ngrep抓取http请求包(因为我们需要探知的是php://input,所以我们这里只抓取http Request数据包)。我们来执行测试脚本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
通过ngrep抓到的http请求包如下:
T 192.168.0.8:57846 -> 192.168.0.6:80[AP]
Host: 192.168.0.6
Content-Type: application/x-www-form-urlencoded
Content-Length: 18
Connection: close
n=perfgeeks&p=7788
仔细观察,我们不难发现
1,$_POST数据,php://input数据与httpd entity body数据是“一致”的
2,http请求中的Content-Type是application/x-www-form-urlencoded ,它表示http请求body中的数据是使用http的post方法提交的表单数据,并且进行了urlencode()处理。
我们再来看看脚本phpinput_xmlrpc.php的原文件内容,它模拟了一个POST方法提交的xml-rpc请求。
1. <?php
2. //@file phpinput_xmlrpc.php
3.
4. $http_entity_body = "\n\n jt_userinfo\n";
5. $http_entity_type= 'text/html';
6. $http_entity_length =strlen($http_entity_body);
7.
8. $host = '192.168.0.6';
9. $port = 80;
10. $path = '/phpinput_server.php';
11. $fp = fsockopen($host, $port, $error_no,$error_desc, 30);
12. if ($fp) {
13. fputs($fp, "POST {$path} HTTP/1.1\r\n");
14. fputs($fp, "Host: {$host}\r\n");
15.
16. fputs($fp, "Content-Type: {$http_entity_type}\r\n");
17. fputs($fp, "Content-Length: {$http_entity_length}\r\n");
18. fputs($fp, "Connection: close\r\n\r\n");
19. fputs($fp, $http_entity_body . "\r\n\r\n");
20. while (!feof($fp)) {
21. $d .= fgets($fp, 4096);
22. }
23.
24. fclose($fp);
25. echo $d;
26. }
27. ?>
同样地,让我们来执行这个测试脚本
@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-------------
<?xml version="1.0">
<methodcall>
<name>jt_userinfo</name>
</methodcall>
执行这个脚本的时候,我们通过ngrep抓取的http请求数据包如下
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
Connection: close
1. <?xml version="1.0">.<methodcall>. <name>jt_userinfo<
2. /name>.</methodcall>....
同样,我样也可以很容易地发现:
1,http请求中的Content-Type是text/xml。它表示http请求中的body数据是xml数据格式。
2,服务端$_POST打印出来的是一个空数组,即与http entity body不一致了。这跟上个例子不一样了,这里的Content-Type是text/xml,而不是application/x-www-form-urlencoded
3,而php://input数据还是跟httpentity body数据一致。也就是php://input数据和$_POST数据不一致了。
我们再来看看通过GET方法提交表单数据的情况,php://input能不能读取到GET方法的表单数据?在这里,我们稍加改动一下phpinput_server.php文件,将$_POST改成$_GET。
1. <?php
2. //@file phpinput_server.php
3. $raw_post_data =file_get_contents('php://input', 'r');
4. echo"-------\$_GET------------------\n";
5. echo var_dump($_GET) . "\n";
6. echo"--
补充:Web开发 , php ,