ホームページ  >  記事  >  バックエンド開発  >  PHP 入力ストリーム php://input 概要の抜粋

PHP 入力ストリーム php://input 概要の抜粋

WBOY
WBOYオリジナル
2016-06-13 13:11:39828ブラウズ

PHP 入力ストリーム php://input はじめに 再版
PHP 入力ストリーム php://input
xml-rpc を使用する場合、サーバー側は、$_POST 配列ではなく、主に PHP 入力ストリーム input を通じてクライアント データを取得します。したがって、ここでは主に php 入力ストリーム php://input

php://input の概要について説明します。公式の PHP マニュアル文書には、明確に概要が説明されている段落があります。

「php://input を使用すると、生の POST データを読み取ることができます。$HTTP_RAW_POST_DATA に代わるメモリ消費量が少なく、特別な php.ini ディレクティブは必要ありません。php://input は使用できません。 enctype="multipart/form-data".
翻訳すると、
"php://input は未処理の POST データを読み取ることができます。 $HTTP_RAW_POST_DATA と比較して、メモリへの負担が少なく、特別な php.ini 設定は必要ありません。 enctype=multipart/form-data には php://input は使用できません。

この概要を 3 つの部分に分けて段階的に理解していきます。 POST データの読み取り
multipart/form-data タイプには使用できません
php://input VS $HTTP_RAW_POST_DATA
POST データの読み取り
PHP を使用する場合は、組み込み変数 $_POST $ に精通している必要があります。 _POST と php://input の関係と違いは何ですか? また、php://input は PHP 入力ストリームであるため、クライアントがサーバーと対話する最も一般的なメソッドは GET です。
これは、テストと観察から要約するのに非常に効果的な方法であることがわかります。

@file 192.168.0.6:/phpinput_server.php は、受信したデータを出力します。
@file 192.168.0.8:/phpinput_post.php は、POST を使用したフォーム データの送信をシミュレートします。 Method
@file 192.168.0.8:/phpinput_xmlrpc.php は、POST メソッドを使用して xmlrpc リクエストの発行をシミュレートします。
@file 192.168.0.8:/phpinput_get.php は、GET メソッド phpinput_server.php および phpinput_post.php を使用してフォーム番号の送信をシミュレートします。 🎜 >

//@file phpinput_server.php
$raw_post_data = file_get_contents('php://input', 'r');
echo "-- - ----$_POST----n";
echo var_dump($_POST) . "n";
echo "--- - ---php://input-------------n";
echo $raw_post_data . "n";
?>

< ? php
//@file phpinput_post.php
$http_entity_body = 'n=' . 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.1rn");
fputs($fp, "ホスト: {$host}rn");
fputs($fp, "Content-Type: {$http_entity_type}rn");
fputs($fp, "Content-Length: {$http_entity_length}rn");
fputs($fp, "接続: closenrn");
fputs($fp, $http_entity_body . "rnrn" ) ;

while (!feof($fp)) {
$d .= fgets($fp, 4096);
}
fclose($fp);
echo $ d;
}
?>

ngrep ツールを使用して http リクエスト パケットを取得できます (検出する必要があるのは php://input であるため、 http ここでデータ パケットをリクエストします)。テスト スクリプト phpinput_post.php を実行してみましょう

@php /phpinput_post.phpHTTP/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
; -------$_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]
POST / phpinput_server .php HTTP/1.1..
ホスト: 192.168.0.6..Content-Type: application/x-www-form-urlencoded..Co
ntent-Length: 18..Connection: close... n=perfgeeks&p=7788.... よく見ると、http 内の
1、$_POST データ、php://input データ、および httpd エンティティ本体データが「一貫している」
2 であることが簡単にわかります。 request Content-Type は application/x-www-form-urlencoded で、HTTP リクエスト本文のデータが HTTP post メソッドを使用して送信されたフォーム データであり、urlencode() によって処理されたことを示します。
(注: 以下ではプロンプトが表示されない太字の部分に注意してください) http://www.k686.com

スクリプト phpinput_xmlrpc の元のファイルの内容を見てみましょう。 php。POST メソッドによって送信された xml-rpc リクエストをシミュレートします。


//@file phpinput_xmlrpc.php
$http_entity_body = "nn jt_userinfo";
$http_entity_type = 'text/html';
$ 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.1rn");
fputs($fp, "ホスト: {$host}rn");
fputs($fp, "Content-Type: {$http_entity_type}rn ");
fputs($fp, "Content-Length: {$http_entity_length}rn");
fputs($fp, "接続: closenrn");
fputs($fp, $http_entity_body . "rnrn");
while (!feof($fp)) {
$d .= fgets($fp, 4096);
}

fclose($fp);
echo $d;
}
?>

同样地,让我们来执行这个测试 脚本

@php /phpinput_xmlrcp.phpHTTP/1.1 200 OK
日付: 木、08 4月 2010 03:47:18 GMT
サーバー: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.1.6
コンテンツの長さ: 154
接続: 閉じる
コンテンツ タイプ: text/html; charset=UTF-8

------$_POST------
array(0) {
}

