Le site perso de Thomas Bigot
Dans les codages de caractères classiques, un caractère = un octet (byte). C'était une aubaine pour toutes les routines de comptages de caractères qui n'avaient qu'à compter les octets occupés en mémoire par une chaîne pour en connaître sa longueur.
Ces codages classiques, comme le ISO-8859, ont atteint leur limites. Avec 8 bits, il leur est impossible de coder tous les caractères du monde. L'utilisation de codages différents (un par type d'alphabet) est elle aussi problèmatique, car elle impose de déclarer au préalable celui qui va être utilisé, et la disponibilité de celui-ci sur le système de destination.
On peut alors imaginer un système à 16 bits pour coder l'ensemble des caractères les plus utilisés sur la terre. Mais la taille des fichiers contenant du texte doublerait ! L'unicode répond à cette problèmatique par un codage sur un octet pour les caractères simlples de l'alphabet latin (grossièrement, les caractères ascii), et sur plus d'octets pour les caractères accentués ou ne faisant pas partie de l'alphabet latin. L'UTF-8 par exemple code ses caractères sur un à quatre octets.
PHP, juqu'à la version 6 non incluse, ne supporte pas nativement les caractères multi-octets. Il utilise, pour compter les caractères d'une chaîne, ou couper cette chaine à X caractères, le comptage du nombre d'octets.
Imaginons le codage multi-octets suivant : les lettres de l'alphabet sont codés sur un caractère, et les lettres accentuées sont codées comme suit :
$1 = é, $2=à, $3=ç...
Le caractère "$" n'est donc pas à afficher, il signifie juste "attendre le prochain caractère pour connaître la lettre à afficher".
Soit maintenant la chaîne "comment ça va", qui sera codée "comment $3a va". Si on demande à php de nous afficher les 9 premiers caractères de cette chaîne (avec substr), il va prendre les 9 premiers octets : "comment $". Je veux mettre cette chaîne en gras, et mettre un texte derrière : "<b>comment $</b> est une chaîne de test". Le problème est ici : $< va être interprété comme un caractère multi-octets (car il commence par $), caractère qui n'existe pas : le chevron ouvrant va donc être avalé par le caractère multi-octet tronqué à sa moitié. À l'affichage, cela donnera : "comment /b> est une chaîne de test". La balise du gras continuera à affecter le reste du texte, car il n'y a plus de balise fermante
Une extension php nommée mbstring (pour multibyte string) permet de gérer les codages de caractères multi-octets. Il faut qu'elle soit installée sur le serveur web de travail et sur celui de votre hébergeur (c'est assez courant).
Il faut la paramétrer, dans votre script de la façon suivante :
mb_internal_encoding('UTF-8');
puis utiliser la fonction mb_substr au lieu de substr par exemple.
Tout ceci dans l'optique où vous n'avez pas accès au paramétrage du php.ini auquel cas, d'autres fonctions plus avancées vous seraient permises.