Seit einigen Tagen bin ich dabei, ein PHP-Projekt von ISO 8859-1 (kurz „Latin 1“) auf den Unicode-Zeichensatz umzusatteln. Wer schon mit Latin 1 und UTF-8 hantieren musste, denkt sich vielleicht: „Alles, nur nicht das!“ Viele Kollegen und Leidensgenossen wollen an solche Umstellungen gar nicht erinnert werden. Dabei ist es so einfach…
…wenn man weiß, was und wie zu tun ist.
1. Sie müssen wissen, welche Komponenten betroffen sind
a) HTML-Ausgabe an den Browser? (wohl immer)
b) E-Mails? (sehr oft)
c) Datenbanken? (nicht unbedingt)
d) dynamisch generierte Bilder? (eher selten)
e) sonstige Dinge?
2 Sie müssen einen Masterplan entwickeln
a) Der Quellcode (-Zeichensatz) hängt direkt mit dem Editor zusammen (oft ist der Zeichensatz in Projekt-Einstellungen einstellbar). Eine Datei mit Sonderzeichen einmal als UTF-8 gespeichert wird so gut wie nie automatisch ins „Latin1“ zurück konvertiert! Am besten IMMER HTML-ENTITIES VERWENDEN („ü“ statt „ü“), damit sind sie immer auf der sicheren Seite! (Egal wann alles andere aus UTF-8 ausgeliefert wird).
b) Übersetzungen und andere Texte aus der Datenbank als UTF-8 lesen und als UTF-8 an „htmlentities“ übergeben – sofern überhaupt noch nötig.
c) Die E-Mails mit zusätzlichem Header für UTF-8 versehen.
d) Fonts auf Unicode-Eignung überprüfen (die im Browser und die für GD-generierte Bilder)
e) Datenbanken anschauen: Wo ist der Umstieg nötig? Wo bringt er nur overhead? Welche Client-Anwendunge verbinden sich mit MySQL-Server und welche Zeichensätze sind dort möglich/voreingestellt? Gibt es bestimmte Sortierungskriterien (grundsätzlich deutsch und dann noch wie telefonbuch: „ä“ = „ae“)?
3 Schritt für Schritt umstellen
a) Sie können mit Datenbanken anfangen. Dabei sollten sie alle in Frage kommenden Tabellen und Spalten auf Kollation „utf8…“ umstellen. Wenn sie die Daten herausholen aber ihre Verbindung keinen Zeichensatz festlegt (und die Datenbank-Collation noch „Latin“ ist) bzw. immer noch „SET NAMES ‚latin1′“ nutzt, passiert erst einmal gar nichts. Alte Daten wurde nach UTF-8 umgestellt und so gespeichert, bzw neu sind als UTF-8 abgelegt. Wenn die Leitung „Latin 1“ ist (sprich: die Verbindung) wird alles von UTF-8 nach Latin 1 konvertiert, damit es „durch eine solche Leitung durchpasst“. Sie nehmen Latin-Daten entgegen, bis die Leitung / Verbindung als UTF-8-fähig deklariert wird („SET NAMES ‚utf8′“ nach „mysql_connect()“). Die Unterschiede in Kollationen lesen sie bitte hier nach.
b) Setzten sie alle Umlaute in den Quelltexten in Entities um. Anschließend schauen sie, ob die Daten in der Datenbank schon als Entities vorliegen (durchaus möglich, wenn auch völlig sinnfrei). Wenn nicht, sollten sie bei Gelegenheit sicherstellen, dass „htmlentities“ mit „utf-8“ als letztem Parameter (am besten „zuschaltbar“ per globale Konstante oder Variable) die Datenbank-Daten in HTML-Entities konvertieren. Damit könnten sie auch gültigen XHTML oder XML ausliefern. (Vergessen Sie nicht die Zeichensatzeinstellungen in den Texteditoren zu ändern: hier lauert die größte Gefahr, wenn sie ihre Skripte erneut „anfassen“.)
c) Für die Ausgabe in Form von Bildchen sollten sie Unicode-fähige TrueType- oder OpenType-Fonts besorgen (und notfalls in TTF konvertieren). Eingebetete Schriftarten sowie einige besondere Schriftarten können wahrscheinlich alle Umlaute darstellen, aber nur wenige bedienen auch die polnischen Sonderzeichen. Der Übermittlungsformat (Zeichensatz der Verbindung) ist egal – es fehlen nur vermutlich Glyphen.
d) In E-Mail-Funktionen müssen 2 Ändrungen vorgenommen werden
- „Content-Type: text/plain; charset=UTF-8“ als zusätzliche Header-Zeile (wenn dies nicht durch eine besondere Klasse/Funktion von alleine geschieht) für Inhalte mit UTF-8 Kodierung (zuschaltbar, wenn auch UTF-8-Daten fließen)
- Für Subject, From, To und Cc ist es wichtig, dass es nur „Amtliche“ Zeichen verwendet, sonst kann es schon mal als Spam angesehen werden… Die Lösung ist, man setzt diese Teile so in den Mail-Header ein (auch per globale Variable gesteuert):
"=?UTF-8?B?'. base64_encode(trim(preg_replace('#[nr]+#s', '', $subject))) ."?="
e) Als letztes – abghängig von der globalen Variable – „SET NAMES ‚utf8′“ nach dem Verbindungsaufbau zur MySQL absetzen. Diese Einstellung gilt für alle Statemenst in dieser Verbindung (bis jemand ein unsinniges „SET NAMES ‚latinX'“ als SQL-Statement startet).
f) Den globalen Switch umlegen und testen: Das HTML sollte UTF-8-Kodiert (als Entities) an den Browser fließen. Der Browser schickt die Eingaben des Benutzers UTF-8-Kodiert (nicht als Entities) an den Server. Der Server übermittelt die Daten über eine UTF-8-Verbindung an den MySQL-Server. Der Server legt diese als UTF-8 ab (oder konvertiert zu passendem Zeichensatz von alleine). MySQL liest UTF-8-Daten und liefert sie als UTF-8 Zeichensatz durch eine UTF-8-Verbindung an PHP. PHP wandelt diese in HTML-Entities (UTF-8 als Zeichensatz annehmend) oder übernimmt sie in UTF-8-konforme Emails oder generiert – und hier ist meines Wissens nach noch ein Problem – Bilder mit Aufschriften, die per „utf8_decode“ aus UTF-8 in einen passenden Latin-Zeichensatz gegossen werden müssen.
Die Umstellung beenden sie mit Umstellung anderer MySQL-Clients (auch der per ODBC eingebundenen). Anschließend spendieren sie dem Author ein Bier – vorausgesetzt, seine Beschreibung war richtig ;-)