dedlfix: AJAX - JSON.stringify - Sonderzeichen

Beitrag lesen

Tach!

mit JSON.stringify übergebe ich einen array an PHP. Funktioniert auch soweit, nur mit einem Problem. Wenn im Text ein Undzeichen vorkommt, werden die Daten nicht korrekt übertragen. Meine Frage - wie sollte ich hier das "Undzeichen" noch codieren? Weiteres Problem ist das Plus-Zeichen, wie codiere ich dieses, damit es bei der Übergabe kein Leerzeichen wird?

Extra für Dich und aus diesem Anlass siehe: Artikel -- leicht verständlich erklärt.

Dann auch von mir der Versuch einer kompletten Erklärung.

Vermutlich ist beim OP ein Stück Javascript nach folgendem Prinzip im Einsatz:

var json = JSON.stringify(some_data_object_or_array);

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", url);
xmlhttp.send("data=" + json);

Nicht zu sehen ist hier, dass der Browser beim Senden an die URL den Content-Type auf den Standard-Wert "application/x-www-form-urlencoded; charset=UTF-8" setzt. Das Problem an obigem Code ist, dass der String in der Variable json Zeichen enthalten kann, die gemäß diesem Content-Type eine besondere Bedeutung haben. Das betrifft vor allem das &, welches als Parameter-Trenner verwendet wird: data=text&moredata=moretext. Es ist deshalb notwendig, dass diese Zeichen mit besonderer Bedeutung in den Nutzdaten (sprich: in dem String in der Variable json) entsprechend maskiert werden. Das kann die Funktion encodeURIComponent().

var json = JSON.stringify(some_data_object_or_array);

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", url);
xmlhttp.send("data=" + encodeURIComponent(json));

So wäre es nun korrekt. Und das Prinzip betrifft alle Daten, nicht nur Strings, die zufälligerweise JSON enthalten. Hat man weitere Daten, hängt man sie nach demselben Prinzip und durch & getrennt aneinander.

var json = JSON.stringify(some_data_object_or_array);

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", url);
xmlhttp.send("data=" + encodeURIComponent(json) + "&" + "moredata=" + encodeURIComponent(moredata));

(Natürlich kann man auch ... + "&moredata=" + ... schreiben, aber ich habe das & zur Verdeutlichung extra geschrieben.)

Wenn man PHP auf der Server-Seite hat, kann man nun die Daten in $_POST entgegennehmen. PHP dekodiert die Daten selbständig gemäß dem mitgesendeten Content-Type application/x-www-form-urlencoded, man muss also nicht das Gegenstück zu encodeURIComponent() ausführen.

<?php
$some_data_object_or_array = json_decode($_POST['data']);
do_something_with_moredata($_POST['moredata']);

Alternativer Ansatz:

Die oben gezeigte Methode eignet sich vor allem auch in Fällen, in denen weitere Daten neben dem JSON-Inhalt zum Server gesendet werden müssen. Ist der JSON-Inhalt hingegen die einzige Nutzlast, die zum Server übertragen werden muss, dann kann man das auch nach diesem Prinzip machen, aber man kann den JSON-Inhalt auch direkt übertragen, ohne zusätzliches data=. Man muss dazu jedoch den Content-Type anpassen.

var json = JSON.stringify(some_data_object_or_array);

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", url);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send(json); // <- nur json, nichts weiter

Auch auf der Serverseite muss man nun anders vorgehen. PHP kennt den Content-Type application/json nicht und erzeugt nun auch keine Einträge in $_POST und dergleichen. Stattdessen muss man sich den Inhalt selbst und direkt aus dem Request-Body holen. PHP stellt den unter der Pseudo-URL php://input zur Verfügung. Diese lässt sich PHP-üblich mit Filesystemfunktionen abfragen lässt.

<?php
$request_body = file_get_contents('php://input');
$some_data_object_or_array = json_decode($request_body);

Man kann die Angelegenheit nun noch weiter verfeinern, indem man die Request-Header nach Content-Type durchsucht (die Funktion apache_request_headers() liefert diese), und diesen auswertet, um auch andere Daten als JSON erkennen zu können. Das lohnt sich aber nicht, wenn man lediglich von seiner eigenen Website Daten erwartet. Stellt man hingegen eine öffentliche API zur Verfügung, wäre das der Weg, den Clienten mehr Freiheiten beim Datenformat zu geben.

dedlfix.