Wie bekomme ich den Körper eines POST in PHP?

273

Ich reiche als POST auf einer PHP-Seite Folgendes ein:

{a:1}

Dies ist der Hauptteil der Anforderung (eine POST-Anforderung).
Was muss ich in PHP tun, um diesen Wert zu extrahieren?

var_dump($_POST); 

ist nicht die Lösung, funktioniert nicht.

Itay Moav-Malimovka
quelle
23
Dies ist eine hilfreiche Frage für Personen, die RESTful-APIs erstellen möchten. Die meisten wissen nicht, wie sie auf die rohen Eingabedaten zugreifen sollen, die an ihre Skripte $_POSTgesendet wurden, da diese nicht über die Superglobale verfügbar sind. Dies gilt (insbesondere) auch für PUT-Anfragen, da PHP kein entsprechendes Superglobal hat.
Rdlowrey
4
Mögliches Duplikat von Wie erhalte ich Anforderungsinhalte (Text) in PHP?
YakovL
1
Es ist erwähnenswert, dass der Name $ _POST irreführend ist, da keine Art von Daten aus einer POST-Anfrage vorhanden ist, sondern nur, wenn der Inhaltstyp application / x-www-form-urlencoded oder multipart / form-data ist
Petruza

Antworten:

549

So greifen Sie auf den Entitätstext einer POST- oder PUT-Anforderung (oder einer anderen HTTP-Methode) zu:

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

Außerdem ist die STDINKonstante ein bereits geöffneter Stream php://input, sodass Sie alternativ Folgendes tun können:

$entityBody = stream_get_contents(STDIN);

Von der PHP manuellen Eingabe auf I / O - Streams docs :

php: // input ist ein schreibgeschützter Stream, mit dem Sie Rohdaten aus dem Anforderungshauptteil lesen können. Im Fall von Anfragen POST, ist es vorzuziehen, Gebrauch php: // input statt , $HTTP_RAW_POST_DATAda es hängt nicht von speziellen php.ini Einstellungen. Darüber hinaus ist es in Fällen, in denen $HTTP_RAW_POST_DATAes nicht standardmäßig ausgefüllt ist, eine möglicherweise weniger speicherintensive Alternative zur Aktivierung von always_populate_raw_post_data. php: // Eingabe ist nicht verfügbar mit enctype = "multipart / form-data".

Insbesondere sollten Sie beachten, dass der php://inputStream unabhängig davon, wie Sie in einem Web-SAPI darauf zugreifen, nicht durchsuchbar ist . Dies bedeutet, dass es nur einmal gelesen werden kann. Wenn Sie in einer Umgebung arbeiten, in der routinemäßig große HTTP-Entitätskörper hochgeladen werden, möchten Sie die Eingabe möglicherweise in ihrer Stream-Form beibehalten (anstatt sie wie im ersten Beispiel oben zu puffern).

So etwas kann hilfreich sein, um die Stream-Ressource zu pflegen:

<?php

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

    return $tempStream;
}

php://tempMit dieser Option können Sie den Speicherverbrauch verwalten, da nach dem Speichern einer bestimmten Datenmenge (standardmäßig 2 MB) transparent auf den Dateisystemspeicher umgeschaltet wird. Diese Größe kann in den php.ini oder durch Anfügen manipuliert werden /maxmemory:NN, wobei NNdie maximale Menge an Daten im Speicher zu halten , bevor eine temporäre Datei, in Bytes verwenden.

Natürlich sollten Sie diese Funktionalität in einer Webanwendung nicht benötigen, es sei denn, Sie haben einen wirklich guten Grund, nach dem Eingabestream zu suchen. Normalerweise reicht es aus, den Hauptteil der HTTP-Anforderungsentität einmal zu lesen. Lassen Sie Clients nicht den ganzen Tag warten, während Ihre App herausfindet, was zu tun ist.

Beachten Sie, dass die Eingabe php: // nicht für Anforderungen verfügbar ist, die einen Content-Type: multipart/form-dataHeader angeben ( enctype="multipart/form-data"in HTML-Formularen). Dies resultiert daraus, dass PHP die Formulardaten bereits in das $_POSTSuperglobale analysiert hat.

