UTF-8 für PHP-Programmierer und Webanwendungen

Keine Lust mehr auf äö????üß??¤?¶as?¶d?¤? – Zeichen, die jedem geplagten Webentwickler ein Begriff sind. Hier erwartet euch eine Kurzabhandlung, wie ihr Schritt für Schritt den Kampf gegen das Zeichensatz-Wirrwarr gewinnt – und zwar an allen Fronten, also Dateien und Datenbank.

Einleitung

Das Allheilmittel für fast alle Anwendungsfälle im Internet lautet UTF-8 und beschreibt einen Unicode-Zeichensatz, der alle für uns relevanten Zeichen (unter anderem natürlich auch Ä,Ö,Ü und ß) beinhaltet. Nur der Komplett-Wechsel ist oft und gerade bei größeren, bereits begonnenen oder gar abgeschlossenen Webprojekten nicht ganz einfach, liegen doch oft tausende Dateien, eine bereits befüllte Datenbank etc.pp. vor. Entities wie ö (ö), ß (ß) helfen auch nicht wirklich weiter. Gehen wir’s an: Die Komplettumstellung auf UTF-8.

Was wir brauchen

  1. Notepad++ – Ein Texteditor, der Zeichensätze beherrscht und konvertieren kann
  2. Ansi2Uni – Ein Programm zur Zeichensatz-Massenkonvertierung
  3. Zugriff auf phpMyAdmin

1) Zum Verständnis: Der Byte-Order-Mark

PHP Header

PHP Header


PHP-Entwickler müssen oft Header setzen, um dem Server vor dem interpretieren der Datei Informationen über die Datei zu geben. Da bei UTF8 allerdings ganz am Anfang der Datei ein BOM (Byte Order Mark, bestehend aus ein paar Bits) gesetzt wird, um dem Webserver mitzuteilen, dass es sich um eine UTF8-codierte Datei handelt, heißt es beim setzen des headers per PHP Cannot modify header information – headers already sent – blöd.

Es wird nämlich erwartet, dass der header als erstes gesetzt wird, und da ist ja nun schon der BOM. Abhilfe schafft das Entfernen des BOM’s.Dann müssen wir dem Webserver zwar im Nachhinein mitteilen, dass es sich um UTF-8 handelt, die Datei selbst ist aber richtig codiert. Wie das geht im nächsten Schritt.

2) Der Texteditor

Notepad++

Notepad++


Das Windows-Notepad ist ungeeignet, da es standardmäßig im ANSI-Zeichensatz (ISO) und nicht in Unicode (UTF) speichert. Um in Zukunft das Zeichensatzchaos zu vermeiden, stellen wir das eben gedownloadete Notepad++ gleich auf UTF-8 (ohne (!) BOM) um.

Vorgehen: Einstellungen -> Einstellungen -> Reiter „Neues Dokument“ -> Kodierung: UTF-8 ohne BOM. Dabei könnt Ihr gleich auch noch unter „Format“ Unix auswählen. Unix versieht Zeilenenden nur mit einem \n, Windows verwendet \r\n. Da in der Regel Apache-Systeme als Webserver zum Einsatz kommen, wollen wir gleich in der Unix-Welt bleiben ;-).

Die aktuelle Codierung der Datei seht ihr in der rechten unteren Ecke. Ansi as UTF8 bedeutet hierbei UTF8 ohne BOM. Konvertieren könnt ihr Dateien per „Format“. Wichtig: Nie einfach den Zeichensatz verstellen, immer konvertieren – nur so bleiben die Umlaute erhalten – aber dazu später.

3) Die Konvertierung der Dateien

Konvertierung

Konvertierung


Jetzt habt ihr dummerweise schon haufenweise Dateien vorliegen, die eben nicht einheitlich in UTF8 ohne BOM codiert sind. Eine Variante wäre jetzt, die von Notepad++ angebotene Funktion wie beschrieben per „Format -> Konvertiere zu UTF8 ohne BOM“ anzuwenden, allerdings wäre das bei vielen Dateien eine echte Sisyphos-Arbeit.

Sollten bei euch einheitlich alle Dateien in ANSI codiert sein, könnt ihr aufatmen: Mit oben angesprochene und unten beschriebenen Minitool Ansi2Uni sind Massenkonvertierungen von Zeichensätzen möglich.

Vorgehensweise Massenkonvertierung in UTF8

ansi2uni

ansi2uni

