PHP/MySQL - HTML : Chinesisch und Russisch mit UTF8



Hallo,

heute musste ich eine Lösung finden, um russischen und chinesischen Text in die MySQL-Datenbank (MySQL 5, utf8_unicode_ci) einzufügen und richtig auf der Seite darzustellen.

Falls ihr auch mal soetwas machen müsst, beachtet folgendes:

1) Die Kollation der Datenbank selbst sollte utf-8 sein. Das kann man ändern, indem man in PHPMyAdmin von der Tabellenübersicht (=Klick auf den Datenbanknamen) auf 'Operationen' geht und dort bei 'Kollation' auf utf8_unicode_ci stellt. Wenn schon Tabellen vorhanden sind, kann es sein, dass angelegte Text/Varchar-Felder noch eine andere Kollation haben (MySQL 5) - in diesem Fall muss diese für die betroffenen Felder und Tabellen einzeln umgestellt werden ("Operationen" aus der Tabellenstruktur heraus um die Standard-Kollation für die Tabelle einzustellen und die Felder einzeln ändern)

2) Alle Texte werden mit einer normalen Query unter Verwendung von mysql_real_escape_string in die utf-8 Datenbank eingefügt, um injections zu verhindern. Der Text darf vorher nicht mit htmlentities kodiert werden.

3) Das Charset der Seite muss auf utf-8 gestellt werden.
<meta http-equiv="content-type" content="application/xhtml+xml;  charset=utf-8" />
oder für IE
<meta http-equiv="content-type" content="text/html;  charset=utf-8" />
Eventuell ist es notwendig, zusätzlich per PHP einen header auszugeben (vor allen anderen Ausgaben)

header("Content-Type: text/html; charset=UTF-8");
Die Datenbankverbindung muss auf utf8 gestellt werden (erste Query nach der Verbindung zur Datenbank, pro Verbindung einmal auszuführen)

mysql_query("SET names 'utf8'")
N.B. Dies ist evtl. nicht notwending, wenn in der PHPMyAdmin-Datenbankübersicht bei 'Kollation der MySQL-Verbindung' bereits 'utf8_unicode_ci' festgelegt ist. Falls nicht oder es sich nicht ändern lässt, muss mittels diesen Befehls die Kollation vor allen anderen Queries festgelegt werden. Die Ausführung schadet jedenfalls auch nicht - um die Portabilität des Codes zu garantieren, ist es unbedingt empfehlenswert, den Befehl auszuführen. Weitere Infos dazu gibt es in der MySQL-Dokumentation

4) Es ist keine schlechte Idee, den ISO-Code der Sprache auch mit anzugeben, also gebt diesen ebenfalls in eine Variable und hinterlegt den Wert dafür in der Tabelle der Sprachen und gebt ihn am Anfang aus (hier wurde XHTML Strict verwendet)
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
<head>

5) Nach der Selektion der Daten aus der Datenbank dürft Ihr für Sprachen wie chinesisch und russisch kein htmlentities anwenden. Verzichtet einfach für alle Sprachen ganz auf htmlentities und beschränkt euch auf htmlspecialchars.

6) Auch utf8_decode darf für Chinesisch und Russisch nach der Selektion des Textes aus der Datenbank nicht verwendet werden. Der Browser erwartet sich nun utf8, dementsprechend kann jede Ausgabe direkt utf8-kodiert erfolgen.

Um Chinesisch unter Windows zu testen, muss die chinesische Sprachunterstützung installiert sein, am einfachsten ist dies zu bewerkstelligen, indem man (ausnahmsweise) mit dem IE z.B. auf Google China surft und die vorgeschlagene Sprachpaket-Installation durchführt, es wird die Windows-CD benötigt.

Zusammenfassung:

Einfügen in die utf-8 Datenbank + anschließende Darstellung des Textes für alle Sprachen (als Beispiel eine Tabelle 'textblocks' mit id (int autoincrement) und block (text, utf8_unicode_ci) aus einer POST-Textarea mit name="textfeld"). Darstellung mit Charset = utf-8

Vorher ausführen:
mysql_query("SET names 'utf8'");
Einfügen:
mysql_query("INSERT INTO textblocks VALUES ('".mysql_real_escape_string($_POST['textfeld'])."')");
Selektieren:
$text = mysql_result(mysql_query("SELECT block FROM textblocks WHERE id=1"), 0, 0);
Darstellen:
echo htmlspecialchars(stripslashes($text));

Hoffe damit jemandem Ärger zu ersparen :)

Edit 17.08.2007: Anleitung korrigiert und ergänzt.

12.08.2006 18:42 | geändert: 17.08.2007 14:02


Danke für diese Zusammenfassung :)

5) Auch utf8_decode darf für Chinesisch und Russisch nach der Selektion des Textes aus der Datenbank nicht verwendet werden, bei Sprachen wie z.B. Deutsch ist das wegen der Umlaute aber weiterhin notwendig.

Man kann Deutsch aber auch in utf8 ausgeben?

13.08.2006 13:08 | geändert: 13.08.2006 13:09


Edit: Ah, du meinst ohne utf8_decode nach der Selektion, nicht mit dem utf-8 Charset? Nein, das geht nicht, weil in die Umlaute (alle Zeichen > 127) mit 2 Bytes gespeichert werden, ohne utf8_decode sehen die bei der Darstellung kryptisch aus, wendet man darauf htmlentities an.

