UTF-8 und die Umstellung von Websites auf dieses Encoding

UTF-8 für alle

Bettina Ramm Redaktion

Aller Anfang ist schwer – zumindest diese Lebensweisheit gilt bei UTF-8 nicht. Denn eine Website in UTF-8 zu kodieren, ist am einfachsten, wenn es von Anfang an konsequent durchgeführt wird. Das Beheben von Zeichensatzfehlern, die dagegen durch inkonsistentes Encoding entstehen, ist oft einiges schwieriger und je nach vorhandenem Daten- und Dokumentenbestand vor allem zeitraubend. In diesem Artikel erfahren Sie, was hinter UTF-8 steckt, warum UTF-8 so beliebt ist und wie Sie Ihre Website Schritt für Schritt auf UTF-8 einstellen bzw. umstellen.

Bevor wir uns ansehen, was UTF-8 ist und kann, sollen zunächst ein paar Begriffe definiert werden. Wenn Sie sich grundsätzlich mit Zeichenkodierungen auskennen, und wissen, was Unicode ist, können Sie direkt bei „Dokumente in UTF-8 speichern“ weiterlesen. Ein Zeichen ist die kleinste Komponente geschriebener Sprachen, das können Buchstaben, Ideogramme (z. B. Chinesische Schriftzeichen), Satzzeichen und Ähnliches sein. Ein Zeichensatz ist eine Gruppe von Zeichen, die aufgrund gemeinsamer Merkmale zusammengefasst werden können (z. B. ein Alphabet oder ein Font). Auch ein Zeichenkodierungsschema ist ein Zeichensatz. Es definiert einen Code, mit dem Zeichen maschinenlesbar werden (siehe unten). Ist in diesem Artikel von einem Zeichensatz die Rede, ist immer ein Zeichenkodierungsschema gemeint. Man nennt es auch „Character Set“ oder „Encoding“ oder „CES“, für Character Encoding Scheme.

Encoding, Unicode und UTF-8

