Come ottenere il corpo di un POST in php?


273

Inoltro come POST a una pagina php quanto segue:

{a:1}

Questo è il corpo della richiesta (una richiesta POST).
In php, cosa devo fare per estrarre quel valore?

var_dump($_POST); 

non è la soluzione, non funziona.


23
Questa è una domanda utile per le persone che desiderano creare API RESTful. Molti non sanno come accedere ai dati di input non elaborati inviati ai loro script in quanto non sono disponibili tramite il $_POSTsuperglobal. Questo è anche (soprattutto) vero nel caso di richieste PUT, poiché PHP non ha superglobal corrispondente.
rdlowrey,


1
Vale la pena notare che il nome $ _POST è fuorviante, poiché non ci sarà alcun tipo di dati da una richiesta POST, ma solo quando il tipo di contenuto è application / x-www-form-urlencoded o multipart / form-data
Petruza

Risposte:


549

Per accedere al corpo dell'entità di una richiesta POST o PUT (o qualsiasi altro metodo HTTP):

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

Inoltre, la STDINcostante è un flusso già aperto a php://input, quindi puoi alternativamente fare:

$entityBody = stream_get_contents(STDIN);

Dalla voce manuale di PHP sui documenti degli stream I / O :

php: // input è un flusso di sola lettura che consente di leggere dati non elaborati dal corpo della richiesta. Nel caso di richieste POST, è preferibile utilizzare php: // input invece $HTTP_RAW_POST_DATAche non dipende da direttive speciali php.ini. Inoltre, per quei casi in cui $HTTP_RAW_POST_DATAnon è popolato per impostazione predefinita, è un'alternativa potenzialmente meno intensiva della memoria all'attivazione di always_populate_raw_post_data. php: // input non è disponibile con enctype = "multipart / form-data".

In particolare, tieni presente che lo php://inputstream, indipendentemente dal modo in cui accedi a un SAPI Web, non è ricercabile . Ciò significa che può essere letto solo una volta. Se lavori in un ambiente in cui i corpi di entità HTTP di grandi dimensioni vengono caricati di routine, potresti voler mantenere l'input nella sua forma di flusso (piuttosto che memorizzarlo come nel primo esempio sopra).

Per mantenere la risorsa di flusso qualcosa di simile può essere utile:

<?php

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

    return $tempStream;
}

php://tempconsente di gestire il consumo di memoria perché passerà in modo trasparente all'archiviazione del file system dopo aver memorizzato una determinata quantità di dati (2 M per impostazione predefinita). Questa dimensione può essere manipolata nel file php.ini o aggiungendo/maxmemory:NNNN , in byte , la quantità massima di dati da conservare in memoria prima di utilizzare un file temporaneo.

Naturalmente, a meno che tu non abbia una buona ragione per cercare nel flusso di input, non dovresti aver bisogno di questa funzionalità in un'applicazione web. La lettura del corpo dell'entità della richiesta HTTP in genere è sufficiente: non tenere i clienti in attesa tutto il giorno mentre l'app capisce cosa fare.

Si noti che php: // input non è disponibile per le richieste che specificano Content-Type: multipart/form-dataun'intestazione ( enctype="multipart/form-data"in moduli HTML). Ciò deriva dal fatto che PHP ha già analizzato i dati del modulo nel $_POSTsuperglobal.


17
Si noti che afaics, il flusso STDIN non è disponibile sui sistemi che eseguono PHP utilizzando CGI, ovvero tramite mod_fcgid o mod_fastcgi ecc.
scy,

ma sto passando una variabile (come modulo-dati) con la richiesta, come posso accedere al valore specificato, sto passando grant_type = password e nome utente = utente e password = passa come corpo di dati modulo con la richiesta, come posso ottenere grant_type da "$ entityBody "
Anvar Pk,

secondo il mio test, questo php://inputè vuoto anche per il application/x-www-form-urlencodedtipo di contenuto (oltre multipart/form-data)
YakovL

6
Per espandere la risposta di @ scy: STDIN non è disponibile, ma lo php://inputè. Quindi, mentre le configurazioni CGI (veloci) stream_get_contents(STDIN)non funzioneranno, lo file_get_contents("php://input")faranno.
Sinus Mackowaty,

16

restituisce valore nella matrice

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

In questo scenario, ora è necessario scorrere la $datamatrice associativa per verificare se ogni valore è codificato nel modo desiderato. Il modo "stream-to-datatype" di guardare le cose può essere semplicistico, ma potrebbe non essere efficiente come gestire la codifica nella "forma stream" usando un filtro stream. Se non si gestiscono problemi di codifica e semplicemente la sanificazione e la convalida, manca un passaggio.
Anthony Rutledge,

13

Una possibile ragione per un vuoto $_POSTè che la richiesta non è POST, o non POSTpiù ... Potrebbe essere iniziata come posta, ma ha incontrato 301o 302reindirizzato da qualche parte, che è passato a GET!

Ispezionare $_SERVER['REQUEST_METHOD']per verificare se questo è il caso.

Vedi https://stackoverflow.com/a/19422232/109787 per una buona discussione sul perché questo non dovrebbe accadere ma continua a farlo.


1
Questa domanda è stata posta nel contesto dello sviluppo di una piattaforma API REST.
Itay Moav -Malimovka

Non sono sicuro di cosa intendi? Un'API REST potrebbe anche trovare reindirizzamenti nel suo percorso, questo è il problema che ho avuto.
Legolas,

Intendevo quando ho posto la domanda, non stavo cercando di risolvere un bug, ma piuttosto cercare di capire come svilupparlo.
Itay Moav -Malimovka

3
questo suggerimento mi ha salvato la giornata. il server ricevente è stato riconfigurato per reindirizzare a https whoch ha rotto alcuni client API.
DesertEagle,

In realtà la mia richiesta era, POSTma dopo l'ispezione stava dimostrando che lo era GET. Una volta aggiunto /a alla fine del mio URL, ha iniziato a mostrare POST. Strano!
zackygaurav,



2

Se hai installato l'estensione pecl / http , puoi anche usare questo:

$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());

Ciò che manca a questo bit di logica è un test del valore trovato nell'intestazione Content-Type. Non ne consegue che solo perché $ _POST è vuoto che JSON devono essere state sottoposte, o che, se json_last_error() == JSON_ERROR_NONEè false, che una matrice vuota deve essere restituito. Cosa succede se qualcuno ha inviato XML o YAML? Aggiungi un test per il Content-Type e vai da lì.
Anthony Rutledge,

Inoltre, il metodo di richiesta HTTP può determinare se si desidera accettare dati di input. Vedi il $_SERVERsuperglobal per i valori utili da controllare.
Anthony Rutledge,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.