------php://input-------------

< methodcall>
jt_userinfo
この脚本を実行するとき、我们通ngrep抓取的http请要求データ包如下

T 192.168.0.8: 45570 -> 192.168.0.6:80 [AP]
POST /phpinput_server.php HTTP/1.1..
ホスト: 192.168.0.6..Content-Type: text/html..Content-Length: 75..Connect
tion: 閉じる.....。   jt_userinfo<
/name>.
....同様に、私も簡単に次の内容を公開できます:
1、http 要求内の Content-Type は text/xml です。これは、http 要求の本文データが xml データ形式であることを示しています。
2、サービス エンド $_POST が出力されるのは空数の集合であり、http エンティティ本文とは一致しません。 -Type は、application/x-www-form-urlencoded
3 ではなく text/xml ですが、php://input データも、http エンティティ本体データと一致します。つまり、php://inputdatabase と $_POSTdatabase

私は GET メソッド経由で表データを交換する場合、php://input は GET メソッドの表データを取得できませんか? ここで、私は phpinput_server.php 文を追加しました。


//@file phpinput_server.php
$raw_post_data = file_get_contents('php://input', 'r ');
echo "------$_GET------n";
echo var_dump($_GET) 。 "n";
echo "------php://input-------------n";
echo $raw_post_data 。 "n";
?>

//@file phpinput_get.php
$query_path = '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.1rn");
fputs($fp, "ホスト: {$host}rn");
fputs($fp, "接続: closenrn");

while (! feof($fp)) {
$d .= fgets($fp, 4096);
}
fclose($fp);
echo $d;
}
? >

同様に、私は以下の phpinput_get.php 検査スクリプトを実行し、通常の場合の GET メソッド提交表データを模倣しました。

@php /phpinput_get.phpHTTP/1.1 200 OK
日付: 木、2010 年 4 月 8 日 07:38:15 GMT
サーバー: Apache/2.2.3 (CentOS)
X-Powered-By: PHP/5.1.6
コンテンツの長さ: 141
接続: 閉じる
コンテンツ タイプ: text/html; charset=UTF-8

------$_GET------
array(2) {
[ "n"]=>
string(9) "perfgeeks"
["p"]=>
string(4) "7788"
}

-- -----php://input---------------この時点では、ngrepTool を使用し、捕捉された関連する http请要求データパケット包如下

T 192.168.0.8 :36775 -> 192.168.0.6:80 [AP]
GET /phpinput_server.php?n=perfgeeks&p=7788 HTTP/1.1..
ホスト: 192.168.0.6..接続: close....比较POST メソッド提交httpただし、ハードデータ http エンティティ ボディの場合は、Content-Type と Content-Length が正しく指定されます。 php://input は、$_GET データではなく、http エンティティ本体データを取得することもできます。値が application/x-www-form-urlencoded の場合、php は http requestbody に関連するデータを $_POST という数値集合に挿入し、$_POST 数値集合内にあるデータは urldecode() 解析の結果となります。除该Content-Type,他有multipart/form-data表示データデータは表单データ,稍後我们介绍)
2. Content-Type が multipart/form-data でない限り、php://input data (この条件は後で紹介します)。 php://input データは、データの http エンティティ本体部分と一致します。この部分的に一貫したデータの長さは、Content-Length によって指定されます。
3. Content-Type が application/x-www-form-urlencoded で、送信メソッドが POST メソッドの場合にのみ、$_POST データと php://input データが「一致」します (引用符付き)。形式を示します)一貫性がなく、一貫した内容)。そうでなければ、それらは矛盾します。
4、php://input は $_GET データを読み取ることができません。これは、http リクエストのボディ部分ではなく、http リクエスト ヘッダー (header) の PATH フィールドに $_GET データが query_path として書き込まれているためです。