Damit Schriftzeichen am PC dargestellt werden können, müssen sie so kodiert werden, dass der Computer sie versteht. Und der versteht bekanntlich nur Bits und Bytes, also Nullen und Einsen. Daher wurden Zeichenkodierungsschemata entwickelt, bei denen jedes Bitmuster für ein bestimmtes Zeichen steht. Ursprünglich wurde dazu (in unserem Sprachraum) der ASCII-Code konzipiert, doch er umfasst nur 128 Zeichen, davon lediglich 96 sichtbare. Das reicht aus, um die großen und kleinen Buchstaben des lateinischen Alphabets, die Ziffern 0 bis 9 und ein paar Sonderzeichen darzustellen. Sprachspezifische Buchstaben, wie deutsche Umlaute, bleiben außen vor. Später wurden sprachspezifische CES entwickelt, für die deutsche Sprache ist das ISO-8859-1 bzw. ISO-8859-15, das auch das Euro-Zeichen enthält. Doch auch der Zeichenvorrat dieser Schemata ist begrenzt. Zwar nicht nur auf eine Sprache, aber doch auf einige wenige, die räumlich nahe beieinander liegen. Probleme entstehen spätestens dann, wenn ein Dokument Zeichen völlig verschiedener Sprachen (etwa Deutsch und Japanisch) enthält. Mit zunehmender Globalisierung und Internationalisierung wurde daher Unicode entwickelt. Unicode bezeichnet Zeichensätze, die möglichst alle Zeichen sämtlicher Sprachen umfassen. Der populärste Unicode ist dabei UTF-8 (8 bit Unicode Transformation Format), der mit einer variablen Codelänge von ein bis vier Byte pro Zeichen über 1.000.000 Zeichen darstellen kann.
Warum ist UTF-8 so bedeutend? Es gibt verschiedene Unicode-Zeichensätze: UTF-8, UTF-16 und UTF-32 sind die bekanntesten. UTF-8 hat einen ganz entscheidenden Vorteil: Es ist rückwärtskompatibel zu ASCII. Gleiche Zeichen werden in ASCII und UTF-8 durch dasselbe Bitmuster repräsentiert. Damit wird nicht nur die Umstellung von ASCII-Dokumenten zu UTF-8 einfacher, da dabei keine Zeichen verloren gehen, sondern UTF-8 lässt sich auch für Applikationen, Dateisysteme und Netzwerkprotokolle verwenden, die eigentlich nur ASCII verstehen. UTF-16 dagegen verwendet teilweise Bitmuster, die in ASCII (andere) Kontrollzeichen darstellen. Deshalb können UTF-8-Dokumente im Gegensatz zu UTF-16 und UTF-32 auch rudimentär (mit Platzhaltern) in Applikationen dargestellt werden, die eigentlich nur ASCII verstehen. Außerdem ist UTF-8 im Vergleich zu seinen „großen Brüdern“ wesentlich bescheidener im Hinblick auf erforderliche Ressourcen. Während UTF-16 ein Zeichen als 16-Bit-Wert speichert, kann UTF-8 einfache Zeichen, die dem Zeichenvorrat von ASCII angehören, als 8-Bit-Wert speichern. Da sich mit ASCII ein Großteil der Zeichen im westeuropäischen und amerikanischen Sprachraum darstellen lassen, können die meisten dieser Sprachen mit einem durchschnittlichen Speicheraufwand von 1.1 Byte pro Zeichen dargestellt werden. Das ist fast genauso effizient wie ASCII, aber durch die Möglichkeit, bei Bedarf insgesamt 4 Byte zu belegen, können darüber hinaus auch sehr exotische und seltene Zeichen dargestellt werden. Außerdem lässt sich UTF-8 im Gegensatz zu anderen Multibytekodierungen sehr einfach manipulieren. Zum Beispiel lässt sich der Anfang eines Zeichens sehr einfach ermitteln. So genannte Trail-Bytes – Bytes, die über das erste Byte hinaus zur Darstellung eines Zeichens benötigt werden, werden immer durch das Bitmuster 10xxxxxx repräsentiert. Der Anfang des zugehörigen Zeichens ist dann maximal 3 Bytes weiter links zu finden. Sie können dieses Thema mit den Artikeln What is UTF-8 And Why Is It Important? und Which character encoding should I use for communicating with other software? vertiefen.
Wir wollen nun Schritt für Schritt die Punkte durchgehen, die Sie beachten müssen, um ein konsistentes UTF-8-Encoding Ihrer Webprojekte zu erreichen. Dabei ist es unwesentlich, ob Sie ein bestehendes Webprojekt umstellen oder ein neues erstellen möchten.

Dokumente in UTF-8 speichern

Für eine durchgängige Verwendung von UTF-8 ist es Voraussetzung, dass alle Dokumente Ihrer Website, die Text enthalten (*.html*.php*.css), UTF-8-kodiert gespeichert werden. Nur so werden alle Sonderzeichen im korrekten Code gespeichert, und kryptische Zeichen werden von Anfang an vermieden. Vorsicht, nicht alle Editoren „sprechen“ UTF-8. Öffnen und bearbeiten Sie Ihre Dokumente nur noch mit Editoren, die es tun. In manchen Editoren lässt sich die Zeichenkodierung beim Speichern auswählen, bei anderen gibt es eine entsprechende Option in den Programmeinstellungen. Bestehenden Dokumente müssen mit einem UTF-8-fähigen Editor geöffnet und in UTF-8 gespeichert werden. Kontrollieren Sie anschließend noch einmal alle Umlaute und Sonderzeichen der Dokumente und korrigieren sie Sie bei Bedarf. Manchmal wird den Dokumenten beim Speichern in UTF-8 ein Byte Order Mark (BOM) vorangestellt. Wenn das in Ihrem Editor optional ist, lassen Sie es weg, denn es ist bei UTF-8 nicht zwingend nötig (siehe Kasten: „UTF-8 und BOM“).
Textlaufrichtung festlegen Auf einer UTF-8-formatierten Website sind internationale Zeichen möglich und werden fehlerfrei angezeigt, solange im Client die erforderlichen Schriftarten installiert sind. Somit ist es bei benutzergeneriertem Content auch möglich, dass Texte fremder Sprachen eingegeben werden, bei denen der Text nicht von links nach rechts, sondern von rechts nach links läuft (z. B. Hebräisch). So kann es passieren, dass der Browser, sobald er ein hebräisches Zeichen im Content entdeckt, geneigt ist, die Textlaufrichtung zu ändern. In (X)HTML lässt sich das durch Setzen des dir-Attributs im HTML-Tag unterbinden. Mit dir=”ltr” legen Sie fest, dass der Text immer von links nach rechts läuft. In CSS-Dateien fügen Sie eine einzige Zeile ganz am Anfang ein: @charset “utf-8″;.

