mysqli_set_charset utf8 warum?
Lisa
- codierung
- mysql
- php
Hallo,
ich habe in einer DB alle Tabellen mit UTF-8, wenn ich eine Abfrage (script natürlich auch UTF-8) mache erscheint auch im Browser als Textcodierung Unicode. Dennoch werden z.B. Umlaute so dargestellt: Pers�nliche
Ich kann das ändern indem ich der DB-Verbindung noch was mit auf dem Weg gebe: mysqli_set_charset($_sql,"utf8");
Aber warum ist das nötig und ist das der empfehlenswerte Weg?
lg.
Hello,
an jeder Schnittstelle wird hier die Kodierung übersetzt. Die "Leitung" zwischen dem Skript und der Datenbank ist eingerahmt von zwei Schnittstellen. Beide passen die Kodierung an.
Das bedeutet quasi, dass Du auf der "Leitung" aka dem Kanal zur Datenbank ISO sprechen kannst und in der Datenbank UTF halten kannst. Wenn die Schnittstelle weiß, was links und rechrt von ihr gesprochen wird, kann sid versuchen, die Kodierungen verlustarm ineinander zu überführen.
An der Textschnittstelle innerhalb des Skriptes läuft das ähnlich.
Glück Auf
Tom vom Berg
Hallo,
an jeder Schnittstelle wird hier die Kodierung übersetzt. Die "Leitung" zwischen dem Skript und der Datenbank ist eingerahmt von zwei Schnittstellen. Beide passen die Kodierung an.
danke für die Info. Wenn ich das richtig verstehe, wird aus 2 x UTF-8 u.U. ISO westlich. Warum? Und noch immer die Frage, ob die Zusatzanweisung der richtige Weg ist, das präventiv zu beheben?
lg.
Hallo Lisa,
an jeder Schnittstelle wird hier die Kodierung übersetzt. Die "Leitung" zwischen dem Skript und der Datenbank ist eingerahmt von zwei Schnittstellen. Beide passen die Kodierung an.
danke für die Info. Wenn ich das richtig verstehe, wird aus 2 x UTF-8 u.U. ISO westlich.
Nein. Was Tom meinte ist, dass MySQL zwei Settings hat: in welcher Kodierung werden die Daten gespeichert und in welcher Kodierung spricht dein Script mit der Datenbank. Ersteres gibst du bei der Erstellung der Tabelle an und zweiteres kannst du bei jeder Verbindung neu angeben mit mysqli_set_charset
. Offensichtlich ist der Default-Wert für die Verbindung mit MySQL ein Ecoding, in dem Umlaute nicht existieren, so dass die UTF-8-kodierten Tabellendaten beim Transport von der Datenbank zu deinem Script umkonvertiert werden müssen – und das geht dann halt nicht verlustfrei.
Und noch immer die Frage, ob die Zusatzanweisung der richtige Weg ist, das präventiv zu beheben?
Ja, das ist der richtige Weg.
LG,
CK
Tach!
Offensichtlich ist der Default-Wert für die Verbindung mit MySQL ein Ecoding, in dem Umlaute nicht existieren, so dass die UTF-8-kodierten Tabellendaten beim Transport von der Datenbank zu deinem Script umkonvertiert werden müssen – und das geht dann halt nicht verlustfrei.
Es gab auf der Verbindung keinen Verlust, der Defaultwert ist Latin1. MySQL hat das (zumindest im Falle der Umlaute) korrekt übersetzen können. Nur hat der Client angenommen, es sei UTF-8, das unverändert und auch als UTF-8 deklariert an den Browser geschickt. Der nun konnte die Latin1-Umlaute nicht als korrekte UTF-8-Sequenz erkennen und hat deshalb das Fragezeichen im Quadrat als Ersatz genommen.
Wenn es beim Übersetzen von UTF-8 nach Latin1 zu Verlusten kommt, wird ein normales Fragezeichen als Ersatz genommen. Das Fragezeichen im Quadrat existiert nicht in Latin1/ISO-8859-x.
dedlfix.
Tach!
mysqli_set_charset($_sql,"utf8");
Aber warum ist das nötig und ist das der empfehlenswerte Weg?
Es ist empfehlenswert, die gewünschte Kodierung explizit anzugeben statt sich auf einen eingestellten Defaultwert zu verlassen.
MySQL hat eine Menge Möglichkeiten, eine Kodierungsangabe zu setzen. Jede wirkt auf einen anderen Teilaspekt. Ohne zu sehr ins Details zu gehen (ist alles in einem eigenen Kapitel im Handbuch beschrieben), da gibt es mindestes einen Wert für den Server, der als Defaultwert für neu angelegte Datenbanken gilt, wenn man im Create-Database-Statement nichts angibt. Der Datenbankwert wiederum ist ein Default-Wert für neu angelegte Tabellen. Der Tabellenwert ist ein Default-Wert für die Felder. Letztlich zählt für die gespeicherten Daten diese Feldangabe. Daraus folgt, dass jedes Feld anders kodiert sein kann.
Nun muss auch noch bekannt sein, welche Kodierung der Client für seine Statements nimmt, und zusätzlich welche er gern für die Results hätte. MySQL kodiert das gegebenenfalls entsprechend um zwischen den jeweiligen Feldkodierungen und den Verbindungskodierungswerten des jeweiligen Clients. Mit mysqli_set_charset() gibt man nun an, welche Kodierung das sein soll. Diese Funktion setzt alle drei Werte für die Verbindung auf denselben Wert, damit DBMS und Client sich richtig verstehen. Zusätzlich ist das auch noch der Wert, den mysqli_real_escape_string() für sich verwendet. Außerdem gibts da noch das SET NAMES
-Statement, das ebenfalls die Verbindungskodierungswerte setzt, abzüglich dem für mysqli_real_escape_string() und andere API-Funktionen. Deswegen ist mysqli_set_charset() vor SET NAMES zu bevorzugen.
dedlfix.
Hello Dedlfix,
ausführliche Erklärung. Reif 1:1 für einen Artikel im Wiki. :-)
[•••]
Außerdem gibts da noch das
SET NAMES
-Statement, das ebenfalls die Verbindungskodierungswerte setzt, abzüglich dem für mysqli_real_escape_string() und andere API-Funktionen. Deswegen ist mysqli_set_charset() vor SET NAMES zu bevorzugen.
Was passiert, wenn man beide Möglichkeiten benutzt und nicht die gleichen Werte einsetzt? An welcher Stelle kneift es dann? Wie macht sich das "optisch" im Browser bemerkbar?
Glück Auf
Tom vom Berg
Hallo
ausführliche Erklärung. Reif 1:1 für einen Artikel im Wiki. :-)
Jep.
Außerdem gibts da noch das
SET NAMES
-Statement, das ebenfalls die Verbindungskodierungswerte setzt, abzüglich dem für mysqli_real_escape_string() und andere API-Funktionen. Deswegen ist mysqli_set_charset() vor SET NAMES zu bevorzugen.Was passiert, wenn man beide Möglichkeiten benutzt und nicht die gleichen Werte einsetzt?
Warum sollte man das tun?
An welcher Stelle kneift es dann? Wie macht sich das "optisch" im Browser bemerkbar?
Warum probierst du das nicht einfach aus, wenn dich die Auswirkungen dieses Bugs so interessieren?
Tschö, Auge
Hello,
Was passiert, wenn man beide Möglichkeiten benutzt und nicht die gleichen Werte einsetzt?
Warum sollte man das tun?
Z. B. aus Dummheit oder aus Versehen oder weil man unbedacht irgendwelche Module zusammenstöpselt oder unausgegorene Frameworks benutzt, oder ...
Es muss die Requester-Version z.B. auch zur Datenbankversion passen.
An welcher Stelle kneift es dann? Wie macht sich das "optisch" im Browser bemerkbar?
Warum probierst du das nicht einfach aus, wenn dich die Auswirkungen dieses Bugs so interessieren?
Weil ich auf meinem Tablet keine geeignete Versuchsumgebung dafür habe.
Glück Auf
Tom vom Berg
Hallo
Was passiert, wenn man beide Möglichkeiten benutzt und nicht die gleichen Werte einsetzt?
Warum sollte man das tun?
Z. B. aus Dummheit oder aus Versehen oder weil man unbedacht irgendwelche Module zusammenstöpselt oder unausgegorene Frameworks benutzt, oder ...
Ah ja, wir konstatieren, dass jemand, aus welchen Gründen auch immer, einen Fehler macht, einen Bug verursacht oder gar Müll verwendet (die von dir so genannten unausgegorenen Frameworks). Das sind alles Fehler, die grundsätzlich behebbar sind.
Das, zumal man den SET-NAMES
-Query typischerweise an der gleichen Stelle im Code platziert, wie den Aufruf von mysqli_set_charset
, nämlich direkt nach dem Aufbau der Datenbankverbindung. Das sollte auffallen. Wenn man hingegen mehrere Verbindungen an verschiedenen Stellen im Code aufbaut (deine „irgendwelche Module“), kann natürlich jede – gewollt oder ungewollt – ihre eigene Kodierung verwenden. Dann ist (bei „ungewollt“) Fehlersuche angesagt.
Es muss die Requester-Version z.B. auch zur Datenbankversion passen.
Das verstehe ich nicht.
An welcher Stelle kneift es dann? Wie macht sich das "optisch" im Browser bemerkbar?
Warum probierst du das nicht einfach aus, wenn dich die Auswirkungen dieses Bugs so interessieren?
Weil ich auf meinem Tablet keine geeignete Versuchsumgebung dafür habe.
Ok.
Tschö, Auge
Tach!
ausführliche Erklärung. Reif 1:1 für einen Artikel im Wiki. :-)
Außerdem gibts da noch das
SET NAMES
-Statement, das ebenfalls die Verbindungskodierungswerte setzt, abzüglich dem für mysqli_real_escape_string() und andere API-Funktionen. Deswegen ist mysqli_set_charset() vor SET NAMES zu bevorzugen.Was passiert, wenn man beide Möglichkeiten benutzt und nicht die gleichen Werte einsetzt?
Für den Teil der Kommunikation zwischen DBMS und Client wirkt das zuletzt ausgeführte. Für in der Client-API selbst ausgeführte Funktionen (Escaping) zieht das, was mysqli_set_charset()
gesetzt hat.
An welcher Stelle kneift es dann? Wie macht sich das "optisch" im Browser bemerkbar?
Beim Escapen kneift es nur, wenn man eine Kodierung hat, die nicht ASCII-basiert ist und dann auch noch die Kodierungen der Sonderzeichen nicht eindeutig zu anderen Teilen der kodierten Zeichen abgrenzbar ist. Bei ISO-8859-x und UTF-8 liegen alle Sonderzeichen im ASCII-Bereich und es gibt keine Kollisionen mit anderweitigen Sequenzen. Da ist also auch praktisch kein Unterschied zwischen SET NAMES
und mysqli_set_charset()
.
Wie die Optik aussieht, hängt immer davon ab, welche Kodierungen und Kodierungsangaben und Konvertierungen in welcher Reihenfolge vermasselt werden. Da gibt es so einige Konstellationen. Allein schon die mehr als 10 Konfigurationswerte MySQLs sorgen für eine sehr hohe Anzahl an Kombinationen. Man kann sowas untersuchen, wenn man mag, aber die Lösung läuft immer darauf hinaus, die korrekten Angaben und Kodierungen bei allen Beteiligten zu verwenden. Und zu wissen, wo man das überall setzt. Dafür hat der Zeichenkodierungsbereich im Wiki auch noch Unterseiten für Webserver und -dokumente.
dedlfix.