Wichtig: Vor der Verwendung des Programms erst diesen kompletten Abschnitt lesen!

  1. From codepage: Hier muss eingestellt werden, was der aktuelle Zeichensatz der vorliegenden Dateien ist. Dummerweise müssen alle zu konvertierenden Dateien einheitlich den hier anzugebenden Zeichensatz haben, sonst gehen entweder die enthaltenen Sonderzeichen kaputt oder die Datei wird ignoriert. Sicherheitshalber hier also ein Backup erstellen oder – so weh es tut – wirklich alle Dateien per Hand mit Notepad++ sicher konvertieren. Wenn allerdings flächendeckend ANSI (iso-8859-1) verwendet wird, dann könnt Ihr das Programm beruhigt einsetzen, denn iso-8859-1 entspricht hier der Codepage 1252.
  2. Select file(s) / Dir(s): Selbsterklärend. Hier wählt ihr das Verzeichnis aus, welches die ganzen zu konvertierenden Dateien beinhaltet
  3. File mask: Leider können hier nicht mehrere zu konvertierende Formate aneinandergehängt werden (etwa *.php,*.css). So muss jedes Dateiformat einzeln durchlaufen werden. Wichtig: Auf keinen Fall den * (alle Dateien) stehen lassen, da so auch Bilder und andere Dateien zu UTF8 konvertiert werden und dabei kaputt gehen.
  4. To: Wie oben beschrieben nehmen wir UTF-8 (no BOM)
  5. Overwrite old files: Wenn ihr diese Option anhakt, werden die existierenden Dateien überschrieben (vorher Backup machen!), sonst müsst ihr ein neues Verzeichnis für die konvertierten Dateien auswählen
  6. Recursive: Auswählen, denn nur so werden auch alle Unterordner erfasst.

4) Die Feinarbeit

Firefox-charset

Firefox-charset


Charset-Anzeige

Charset-Anzeige


Jetzt liegen also die Datei schonmal in der korrekten Speicherung vor! Exemplarisch überprüfen könnt ihr das, indem ihr stichprobenartig mit Notepad++ konvertierte Dateien auswählt und in die rechte untere Ecke schaut. Das sollte dem Screenshot rechts entsprechen.

Da der Browser aber bei der automatichen Erkennung der Dateicodierung ohne den Byte Order Mark Probleme bekommen kann, sollten wir ihm auch in der Datei selbst noch mitteilen, dass es sich um UTF-8 handelt. Das geht bei HTML, PHP…-Dateien per Metatag

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

(im head-Bereich der Seite unterzubringen) und bei PHP-Dateien zusätzlich noch mit dem Header

<?php header( 'content-type: text/html; charset=utf-8' ); ?> 

ganz am Anfang des Dokuments (gibt ja dank unseres Verzichts auf den BOM auch keine Probleme mehr). Bei CSS-Dateien wird in die erste Zeile ein

@charset "utf-8"; 

gesetzt – fertig. Javascript benötigt keine explizite Deklaration.

Welchen Charset der Browser aktuell verwendet, lässt sich im Firefox per Rechtsklick -> Seiteninformationen anzeigen (siehe Screenshot links) und im IE7 per Ansicht -> Codierungerfahren. Um ganz sicher zu gehen, setzen wir aber noch einen drauf.

5) Der Webserver

Auch dem Webserver können wir nochmal explizit mitteilen, dass er alle relevanten Dateien in UTF-8 ausliefern soll. Dazu erstellen wir eine Datei mit dem Namen .htaccess (Charset ist hier zwar egal, konsequenterweise sollte es aber auch UTF8 sein) und dem Inhalt

AddCharset utf-8 .css .htm .html .js php_value default_charset utf-8 

und laden diese in das Hauptverzeichnis des Servers hoch, also direkt in die „Wurzel“. Da Dateinamen unter Windows nicht mit einem Punkt beginnen dürfen, könnt Ihr die Datei dann auch erst auf dem Server umbenennen. Jetzt werden alle Dateien mit den Endungen in der ersten Reihe (beliebig zu ergänzen, etwa .xml…) in UTF8 interpretiert. Für PHP muss die zweite Zeile zusätzlich ran, da die Definition der ersten Reihe für .php-Dateien keine Gültigkeit hat. Dieser Schritt ist zwar „doppelt gemoppelt“, aber das hält ja bekanntlich besser ;).

6) Die Datenbank

Die Datenbank und Ihre ganzen Parameter wären nochmal ein Kapitel für sich. Um auch hier radikal aufzuräumen und nur noch UTF-8 zu verwenden, Backuppen wir die Datenbank,löschen anschließend alle Tabellen, konvertieren das Backup in UTF-8 und erstellen die Datenbank wieder neu – wesentlich einfacher, als mit Spezialtools und Scripten eine Konvertierung des laufenden Datenbestandes erreichen zu wollen.

Schritt 1: Datenbank backuppen

PhpMyAdmin Export

PhpMyAdmin Export


Die zu exportierende Datenbank in phpMyAdmin auswählen und oben den Reiter „Exportieren“ anwählen. Wichtig hierbei ist, dass alle Tabellen der Datenbank ausgewählt sind. Sonst können in der Regel alle Voreinstellungen belassen werden. Zur Sicherheit rechts ein Screenshot, wie es aussehen sollte.

Nun erstellen wir eine backup.sql-Datei, öffnen diese mit Notepad++ und kopieren der Inhalt der Textarea aus phpMyAdmin (das Datenbankbackup incl. aller in der Datenbank enthaltetenen Daten) in diese Datei hinein. Das kann bei großen Datenbanken etwas dauern.

Schritt 2: Backup anpassen