これは、xml_rpc サーバーが file_get_contents(‘php://input’, ‘r’) を通じてデータを読み取る理由を理解するのにも役立ちます。 $_POST から読み取るのではなく、xml_rpc のデータ仕様が xml であり、その Content-Type が text/xml であるためです。

php://input は multipart/form-data と遭遇します
ファイルをアップロードするとき、フォームは次のように記述されます








では、ここで enctype=multipart/form-data の意味http リクエストのヘッダーの Content-Type を multipart/form-data に設定することです。説明については RFC1867 を確認してください。 multipart/form-data も POST メソッドを使用してフォーム データを送信することを意味し、ファイルのアップロードを伴うため、application/x-www-form-urlencoded データ形式とは異なります。より合理的かつ効率的なデータ形式でサーバーに渡されます。次のように、フォーム データを送信し、応答結果を出力します:

------$_POST------
array(1) { ["n"]=> string(9) "perfgeeks" }
----------php://input-------------同時に、ngrep を通じてキャプチャした対応する http リクエスト パケットは次のとおりです。 AP]
POST /phpinput_server.php HTTP/1.1..ホスト: 192.168.0.6..接続: kee
p-alive..ユーザーエージェント: Mozilla/5.0 (Windows; U; Windows NT 5.1; en -US) A
ppleWebKit/533.2 (Gecko のような KHTML) Chrome/5.0.342.3 Safari/533.2..Re
フェラー: 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; border=----WebKitFormBoundarybLQwkp4opIEZn1fA。 .Acce
pt: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q
=0.8,image/png,*/*;q=0.5..Accept -エンコーディング: gzip、deflate、sdch..Accept-L
言語: zh-CN,zh;q=0.8..Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3..クック
例: 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; "f" ; filename="test.txt"..Content-
タイプ: text/plain....私は file..multipart/form-data..-----WebKitFormBo
undarybLQwkp4opIEZn1fA --. .
##応答出力と比較すると、$_POST データは要求送信データと一致しています ($_POST = array('n' => 'perfgeeks'))。これは http リクエスト本文のデータもエコーし、PHP が対応するデータを $_POST グローバル変数に入力することも示します。 http リクエスト パケットの本文は空ではありませんが、php://input の出力は空で何も出力されません。これは、Content-Type が multipart/form-data の場合、HTTP リクエストボディにデータがあっても、php://input が空になることを意味します。このとき、PHP は php:// にデータを入力しません。入力ストリーム。したがって、php://input を使用して enctype=multipart/form-data データを読み取ることはできないことは確かです。

今回、ngrep でキャプチャした http リクエスト パケットを比較してみましょう。最大の違いは、Content-Type の後にデータの区切り文字を定義する境界があり、境界がランダムに生成されることです。もう 1 つの大きな違いは、http エンティティ本体のデータ構成構造が異なることです。

前のセクションでは、Content-Type が application/x-www-form-urlencoded の場合、php://input と $_POST データは「一貫性」があり、他の Content-Type の場合、php:/ であることを説明しました。 /input と $_POST データが矛盾しています。 Content-Type が application/x-www-form-urlencoded または multipart/form-data の場合にのみ、PHP は http リクエスト パケット内の本体データの対応する部分を $_POST グローバル変数に埋め込むためです。両方を無視します。データ型が multipart/form-data の場合は php://input が空であることを除き、他の状況では空にならない場合があります。このセクションを通じて、php://input と $_POST の違いと関係についてより深く理解できました。したがって、php://input が enctype=multipart/form-data データを読み取ることができないことを再度確認してください。php://input がそれに遭遇すると、http エンティティ本体にデータがある場合でも、常に空になります。

php://input VS $http_raw_post_data
誰もがすでに php://input についてある程度深く理解していると思います。では、$http_raw_post_data とは何でしょうか? $http_raw_post_data は、PHP に組み込まれているグローバル変数です。これは、Content-Type が認識できない場合に、POST データを変数 $http_raw_post_data にそのまま埋めるために PHP によって使用されます。また、Content-Type が multipart/form-data である POST データを読み取ることもできません。 PHP が常に POST データを変数 $http_raw_post_data に入力できるように、php.ini の always_populate_raw_post_data 値を On に設定する必要があります。

スクリプト phpinput_server.php を変更して上記の内容を確認します


$raw_post_data = file_get_contents('php://input', 'r' ) ;
$rtn = ($raw_post_data == $HTTP_RAW_POST_DATA) ? 1 : 0;
echo $rtn;
?>

テスト スクリプトを実行

@ php phpinput_post.php
@php phpinput_get.php
@php phpinput_xmlrpc.php の結果出力はすべて同じです。つまり、すべて 1 です。これは、php://input と $HTTP_RAW_POST_DATA が同じであることを意味します。メモリへの負荷に関しては、ここでは詳細なテストは行いません。興味があれば、xhprof を通じてテストして観察することができます。

これにより、このセクションを次のように要約できます。
1、php://input は http エンティティ本体で指定された長さの値を読み取ることができ、長さは Content-Length で指定されます。 、それが POST メソッドであるか、GET メソッドによって送信されたデータであるか。ただし、通常、GET メソッドがデータを送信するとき、http リクエスト エンティティの本体部分は空です。
2. php://input と $HTTP_RAW_POST_DATA で読み取られるデータは、Content-Type が multipart/form-data ではないデータのみを読み取ります。

研究メモ
1. Coentent-Type には、値が application/x-www-data-urlencoded および multipart/form-data である場合にのみ、http 要求データ パケットが含まれます。グローバル変数 $_POST
2. PHP が Content-Type タイプを認識できない場合、http リクエスト パッケージ内の対応するデータは変数 $HTTP_RAW_POST_DATA
に入力されます。 multipart/form-data の場合、PHP は http リクエスト パケット内の対応するデータを php://input に埋め込みません。それ以外の場合は、他の状況でも同じになります。 Coentent-Length で指定されるパディングの長さ。
4. Content-Type が application/x-www-data-urlencoded の場合のみ、php://input データは $_POST データと一致します。
5. php://input データは常に $HTTP_RAW_POST_DATA と同じですが、php://input は $HTTP_RAW_POST_DATA より効率的であり、php.ini での特別な設定は必要ありません。
6. PATH フィールド query_path 部分には、グローバル変数 $_GET を入力します。通常、GET メソッドによって送信される http リクエストの本文は空です。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。