You are not logged in.

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

1. Was wir wollen


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.";


2. Anwenden der Funktion utf8_encode() auf fehlerhafte Kodierung


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.


3. Anwenden der Funktion utf8_encode() auf korrekte Kodierung


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.


4. Erkennen ob UTF-8 verwendet wird


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;
}


5. Implementierung und Test


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);
}


6. Aktuelle Vorgehensweise


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

Lexikon 4.1.3, developed by www.viecode.com