Informatique > Faire un site multilingue > PHP et l'UTF8

derniére édition le: 7/09/2006

PHP et l'UTF8

PHP ne gére pas correctement l'UTF8. Ce qui ne signifie pas qu'il soit impossible d'utiliser cet encodage. L'important est de connaitre le comportement de PHP et de contourner les problémes.

Pour comprendre cet article, mieux vaut savoir programmer en PHP. La lecture de cet article sur l'encodage UTF8 est également conseillée.

Le fonctionnement interne de PHP

J'ai cherché longtemps une information claire sur les problémes liés à l'UTF8 avec PHP mais presque toutes les pages se bornent a parler de la fonction utf_encode().

php.net déclare sur son site que les encodages multi-octets compatibles avec la norme ASCII pour les caractères de l'intervalle 0à 127 sont supportés. UTF8 est mentionné comme un encodage supporté. Cela veut dire que l'on peut continuer a écrire nos scripts normalement: il ne faut pas utiliser de caractéres accentués sauf dans une chaine de caractéres. Cette chaine devra tout de même être manipulée à l'aide de fonctions adaptées aux encodages multi octets. Super!heureux

Seulement il semble y avoir quelques problémes qui rendent l'utilisation d'UTF8 trés difficile.

Haut

La fonction include() et UTF8

Nous allons créer une page web encodée en UTF8 qui inclus un script PHP. La page sera composée de deux DIVS l'un en dessous de l'autre. Voici le code de la page test.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body>
<div style="background-color:blue;">eee</div>
<?
include('test2.php');
?>
</body>
</html>

Voici le code de test2.php:

<?echo '<div style="background-color:green;">eee</div>';?>

Testez donc cette page sous internet explorer6, histoire de rigoler. heureux Les deux blocs ne sont pas collés. Et vous pourrez bidouiller tant que vous voudrez votre CSS, le blanc ne disparaitra pas! J'en ai fait la douloureuse expérience. Maintenant affichez la source de cette page: comme vous pouvez le voir, un caractére parasite s'est inséré entre les deux DIVS!surpris

Si vous essayez sous Firefox, l'affichage sera correct, mais ne vous y trompez pas, les caractéres parasites sont tout de même présents et peuvent avoir des effets imprévisibles. Essayez d'inclure la page test toute entiére dans une autre page test3. Si vous mettez la page en ligne et que votre débit n'est pas trop puissant, vous devez voir apparaitre le phénomène suivant: une page blanche s'affiche et le texte  s'affiche à l'écran. Tout de suite aprés, la page s'affiche, avec les deux DIVS. confus

C'est que des caractéres imprévus ont été insérés avant le doctype! Ce qui a pour conséquence facheuse de faire passer internet explorer et firefox en mode brouillon! De quoi passer des heures inutiles à batailler avec votre CSS. Et puis c'est quelque chose que les validateurs ne doivent pas aimer, les moteurs de recherche non plus. Le pire, c'est que vous ne pouvez rien contre ce bug.malheureux

Il faut donc abandonner l'idée d'encoder ses scripts php en UTF8. malheureux

Haut

Une premiére solution: utiliser utf8_encode()

PHP ne sait pas lire les scripts encodés en UTF8, trés bien.tire la langue Mais nous avons tout de même a disposition deux fonctions indispensables: utf8_encode(), et utf8_decode(). On peut donc continuer a encoder nos fichiers PHP en ANSI. Par contre, dés que l'on veut afficher une chaine de caractéres il faut l'encoder en UTF8 au préalable.heureux

Hélas, cette solution a un coût: elle complique la relecture en ajoutant des fonctions suplémentaires, et surtout elle allonge le temps d'éxécution du script! J'ai fait un petit essai pour voir:

<?
function microtime_float() {
return array_sum(explode(' ', microtime()));
}
$temps_debut = microtime_float();
for($i=0;$i<1000;++$i)
echo 'é';
$temps_fin = microtime_float();
echo 'Temps d\'execution du script : '.round($temps_fin - $temps_debut, 4);
?>

Résultat: 0.0007 secondes.

<?
function microtime_float() {
return array_sum(explode(' ', microtime()));
}
$temps_debut = microtime_float();
for($i=0;$i<1000;++$i)
echo utf8_encode('é');
$temps_fin = microtime_float();
echo 'Temps d\'execution du script : '.round($temps_fin - $temps_debut, 4);
?>

Résultat: 0.0539 secondes!surpris Bon, ce chiffre est tout de même à nuancer, jamais vous utiliserez 1000 utf8_encode dans un script. Ou alors c'est déja du bon script!

Haut

Une astuce pour ne pas utiliser utf8_encode()

L'astuce repose sur l'utilisation de Notepad++. C'est un bloc notes amélioré trés adapté aux programmeurs. On peut éditer plusieurs documents grâce à un systéme d'onglets. Les numéros de lignes sont affichés et une coloration syntaxique est disponible pour 25 languages de programmation. Mais ce qui nous intéresse pour le moment c'est son menu format avec la possibilité de voir un fichier ANSI comme s'il était encodé en UTF8.

capture d'écran de notepad++
Le menu format de Notepad++

Grâce à cette option, vous pouvez continuer à encoder vos scripts php en ASCII, tout en étant capable d'écrire du texte sans se soucier des caractéres spéciaux. Votre fichier sera vu comme de l'UTF8, vous pouvez écrire le texte, mais si vous désactivez cette option votre texte deviendra du charabia.Cependant, aucun souci au niveau des navigateur si vous avec spécifié que votre page HTML est encodée en UTF8. Testé sous internet explorer6 et Gecko.clin d'oeuil

Encore une petite précision, hélas il y a un bug dans notepad++, parfois il arrive que le texte devienne incompréhensible pour les navigateurs. Quand on édite la source de la page, on voit que des caractéres ont été insérés un peu partout. Je ne sais pas exactement comment ça arrive, je me suis arraché les cheveux avant d'écrire cet article mais j'ai trouvé un parade. En cas de probléme étditez votre fichier, rajoutez un caractére puis supprimé le. Enregistrez votre fichier et ça remarche!heureux

Haut

Manipulation des chaines de caractéres

Reste un dernier probléme à aborder. La manipulation de chaines de caractéres encodées en UTF8 ne doit pas se faire à l'aide des fonctions standard. Prenons ce code pour exemple:

<?
$a=utf8_encode('é');
$b=strlen($a);
$a=utf8_decode($a);
echo 'longueur de "'.$a.'" : '.$b.' caractéres';
?>

Le résultat obtenu sera: "longueur de "é" : 2 caractéres".malheureux Heureusement des modules ont été rédigés pour permettre malgré tout de manipuler des chaines.heureux Personnellement j'ai utilisé la fonction mb_convert_encoding , qui permet de convertir une chaine de caractéres UTF8 en chaine ASCII. Il existe de nombreuses fonctions permettant de manipuler des chaines dans divers encodages, vous trouverez surement votre bonheur. Pensez aussi a voir le module iconv.

Haut

Conclusion

Voilà l'inventaire des problémes que j'ai eu avec l'UTF8. Je crois que cet article peut vous faire économiser un grand nombre d'heures de travail. A présent j'utilise Notepad++ avec mb_conv et je n'ai plus du tout de probléme, pourvu que ça dure!

Par bigguiz

Informatique > Faire un site multilingue > PHP et l'UTF8