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'");

Ende

Bei Kritik und Anmerkungen zu diesem kurzen Abriss bitte ich um eine e-Mail. Nochmal sei auf besondere Vorsicht im Umgang mit dem beschriebenen Programm Ansi2uni hingewiesen, da nicht in der angegebenen „Codepage“ codierte Dateien und sensible Formate wie Bilder oder Zip-Dateien der UTF8-Konvertierung zum Opfer fallen.

Update

Wie Gabriel per Kommentar dankenswerterweise noch ergänzt hat: 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!

Weitere Posts:

Dieser Beitrag wurde unter php, Datenbanken, webdev veröffentlicht. Setze ein Lesezeichen auf den Permalink.

24 Antworten auf UTF-8 für PHP-Programmierer und Webanwendungen

  1. Gabriel sagt:

    Danke für den informativen Artikel!

    Du hast einen extrem wichtigen Schritt vergessen: Das Anpassen des Codes. Die PHP-internen String-Funktionen arbeiten nämlich Byte-weise (1 Zeichen = 1 Byte), UTF-8 codiert Zeichen mit 1-4 Byte. Bei Strings mit Umlauten liefert strlen dann Werte zurück, die zu lang sind, substr schneidet an der falschen Stelle, etc. Die Lösung dafür ist das Verwenden der mbstring-Extension (bei vielen Hostern nicht verfügbar) oder die iconv-Extension. iconv bringt multibyte-sichere Versionen von strlen, strpos und substr mit, für alle anderen String-Funktionen muss der String mit der iconv – Funktion kopiert werden.

    • franc sagt:

      Das ist ja sehr interessant!
      Also ist es doch nicht „so einfach“ und mit dem einfachen Umwandeln nicht getan. Viele Seiten würden so wohl nicht mehr richtig funktionieren.
      Was sagt der Autor dazu, bzw. warum sagt er bis jetzt nichts dazu?

  2. bvet sagt:

    Vielen Dank, hat mir sehr geholfen!

    Ich hatte ganz mysteriöse Probleme. Von Zeichensalat, bis hin zu php-Seiten die plötzlich wenn der Zeichensalat weg war nur noch halb funktionierten.

    Mit dem php-Header der mir wohl fehlte funktioniert alles.

    Suche mich schon seit zwei Tagen im Internet zu Tode, nichts half. Ich habe an 250 Stellen UTF-8 angegeben, udn mit BIM und ohne BOM und BUM bespeichert – jedesmal passierten die irrsten Sachen, aber nie war es richtig.

    Hier war die Lösung!

    Nochmals vielen Dank für die erklärung, die für mcih auch viel Verständlicher war als vieles andere das ich schon gesehen habe zum Thema.

  3. Bachsau sagt:

    Um die Datenbank zu konvertieren brauchst du keine Spezialtools. Du änderst einfach den Zeichensatz der Tabellen, Datenbanken und Felder. Den Rest macht MySQL automatisch.

    Wenn es beim Auslesen und Anzeigen Probleme gibt, dann hat das nicht mit dieser Einstellung zu tun, sondern es wurde ein falscher Verbindungs-Zeichensatz gewählt.

  4. Daniel sagt:

    Sehr guter Beitrag, alles auf einer Seite übersichtlich und gut ausgeführt, als gestandener Programmierer freue ich mich über solche Dokumentationen
    und natürlich Menschen die dieses Wissen vermitteln und teilen.
    Weiter so :-)

  5. Björn sagt:

    Vielen Dank, nach diversen Nachtschichten endlich eine Lösung gefunden für mein kleines Problem mit diakritischen Zeichen. Kann ich an jeder Stelle für derartige Probleme als derzeit verständlichste Erklärung empfehlen.

  6. adalo sagt:

    Super simples Tool das Ansis2Uni. Hat mir gerade viel Zeit erspart. War auch überrascht, wie schnell das Tool bei den tausenden Files gearbeitet hat, die in Konvertiert habe.

  7. Sehr schöner ausführlicher Beitrag zu einer immer wiederkehrenden Problematik. Vielen Dank dafür!

  8. Herbert sagt:

    Dank dieser Seite kann ich jetzt PHP-Seiten in UTF-8 erstellen.

  9. chris e. sagt:

    klasse doku!!!! sehr ausfuehrlich erklaert. Danke!
    Anmerkung: mann mir jemand einen tip geben: sobald ich die .htaccess auf den server lade, erscheint bei seitenaufruf (auch Unterseiten) nur noch die Fehlermeldung: Internal Server Error – misconfiguration. Hat jemand eine Idee dazu?
    Merci im voraus.

    • franc sagt:

      Diese Fehlermeldung kommt, wenn dein Server eine der .htaccess Regeln nicht akzeptiert, in diesem Fall wahrscheinlich die php_value
      Das liegt dann möglicherweise daran, dass dein Webserver PHP als CGI und nicht als Apache-Modul eingebunden hat.
      Dann kannst du nichts tun, wenn du keinen Zugriff auf die php.ini hast.

  10. Tyssen sagt:

    Hallo,
    was habe ich denn falsch gemacht wenn Notepad++ UTF-8 anzeigt, aber die Umlaute nicht umkonvertiert. Und wo kann ich sehen das die Umlaute umkonvertiert wurden. Für den Browser habe ich alles eingestellt. Nur den Datenbankinhalt bekomme ich nicht wie oben erwähnt hin. Großes Danke im vorraus!

    • david sagt:

      Ein Problem könnte sein, dass du die Umlaute nicht konvertiert hast, sondern einfach die Enkodierung der Datei geändert hast.

      Testen kann man das ganz gut mit dem „perfekten Setup“ (Meta-Tag + PHP UTF8-Header) und dann den Text auf der Seite ausgeben.

      • Tyssen sagt:

        Ups war das schnell. Danke!
        1.) Sorry komme ich nicht mit weiter. Wo soll ich da ansetzen?
        Warum werden alle anderen Dateinen richtig umkonventiert nur die Datenbankdatei nicht.
        2.) Also nur über eine fertige Webseite?

        • david sagt:

          1) Meine Vermutung war, dass du das Encoding nur wechselst (rot) und nicht konvertierst (grün).

          2) Genau den Header < ?php header( 'content-type: text/html; charset=utf-8' ); ?> drübersetzen und rein und dann mal schaun.

          • Tyssen sagt:

            Das ist ja alles oben sehr gut beschrieben – Danke nochmal-. Ich schreibe ja nur, weils bei mir nicht richtig funkt. Kann es sein das die Konvertierung nicht funktioniert weil der Dateien für Notepad oder PHPedit zu groß sind (52 MB)?

          • Tyssen sagt:

            …auch wenn ich die Datei verkleinere wird nicht umkonvertiert.

  11. Ben sagt:

    Suuuper Artikel!
    Vielen Dank :)

  12. Martin sagt:

    Hallo David,
    vielen Dank, das ist wirklich hilfreich und trotz des Artikels aus 2009 noch immer alles aktuell?
    Bei Notepad++ ist bei mir UTF8 ohne BOM bereits defaultmäßig voreingestellt, hat sich das zwischenzeitlich also wohl geändert?

    Wenn man dann also einfach ein neues Dokument im Notepad erstellt, passt es ganz automatisch und man muss nichts mehr umstellen?

    Grüße,

    Martin

  13. Martin sagt:

    Jetzt fällt mir gerade noch was ein. Kann ich an der bestehenden Kodierung eines txt.-Dokumentes irgendwas „vermurksen“, indem ich Textteile – die vielleicht in andere Kodierung erstellt wurden – dort hineinkopiere (STRGC/V)? Oder wird das Hineinkopierte automatisch und zwangsläufig dann problemlos ebenfalls UTF8 ohne BOM?

    Grüße,

    Martin

  14. Dirk sagt:

    Hallo David,
    vielen Dank für diesen aufschlussreichen Artikel. Schade, dass ich ihn nicht früher gefunden habe. Das hätte mit viele Stunden Arbeit und Grübeln erspart. Zwar war’s bei mir genau anders herum, aber egal. BOM war der Schlüssel.
    Bei mir waren alle PHP-Dateien in ANSI, nur eine mit wichtigen Stringvariablen war in UTF-8. Ich bin einfach nicht dahinter gekommen, warum die Texte aus dieser Datei immer mit Hieroglyphen ausgegeben wurden. Notepad++ hat’s gelöst und ich weiß in Zukunft, worauf ich achten muss.
    Ich hoffe, diese Abhandlung bleibt noch lange im Netz – eine echte Bereicherung.
    Gruß Dirk

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.