Mittwoch, 23. Mai 2012


Artikel

Januar 2010 | Artikel

UTF-8 für alle Fortsetzung, Teil 3

Teil 1   Teil 2   Teil 3   

 

Interessanter Artikel?

PHP Magazin 2.2010

Hat Ihnen der Artikel gefallen? Dies und mehr ist alles Teil des PHP Magazin 2.2010. Alle zwei Monate frisch am Kiosk! Zur jeweils aktuellen Ausgabe geht es hier.

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.

  1. <?php
  2. // ist $string valides UTF-8 ? Rückgabewert true, sonst false
  3. function isUtf8($string) {
  4. return preg_match('%^(?:
  5. [\x09\x0A\x0D\x20-\x7E] # ASCII
  6. [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
  7. | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
  8. | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
  9. | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
  10. | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
  11. | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
  12. | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
  13. )*$%xs', $string);
  14. }
  15. ?>

Listing 1: Daten auf UTF-Kodierung prüfen.

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. &auml; steht z. B. für „ä“, &szlig; 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: &quot;, &amp;, &lt; und &gt;.

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.

Bettina RammBettina Ramm ist selbständige Webentwicklerin (www.die-web-architektin.de) und programmiert seit mehreren Jahren mit PHP. Sie entwickelt Webanwendungen mit dem Zend Framework und unterstützt Webdesigner und Webagenturen bei der technischen Umsetzung von Websites.

Teil 1   Teil 2   Teil 3   

Kommentare

Gravatar Herbert Bohlscheid 17.03.2010
um 23:12 Uhr
Ich schlage mich gerade mit UTF8, MySQL und PHP rum, seit ich heute morgen festgestellt habe, dass in meine MySQL-DB Umlaute falsch angezeigt wurde. Dank dieses Beitrags ist mir vieles klarer geworden. Super-Arbeit. Nur mein PHP will noch nicht so recht mitmachen: Formulardaten werden von PHP immer noch mit Sonderzeichen dargestellt (aber richtig in die DB übernommen). Dabei habe ich in meinem Dreamweaver als Zeichencodierung UTF-8 vorgewählt. Gibtrzu noch einen Tipp? #zitieren
Gravatar Adrian Preuß 27.08.2010
um 17:13 Uhr
Du musst alles auch auf UTF-8 setzen.
Ob es nun die Ausgabe ist (Ein HTML-Dokument) mit einem UTF-8 charset in der Meta angabe, die PHP und/oder die DB-verbindung. Wenn Du UTF-8 verwenden willst (und das Ohne Probleme) dann versuche folgendes:
1. Die meta-angaben mit charset UTF-8 setzen
()

2. einen PHP-header mit nem UTF-8 Charset erzeugen
(header("Content-type: text/html; charset=utf-8");

3. Die DB-Connection auch auf UTF-8 Setzen
(mysql_set_charset("utf8");)

Wenn du alle drei gesezt hast sollte alles funzen.

Warum wird das benötigt?
Ganz einfach.
beispiel: Hast du deine PHP auf UTF-8 gesezt, die DB-Connection aber nicht, so gibt es da probleme mit den zeichensätzen.

Beispiel:
Ich: "Hallo Datenbank, ich bin PHP und gebe dir nun eine UTF-8 String"
Datenbank: "Hallo PHP, Danke für die Daten. Ich kann viel davon lesen, aber einige zeichen sind mir unbekannt, da ich iso-8859-1 benutze - Egal ich ersetze diese einfach durch einen passenden eintrag aus meiner Tabelle mit der gleichen position".

Und genau dann bekommst du so schöne Umlautprobleme.
Wenn du ein charset verwenden willst, solltest du auch das ganze system darauf einstellen, und nicht nur eine Seite mitteilen das du nun UTF-8 verwendest.
#zitieren