¿Cómo obtener el cuerpo de un POST en php?

273

Presento como POST a una página php lo siguiente:

{a:1}

Este es el cuerpo de la solicitud (una solicitud POST).
En php, ¿qué tengo que hacer para extraer ese valor?

var_dump($_POST); 

No es la solución, no funciona.

Itay Moav -Malimovka
fuente
23
Esta es una pregunta útil para las personas que buscan crear API RESTful. La mayoría no sabe cómo acceder a los datos de entrada sin procesar enviados a sus scripts, ya que no está disponible a través de la $_POSTsuperglobal. Esto también es (especialmente) cierto en el caso de solicitudes PUT, ya que PHP no tiene un superglobal correspondiente.
rdlowrey
1
Vale la pena señalar que el nombre $ _POST es engañoso, ya que no habrá ningún tipo de datos de una solicitud POST, sino solo cuando el tipo de contenido sea application / x-www-form-urlencoded o multipart / form-data
Petruza

Respuestas:

549

Para acceder al cuerpo de la entidad de una solicitud POST o PUT (o cualquier otro método HTTP):

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

Además, la STDINconstante es una secuencia ya abierta php://input, por lo que puede hacer alternativamente:

$entityBody = stream_get_contents(STDIN);

De la entrada manual de PHP en documentos de flujos de E / S :

php: // input es una secuencia de solo lectura que le permite leer datos sin procesar del cuerpo de la solicitud. En el caso de solicitudes POST, es preferible usar php: // input en lugar de, $HTTP_RAW_POST_DATAya que no depende de directivas especiales php.ini. Además, para aquellos casos en los $HTTP_RAW_POST_DATAque no se rellena de manera predeterminada, es una alternativa potencialmente menos intensiva en memoria para activar always_populate_raw_post_data. php: // input no está disponible con enctype = "multipart / form-data".

Específicamente, querrá tener en cuenta que la php://inputtransmisión, independientemente de cómo acceda a ella en un SAPI web, no es buscable . Esto significa que solo se puede leer una vez. Si está trabajando en un entorno donde se cargan rutinariamente grandes cuerpos de entidades HTTP, es posible que desee mantener la entrada en su forma de flujo (en lugar de almacenarla en el búfer como en el primer ejemplo anterior).

Para mantener el recurso continuo, algo como esto puede ser útil:

<?php

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

    return $tempStream;
}

php://temple permite administrar el consumo de memoria porque cambiará de forma transparente al almacenamiento del sistema de archivos después de que se almacene una cierta cantidad de datos (2M por defecto). Este tamaño se puede manipular en el archivo php.ini o agregando /maxmemory:NN, donde NNestá la cantidad máxima de datos para guardar en la memoria antes de usar un archivo temporal, en bytes.

Por supuesto, a menos que tenga una buena razón para buscar en la secuencia de entrada, no debería necesitar esta funcionalidad en una aplicación web. Por lo general, leer el cuerpo de la entidad de solicitud HTTP una vez es suficiente: no haga que los clientes esperen todo el día mientras su aplicación determina qué hacer.

Tenga en cuenta que php: // input no está disponible para solicitudes que especifican un Content-Type: multipart/form-dataencabezado ( enctype="multipart/form-data"en formularios HTML). Esto resulta de que PHP ya ha analizado los datos del formulario en el $_POSTsuperglobal.

rdlowrey
fuente
17
Tenga en cuenta que afaics, la corriente STDIN no está disponible en sistemas que ejecutan PHP usando CGI, es decir, a través de mod_fcgid o mod_fastcgi etc.
scy
pero, estoy pasando variable (como datos de formulario) con la solicitud, ¿cómo puedo acceder al valor especificado, estoy pasando grant_type = contraseña & username = user & password = pasar como cuerpo de datos de formulario con la solicitud, cómo obtendré grant_type de "$ entityBody "
Anvar Pk
según mi prueba, esto también php://inputestá vacío para application/x-www-form-urlencodedel tipo de contenido (además multipart/form-data)
YakovL
66
Para ampliar la respuesta de @ scy: STDIN no está disponible, pero lo php://inputestá. Entonces, mientras que las configuraciones CGI (rápidas) stream_get_contents(STDIN)no funcionen, lo file_get_contents("php://input")harán.
Sinus Mackowaty
16

valor de retorno en la matriz

 $data = json_decode(file_get_contents('php://input'), true);
umesh bhanderi
fuente
En este escenario, ahora tiene que recorrer la $datamatriz asociativa para verificar si cada valor está codificado de la manera deseada. La forma de ver las cosas de "flujo a tipo de datos" puede ser simplista, pero puede no ser tan eficiente como tratar con la codificación en el "formulario de flujo" usando un filtro de flujo. Si no está manejando problemas de codificación y simplemente desinfectando y validando, se está perdiendo un paso.
Anthony Rutledge
13

Una posible razón para un vacío $_POSTes que la solicitud ya no es POST, o POSTya no ... Puede haber comenzado como una publicación, pero se encontró 301o se 302redirigió en algún lugar, ¡que se cambió a GET!

Inspeccione $_SERVER['REQUEST_METHOD']para verificar si este es el caso.

Vea https://stackoverflow.com/a/19422232/109787 para una buena discusión de por qué esto no debería suceder, pero aún así sucede.

Legolas
fuente
1
Esta pregunta se hizo en el contexto del desarrollo de una plataforma API REST.
Itay Moav -Malimovka
¿No estoy seguro de lo que quieres decir? Una API REST también podría encontrar redireccionamientos en su ruta, ese es el problema que tuve.
Legolas
Cuando hice la pregunta, quise decir que no estaba tratando de resolver un error, sino más bien tratando de descubrir cómo desarrollarlo.
Itay Moav -Malimovka
3
Esta pista me salvó el día. el servidor receptor se ha reconfigurado para redirigir a https whoch rompió algunos clientes API.
DesertEagle
En realidad, mi solicitud fue, POSTpero después de inspeccionar estaba demostrando que sí GET. Una vez que agregué un /al final de mi URL, comenzó a mostrar POST. ¡Extraño!
zackygaurav
4

Comprueba la $HTTP_RAW_POST_DATAvariable

linepogl
fuente
77
El método preferido para acceder a los datos POST sin procesar es php://input. $HTTP_RAW_POST_DATAno está disponible con enctype="multipart/form-data".
nulabilidad
38
Esta característica fue DEPRECADA en PHP 5.6.0 y eliminada a partir de PHP 7.0.0.
Charles
3

Si ha instalado la extensión HTTP PECL, puede hacer uso de la http_get_request_body()función para obtener datos del cuerpo como una cadena.

shivanshu patel
fuente
La función no existe.
Rick
2

Si tiene instalada la extensión pecl / http , también puede usar esto:

$request = new http\Env\Request();
$request->getBody();
Spinkus
fuente
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
fuente
Lo que falta este poco de lógica es una prueba del valor encontrado en el encabezado Content-Type. No se sigue que solo porque $ _POST esté vacío, se haya enviado JSON, o que si json_last_error() == JSON_ERROR_NONEes así false, se deba devolver una matriz vacía. ¿Qué pasa si alguien ha enviado XML o YAML? Agregue una prueba para Content-Type y vaya desde allí.
Anthony Rutledge
Además, el método de solicitud HTTP puede determinar si desea aceptar datos de entrada. Vea el $_SERVERsuperglobal para valores útiles para verificar.
Anthony Rutledge