UTF-8 in (X)HTML und CSS-Dokumenten

Sie sollten den (X)HTML-Dokumenten die Information zur verwendeten Zeichenkodierung in den Metatags im HTML-Header mitgeben. Das entsprechende Metatag lautet für HTML  und für XHTML <meta http-equiv=”content-type” content=”application/xhtml+xml;charset=utf-8″ //ht;. Zusätzlich kann in XHTML-Dokumenten die Kodierung auch in der XML-Deklaration erwähnt werden. Das ist zwar nicht unbedingt nötig, da XHTML immer UTF-8 kodiert ist, aber es schadet auch nicht: . Im HTML-Tag können Sie dem Client (Browser) Informationen über die auf der Website verwendete Sprache übergeben. Dazu wird der ISO-Code der Spracheangegeben. Für XHTML sieht die Zeile dann so aus: <html xmlns=”http://www.w3.org/1999/xhtml” xml:lang=”de” lang=”de” dir=”ltr”>. Das dir-Attribut am Ende dieses HTML-Tags legt übrigens die Textlaufrichtung fest (ltr = left-to-right, von links nach rechts). Das ist auf UTF-8 kodierten Websites mit benutzergeneriertem Content empfehlenswert (siehe Kasten: „Textlaufrichtung festlegen“).

Webserver und HTTP-Header

Über eine entsprechende Direktive können wir Apache explizit anweisen, unsere Daten und Dokumente nur noch in UTF-8 auszuliefern. Dazu sind folgende Zeilen in der .htaccesseinzufügen: AddCharset utf-8 .css .html .xhtml .php. Ergänzen Sie die Zeile einfach um die Extensions aller weiteren Dateitypen, die Sie von Ihrem Webserver ausliefern und die Text enthalten. Der führende Punkt vor den Extensions ist optional, die Extension-Angabe ist Case-sensitive. Das funktioniert allerdings nur, wenn Ihr Webhoster das Überschreiben des Charsets erlaubt hat. Alternativ können Sie per PHP einen HTTP-Header an den Browser liefern, der diesem bereits vor dem Empfang der eigentlichen HTML-Seite mitteilt, dass die gelieferten Daten in UTF-8 sind: header(‘content-type: text/html; charset=utf-8′);. Falls Sie Zugriff auf die php.ini haben, können Sie die Einstellung auch dort vornehmen:
default_mimetype = "text/html"
default_charset = "utf-8"

MySQL-Datenbanken