rdlowrey
quelle
17
Bitte beachten Sie, dass afaics, der STDIN-Stream nicht auf Systemen verfügbar ist, auf denen PHP mit CGI ausgeführt wird, dh über mod_fcgid oder mod_fastcgi usw.
scy
Aber ich übergebe eine Variable (als Formulardaten) mit der Anfrage. Wie kann ich auf den angegebenen Wert zugreifen? Ich übergebe Grant_Type = Passwort & Benutzername = Benutzer & Passwort = Übergeben als Formulardatenkörper mit der Anfrage. Wie erhalte ich Grant_Type von "$"? entityBody "
Anvar Pk
Laut meinem Test ist dies auch php://inputfür den application/x-www-form-urlencodedInhaltstyp (außerdem multipart/form-data)
leer
6
Um die Antwort von @ scy zu erweitern: STDIN ist nicht verfügbar, php://inputist es aber . Wenn also (schnelle) CGI-Konfigurationen stream_get_contents(STDIN)nicht funktionieren, funktioniert dies file_get_contents("php://input")auch.
Sinus Mackowaty
16

Rückgabewert im Array

 $data = json_decode(file_get_contents('php://input'), true);
umesh bhanderi
quelle
In diesem Szenario müssen Sie jetzt das $dataassoziative Array durchlaufen , um zu überprüfen, ob jeder Wert wie gewünscht codiert ist. Die Sichtweise von "Stream-to-Datatype" mag vereinfacht sein, ist jedoch möglicherweise nicht so effizient wie die Codierung in der "Stream-Form" mithilfe eines Stream-Filters. Wenn Sie keine Codierungsprobleme behandeln und lediglich bereinigen und validieren, fehlt Ihnen ein Schritt.
Anthony Rutledge
13

Ein möglicher Grund für ein Leerzeichen $_POSTist, dass die Anfrage nicht POSToder nicht POSTmehr ... Sie hat möglicherweise als Post begonnen, ist aber irgendwo auf eine 301oder eine 302Weiterleitung gestoßen , auf die umgeschaltet wird GET!

Überprüfen Sie $_SERVER['REQUEST_METHOD']zu überprüfen , ob dies der Fall ist.

Unter https://stackoverflow.com/a/19422232/109787 finden Sie eine ausführliche Beschreibung, warum dies nicht passieren sollte, aber dennoch geschieht.

Legolas
quelle
1
Diese Frage wurde im Zusammenhang mit der Entwicklung einer REST-API-Plattform gestellt.
Itay Moav-Malimovka
Ich bin mir nicht sicher was du meinst? Eine REST-API könnte genauso gut Weiterleitungen auf ihrem Weg finden, das ist das Problem, das ich hatte.
Legolas
Ich meinte, als ich die Frage stellte, versuchte ich nicht, einen Fehler zu beheben, sondern herauszufinden, wie man ihn entwickelt.
Itay Moav-Malimovka
3
Dieser Hinweis hat mir den Tag gerettet. Der empfangende Server wurde neu konfiguriert, um zu https umzuleiten, wodurch einige API-Clients beschädigt wurden.
DesertEagle
Eigentlich war meine Anfrage, POSTaber nach der Inspektion zeigte sich, dass es war GET. Nachdem ich /am Ende meiner URL eine hinzugefügt hatte , wurde POST angezeigt. Seltsam!
Zackygaurav
4

Überprüfen Sie die $HTTP_RAW_POST_DATAVariable

linepogl
quelle
7
Die bevorzugte Methode für den Zugriff auf die POST-Rohdaten ist php://input. $HTTP_RAW_POST_DATAist nicht verfügbar mit enctype="multipart/form-data".
Nichtigkeit
38
Diese Funktion wurde in PHP 5.6.0 VERRINGERT und ab PHP 7.0.0 ENTFERNT.
Charles
3

Wenn Sie die HTTP PECL-Erweiterung installiert haben, können Sie die http_get_request_body()Funktion verwenden, um Körperdaten als Zeichenfolge abzurufen.

Shivanshu Patel
quelle
Funktion existiert nicht.
Rick
2

Wenn Sie die Erweiterung pecl / http installiert haben, können Sie auch Folgendes verwenden:

$request = new http\Env\Request();
$request->getBody();
Spinkus
quelle
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());
Hatzegopteryx
quelle
Was dieser Logik fehlt, ist ein Test des Werts im Content-Type-Header. Daraus folgt nicht, dass JSON gesendet werden muss, wenn $ _POST leer ist, oder dass, falls dies der Fall json_last_error() == JSON_ERROR_NONEist false, ein leeres Array zurückgegeben werden sollte. Was ist, wenn jemand XML oder YAML eingereicht hat? Fügen Sie einen Test für den Inhaltstyp hinzu und gehen Sie von dort aus.
Anthony Rutledge
Die HTTP-Anforderungsmethode kann auch berücksichtigen, ob Sie Eingabedaten akzeptieren möchten. Im $_SERVERSuperglobal finden Sie nützliche Werte, die überprüft werden müssen.
Anthony Rutledge