Hier ein Beispiel-Ausschnitt aus dem SQL-Code des erstellten Backups:

CREATE TABLE IF NOT EXISTS `g2_AccessMap` ( `g_accessListId` int(11) NOT NULL default '0', `g_userOrGroupId` int(11) NOT NULL default '0' ) ENGINE=MyISAM DEFAULT CHARSET=LATIN1; 

Das CHARSET=LATIN1 stört uns, gibt es doch den ANSI-Zeichensatz iso-8859-1 vor. Richtig wäre hier UTF8. Also (was auch immer bei euch unter Charset eingetragen sein sollte): Suchen und Ersetzen (Strg+H) und alle Vorkommen des „anderen“ Zeichensatzes in UTF8 abändern, sodass am Ende alle „CREATE TABLE“-Anweisungen nach folgendem Schema aussehen:

CREATE TABLE IF NOT EXISTS Tabellenname ( [...] ) ENGINE=MyISAM DEFAULT CHARSET=UTF8; 

Schritt 3: Backup konvertieren

Nun konvertieren wir die backup.sql zu UTF-8 (also nicht ‚ohne BOM‘, sondern normal UTF-8). Das sollte nun zusammen mit dem vorangegangenen Schritt etwa so aussehen:

Notepad Dump

Notepad Dump

Schritt 4: phpMyAdmin konfigurieren

Zurück in phpMyAdmin leeren wir erstmal die Datenbank. In der Tabellenübersicht unten klicken wir „Alle auswählen“ und „markierte löschen“ – keine Angst, wir haben ja das Backup.

PhpMyAdmin Tabellen löschen

PhpMyAdmin Tabellen löschen


In der jetzt jungfräulichen Datenbank verstellen wir im Reiter „Operationen“ die Kollation (Sortierreihenfolge) der Datenbank auf utf8_unicode_ci.

Kollation

Kollation

Jetzt gehen wir wieder ins „Hauptmenü“ von phpMyAdmin (auf das Logo links oben klicken) und wählen bei „Zeichensatz / Kollation der mySQL-Verbindung“ ebenfalls utf8_unicode_ci – Damit sind die Grundeinstellungen angepasst. Viel mehr können wir nicht tun.

PhpMyAdmin Einstellungen

PhpMyAdmin Einstellungen

Schritt 5: Backup zurückspielen

PhpMyAdmin importieren

PhpMyAdmin importieren


Nun wählen wir wieder unsere jetzt leere Datenbank aus, klicken oben auf den Reiter „Importieren“ und wählen unser eben erstelltes Datenbankbackup backup.sql. Natürlich wird bei „Zeichencodierung der Datei“ utf8 ausgewählt. Bei großen Datenbankbackups könnte es nun etwas dauern – falls es gar zu einem Abbruch kommen sollte, müssen Spezialtools wie der mysqlDumper zum Einsatz kommen. Das führt jetzt hier aber zu weit. Nun können wir auf „OK“ klicken und hoffen, dass alles gut geht

Der Fall der Fälle

Falls die Umlaute immernoch „schräg“ ankommen sollten, kann es sein, dass phpMyAdmin quer schießt. Falls das der Fall sein sollte, ist der letzte „Rettungsstrick“ direkt nach der Verbindung zur Datenbank

mysql_query("SET NAMES 'UTF8'"); 

auszuführen, sodass es bei euch ungefährt so aussieht:

//connect $connectionid = @mysql_connect ($host,$user,$pw); mysql_select_db ($db, $connectionid); mysql_query("SET NAMES 'UTF8'"); 

Update

Auf PHP-Seite müssen für die ultimative „UTF8-Experience“ die Multibyte-Stringfunktionen (mbstring) statt der Standard-Stringfunktionen verwendet werden. Hierzu ist es zum Glück nicht nötig, alle Vorkommen von substr, strlen etc. mit ihren Multibyte-Pendants händisch zu ersetzen: Durch die php.ini – Einstellung mbstring.func_overload = 7 lassen sich alle Standard-Stringfunktionen überladen. Wichtig: Mit ini_set ist es hierbei nicht getan, fürs Überladen ist zwingend eine Änderung der php.ini nötig. In diesem Zuge möchte ich auch noch auf meinen Post PHP WTF #7 hinweisen, mit dessen Hilfe sich schön testen lässt, ob das Überladen durch die Multibyte-Funktionen erfolgreich war:

<meta charset="utf8"> <?php mb_internal_encoding("utf-8"); $a = 'äa'; echo "substr 0,1: " . substr($a, 0, 1); 

Der Output vor dem Setzen von mbstring.func_overload = 7: ? – und danach wie erwartet ä. Hierbei weisen wir die überladenen mbstring-Funktionen mittels mb_internal_encoding auch gleich noch darauf hin, dass wir gern UTF-8 verwenden möchten. In diesem Zusammenhang muss auch noch die iconv-Funktion erwähnt werden, die PHP ebenfalls zum Multibyte-Handling erzieht. Danke an franc für den Hinweis per E-Mail!


Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0