Mi è stato chiesto di utilizzare il metodo php://input
invece di $_POST
interagire con le richieste Ajax da JQuery. Quello che non capisco sono i vantaggi dell'utilizzo di questo rispetto al metodo globale di $_POST
o $_GET
.
Mi è stato chiesto di utilizzare il metodo php://input
invece di $_POST
interagire con le richieste Ajax da JQuery. Quello che non capisco sono i vantaggi dell'utilizzo di questo rispetto al metodo globale di $_POST
o $_GET
.
Risposte:
Il motivo è che php://input
restituisce tutti i dati non elaborati dopo le intestazioni HTTP della richiesta, indipendentemente dal tipo di contenuto.
Il superglobal PHP dovrebbe$_POST
solo avvolgere i dati
application/x-www-form-urlencoded
(tipo di contenuto standard per semplici moduli) omultipart/form-data
(utilizzato principalmente per i caricamenti di file)Questo perché questi sono gli unici tipi di contenuto che devono essere supportati dagli agenti utente . Quindi il server e PHP tradizionalmente non si aspettano di ricevere nessun altro tipo di contenuto (il che non significa che non potrebbero).
Quindi, se semplicemente POST un buon vecchio HTML form
, la richiesta è simile alla seguente:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
Ma se lavori molto con Ajax, questo probaby include anche lo scambio di dati più complessi con tipi (string, int, bool) e strutture (array, oggetti), quindi nella maggior parte dei casi JSON è la scelta migliore. Ma una richiesta con un payload JSON sarebbe simile a questa:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
Il contenuto ora sarebbe application/json
(o almeno nessuno dei precedenti), quindi il $_POST
wrapper di PHP non sa come gestirlo (ancora).
I dati sono ancora lì, non è possibile accedervi tramite il wrapper. Quindi è necessario recuperarlo da soli in formato raw con file_get_contents('php://input')
( purché non sia multipart/form-data
codificato ).
Questo è anche il modo in cui si accede ai dati XML o a qualsiasi altro tipo di contenuto non standard.
application/json
come fonte di dati valida per l' $_POST
array. E ci sono persino richieste pubblicate per quel supporto specifico.
php://input
può darti i byte grezzi dei dati. Ciò è utile se i dati POST sono una struttura codificata JSON, che è spesso il caso di una richiesta POST AJAX.
Ecco una funzione per fare proprio questo:
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/
private function retrieveJsonPostData()
{
// get the raw POST data
$rawData = file_get_contents("php://input");
// this returns null if not valid json
return json_decode($rawData);
}
L' $_POST
array è più utile quando si gestiscono i dati valore-chiave da un modulo, inviati da un POST tradizionale. Funziona solo se i dati POST sono in un formato riconosciuto, di solito application/x-www-form-urlencoded
(vedi http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 per i dettagli).
true
come secondo parametro a json_decode
, verrà restituito un array associativo.
Se i dati post non sono corretti, $ _POST non conterrà nulla. Tuttavia, php: // input avrà la stringa non valida.
Ad esempio, ci sono alcune applicazioni ajax, che non formano una corretta sequenza di valori-chiave post per il caricamento di un file e scaricano semplicemente tutto il file come dati post, senza nomi di variabili o altro. $ _POST sarà vuoto, anche $ _FILES vuoto e php: // input conterrà un file esatto, scritto come una stringa.
PHP non è stato progettato per darti esplicitamente un'interfaccia pura REST (GET, POST, PUT, PATCH, DELETE) per la gestione delle richieste HTTP .
Tuttavia, il $_POST
, $_GET
e i $_FILES
superglobali e la funzione filter_input_array()
sono molto utili per le esigenze della persona media / laica.
Il vantaggio nascosto numero uno di $_POST
(e $_GET
) è che i tuoi dati di input vengono automaticamente codificati da PHP . Non hai mai pensato di doverlo fare, specialmente per i parametri della stringa di query all'interno di una richiesta GET standard.
Detto questo, man mano che avanzi nelle tue conoscenze di programmazione e desideri utilizzare l' XmlHttpRequest
oggetto JavaScript (jQuery per alcuni), arriverai a vedere i limiti di questo schema.
$_POST
ti limita all'uso di due tipi di media Content-Type
nell'intestazione HTTP :
application/x-www-form-urlencoded
, emultipart/form-data
Pertanto, se si desidera inviare valori di dati a PHP sul server e visualizzarli nel $_POST
superglobal , è necessario codificarli sul lato client e inviare tali dati come coppie chiave / valore - un passaggio scomodo per i principianti (soprattutto quando si cerca di capire se parti diverse dell'URL richiedono forme diverse di urlencoding: normale, grezzo, ecc.).
Per tutti voi utenti jQuery, il $.ajax()
metodo sta convertendo il vostro JSON in coppie chiave / valore codificate URL prima di trasmetterle al server. È possibile ignorare questo comportamento impostando processData: false
. Basta leggere la documentazione $ .ajax () e non dimenticare di inviare il tipo di supporto corretto nell'intestazione Content-Type.
In genere, se si esegue una richiesta HTTP normale, sincrona (quando l'intera pagina viene ridisegnata) con un modulo HTML, l'utente-agente (browser Web) codificherà i dati del modulo per voi. Se si desidera eseguire richieste HTTP asincrone utilizzando l' XmlHttpRequest
oggetto, è necessario creare una stringa codificata e inviarla, se si desidera che tali dati $_POST
vengano visualizzati nel superglobal .
La conversione da un array o un oggetto JavaScript in una stringa codificata urlata disturba molti sviluppatori (anche con nuove API come Form Data ). Preferirebbero semplicemente inviare JSON e sarebbe più efficiente per il codice client farlo.
Ricorda (occhiolino, occhiolino), lo sviluppatore web medio non impara ad usare XmlHttpRequest
direttamente l' oggetto, le funzioni globali, le funzioni di stringa, le funzioni di matrice e le espressioni regolari come te e io ;-). La codifica URL per loro è un incubo. ;-)
La mancanza di gestione XML e JSON intuitiva di PHP disattiva molte persone. Penseresti che ora sarebbe parte di PHP (sospiro).
XML, JSON e YAML hanno tutti tipi di media che possono essere inseriti in Content-Type
un'intestazione HTTP .
Guarda quanti tipi di media (precedentemente, tipi MIME) sono definiti da IANA.
Guarda quante intestazioni HTTP ci sono.
L'uso del php://input
flusso ti consente di aggirare il livello di astrazione che il PHP ha imposto al mondo da baby-sitter / mano. :-) Con un grande potere viene una grande responsabilità!
Ora, prima di gestire i valori dei dati trasmessi in streaming php://input
, dovresti / devi fare alcune cose.
AH, HA! Sì, potresti voler inviare il flusso di dati nell'applicazione con codifica UTF-8, ma come puoi sapere se lo è o no?
php://input
.Tenterai di gestire i dati di flusso senza sapere quanto c'è prima? Questa è un'idea terribile . Non è possibile fare affidamento esclusivamente sull'intestazione HTTP Content-Length
per indicazioni sulla dimensione dell'input in streaming perché può essere falsificato.
Avrai bisogno di un:
Tenterai di convertire i dati del flusso in UTF-8 senza conoscere la codifica corrente del flusso? Come? Il filtro iconv stream ( esempio di filtro iconv stream ) sembra desiderare una codifica iniziale e finale, come questa.
'convert.iconv.ISO-8859-1/UTF-8'
Pertanto, se sei coscienzioso, avrai bisogno di:
( Aggiornamento : 'convert.iconv.UTF-8/UTF-8'
forzerà tutto su UTF-8, ma devi comunque tenere conto dei caratteri che la libreria iconv potrebbe non sapere come tradurre. In altre parole, devi in qualche modo definire quale azione intraprendere quando un personaggio non può essere tradotto : 1) Inserisci un personaggio fittizio, 2) Fallimento / lancio ed eccezione).
Non puoi fare affidamento esclusivamente sull'intestazione HTTP Content-Encoding
, poiché ciò potrebbe indicare qualcosa di simile alla compressione come nel seguito. Questo non è ciò di cui vuoi prendere una decisione riguardo a iconv.
Content-Encoding: gzip
Parte I: Richiesta HTTP relativa
Parte II: Stream dati correlati
Parte III: relativi al tipo di dati
(Ricorda, i dati possono comunque essere una stringa codificata URL che devi quindi analizzare e decodificare URL).
Parte IV: valore relativo ai dati
Filtra i dati di input.
Convalida dati di input.
Il $_POST
superglobal, insieme alle impostazioni php.ini per i limiti di input, sono più semplici per i non addetti ai lavori. Tuttavia, gestire la codifica dei caratteri è molto più intuitivo ed efficiente quando si usano i flussi perché non è necessario eseguire il ciclo tra superglobali (o array, in generale) per verificare i valori di input per la codifica corretta.
Quindi ho scritto una funzione che otterrebbe i dati POST dal flusso di input php: // .
Quindi la sfida qui era passare al metodo di richiesta PUT, DELETE O PATCH e ottenere comunque i dati di post che sono stati inviati con quella richiesta.
Sto condividendo questo forse per qualcuno con una sfida simile. La funzione di seguito è quella che mi è venuta in mente e funziona. Spero possa essere d'aiuto!
/**
* @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 empty
if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :
$postsize = "---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);
// update input
if (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 keys
if (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 value
foreach ($values as $i => $val) $value[] = $val;
// push to post
foreach ($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 array
return $_POST;
}
Semplice esempio di come usarlo
<?php
if(!isset($_POST) || empty($_POST)) {
?>
<form name="form1" method="post" action="">
<input type="text" name="textfield"><br />
<input type="submit" name="Submit" value="submit">
</form>
<?php
} else {
$example = file_get_contents("php://input");
echo $example; }
?>