Was den Charset=utf8 betrifft: Alle Sprachen mit lateinischen Schriftzeichen lassen sich mit damit ausgeben, auch z.B. arabische, nur mit chinesisch und russisch hatte ich bisher Probleme. Chinesisch ließ sich gar nicht darstellen, bei Russisch fehlten viele Zeichen. Dabei dachte ich, dass Russisch mit den kyrillischen Schriftzeichen genau was für utf-8 wäre, wurde aber nach den Tests eines besseren belehrt.

Auch das W3C empfiehlt für mehrsprachige Seiten utf8, weil es das weiteste Spektrum an Zeichenunterstützung hat. Seit in MySQL 5 die Kollationen eingeführt wurden, ist es sehr einfach, damit zu arbeiten, und man löst auf einen Schlag viele Probleme, die man sonst mit Fremdsprachen und ISO-Zeichensätzen hat.

13.08.2006 14:13 | geändert: 13.08.2006 15:35


alle Sprachen mit lateinischen Schriftzeichen lassen sich damit sowieso ausgeben

Ja, deine Äußerung, dass utf8_decode wegen deutscher Umlaute notwendig ist, war etwas missverständlich, so als ob utf-8 für Deutsch ungeeignet ist - deswegen hatte ich nachgefragt ;)

bei Russisch fehlten viele Zeichen

Tritt dieses Problem browser- oder OS-spezifisch auf? Das wundert mich schon etwas - das Dmoz z.B. gibt bei russischsprachigen Seiten den Charset UTF 8 an (Beispielseite)

13.08.2006 14:34


Nein, ungeeignet ist der utf-8 charset selbst nicht, nur nach der Selektion aus der Datenbank mit utf-8 Kollation muss utf8_decode vor htmlentities angewandt werden, weil MySQL5 beim Einfügen die Kodierung automatisch vornimmt. Wenn man kein utf8_decode und htmlentities macht, bekommt man doppelte Zeichen, die mit dem Alphabet so gar nichts zu tun haben. Wenn man kein htmlentities anwendet und nur utf8_decode, bekommt man Fragezeichen anstatt Umlaute. Wenn man kein htmlentities und kein utf8_decode verwendet, geht die Darstellung. Ich hab das oben nun ergänzt.

Tritt dieses Problem browser- oder OS-spezifisch auf?
Bei mir (WinXP) habe ich dieses Problem. Das finde ich schon etwas seltsam, aber ich bin etwas auf russischen Seiten gesurft und traf da oft auf den windows-1251 charset, als ich den ausprobiert habe, ging es. Mich wundert auch, ob das nun von MySQL abhängt oder wovon sonst. Browser-spezifisch ist es nicht, dasselbe Problem trat unter IE, Firefox, Opera auf.

13.08.2006 14:55 | geändert: 13.08.2006 15:27


OK, jetzt ist verständlicher :):

bei Sprachen wie z.B. Deutsch ist das wegen der Umlaute aber notwendig, wenn ihr weiterhin htmlentities verwenden möchtet.

Wegen dem Russischen: hast du auch Probleme auf der Dmoz-Seite? Bei mir wird diese in Windows XP normal angezeigt. Irgendwie finde ich es auch merkwürdig, dass eine UTF-8-Ausgabe nur richtig angezeigt wird, wenn die Browser diese als windows-1251 behandeln

Mich wundert auch, ob das nun von MySQL abhängt oder wovon sonst.

Wie sieht denn das Ergebnis aus, wenn du direkt nach der Eingabe in das Textfeld (vor dem INSERT) den Text ausgeben lässt - mit charset=utf-8 bzw. mit charset=windows-1251?

13.08.2006 17:17 | geändert: 13.08.2006 17:21


Das Problem könnte auch noch daran liegen, dass für die Verbindung zwischen Script und Datenbank auch nochmal explizit das Charset angegeben werden muss:

mysql_query("SET NAMES 'utf8'");

mysql_query("INSERT INTO textblocks VALUES ('".mysql_real_escape_string($_POST['textfeld'])."')");

mysql_query("SET NAMES 'utf8'");

$text = mysql_result(mysql_query("SELECT block FROM textblocks WHERE id=1"), 0, 0);

Ansonsten kommt bei Script kein utf-8 an, auch wenn für die MSQL-Tabelle die richtige Kollation gewählt ist

14.08.2006 16:07


Hallo Jörg,

sorry, war und bin wieder mal im Stress und kam bis jetzt nicht dazu, das zu testen - weil es mir aber schon lange im Kopf rumschwirrt habe ich es nun heute probiert - die names- System-Variable war tatsächlich ausschlaggebend (der Server arbeitet mit MySQL4, ich habe es bisher leider nicht auf einem 5er testen können, berichte aber, wenn ich das mache). Nun kann ich endlich russisch auch mit utf-8 anzeigen, Dankeschön!

20.09.2006 23:58


Ich habe ein Problem. Ich habe per utf-8 - Meta-Tag (<meta http-equiv="content-type" content="text/html; charset=utf-8" />)
und per
mysql_query("SET names 'utf8'");
die Verbindung auf utf8-Übertragung gestellt. Jedoch wird aus dem Russischem Добро пожаловать
folgendes:
Добро пожаловать
Woran kann das liegen? Die Tabelle ist komplett in utf8_unicode_ci gestellt.

16.08.2007 21:00


Wie sieht es im PHPMyAdmin aus? Auch schon falsch?

Die Tabelle ist komplett in utf8_unicode_ci gestellt.

Die Kollation der Felder natürlich auch, oder?

16.08.2007 21:04 | geändert: 16.08.2007 21:05