回答:
その理由はphp://input
、コンテンツタイプに関係なく、リクエストのHTTPヘッダーの後にすべての生データを返すためです。
PHPのスーパーグローバル$_POST
、のみになっているのいずれかであるラップデータ
application/x-www-form-urlencoded
(シンプルなフォーム投稿の標準コンテンツタイプ)またはmultipart/form-data
(主にファイルのアップロードに使用されます)これは、これらがユーザーエージェントによってサポートされる必要がある唯一のコンテンツタイプであるためです。したがって、サーバーとPHPは伝統的に他のコンテンツタイプを受信することを期待していません(これは、受信できなかったという意味ではありません)。
したがって、古き良きHTMLを単にPOSTするとform
、リクエストは次のようになります。
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
ただし、Ajaxを頻繁に使用している場合、このprobabyには、タイプ(string、int、bool)および構造(配列、オブジェクト)とのより複雑なデータの交換も含まれるため、ほとんどの場合、JSONが最良の選択です。しかし、JSONペイロードを含むリクエストは次のようになります。
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
コンテンツは現在application/json
(または少なくとも上記のいずれでもない)であるため、PHPの$_POST
-wrapperは(まだ)その処理方法を認識していません。
データはまだそこにあり、ラッパーを介してアクセスすることはできません。そのため、file_get_contents('php://input')
(-encodedされていないmultipart/form-data
限り)を使用して自分でraw形式でフェッチする必要があります。
これは、XMLデータまたはその他の非標準コンテンツタイプにアクセスする方法でもあります。
application/json
が$_POST
配列の有効なデータソースとして認識されるのを妨げるものはありません。また、具体的にそのサポートを求めるリクエストも公開されています。
php://input
データの生のバイトを与えることができます。これは、POSTされたデータがJSONエンコードされた構造である場合に役立ちます。これは、AJAX POSTリクエストの場合によく見られます。
これを行うための関数を次に示します。
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/
private function retrieveJsonPostData()
{
// get the raw POST data
$rawData = file_get_contents("php://input");
// this returns null if not valid json
return json_decode($rawData);
}
$_POST
あなたは伝統的なPOSTによって送信されたフォームから、キーと値のデータを処理しているとき、アレイは、より有用です。POSTされたデータは通常、認識されるフォーマットである場合にのみ動作しますapplication/x-www-form-urlencoded
(参照http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4を詳細)。
true
2番目のパラメータとしてに渡すとjson_decode
、連想配列が返されることに注意してください。
PHPは、HTTPリクエストを処理するための純粋なREST(GET、POST、PUT、PATCH、DELETE)のようなインターフェースを明示的に提供するようには設計されていません。
しかし、$_POST
、$_GET
、および$_FILES
スーパーグローバル、および機能は、filter_input_array()
平均的な人の/素人のニーズのために非常に有用です。
の最大の隠された利点 $_POST
(および$_GET
)の最大の、入力データがPHPによって自動的にurldecodeされることです。特に標準のGETリクエスト内のクエリ文字列パラメーターの場合は、それを行う必要があることさえ考えません。
そうは言っても、プログラミングの知識が進歩し、JavaScriptの XmlHttpRequest
オブジェクト(一部ではjQuery)場合、このスキームの制限に気付くでしょう。
$_POST
HTTPでの2つのメディアタイプの使用に制限します Content-Type
ヘッダー。
application/x-www-form-urlencoded
、およびmultipart/form-data
したがって、サーバー上のPHPにデータ値を送信し$_POST
、それをスーパーグローバルに表示させる場合は、urlencodeを実行する必要があります。場合は、クライアント側でし、そのデータをキー/値のペアとして送信ます。初心者には不便な手順です。 (特に、URLの異なる部分が異なる形式のurlencodingを必要とするかどうかを判断しようとする場合:通常、未加工など)。
すべてのjQueryユーザーに対して、$.ajax()
メソッドはJSONをURLエンコードされたキー/値のペアに変換してから、サーバーに送信します。を設定することで、この動作を上書きできますprocessData: false
。$ .ajax()のドキュメントを読んでくださいで、Content-Typeヘッダーで正しいメディアタイプを送信することを忘れないでください。
通常、通常の同期(ページ全体が再描画されるとき)HTTPリクエストをHTMLフォームで実行している場合、ユーザーエージェント(Webブラウザ)がフォームデータをURLエンコードします。XmlHttpRequest
オブジェクトを使用して非同期HTTPリクエストを行う場合、そのデータを$_POST
スーパーグローバルに表示するには、urlencoded文字列を作成して送信する必要があります。
JavaScriptの配列またはオブジェクトをURLエンコードされた文字列に変換すると、多くの開発者が(Form Dataなどの新しいAPIを使用しても)煩わしくなります。彼らはむしろJSONを送信できるだけであり、それはより効率的です、クライアントコードが送信するです。
(ウィンク、ウィンク)を覚えておいてください。平均的なWeb開発者は、 XmlHttpRequest
オブジェクト、グローバル関数、文字列関数、配列関数、そしてあなたやIのような正規表現方法を ;-)。それらのUrlencodingは悪夢です。;-)
PHPには直感的なXMLおよびJSON処理がないため、多くの人が気を失っています。あなたはそれが今ではPHPの一部になると思うでしょう(ため息)。
XML、JSON、YAMLにはすべて、HTTP Content-Type
ヘッダーに入れることができるメディアタイプがあります。
IANAで定義されているメディアタイプ(以前のMIMEタイプ)の数を確認します。
どのように多く見HTTPヘッダがあります。
を使用して php://input
ストリームすると、PHPが世界に強制されたことを抽象化のベビーシッター/手保持レベルを回避することができます。:-)大きな力には大きな責任が伴います。
さて、を通じてストリーミングされるデータ値を処理する前にphp://input
、いくつかのことを行う必要があります。
ああ、ハ!はい、アプリケーションに送信されるデータストリームをUTF-8でエンコードすることをお勧めしますが、それがエンコードされているかどうかはどうすればわかりますか?
php://input
。最初にどれだけあるかを知らずにストリームデータを処理しようとしますか?それはひどい考えです。Content-Length
スプーフィングされる可能性があるため、ストリーミングされた入力のサイズに関するガイダンスをHTTP ヘッダーだけに依存することはできません。
次のものが必要になります。
ストリームの現在のエンコーディングを知らなくても、ストリームデータをUTF-8に変換しようとしますか?どうやって?iconvストリームフィルター(iconvストリームフィルターの例)では、次のように開始と終了のエンコーディングが必要なようです。
'convert.iconv.ISO-8859-1/UTF-8'
したがって、良心的であれば、次のものが必要です。
(更新:'convert.iconv.UTF-8/UTF-8'
すべてを強制的にUTF-8にしますが、iconvライブラリが翻訳方法を認識していない可能性がある文字を考慮する必要があります。つまり、文字を翻訳できない場合に実行するアクションを定義する必要があります。 :1)ダミー文字を挿入します。2)失敗/スローと例外)。
Content-Encoding
これは、次のような圧縮のようなものを示す可能性があるため、HTTP ヘッダーだけに依存することはできません。これは、iconvに関して決定を下したいものではありません。
Content-Encoding: gzip
パートI:HTTPリクエスト関連
パートII:ストリームデータ関連
パートIII:データ型関連
(データは引き続きURLエンコードされた文字列である可能性があることに注意してください。この文字列は、解析してURLデコードする必要があります)。
パートIV:データ値関連
入力データをフィルタリングします。
入力データを検証します。
$_POST
入力上の制限のためにphp.iniの設定と共にスーパーグローバルは、素人のために簡単です。ただし、適切なエンコーディングの入力値をチェックするためにスーパーグローバル(または一般に配列)をループする必要がないため、ストリームを使用する場合、文字エンコーディングの処理ははるかに直感的で効率的です。
そこで、php:// inputストリームからPOSTデータを取得する関数を作成しました。
したがって、ここでの課題は、PUT、DELETE OR PATCHリクエストメソッドに切り替え、そのリクエストで送信されたポストデータを取得することでした。
私はこれを同じような挑戦をしている誰かのために多分共有しています。以下の関数は私が思いついたものであり、機能します。お役に立てば幸いです。
/**
* @method Post getPostData
* @return array
*
* Convert Content-Disposition to a post data
*/
function getPostData() : array
{
// @var string $input
$input = file_get_contents('php://input');
// continue if $_POST is empty
if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :
$postsize = "---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);
// update input
if (count($match) > 0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/', '', $input);
// extract the content-disposition
preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);
// let's get the keys
if (count($matches) > 0 && count($matches[0]) > 0)
{
$keys = $matches[2];
foreach ($keys as $index => $key) :
$key = trim($key);
$key = preg_replace('/^["]/','',$key);
$key = preg_replace('/["]$/','',$key);
$key = preg_replace('/[\s]/','',$key);
$keys[$index] = $key;
endforeach;
$input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);
$input = preg_replace("/(Content-Length: )+([^\n]+)/im", '', $input);
// now let's get key value
$inputArr = explode($postsize, $input);
// @var array $values
$values = [];
foreach ($inputArr as $index => $val) :
$val = preg_replace('/[\n]/','',$val);
if (preg_match('/[\S]/', $val)) $values[$index] = trim($val);
endforeach;
// now combine the key to the values
$post = [];
// @var array $value
$value = [];
// update value
foreach ($values as $i => $val) $value[] = $val;
// push to post
foreach ($keys as $x => $key) $post[$key] = isset($value[$x]) ? $value[$x] : '';
if (is_array($post)) :
$newPost = [];
foreach ($post as $key => $val) :
if (preg_match('/[\[]/', $key)) :
$k = substr($key, 0, strpos($key, '['));
$child = substr($key, strpos($key, '['));
$child = preg_replace('/[\[|\]]/','', $child);
$newPost[$k][$child] = $val;
else:
$newPost[$key] = $val;
endif;
endforeach;
$_POST = count($newPost) > 0 ? $newPost : $post;
endif;
}
endif;
// return post array
return $_POST;
}
使い方の簡単な例
<?php
if(!isset($_POST) || empty($_POST)) {
?>
<form name="form1" method="post" action="">
<input type="text" name="textfield"><br />
<input type="submit" name="Submit" value="submit">
</form>
<?php
} else {
$example = file_get_contents("php://input");
echo $example; }
?>