Bei Datenbanken macht die Regel der konsistenten Zeichensatzkodierung eine Ausnahme. Zwar lässt sich eine MySQL-Datenbank (ab Version 4.1.1) auf UTF-8 umstellen, das ist aber in den meisten Fällen nicht notwendig und dann auch nicht empfehlenswert. Während sprachspezifische ISO-Kodierungen pro Zeichen eine Länge von einem Byte umfassen, „frisst“ UTF-8 in MySQL bis zu drei Byte pro Zeichen. Das hat natürlich Auswirkungen auf Speicherplatzbedarf und Performance. MySQL unterscheidet Character Set (Charset) und Kollation. Das Charset ist das Encoding, während die Kollation die Sortierung der Daten regelt. Beide stehen in enger Beziehung, d. h. nicht jedes Charset macht mit jeder Kollation Sinn (die möglichen Kombinationen können Sie INFORMATION_SCHEMA..COLLATION_CHARACTER_SET_APPLICABILITY entnehmen). Für UTF-8 kennt MySQL das Charset ‘utf8′ und die Kollation ‘utf8_general_ci’. Sie finden alle Encodings, die MySQL kennt, in INFORMATION_SCHEMA.CHARACTER_SETS. Die Spalte Maxlen gibt übrigens an, wie viele Bytes ein Zeichen dieses Zeichensatzes maximal verbraucht. Die Kollation, und damit das zu verwendende Charset, wird von oben nach unten vererbt. Jede Spalte, die Text-, Char- oder Varchar-Werte enthält, hat automatisch eine Kollation und ein Charset, die sie von ihrer Tabelle erbt, wenn es nicht explizit anders angegeben ist. Diese wiederum erbt standardmäßig die Kollation die Datenbank, und diese wiederum die Default-Kollation. UTF-8 macht in MySQL nur Sinn, wenn eine Spalte Zeichen verschiedener (!) Sprachen enthält. Dann sollten diese – und nur diese – Spalten die Kollation utf8_general_ci zugewiesen bekommen. In allen anderen Fällen ist es günstiger, die passende ISO-Kodierung zu verwenden, da sie wesentlich sparsamer mit den verfügbaren Ressourcen umgeht. Um mit einer ISO-kodierten MySQL-Datenbank und einem UTF-8-Client fehlerfrei zu arbeiten, genügt die Angabe eines einzigen SQL-Statements direkt nach Herstellung der Datenbankverbindung (vor dem ersten Datentransfer): SET names ‘utf8′. Damit weiß MySQL, dass der Client UTF-8 spricht und wandelt die Daten selbständig um. Wenn Sie dieses Thema vertiefen möchten, sei Ihnen ein Beitrag von Kristian Köhntopp empfohlen.
UTF-8 und BOM Das BOM (Byte Order Mark) ist eine Unicode-Signatur, die UTF-8-kodierten Dateien vorangestellt sein kann. Im Gegensatz zu UTF-16 und UTF-32, wo das BOM für eine korrekte Darstellung der Inhalte notwendig ist, ist es bei UTF-8 jedoch optional, sodass nur einige Editoren es speichern. In manchen lässt sich sogar auswählen, ob eine Unicode-Signatur mitgespeichert werden soll. Nicht alle Anwendungsprogramme interpretieren das BOM in UTF-8 korrekt, in solchen Programmen (auch Browsern) wird am Anfang der Datei eine Leerzeile oder auch die Zeichenfolge  dargestellt. Das liegt daran, dass der verwendete Code U+FEFF ursprünglich für ein Leerzeichen stand. Eine ausführliche Information und Handlungsempfehlungen.

Daten-Upload und Verarbeitung mit PHP

