This articles has been requested to be deleted.
Friday, January 9th 2009, 1:24pm
Tags
utf8,
utf8_encode,
zeichenkodierung
Abstract
Wer Inhalte aus fremden Quellen bezieht, hat häufig das Problem mit fehlenden oder gar fehlerhaften Angaben zur Zeichenkodierung. PHP bietet in aktueller Version (5.2) leider keine Hilfsmittel zum sicheren Umgang mit UTF-8 Zeichenketten.
Article
Die Anforderung ist einfach. Wir wollen einen UTF-8 String erhalten - egal welche Zeichenkodierung die Quelle hatte.
Entweder der String ist korrekt und sieht folgendermaßen aus:
|
PHP Quellcode
|
1
|
$string_correct = "umlaute läuten die wende ein.";
|
Oder er ist falsch und sieht zum Beispiel so aus:
|
PHP Quellcode
|
1
|
$string_wrong = "umlaute l�uten die wende ein.";
|
Wenn wir wissen, dass die Eingabe fehlerhaft kodiert ist, dann fällt die Wahl einfach. Wir wenden die Funktion utf8_encode() also nur auf den falschen String an:
|
PHP Quellcode
|
1
2
3
|
$string_wrong = "umlaute l�uten die wende ein.";
echo utf8_encode($string_wrong);
//Ausgabe = umlaute läuten die wende ein.
|
Doch was geschieht eigentlich wenn wir die Funktion utf8_encode() auf eine Zeichenkette anwenden, die bereits in UTF-8 vorliegt? Man könnte erwarten, dass wir weiterhin einen gültigen UTF-8 String erhalten, doch leider ist dem nicht so.
|
PHP Quellcode
|
1
2
3
|
$string_correct = 'umlaute läuten die wende ein.';
echo utf8_encode($string_correct);
//Ausgabe = umlaute läuten die wende ein.
|
Das Problem beschränkt sich also darauf zu erkennen ob der String in UTF-8 vorliegt. Dankenswerterweise liefert uns das PHP Manual die Lösung dazu und sagt uns welche Bit die Funktion utf8 selbst manipuliert.
Wir erstellen also die folgende Funktion um zu erkennen ob es sich bei einem String um einen UTF-8 String handelt - die Lösung wurde bereits im Jahre 2004 von "bmorel at ssi dot fr" gepostet.
|
PHP Quellcode
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function seems_utf8($Str) {
for ($i=0; $i<strlen($Str); $i++) {
if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
else if ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
else if ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
else if ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
else if ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
else if ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
else return false; // Does not match any model
for ($j=0; $j<$n; $j++) {
// n bytes matching 10bbbbbb follow ?
if ((++$i == strlen($Str)) || ((ord($Str[$i]) & 0xC0) != 0x80)) {
return false;
}
}
}
return true;
}
|
Wir können die Funktion beliebig oft auf falsche und richtige String anwenden. Wir erhalten immer einen korrekten UTF-8-String
|
PHP Quellcode
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
$string_correct = utf8_ensure($string_wrong);
echo $string_correct;
echo utf8_ensure(utf8_ensure(utf8_ensure($string_correct)));
function seems_utf8($Str) {
for ($i=0; $i<strlen($Str); $i++) {
if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb
else if ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb
else if ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb
else if ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb
else if ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb
else if ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b
else return false; // Does not match any model
for ($j=0; $j<$n; $j++) {
// n bytes matching 10bbbbbb follow ?
if ((++$i == strlen($Str)) || ((ord($Str[$i]) & 0xC0) != 0x80)) {
return false;
}
}
}
return true;
}
function utf8_ensure($str) {
return seems_utf8($str)? $str: utf8_encode($str);
}
|
Mit den PHP 4 Versionen >= 4.4.3 und den PHP 5 Versionen >= 5.1.3 wurde eine neue Methode eingeführt, die uns das lange Script erleichtert.
Wenn garantiert werden kann, dass diese Versionen installiert sind, kann daher folgende Version verwendet werden:
|
PHP Quellcode
|
1
2
3
4
|
function utf8_ensure($str) {
return mb_check_encoding($str, 'UTF-8') ? $str : mb_convert_encoding($str, 'UTF-8', 'auto');
}
|
report critical content