POST und UTF8 -> Sonderzeichen
Anne
- php
0 Cheatah0 Anne1 Der Martin3 dedlfix
0 Gunnar Bittersmann
Hallo,
ich arbeite gerade an meinem ersten PHP Formular, das ich per POST in eine MYSQL Datenbank übertragen möchte.
Mein Problem ist, das offenbar die Sonderzeichen nicht korrekt übertragen werden. Ich habe daher vor dem Eintrag in die Datenbank einen ECHO Befehl gesetzt und auch hier wird aus ä ein ä. Somit dürfte das Problem ja schon vor der MYSQL Datenbank liegen
Wenn ich das mir richtig in den Dokumentationen an-gelesen habe ist es ein UTF8 Fehler.
Um sicher zu stellen, das sowohl die sendende als auch die eintragende Domain den entsprechenden Content Type haben ich diese mit dem HTTP LIVE Header überprüft.
Content-Type: text/html; charset=utf-8
ist also nach meinem Verständnis richtig.
Der POST - Querry sieht auch schon komisch aus beim Absenden
&ort=M%C3%A4dchen
ist das so richtig?
Danke Anne
Hi,
Ich habe daher vor dem Eintrag in die Datenbank einen ECHO Befehl gesetzt und auch hier wird aus ä ein ä.
das ist ein UTF-Zeichen, welches in ISO-Kodierung dargestellt wird.
Der POST - Querry sieht auch schon komisch aus beim Absenden
&ort=M%C3%A4dchen
ist das so richtig?
Ja, das ist UTF-kodiert. Zum Verständnis: ISO ist der zum Scheitern verurteilte Versuch, Sonderzeichen in nur ein einziges Byte zu packen. Da es auf der Welt mehr als 256 Zeichen gibt, kann dies nur schief gehen. UTF räumt damit auf, indem es die Möglichkeit eröffnet, einzelne Zeichen mit mehr als nur einem Byte zu kodieren. Hast Du also mehrere Bytes bzw. "Zeichen", die nur ein Zeichen (diesmal ohne Anführungszeichen) ergeben müssen, so ist das Zeichen UTF-kodiert.
Cheatah
Hallo Cheatah,
danke für die Aufklärung. Ich glaube ich habe den Übeltäter gefunden: ~~~php
foreach($_POST as $key => $value) {
$data[$key] = filter($value);
Den der Filter soll eigentlich XSS unmöglich machen:
~~~php
function filter($data) {
$data = trim(htmlentities(strip_tags($data)));
if (get_magic_quotes_gpc())
$data = stripslashes($data);
$data = mysql_real_escape_string($data);
return $data;
}
Und nach dem Filter passiert das ÖÄÜ Problem. Gibt es da vielleicht einen Trick, wie man die Sonderzeichen rettet?
Ich habe daher vor dem Eintrag in die Datenbank einen ECHO Befehl gesetzt und auch hier wird aus ä ein ä.
das ist ein UTF-Zeichen, welches in ISO-Kodierung dargestellt wird.
Der POST - Querry sieht auch schon komisch aus beim Absenden
&ort=M%C3%A4dchen
ist das so richtig?Ja, das ist UTF-kodiert. Zum Verständnis: ISO ist der zum Scheitern verurteilte Versuch, Sonderzeichen in nur ein einziges Byte zu packen. Da es auf der Welt mehr als 256 Zeichen gibt, kann dies nur schief gehen. UTF räumt damit auf, indem es die Möglichkeit eröffnet, einzelne Zeichen mit mehr als nur einem Byte zu kodieren. Hast Du also mehrere Bytes bzw. "Zeichen", die nur ein Zeichen (diesmal ohne Anführungszeichen) ergeben müssen, so ist das Zeichen UTF-kodiert.
Cheatah
Hallo,
Ich glaube ich habe den Übeltäter gefunden:
anscheinend nicht ganz - aber zumindest den Codeblock, in dem er steckt.
Den der Filter soll eigentlich XSS unmöglich machen:
Okay - dann aber bitte richtig.
$data = trim(htmlentities(strip_tags($data)));
Was genau versprichst du dir hier von htmlentities()? - Diese Funktion ist dafür gedacht (aber dennoch nicht geeignet), Daten zu behandeln, wenn sie in den Kontext HTML gebracht werden. Für andere Zwecke ist diese Funktion völlig ungeeignet. Und selbst für die Aufbereitung für HTML ist htmlspecialchars() besser geeignet.
Übrigens ist strip_tags() auch nicht immer schlau, weil diese Funktion radikal alles löscht, was mit '<' beginnt und mit '>' endet. Das ist nicht immer erwünscht; hier wäre htmlspecialchars() günstiger. Das wandelt '<' in < und '>> in >, so dass diese Zeichen risikolos im HTML-Kontext wieder ausgegeben werden können und die Eingabedaten exakt erhalten bleiben.
Genau diese Funktion htmlentities() verstümmelt dir tatsächlich deine Eingaben. Denn sie behandelt jedes Byte als ein Zeichen und geht dabei von einer ISO-8859-x-Codierung aus. Aus zwei Bytes, die eigentlich *ein* UTF-8-Zeichen darstellen, macht die Funktion zwei HTML-Entities. Und das ist Murx.
$data = mysql_real_escape_string($data);
Okay, mysql_real_escape_string() ist die richtige Funktion, um Strings für den Kontext SQL zu maskieren. Der Ordnung halber sollte diese Maskierung aber erst an der Stelle erfolgen, an der der String auch an eine mysql*-Funktion übergeben wird, und nicht "auf Verdacht" irgendwo in der Verarbeitungskette.
Und nach dem Filter passiert das ÖÄÜ Problem.
Ja, und nicht nur das - du hast anstatt UTF-8-codierter Klartext-Zeichen sogar noch unnötig HTML-Entity-Referenzen im Quellcode stehen.
Ciao,
Martin
Hi!
Den der Filter soll eigentlich XSS unmöglich machen:
function filter($data) {
$data = trim(htmlentities(strip_tags($data)));
if (get_magic_quotes_gpc())
$data = stripslashes($data);$data = mysql_real_escape_string($data);
return $data;
}
Du versuchst, alles auf einmal zu erledigen: Eingabedatenbehandlung plus Ausgabedatenbehandlung für zwei verschiedene Medien und beachtest dabei nicht einmal die Zeichenkodierung und die Funktionsparameter, die dafür zuständig sind. Das ist alles ungünstig. Lies bitte den Artikel zum [Kontextwechsel](http://wiki.selfhtml.org/wiki/Artikel:Kontextwechsel) und achte bitte in Zukunft genau darauf, wann welche Daten in welchen Kontext übergehen und behandle sie erst dann und nur genau dafür (siehe Abschnitt [HTML in der Datenbank](http://wiki.selfhtml.org/wiki/Artikel:Kontextwechsel/erkennen_und_behandeln#HTML_in_der_Datenbank)).
Außerdem solltest du die Reihenfolge der verschiedenen Schritte beachten, durch die die Daten bereits gegangen sind. PHP fügt als Letztes die Magic Quotes hinzu (falls man dieses Feature immer noch aktiviert hat), also sollte man auch zuerst die Magic Quotes wieder entfernen. Das hat zwar möglicherweise keine Auswirkungen, wenn sich die Funktionen aufgrund der von ihnen behandelten verschiedenen Zeichen nicht in die Quere kommen, aber zumindest sieht es undurchdacht aus. Es ist jedenfalls einfacher, die Reihenfolge einzuhalten, als sich davon zu überzeugen, dass alle Kombinationen von Zeichen und Funktionen in einer anderen Reihenfolge problemlos zusammenarbeiten.
Jedenfalls hast du nach der M.Q.-Entfernung die Daten so vorliegen, wie sie eingegeben wurden. Die zum Transport vom Browser hinzugefügte URL- oder Prozent-Kodierung wird von PHP selbständig entfernt (bevor es eventuelle M.Q. hinzufügt).
> Und nach dem Filter passiert das ÖÄÜ Problem. Gibt es da vielleicht einen Trick, wie man die Sonderzeichen rettet?
Damit zeigt sich, das Cheatah nicht richtig geraten hat. Warum das passiert, hat dir Der Martin schon erzählt. Abgesehen davon käme htmlentities() mit UTF-8-kodierten Zeichen klar, wenn du den entsprechenden Funktionsparameter richtig versorgt hättest, aber diese Funktion ist normalerweise (also, wenn man konsequent mit UTF-8 arbeitet) unnötig, selbst wenn sie für den Kontext HTML verwendet wird. Nicht unnötig ist hingegen ihre "kleine Schwester" htmlspecialchars(), denn die kümmert sich lediglich um die HTML-eigenen Zeichen. Für alle anderen bist du mit UTF-8 bereits bestens bedient.
> > > Ich habe daher vor dem Eintrag in die Datenbank einen ECHO Befehl gesetzt und auch hier wird aus ä ein ä.
> > das ist ein UTF-Zeichen, welches in ISO-Kodierung dargestellt wird.
Richtig formuliert wäre eher, dass die UTF-8-Bytefolge des ä gemäß der ISO-8859-1-Kodierung interpretiert wurde (nicht nur "ISO", denn es gibt eine Menge ISO-Standards). Für eine Darstellung ist keine Kodierung sondern eine Glyphe zuständig.
Für die Kommunikation mit MySQL ist noch ein wenig mehr zu beachten: SELFHTML-Wiki [Themen:Zeichencodierung/MySQL](http://wiki.selfhtml.org/wiki/Themen:Zeichencodierung/MySQL). Auch der Rest zum Thema [Zeichenkodierung](http://wiki.selfhtml.org/wiki/Themen:Zeichencodierung) kann nicht schaden.
Lo!
@@Cheatah:
nuqneH
hier wird aus ä ein ä.
das ist ein UTF-Zeichen
?? Du solltest wissen, dass es genausowenig UTF-Zeichen wie CSS-Klassen gibt.
&ort=M%C3%A4dchen
Ja, das ist UTF-kodiert.
Das ist nicht einmal die halbe Wahrheit: Es ist UTF-_8_-codiert (und nicht etwa UTF-16 oder UTF-32) und die sich dabei ergebenden Bytewerte sind Prozent-escapet.
Zum Verständnis: ISO ist der zum Scheitern verurteilte Versuch, Sonderzeichen in nur ein einziges Byte zu packen.
Meinem Verständnis nach ist 'ä' kein Sonderzeichen, sondern ein ganz normaler Buchstabe vieler Alphabete lateinischer Schrift. http://forum.de.selfhtml.org/archiv/2010/6/t198491/#m1333251 ff.
Qapla'