Fui orientado a usar o método em php://inputvez de $_POSTinteragir com solicitações Ajax do JQuery. O que eu não entendo são os benefícios de usar isso vs o método global de $_POSTor $_GET.
Eu costumava usar "hacks" para receber chamadas de ajax no lado do PHP antes de tropeçar neste post e ler suas respostas impressionantes! Para outras pessoas com o mesmo problema no futuro, espero que os mecanismos de pesquisa também leiam meu comentário! :)
aderchox 21/09/18
Respostas:
484
A razão é que php://input retorna todos os dados brutos após os cabeçalhos HTTP da solicitação, independentemente do tipo de conteúdo.
O superglobal do PHP $_POSTapenas deve agrupar dados que sejam
application/x-www-form-urlencoded (tipo de conteúdo padrão para postagens simples) ou
multipart/form-data (usado principalmente para upload de arquivos)
Isso ocorre porque esses são os únicos tipos de conteúdo que devem ser suportados pelos agentes do usuário . Portanto, o servidor e o PHP tradicionalmente não esperam receber nenhum outro tipo de conteúdo (o que não significa que não possam).
Portanto, se você simplesmente POSTAR um bom e velho HTML form, a solicitação se parece com isso:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
Mas se você trabalha muito com o Ajax, esse probaby também inclui a troca de dados mais complexos com tipos (string, int, bool) e estruturas (matrizes, objetos); portanto, na maioria dos casos, o JSON é a melhor opção. Mas uma solicitação com uma carga JSON se pareceria com isso:
POST /page.php HTTP/1.1{"key1":"value1","key2":"value2","key3":"value3"}
O conteúdo agora seria application/json(ou pelo menos nenhum dos mencionados acima), portanto, o $_POSTww-wrapper do PHP ainda não sabe como lidar com isso (ainda).
Os dados ainda estão lá, você simplesmente não pode acessá-los através do wrapper. Portanto, você deve buscá-lo no formato bruto com file_get_contents('php://input')( desde que não seja multipart/form-datacodificado) ).
Também é assim que você acessaria dados XML ou qualquer outro tipo de conteúdo não padrão.
@Quasdank estou enviando JSON do aplicativo Android para o servidor php xampp na nuvem ( stackoverflow.com/questions/36558261/… ), mas não consegui fazê-lo funcionar quando tentei file_get_contents ('php: // input'), que simplesmente retorna string (0). Isso costumava funcionar na minha máquina local, mas não funciona quando eu a implantei na nuvem. Você poderia me ajudar por favor?
precisa saber é o seguinte
1
Vale ressaltar que o uso do objeto XMLHttpRequest em uma solicitação AJAX para PHP não significa que é necessário postar JSON. É uma sobrecarga extra, mas o JavaScript do lado do cliente pode ser convertido para o formato application / x-www-form-urlencoded. No entanto, a tradução pode não ser do tipo de dados puro .
Anthony Rutledge
É necessário dizer que o limite de dois tipos de conteúdo reconhecidos é amplamente histórico. Nada impede que o PHP reconheça, ou seja, application/jsoncomo fonte de dados válida para o $_POSTarray. E há até pedidos publicados especificamente para esse suporte.
php://inputpode fornecer os bytes brutos dos dados. Isso é útil se os dados POSTed forem uma estrutura codificada em JSON, que geralmente é o caso de uma solicitação AJAX POST.
Aqui está uma função para fazer exatamente isso:
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/privatefunction retrieveJsonPostData(){// get the raw POST data
$rawData = file_get_contents("php://input");// this returns null if not valid jsonreturn json_decode($rawData);}
A $_POSTmatriz é mais útil quando você manipula dados de valor-chave de um formulário, enviado por um POST tradicional. Isso funciona apenas se os dados do POSTed estiverem em um formato reconhecido, normalmente application/x-www-form-urlencoded(consulte http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 para obter detalhes).
Vale a pena notar que, se você passar truecomo o segundo parâmetro json_decode, ele retornará uma matriz associativa.
Vahid Amiri
28
Se os dados da postagem estiverem malformados, $ _POST não conterá nada. No entanto, php: // input terá a string malformada.
Por exemplo, existem alguns aplicativos ajax que não formam a sequência correta de valor-chave de postagem para fazer upload de um arquivo e apenas despejam todo o arquivo como dados de postagem, sem nomes de variáveis ou qualquer coisa. $ _POST estará vazio, $ _FILES também vazio e php: // input conterá o arquivo exato, escrito como uma string.
O PHP não foi projetado para fornecer explicitamente uma interface REST pura (GET, POST, PUT, PATCH, DELETE) para lidar com solicitações HTTP .
No entanto, os $_POST, $_GETe $_FILESsuperglobals , e a funçãofilter_input_array() são muito úteis para as necessidades / leigos da pessoa média.
A principal vantagem oculta de $_POST(e $_GET) é que seus dados de entrada são codificados automaticamente pelo PHP . Você nunca pensa em fazê-lo, especialmente para parâmetros de sequência de consulta em uma solicitação GET padrão.
No entanto, você aprende mais ...
Dito isto, à medida que você avança no seu conhecimento de programação e deseja usar o XmlHttpRequestobjeto JavaScript (jQuery para alguns), você vê a limitação desse esquema.
$_POSTlimita você ao uso de dois tipos de mídia no Content-Typecabeçalho HTTP :
application/x-www-form-urlencodede
multipart/form-data
Portanto, se você deseja enviar valores de dados para o PHP no servidor e mostrá-los na $_POSTsuperglobal , deve codificá- los no lado do cliente e enviar os dados como pares de chave / valor - uma etapa inconveniente para iniciantes (especialmente ao tentar descobrir se partes diferentes do URL exigem formas diferentes de codificação de URL: normal, bruto, etc.).
Para todos os usuários do jQuery, o $.ajax()método é converter seu JSON em pares de chave / valor codificado em URL antes de transmiti-los ao servidor. Você pode substituir esse comportamento, definindo processData: false. Basta ler a documentação $ .ajax () e não se esqueça de enviar o tipo de mídia correto no cabeçalho Content-Type.
Codificação de URL? Que diabos!!!???
Normalmente, se você estiver executando solicitações HTTP normais e síncronas (quando a página inteira redesenhar) com um formulário HTML, o agente do usuário (navegador da Web) codificará os dados do formulário para você. Se você deseja fazer solicitações HTTP assíncronas usando o XmlHttpRequestobjeto, é necessário criar uma string codificada em url e enviá-la, se desejar que esses dados sejam exibidos na $_POSTsuperglobal .
Como você está em contato com o JavaScript? :-)
A conversão de uma matriz ou objeto JavaScript em uma string codificada em url incomoda muitos desenvolvedores (mesmo com novas APIs como Form Data ). Eles prefeririam apenas enviar JSON, e seria mais eficiente o código do cliente fazer isso.
Lembre-se (wink, wink), o desenvolvedor da Web comum não aprende a usar o XmlHttpRequest objeto diretamente, funções globais, funções de string, funções de array e expressões regulares como você e eu ;-). Urlencoding para eles é um pesadelo. ;-)
PHP, o que dá?
A falta de manipulação intuitiva de XML e JSON do PHP desativa muitas pessoas. Você pensaria que seria parte do PHP agora (suspiro).
Tantos tipos de mídia (tipos MIME no passado)
XML, JSON e YAML todos têm tipos de mídia que podem ser colocados em um Content-Typecabeçalho HTTP .
application / xml
applicaiton / json
application / yaml (embora a IANA não tenha uma designação oficial listada)
Veja quantos tipos de mídia (anteriormente, tipos MIME) são definidos pela IANA.
Usando o php://input fluxo permite contornar o nível de abstração de babás / mãos que o PHP impôs ao mundo. :-) Com grandes poderes vem grandes responsabilidades!
Agora, antes de lidar com valores de dados transmitidos php://input, você deve / deve fazer algumas coisas.
Determine se o método HTTP correto foi indicado (GET, POST, PUT, PATCH, DELETE, ...)
Determine se o cabeçalho HTTP Content-Type foi transmitido.
Determine se o valor para o Tipo de conteúdo é o tipo de mídia desejado.
Determine se os dados enviados estão bem formados XML / JSON / YMAL / etc.
Se necessário, converta os dados em um tipo de dados PHP: matriz ou objeto.
Se alguma dessas verificações ou conversões básicas falhar, crie uma exceção !
E a codificação de caracteres?
Ah, ah! Sim, você pode querer que o fluxo de dados enviado ao seu aplicativo seja codificado em UTF-8, mas como você pode saber se é ou não?
Dois problemas críticos.
Você não sabe quantos dados estão chegando php://input.
Você não sabe ao certo a codificação atual do fluxo de dados.
Você tentará manipular dados de fluxo sem saber quanto há primeiro? Essa é uma péssima ideia . Você não pode confiar exclusivamente no Content-Lengthcabeçalho HTTP para obter orientação sobre o tamanho da entrada transmitida porque pode ser falsificada.
Você vai precisar de:
Algoritmo de detecção de tamanho de fluxo.
Limites de tamanho de fluxo definidos pelo aplicativo (os limites do Apache / Nginx / PHP podem ser muito amplos).
Você tentará converter dados de fluxo em UTF-8 sem conhecer a codificação atual do fluxo? Quão? O filtro de fluxo iconv ( exemplo de filtro de fluxo iconv ) parece querer uma codificação inicial e final, como esta.
'convert.iconv.ISO-8859-1/UTF-8'
Assim, se você tiver consciência, precisará de:
Algoritmo de detecção de codificação de fluxo.
Algoritmo de definição de filtro de fluxo dinâmico / de tempo de execução (porque você não pode saber a codificação inicial a priori).
( Atualização : 'convert.iconv.UTF-8/UTF-8'forçará tudo para UTF-8, mas você ainda precisará considerar os caracteres que a biblioteca iconv talvez não saiba traduzir. Em outras palavras, você precisa definir como agir quando um personagem não puder ser traduzido : 1) Insira um caractere fictício, 2) Fail / throw e exceção).
Você não pode confiar exclusivamente no Content-Encodingcabeçalho HTTP , pois isso pode indicar algo como compactação, como a seguir. Não é disso que você deseja tomar uma decisão em relação ao iconv.
Content-Encoding: gzip
Portanto, as etapas gerais podem ser ...
Parte I: Solicitação HTTP Relacionada
Determine se o método HTTP correto foi indicado (GET, POST, PUT, PATCH, DELETE, ...)
Determine se o cabeçalho HTTP Content-Type foi transmitido.
Determine se o valor para o Tipo de conteúdo é o tipo de mídia desejado.
Parte II: Dados relacionados ao fluxo
Determine o tamanho do fluxo de entrada (opcional, mas recomendado).
Determine a codificação do fluxo de entrada.
Se necessário, converta o fluxo de entrada na codificação de caracteres desejada (UTF-8).
Se necessário, inverta qualquer compactação ou criptografia no nível do aplicativo e repita as etapas 4, 5 e 6.
Parte III: Relacionado ao Tipo de Dados
Determine se os dados enviados estão bem formados XML / JSON / YMAL / etc.
(Lembre-se de que os dados ainda podem ser uma string codificada em URL que você deve analisar e decodificar em URL).
Se necessário, converta os dados em um tipo de dados PHP: matriz ou objeto.
Parte IV: Relacionado ao Valor dos Dados
Filtre os dados de entrada.
Valide os dados de entrada.
Agora você vê?
A $_POSTsuperglobal, juntamente com as configurações do php.ini para limites de entrada, são mais simples para o leigo. No entanto, lidar com a codificação de caracteres é muito mais intuitivo e eficiente ao usar fluxos, porque não há necessidade de passar por superglobais (ou matrizes, geralmente) para verificar os valores de entrada para a codificação adequada.
Oh uau! Esta resposta deve ter uma classificação muito mais alta. Muito obrigado por trazer a luz da inundação para a escuridão.
Lox
Na análise final, o PHP faria bem em atualizar os padrões básicos. No entanto, é uma falácia lógica acoplar um método de solicitação HTTP com uma estrutura de dados com o mesmo nome ($ _GET, $ _POST). O que importa é (1) o método de solicitação HTTP desejado e (2) existem dados de solicitação com essa solicitação (Tipo de Conteúdo). Portanto, como no Perl, você deve ver que pode ser vítima voluntária das opiniões dos criadores / mantenedores de idiomas.
Anthony Rutledge
0
Então, eu escrevi uma função que obteria os dados POST do fluxo de entrada php: // .
Portanto, o desafio aqui foi mudar para o método de solicitação PUT, DELETE OR PATCH e ainda obter os dados de postagem enviados com essa solicitação.
Estou compartilhando isso talvez para alguém com um desafio semelhante. A função abaixo é o que eu criei e funciona. Espero que ajude!
/**
* @method Post getPostData
* @return array
*
* Convert Content-Disposition to a post data
*/function getPostData(): array
{// @var string $input
$input = file_get_contents('php://input');// continue if $_POST is emptyif(strlen($input)>0&& count($_POST)==0|| count($_POST)>0):
$postsize ="---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);// update inputif(count($match)>0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/','', $input);// extract the content-disposition
preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);// let's get the keysif(count($matches)>0&& count($matches[0])>0){
$keys = $matches[2];foreach($keys as $index => $key):
$key = trim($key);
$key = preg_replace('/^["]/','',$key);
$key = preg_replace('/["]$/','',$key);
$key = preg_replace('/[\s]/','',$key);
$keys[$index]= $key;
endforeach;
$input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);
$input = preg_replace("/(Content-Length: )+([^\n]+)/im",'', $input);// now let's get key value
$inputArr = explode($postsize, $input);// @var array $values
$values =[];foreach($inputArr as $index => $val):
$val = preg_replace('/[\n]/','',$val);if(preg_match('/[\S]/', $val)) $values[$index]= trim($val);
endforeach;// now combine the key to the values
$post =[];// @var array $value
$value =[];// update valueforeach($values as $i => $val) $value[]= $val;// push to postforeach($keys as $x => $key) $post[$key]= isset($value[$x])? $value[$x]:'';if(is_array($post)):
$newPost =[];foreach($post as $key => $val):if(preg_match('/[\[]/', $key)):
$k = substr($key,0, strpos($key,'['));
$child = substr($key, strpos($key,'['));
$child = preg_replace('/[\[|\]]/','', $child);
$newPost[$k][$child]= $val;else:
$newPost[$key]= $val;
endif;
endforeach;
$_POST = count($newPost)>0? $newPost : $post;
endif;}
endif;// return post arrayreturn $_POST;}
Respostas:
A razão é que
php://input
retorna todos os dados brutos após os cabeçalhos HTTP da solicitação, independentemente do tipo de conteúdo.O superglobal do PHP
$_POST
apenas deve agrupar dados que sejamapplication/x-www-form-urlencoded
(tipo de conteúdo padrão para postagens simples) oumultipart/form-data
(usado principalmente para upload de arquivos)Isso ocorre porque esses são os únicos tipos de conteúdo que devem ser suportados pelos agentes do usuário . Portanto, o servidor e o PHP tradicionalmente não esperam receber nenhum outro tipo de conteúdo (o que não significa que não possam).
Portanto, se você simplesmente POSTAR um bom e velho HTML
form
, a solicitação se parece com isso:Mas se você trabalha muito com o Ajax, esse probaby também inclui a troca de dados mais complexos com tipos (string, int, bool) e estruturas (matrizes, objetos); portanto, na maioria dos casos, o JSON é a melhor opção. Mas uma solicitação com uma carga JSON se pareceria com isso:
O conteúdo agora seria
application/json
(ou pelo menos nenhum dos mencionados acima), portanto, o$_POST
ww-wrapper do PHP ainda não sabe como lidar com isso (ainda).Os dados ainda estão lá, você simplesmente não pode acessá-los através do wrapper. Portanto, você deve buscá-lo no formato bruto com
file_get_contents('php://input')
( desde que não sejamultipart/form-data
codificado) ).Também é assim que você acessaria dados XML ou qualquer outro tipo de conteúdo não padrão.
fonte
application/json
como fonte de dados válida para o$_POST
array. E há até pedidos publicados especificamente para esse suporte.php://input
pode fornecer os bytes brutos dos dados. Isso é útil se os dados POSTed forem uma estrutura codificada em JSON, que geralmente é o caso de uma solicitação AJAX POST.Aqui está uma função para fazer exatamente isso:
A
$_POST
matriz é mais útil quando você manipula dados de valor-chave de um formulário, enviado por um POST tradicional. Isso funciona apenas se os dados do POSTed estiverem em um formato reconhecido, normalmenteapplication/x-www-form-urlencoded
(consulte http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 para obter detalhes).fonte
true
como o segundo parâmetrojson_decode
, ele retornará uma matriz associativa.Se os dados da postagem estiverem malformados, $ _POST não conterá nada. No entanto, php: // input terá a string malformada.
Por exemplo, existem alguns aplicativos ajax que não formam a sequência correta de valor-chave de postagem para fazer upload de um arquivo e apenas despejam todo o arquivo como dados de postagem, sem nomes de variáveis ou qualquer coisa. $ _POST estará vazio, $ _FILES também vazio e php: // input conterá o arquivo exato, escrito como uma string.
fonte
Primeiro, uma verdade básica sobre PHP.
O PHP não foi projetado para fornecer explicitamente uma interface REST pura (GET, POST, PUT, PATCH, DELETE) para lidar com solicitações HTTP .
No entanto, os
$_POST
,$_GET
e$_FILES
superglobals , e a funçãofilter_input_array()
são muito úteis para as necessidades / leigos da pessoa média.A principal vantagem oculta de
$_POST
(e$_GET
) é que seus dados de entrada são codificados automaticamente pelo PHP . Você nunca pensa em fazê-lo, especialmente para parâmetros de sequência de consulta em uma solicitação GET padrão.No entanto, você aprende mais ...
Dito isto, à medida que você avança no seu conhecimento de programação e deseja usar o
XmlHttpRequest
objeto JavaScript (jQuery para alguns), você vê a limitação desse esquema.$_POST
limita você ao uso de dois tipos de mídia noContent-Type
cabeçalho HTTP :application/x-www-form-urlencoded
emultipart/form-data
Portanto, se você deseja enviar valores de dados para o PHP no servidor e mostrá-los na
$_POST
superglobal , deve codificá- los no lado do cliente e enviar os dados como pares de chave / valor - uma etapa inconveniente para iniciantes (especialmente ao tentar descobrir se partes diferentes do URL exigem formas diferentes de codificação de URL: normal, bruto, etc.).Para todos os usuários do jQuery, o
$.ajax()
método é converter seu JSON em pares de chave / valor codificado em URL antes de transmiti-los ao servidor. Você pode substituir esse comportamento, definindoprocessData: false
. Basta ler a documentação $ .ajax () e não se esqueça de enviar o tipo de mídia correto no cabeçalho Content-Type.Codificação de URL? Que diabos!!!???
Normalmente, se você estiver executando solicitações HTTP normais e síncronas (quando a página inteira redesenhar) com um formulário HTML, o agente do usuário (navegador da Web) codificará os dados do formulário para você. Se você deseja fazer solicitações HTTP assíncronas usando o
XmlHttpRequest
objeto, é necessário criar uma string codificada em url e enviá-la, se desejar que esses dados sejam exibidos na$_POST
superglobal .Como você está em contato com o JavaScript? :-)
A conversão de uma matriz ou objeto JavaScript em uma string codificada em url incomoda muitos desenvolvedores (mesmo com novas APIs como Form Data ). Eles prefeririam apenas enviar JSON, e seria mais eficiente o código do cliente fazer isso.
Lembre-se (wink, wink), o desenvolvedor da Web comum não aprende a usar o
XmlHttpRequest
objeto diretamente, funções globais, funções de string, funções de array e expressões regulares como você e eu ;-). Urlencoding para eles é um pesadelo. ;-)PHP, o que dá?
A falta de manipulação intuitiva de XML e JSON do PHP desativa muitas pessoas. Você pensaria que seria parte do PHP agora (suspiro).
Tantos tipos de mídia (tipos MIME no passado)
XML, JSON e YAML todos têm tipos de mídia que podem ser colocados em um
Content-Type
cabeçalho HTTP .Veja quantos tipos de mídia (anteriormente, tipos MIME) são definidos pela IANA.
Veja quantos cabeçalhos HTTP existem.
php: // input ou busto
Usando o
php://input
fluxo permite contornar o nível de abstração de babás / mãos que o PHP impôs ao mundo. :-) Com grandes poderes vem grandes responsabilidades!Agora, antes de lidar com valores de dados transmitidos
php://input
, você deve / deve fazer algumas coisas.E a codificação de caracteres?
Ah, ah! Sim, você pode querer que o fluxo de dados enviado ao seu aplicativo seja codificado em UTF-8, mas como você pode saber se é ou não?
Dois problemas críticos.
php://input
.Você tentará manipular dados de fluxo sem saber quanto há primeiro? Essa é uma péssima ideia . Você não pode confiar exclusivamente no
Content-Length
cabeçalho HTTP para obter orientação sobre o tamanho da entrada transmitida porque pode ser falsificada.Você vai precisar de:
Você tentará converter dados de fluxo em UTF-8 sem conhecer a codificação atual do fluxo? Quão? O filtro de fluxo iconv ( exemplo de filtro de fluxo iconv ) parece querer uma codificação inicial e final, como esta.
Assim, se você tiver consciência, precisará de:
( Atualização :
'convert.iconv.UTF-8/UTF-8'
forçará tudo para UTF-8, mas você ainda precisará considerar os caracteres que a biblioteca iconv talvez não saiba traduzir. Em outras palavras, você precisa definir como agir quando um personagem não puder ser traduzido : 1) Insira um caractere fictício, 2) Fail / throw e exceção).Você não pode confiar exclusivamente no
Content-Encoding
cabeçalho HTTP , pois isso pode indicar algo como compactação, como a seguir. Não é disso que você deseja tomar uma decisão em relação ao iconv.Portanto, as etapas gerais podem ser ...
Parte I: Solicitação HTTP Relacionada
Parte II: Dados relacionados ao fluxo
Parte III: Relacionado ao Tipo de Dados
(Lembre-se de que os dados ainda podem ser uma string codificada em URL que você deve analisar e decodificar em URL).
Parte IV: Relacionado ao Valor dos Dados
Filtre os dados de entrada.
Valide os dados de entrada.
Agora você vê?
A
$_POST
superglobal, juntamente com as configurações do php.ini para limites de entrada, são mais simples para o leigo. No entanto, lidar com a codificação de caracteres é muito mais intuitivo e eficiente ao usar fluxos, porque não há necessidade de passar por superglobais (ou matrizes, geralmente) para verificar os valores de entrada para a codificação adequada.fonte
Então, eu escrevi uma função que obteria os dados POST do fluxo de entrada php: // .
Portanto, o desafio aqui foi mudar para o método de solicitação PUT, DELETE OR PATCH e ainda obter os dados de postagem enviados com essa solicitação.
Estou compartilhando isso talvez para alguém com um desafio semelhante. A função abaixo é o que eu criei e funciona. Espero que ajude!
fonte
Exemplo simples de como usá-lo
fonte