Como obter o corpo de um POST em php?

273

Eu envio como POST para uma página php o seguinte:

{a:1}

Este é o corpo da solicitação (uma solicitação POST).
No php, o que devo fazer para extrair esse valor?

var_dump($_POST); 

não é a solução, não está funcionando.

Itay Moav-Malimovka
fonte
23
Esta é uma pergunta útil para pessoas que desejam criar APIs RESTful. A maioria não sabe como acessar os dados de entrada brutos enviados para seus scripts, pois não estão disponíveis na $_POSTsuperglobal. Isso também é (especialmente) verdadeiro no caso de solicitações PUT, pois o PHP não possui superglobal correspondente.
Rdlowrey
1
Vale ressaltar que o nome $ _POST é enganoso, pois nenhum tipo de dado de uma solicitação POST estará lá, mas apenas quando o tipo de conteúdo for application / x-www-form-urlencoded ou multipart / form-data
Petruza

Respostas:

549

Para acessar o corpo da entidade de uma solicitação POST ou PUT (ou qualquer outro método HTTP):

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

Além disso, a STDINconstante é um fluxo já aberto para php://input, portanto, você pode alternativamente:

$entityBody = stream_get_contents(STDIN);

Na entrada manual do PHP nos documentos de fluxos de E / S :

php: // input é um fluxo somente leitura que permite ler dados brutos do corpo da solicitação. No caso de solicitações POST, é preferível usar php: // input em vez de $HTTP_RAW_POST_DATAnão depender de diretivas especiais do php.ini. Além disso, nos casos em que $HTTP_RAW_POST_DATAnão é preenchido por padrão, é uma alternativa potencialmente menos intensiva em memória para ativar always_populate_raw_post_data. php: // input não está disponível com enctype = "multipart / form-data".

Especificamente, você deve observar que o php://inputfluxo, independentemente de como você o acessa em uma SAPI da web, não é procurável . Isso significa que ele só pode ser lido uma vez. Se você estiver trabalhando em um ambiente em que grandes corpos de entidades HTTP são carregados rotineiramente, convém manter a entrada em sua forma de fluxo (em vez de armazená-la em buffer, como no primeiro exemplo acima).

Para manter o recurso de fluxo, algo como isto pode 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://temppermite que você gerencie o consumo de memória, pois ele mudará de maneira transparente para o armazenamento do sistema de arquivos após o armazenamento de uma certa quantidade de dados (2M por padrão). Esse tamanho pode ser manipulado no arquivo php.ini ou anexando /maxmemory:NN, onde NNestá a quantidade máxima de dados a serem armazenados na memória antes de usar um arquivo temporário, em bytes.

Obviamente, a menos que você tenha um bom motivo para procurar no fluxo de entrada, não precisará dessa funcionalidade em um aplicativo da web. A leitura do corpo da entidade de solicitação HTTP uma vez é geralmente suficiente - não deixe os clientes esperando o dia todo enquanto o aplicativo descobre o que fazer.

Observe que php: // input não está disponível para solicitações que especificam um Content-Type: multipart/form-datacabeçalho ( enctype="multipart/form-data"em formulários HTML). Isso resulta do PHP já ter analisado os dados do formulário no $_POSTsuperglobal.

rdlowrey
fonte
17
Por favor, note que AFAICS, o fluxo STDIN não está disponível em sistemas que executam o PHP usando CGI, ou seja, através mod_fcgid ou mod_fastcgi etc.
Scy
mas, estou passando a variável (como formulário-dados) com a solicitação, como posso acessar o valor especificado? entityBody "
Anvar Pk
de acordo com o meu teste, esta php://inputestá vazia para application/x-www-form-urlencodedo tipo de conteúdo, bem como (para além multipart/form-data)
YakovL
6
Para expandir a resposta do @ scy: STDIN não está disponível, mas php://inputestá. Então, enquanto as configurações de CGI (rápidas) stream_get_contents(STDIN)não funcionarem, funcionará file_get_contents("php://input").
Sinus Mackowaty 15/01/19
16

valor de retorno na matriz

 $data = json_decode(file_get_contents('php://input'), true);
umesh bhanderi
fonte
Nesse cenário, agora você precisa percorrer a $datamatriz associativa para verificar se cada valor está codificado da maneira que você deseja. A maneira de ver as coisas "fluxo para tipo de dados" pode ser simplista, mas pode não ser tão eficiente quanto lidar com a codificação no "formulário de fluxo" usando um filtro de fluxo. Se você não está lidando com problemas de codificação e simplesmente limpando e validando, está faltando uma etapa.
Anthony Rutledge
13

Uma possível razão para um vazio $_POSTé que a solicitação não está POST, ou não está POSTmais ... Ela pode ter começado como postagem, mas encontrou um 301ou 302redirecionado para algum lugar, para o qual foi alternada GET!

Inspecione $_SERVER['REQUEST_METHOD']para verificar se é esse o caso.

Consulte https://stackoverflow.com/a/19422232/109787 para obter uma boa discussão sobre por que isso não deveria acontecer, mas ainda acontece.

Legolas
fonte
1
Esta pergunta foi feita no contexto do desenvolvimento de uma plataforma API REST.
Itay Moav -Malimovka 16/03/16
Eu não tenho certeza do que você quer dizer? Uma API REST pode também encontrar redirecionamentos no caminho, esse é o problema que tive.
Legolas
Eu quis dizer que, quando fiz a pergunta, não estava tentando resolver um bug, mas tentando descobrir como desenvolvê-lo.
Itay Moav -Malimovka 17/03
3
Essa dica salvou meu dia. o servidor de recebimento foi reconfigurado para redirecionar para https, que quebrou alguns clientes da API.
DesertEagle 15/02
Na verdade, o meu pedido foi, POSTmas depois de inspecionar, estava mostrando que sim GET. Depois de adicionar um /no final do meu URL, ele começou a mostrar POST. Esquisito!
zackygaurav
4

Verifique a $HTTP_RAW_POST_DATAvariável

linepogl
fonte
7
O método preferido para acessar os dados brutos do POST é php://input. $HTTP_RAW_POST_DATAnão está disponível com enctype="multipart/form-data".
nullability
38
Este recurso foi DEPRECADO no PHP 5.6.0 e REMOVIDO a partir do PHP 7.0.0.
Charles
3

Se você instalou a extensão HTTP PECL, poderá usar a http_get_request_body()função para obter dados do corpo como uma sequência.

shivanshu patel
fonte
função não existe.
Rick
2

Se você possui a extensão pecl / http instalada, também pode usar:

$request = new http\Env\Request();
$request->getBody();
spinkus
fonte
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
fonte
O que esse bit de lógica está faltando é um teste do valor encontrado no cabeçalho Content-Type. Não se segue que, apenas porque $ _POST está vazio, o JSON deve ter sido enviado ou, se json_last_error() == JSON_ERROR_NONEestiver false, que uma matriz vazia deve ser retornada. E se alguém tiver enviado XML ou YAML? Adicione um teste para o tipo de conteúdo e vá a partir daí.
Anthony Rutledge
Além disso, o método de solicitação HTTP pode levar em consideração se você deseja aceitar dados de entrada. Veja a $_SERVERsuperglobal para obter valores úteis a serem verificados.
Anthony Rutledge