Ich wurde angewiesen, die Methode php://input
anstelle der $_POST
Interaktion mit Ajax-Anforderungen von JQuery zu verwenden. Was ich nicht verstehe, sind die Vorteile dieser Verwendung gegenüber der globalen Methode von $_POST
oder $_GET
.
Ich wurde angewiesen, die Methode php://input
anstelle der $_POST
Interaktion mit Ajax-Anforderungen von JQuery zu verwenden. Was ich nicht verstehe, sind die Vorteile dieser Verwendung gegenüber der globalen Methode von $_POST
oder $_GET
.
Antworten:
Der Grund ist, dass php://input
alle Rohdaten nach den HTTP-Headern der Anfrage zurückgegeben werden, unabhängig vom Inhaltstyp.
Die PHP - Superglobal $_POST
, nur auf vermeintliche Wrap Daten , die entweder
application/x-www-form-urlencoded
(Standardinhaltstyp für einfache Formularbeiträge) odermultipart/form-data
(meistens für Datei-Uploads verwendet)Dies liegt daran, dass dies die einzigen Inhaltstypen sind , die von Benutzeragenten unterstützt werden müssen . Daher erwarten der Server und PHP traditionell keinen anderen Inhaltstyp (was nicht bedeutet, dass sie dies nicht können).
Wenn Sie also einfach einen guten alten HTML-Code veröffentlichen form
, sieht die Anfrage ungefähr so aus:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
Wenn Sie jedoch häufig mit Ajax arbeiten, umfasst dieses Probaby auch den Austausch komplexerer Daten mit Typen (Zeichenfolge, Int, Bool) und Strukturen (Arrays, Objekte). In den meisten Fällen ist JSON daher die beste Wahl. Eine Anfrage mit einer JSON-Nutzlast würde jedoch ungefähr so aussehen:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
Der Inhalt wäre jetzt application/json
(oder zumindest keiner der oben genannten), so dass der PHP- $_POST
Wrapper (noch) nicht weiß, wie er damit umgehen soll.
Die Daten sind noch vorhanden, Sie können einfach nicht über den Wrapper darauf zugreifen. Sie müssen es also selbst im Rohformat mit abrufenfile_get_contents('php://input')
( solange es nicht multipart/form-data
-codiert ist ).
Auf diese Weise können Sie auch auf XML-Daten oder andere nicht standardmäßige Inhaltstypen zugreifen.
application/json
als gültige Datenquelle für das $_POST
Array zu erkennen. Und es gibt sogar veröffentlichte Anfragen für speziell diese Unterstützung.
php://input
kann Ihnen die Rohbytes der Daten geben. Dies ist nützlich, wenn die POST-Daten eine JSON-codierte Struktur sind, was häufig bei einer AJAX-POST-Anforderung der Fall ist.
Hier ist eine Funktion, um genau das zu tun:
/**
* 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);
}
Das $_POST
Array ist nützlicher, wenn Sie Schlüsselwertdaten aus einem Formular verarbeiten, das von einem herkömmlichen POST gesendet wird. Dies funktioniert normalerweise nur, wenn die POST-Daten in einem erkannten Format vorliegen application/x-www-form-urlencoded
( Einzelheiten finden Sie unter http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 ).
true
als zweiten Parameter an übergeben json_decode
, wird ein assoziatives Array zurückgegeben.
Wenn die Postdaten fehlerhaft sind, enthält $ _POST nichts. Die Eingabe von php: // enthält jedoch die fehlerhafte Zeichenfolge.
Zum Beispiel gibt es einige Ajax-Anwendungen, die keine korrekte Post-Key-Value-Sequenz zum Hochladen einer Datei bilden und einfach die gesamte Datei als Post-Daten ohne Variablennamen oder ähnliches ausgeben. $ _POST ist leer, $ _FILES ist ebenfalls leer und die Eingabe von php: // enthält eine genaue Datei, die als Zeichenfolge geschrieben ist.
PHP wurde nicht entwickelt, um Ihnen explizit eine reine REST-ähnliche Schnittstelle (GET, POST, PUT, PATCH, DELETE) für die Verarbeitung von HTTP-Anforderungen zu geben .
Allerdings ist der $_POST
, $_GET
und $_FILES
superglobals und die Funktion filter_input_array()
ist sehr nützlich für die durchschnittliche Person / Laien Bedürfnisse.
Der versteckte Vorteil Nummer eins von $_POST
(und $_GET
) ist, dass Ihre Eingabedaten von PHP automatisch urldecodiert werden . Sie denken nicht einmal daran, dies tun zu müssen, insbesondere bei Abfragezeichenfolgenparametern innerhalb einer Standard-GET-Anforderung.
Wenn Sie jedoch Ihre Programmierkenntnisse erweitern und das JavaScript- XmlHttpRequest
Objekt (für einige jQuery) verwenden möchten , werden Sie feststellen, dass dieses Schema Einschränkungen aufweist.
$_POST
beschränkt Sie auf die Verwendung von zwei Medientypen im HTTP- Content-Type
Header:
application/x-www-form-urlencoded
, undmultipart/form-data
Wenn Sie also Datenwerte an PHP auf dem Server senden und diese im $_POST
Superglobal anzeigen lassen möchten , müssen Sie sie auf der Clientseite urlencodieren und diese Daten als Schlüssel / Wert-Paare senden - ein unpraktischer Schritt für Anfänger (insbesondere, wenn Sie herausfinden möchten, ob verschiedene Teile der URL unterschiedliche Formen der Urlencodierung erfordern: normal, roh usw.).
Für alle jQuery-Benutzer $.ajax()
konvertiert die Methode Ihren JSON in URL-codierte Schlüssel / Wert-Paare, bevor sie an den Server übertragen werden. Sie können dieses Verhalten durch Festlegen überschreiben processData: false
. Lesen Sie einfach die Dokumentation zu $ .ajax () und vergessen Sie nicht, den richtigen Medientyp im Content-Type-Header zu senden.
Wenn Sie normale, synchrone (wenn die gesamte Seite neu gezeichnet wird) HTTP-Anforderungen mit einem HTML-Formular ausführen, codiert der Benutzeragent (Webbrowser) normalerweise Ihre Formulardaten für Sie. Wenn Sie mit dem XmlHttpRequest
Objekt asynchrone HTTP-Anforderungen ausführen möchten, müssen Sie eine urlencodierte Zeichenfolge erstellen und diese senden. möchten, wenn diese Daten im $_POST
Superglobal angezeigt werden sollen .
Das Konvertieren von einem JavaScript-Array oder -Objekt in eine urlencodierte Zeichenfolge stört viele Entwickler (selbst bei neuen APIs wie Formulardaten ). Sie würden viel lieber nur JSON senden können, und das wäre es auch effizienter für den Client-Code, dies zu tun.
Denken Sie daran (zwinker, zwinker), dass der durchschnittliche Webentwickler nicht lernt, das zu verwenden XmlHttpRequest
Objekt, globale Funktionen, Zeichenfolgenfunktionen, Arrayfunktionen und reguläre Ausdrücke wie Sie und ich direkt ;-). Urlencodierung ist für sie ein Albtraum. ;-);
Das Fehlen einer intuitiven XML- und JSON-Verarbeitung in PHP macht viele Leute aus. Sie würden denken, dass es jetzt Teil von PHP sein würde (seufz).
XML, JSON und YAML verfügen alle über Medientypen, die in einen HTTP- Content-Type
Header eingefügt werden können.
Schauen Sie, wie viele Medientypen (früher MIME-Typen) von IANA definiert wurden.
Schauen Sie, wie viele HTTP-Header es gibt.
Verwendung der php://input
Stream können Sie die Abstraktionsstufe für Babysitting / Handhaltung umgehen, die PHP der Welt aufgezwungen hat. :-) Mit großer Macht kommt große Verantwortung!
Bevor Sie sich mit Datenwerten befassen, die durch sie gestreamt werden php://input
, sollten / müssen Sie einige Dinge tun.
AH, HA! Ja, Sie möchten möglicherweise, dass der an Ihre Anwendung gesendete Datenstrom UTF-8-codiert wird. Wie können Sie jedoch feststellen, ob dies der Fall ist oder nicht?
php://input
.Versuchen Sie, Stream-Daten zu verarbeiten, ohne zu wissen, wie viel zuerst vorhanden ist? Das ist eine schreckliche Idee . Sie können sich nicht ausschließlich auf den HTTP- Content-Length
Header verlassen, um eine Anleitung zur Größe der gestreamten Eingabe zu erhalten, da diese gefälscht werden kann.
Sie benötigen eine:
Versuchen Sie, Stream-Daten in UTF-8 zu konvertieren, ohne die aktuelle Codierung des Streams zu kennen? Wie? Der iconv-Stream-Filter ( Beispiel für einen iconv-Stream-Filter ) scheint eine Start- und Endcodierung wie diese zu wollen.
'convert.iconv.ISO-8859-1/UTF-8'
Wenn Sie gewissenhaft sind, benötigen Sie:
( Update : 'convert.iconv.UTF-8/UTF-8'
Erzwingt alles auf UTF-8, aber Sie müssen immer noch Zeichen berücksichtigen, die die iconv-Bibliothek möglicherweise nicht übersetzen kann. Mit anderen Worten, Sie müssen festlegen, welche Aktion ausgeführt werden soll, wenn ein Zeichen nicht übersetzt werden kann : 1) Fügen Sie ein Dummy-Zeichen ein, 2) Fail / Throw und Exception).
Sie können sich nicht ausschließlich auf den HTTP- Content-Encoding
Header verlassen, da dies möglicherweise auf eine Komprimierung wie im Folgenden hinweist. Dies ist nicht das, woraus Sie eine Entscheidung in Bezug auf iconv treffen möchten.
Content-Encoding: gzip
Teil I: HTTP-Anfrage im Zusammenhang
Teil II: Stream-Daten
Teil III: Datentypbezogen
(Denken Sie daran, dass die Daten immer noch eine URL-codierte Zeichenfolge sein können, die Sie dann analysieren und URL-dekodieren müssen.)
Teil IV: Datenwertbezogen
Eingabedaten filtern.
Eingabedaten validieren.
Das $_POST
Superglobale ist zusammen mit den php.ini-Einstellungen für Eingabegrenzen für den Laien einfacher. Der Umgang mit der Zeichenkodierung ist jedoch bei der Verwendung von Streams viel intuitiver und effizienter, da keine Superglobalen (oder Arrays im Allgemeinen) durchlaufen werden müssen, um die Eingabewerte auf die richtige Kodierung zu überprüfen.
Also habe ich eine Funktion geschrieben, die die POST-Daten aus dem php: // Eingabestream abruft .
Die Herausforderung bestand darin, auf die Anforderungsmethode PUT, DELETE OR PATCH umzuschalten und trotzdem die Post-Daten zu erhalten, die mit dieser Anforderung gesendet wurden.
Ich teile dies vielleicht für jemanden mit einer ähnlichen Herausforderung. Die folgende Funktion ist das, was ich mir ausgedacht habe und sie funktioniert. Ich hoffe, es hilft!
/**
* @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;
}
Einfaches Beispiel für die Verwendung
<?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; }
?>