Für eine konsistente Kodierung ist es besonders wichtig, benutzergenerierte Inhalte in UTF-8 umzuwandeln bzw. UTF-8 zu erzwingen. Daten, die aus Formularen an den Webserver gesendet werden, sind in der Regel genauso kodiert wie die Seite, in der das Formular eingebettet ist. Es schadet aber nicht, dem Formular mit dem Attribut accept-charset=”UTF-8″ die Kodierung zusätzlich mitzuteilen. Trotzdem sollten alle eingehenden Daten zusätzlich auf ihre Kodierung überprüft werden. Irgendwas kann schließlich immer schiefgehen. Das gilt insbesondere für Upload-Daten (z. B. CSV-Dateien), die von der Webanwendung weiterverarbeitet werden sollen. Das W3C hat eine Regular Expression veröffentlicht, mit der sich ermitteln lässt, ob ein Text UTF-8-kodiert ist (Listing 1). Alternativ kann die Funktion mb_detect_encoding verwendet werden, die das Encoding des übergebenen Strings ermittelt. Insbesondere Upload-Daten werden oftmals ISO-8859-1 kodiert sein. Mittels utf8_encode() können Sie diese Daten in UTF-8 umwandeln. Der Vollständigkeit halber sei an dieser Stelle auch das Encoding Windows-1252 genannt, auch als ANSI bekannt, das ISO-8859-1 stark ähnelt, aber nicht identisch ist. ANSI-kodierte Dokumente können Sie nicht einfach mit utf8_encode() umwandeln (ebenso wie alle anderen ISO-Zeichensätze), da die Funktion ISO-8859-1 erwartet. Eine ausführliche Behandlung dieser Frage würde den vorliegenden Artikel sprengen, eine mögliche Lösung finden Sie im Kommentar von Aidan Kehoe in der PHP-Dokumentation. Empfohlen sei an dieser Stelle auch die iconv-Extension von PHP.
HTML-Entities Mit dem Siegeszug von UTF-8 durch das Web werden so genannte HTML-Entitäten (HTML-Entities) unwichtiger. HTML-Entitäten sind Codes, die aus dem Zeichenvorrat von ASCII gebildet werden und für mit ASCII nicht darstellbare Zeichen stehen. Sie beginnen mit & und enden mit einem Semikolon (;). Dazwischen steht ein bis zu sechs Zeichen umfassender Code. ästeht z. B. für „ä“, ß für „ß“. Auch wenn die meisten HTML-Entitäten mit UTF-8 überflüssig sind, sind sie doch nicht verboten und funktionieren weiterhin. Die Zeichen &< und > sollten jedoch immer in HTML-Entities kodiert werden, da sie auch von HTML verwendet werden: ,&&lt; und >.
PHP bietet viele leistungsstarke Funktionen zur String-Manipulation, die jedoch ursprünglich für die Verarbeitung von ISO-kodiertem Text entwickelt wurden. Sie erwarten intern pro Zeichen ein Byte. Das wird sich auch voraussichtlich bis zum Release von PHP 6 nicht ändern. Daher kann es bei der Verarbeitung von UTF-8-kodierten Texten mit diesen Funktionen zu Fehlern kommen. So zählt strlen() beispielsweise die verwendeten Bytes eines Texts. Da UTF-8 aber für ein Zeichen auch mehr als ein Byte verwenden kann, entspricht der Rückgabewert der Funktion nicht in jedem Fall der tatsächlichen Zeichenlänge. In manchen Fällen stellt dieser Effekt ein Sicherheitsrisiko dar. So ermöglicht eine falsche Anwendung von htmlentities() sogar die Einschleusung von Junk-Code, wenn nicht UTF-8 als Charset angegeben wird (dritter Parameter), denn sonst erwartet die Funktion ISO-8859-1 kodierten Text. Dasselbe gilt für html_entity_decode(). Abgesehen davon genügt htmlspecialchars() zum Umwandeln der Zeichen, die HTML verwendet (Kasten: „HTML-Entities“). Einen Überblick über die String-Funktionen von PHP und jeweilige Effekte sowie Sicherheitsrisiken bei der Nutzung mit UTF-8 finden Sie im Artikel Handling UTF-8 with PHP.

Fazit

Zeichensatzprobleme bei Websites entstehen in erster Linie durch Durchmischung verschiedener Encodings, aber auch, wenn der Client (Browser) das verwendete Encoding nicht kennt. Nicht umsonst hat UTF-8 sich als Encoding bereits auf vielen Websites durchgesetzt und ist weiter auf dem Vormarsch. Sein großer Zeichenvorrat und seine Rückwärtskompatibilität zu ASCII haben zu einer weiten Verbreitung beigetragen, die wiederum sicherstellt, dass eine UTF-8-kodierte Website von vielen Browsern „verstanden“ wird. Wenn Sie die Nase voll haben – von merkwürdigen Zeichen und unlesbaren Wörtern auf Ihrer Website – stellen Sie Ihre Website noch heute auf UTF-8 um. Das nötige Rüstzeug dazu haben Sie jetzt.
Geschrieben von

Bettina Ramm Redaktion

Kommentare

Hinterlasse eine Antwort

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


vier × 8 =

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>