PHPでPOSTの本体を取得するにはどうすればよいですか?


273

次のように、phpページにPOSTとして送信します。

{a:1}

これはリクエストの本文です(POSTリクエスト)。
PHPでは、その値を抽出するために何をしなければなりませんか?

var_dump($_POST); 

解決策ではなく、機能していません。


23
これは、RESTful APIを作成しようとしている人にとって役立つ質問です。$_POSTスーパーグローバル経由では利用できないため、スクリプトに送信された生の入力データにアクセスする方法はほとんどわかりません。PHPには対応するスーパーグローバルがないため、これは(特に)PUTリクエストの場合にも当てはまります。
rdlowrey、2012年


1
それの価値名ことに注意$ _POSTを POST要求からデータのない任意のタイプがあるだろうとして、誤解を招くされていますが、コンテンツタイプがある場合にのみ、アプリケーション/ x-www-form-urlencodedでまたはマルチパート/フォームデータ
Petruza

回答:


549

POSTまたはPUTリクエスト(またはその他のHTTPメソッド)のエンティティ本体にアクセスするには:

$entityBody = file_get_contents('php://input');

また、STDIN定数はへのすでに開いているストリームなphp://inputので、代わりに次のようにできます。

$entityBody = stream_get_contents(STDIN);

I / OストリームドキュメントPHPマニュアルエントリから:

php:// inputは読み取り専用ストリームで、リクエストの本文から生データを読み取ることができます。POSTリクエストの場合、特別なphp.iniディレクティブに依存しないため、代わりにphp:// inputを使用することをお$HTTP_RAW_POST_DATA勧めします。さらに、$HTTP_RAW_POST_DATAデフォルトでデータが設定されていない場合、 always_populate_raw_post_dataをアクティブにする代わりに、メモリをあまり消費しない可能性があります。php:// inputはenctype = "multipart / form-data"では使用できません。

特にphp://input、Web SAPIでストリームにアクセスする方法に関係なく、ストリームはシークできないことに注意してください。これは、一度だけ読み取ることができることを意味します。大きなHTTPエンティティボディが定期的にアップロードされる環境で作業している場合は、(上記の最初の例のようにバッファリングするのではなく)ストリーム形式で入力を維持することをお勧めします。

ストリームリソースを維持するには、次のようなものが役立ちます。

<?php

function detectRequestBody() {
    $rawInput = fopen('php://input', 'r');
    $tempStream = fopen('php://temp', 'r+');
    stream_copy_to_stream($rawInput, $tempStream);
    rewind($tempStream);

    return $tempStream;
}

php://temp一定量のデータ(デフォルトでは2M)が保存された後、透過的にファイルシステムストレージに切り替わるため、メモリ消費を管理できます。このサイズは、php.iniファイルまたは追加することによって操作することができる/maxmemory:NN場合、NNデータの最大量をバイト単位で、一時ファイルを使用する前に、メモリ内に保持することです。

もちろん、入力ストリームを探す正当な理由がない限り、Webアプリケーションでこの機能を使用する必要はありません。通常、HTTPリクエストエンティティの本文を1回読み取るだけで十分です。アプリが何をすべきかを理解している間、クライアントを1日中待たせないでください。

php:// inputは、Content-Type: multipart/form-dataヘッダーを指定するリクエスト(enctype="multipart/form-data"HTMLフォーム)では使用できないことに注意してください。これは、PHPがフォームデータをすでに$_POSTスーパーグローバルに解析しているためです。


17
afaicsは、STDINストリームはPHP CGIを使用して、すなわち経由mod_fcgidまたはmod_fastcgiのなどを実行しているシステムでは利用できませんのでご注意ください
SCY

しかし、私はリクエストで変数を(フォームデータとして)渡しています。指定した値にアクセスするにはどうすればよいですか。リクエストでgrant_type = password&username = user&password = passをフォームデータの本体として渡しています。 entityBody "
Anvar Pk

私のテストによると、これphp://inputapplication/x-www-form-urlencoded(をmultipart/form-data
除いて

6
@scyの応答を拡張するには:STDINは利用できませんが、利用できますphp://input。したがって、(高速)CGI構成でstream_get_contents(STDIN)は機能しませんが、機能しfile_get_contents("php://input")ます。
Sinus Mackowaty

16

配列の戻り値

 $data = json_decode(file_get_contents('php://input'), true);

このシナリオでは、$data連想配列をループして、各値が希望どおりにエンコードされているかどうかを確認する必要があります。「ストリームからデータ型へ」の見方は単純化されているかもしれませんが、ストリームフィルターを使用して「ストリーム形式」でエンコードする場合ほど効率的ではありません。エンコーディングの問題を処理せず、単純にサニタイズと検証を行っている場合、ステップがありません。
Anthony Rutledge

13

空の可能性のある理由$_POSTは、リクエストがでないPOSTか、POSTもうないことです...ポストとして開始された可能性がありますが301、に302リダイレクトされたか、リダイレクトされましたGET

点検$_SERVER['REQUEST_METHOD']これが事実であるかどうかをチェックします。

これが発生してはならないのに発生する理由については、https://stackoverflow.com/a/19422232/109787を参照してください


1
この質問は、REST APIプラットフォームの開発のコンテキストで行われました。
Itay Moav -Malimovka 2016年

どういう意味かわかりませんか?REST APIは、そのパスでリダイレクトを見つけることもできますが、それが私が抱えていた問題です。
Legolas

私が質問したとき、私はバグを解決しようとするのではなく、それを開発する方法を理解しようとしていたのです。
Itay Moav -Malimovka 2016年

3
このヒントは私の日を救った。受信サーバーはhttpsにリダイレクトするように再構成され、whochは一部のAPIクライアントを壊しました。
DesertEagle 2017

実は私の要望でしたPOSTが、調べてみるとそうでしたGET/URLの最後にを追加すると、POSTが表示され始めました。おかしい!
zackygaurav



2

pecl / http拡張機能がインストールされている場合は、これも使用できます。

$request = new http\Env\Request();
$request->getBody();

2
function getPost()
{
    if(!empty($_POST))
    {
        // when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
        // NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
        return $_POST;
    }

    // when using application/json as the HTTP Content-Type in the request 
    $post = json_decode(file_get_contents('php://input'), true);
    if(json_last_error() == JSON_ERROR_NONE)
    {
        return $post;
    }

    return [];
}

print_r(getPost());

このロジックに欠けているのは、Content-Typeヘッダーにある値のテストです。$ _POSTはJSONが提出されていなければならないこと空である場合、またはことを理由だけでそれはそれに従わないjson_last_error() == JSON_ERROR_NONEfalse、空の配列が返されるべきであること。誰かがXMLまたはYAMLを送信した場合はどうなりますか?Content-Typeのテストを追加し、そこから進みます。
Anthony Rutledge

また、HTTP要求メソッドは、入力データを受け入れるかどうかを決定する際に考慮できます。$_SERVER確認に役立つ値については、スーパーグローバルを参照してください。
アンソニー・ラトリッジ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.