Le codage UTF-8 est, depuis quelques années, le plus utilisé dans le monde des applications Web.
Bien que simple à utiliser, il pose souvent problème aux débutants. Nous allons donc voir comment l’utiliser pour la réalisation d’un site Web.
La configuration logicielle sous laquelle fonctionnera notre site sera le classique trio :
- Apache pour le serveur HTTP.
- PHP 5.x comme langage de script.
- MySQL 5.x pour le gestionnaire de bases de données.
Pour utiliser UTF-8 sans problème avec cet environnement, il suffit de suivre ces quelques règles :
- Les fichiers du site doivent être codés en UTF-8.
- Les entêtes définissant l’encodage des caractères comme étant de l’UTF-8 doivent être envoyés au client.
- La base de données doit être codée et déclarée en UTF-8.
- Certaines fonctions de PHP ne supportant pas l’UTF-8 doivent être abandonnées au profit de leurs équivalents supportant ce format.
- Il faut s’assurer que les données externes utilisées par le site sont bien codées en UTF-8 et dans le cas contraire les convertir.
Encodage des fichiers
La première étape pour utiliser le codage UTF-8 est d’être sûr que les fichiers du site sont bien encodés dans ce format. Pour cela, il faut utiliser un éditeur de texte ou un IDE qui le supporte correctement. À l’heure actuelle, ce n’est plus un problème, car tous les éditeurs modernes supportent correctement l’UTF-8.
Avec ou sans BOM ?
Le BOM (Byte Order Mark) est un caractère qui peut être utilisé pour spécifier qu’un fichier est encodé en UTF-8. Il est écrit automatiquement par votre éditeur de texte au tout début du fichier. Quand il est utilisé, l’éditeur de texte reconnaitra automatiquement que le fichier est encodé en UTF-8 et le traitera comme tel.
Un problème peut survenir quand des fichiers enregistrés avec BOM sont utilisés avec PHP. Ce problème survient quand on inclut des fichiers avec les directives include, include_once, require ou require_once. Dans ces cas le BOM des fichiers inclus est envoyé sur la sortie ce qui casse le fonctionnement des fonctions d’envoi d’entêtes, des cookies ainsi que des sessions.
La solution à ce problème est très simple : il suffit de configurer votre éditeur pour enregistrer les fichiers UTF-8 sans BOM.
Si vous vous retrouvez dans vos scripts avec une erreur PHP du type : « Headers already sent… », vérifiez bien que tous vos fichiers sont bien enregistrés sans BOM.
Néanmoins il peut exister un petit problème avec quand on utilise des fichiers sans BOM. Si vous avez un fichier qui ne contient que des caractères contenus dans la table de caractères US-ASCII votre éditeur n’aura aucun moyen de faire la différence avec de l’UTF-8 car ce dernier est rétro compatible avec le standard ASCII. Ce qui peut arriver c’est que plus tard vous éditez votre fichier et vous saisissez des caractères spécifiques à l’UTF-8. Quand vous sauvegardez votre fichier, l’éditeur l’enregistrera dans le codage par défaut, et si ce dernier n’est pas de l’UTF-8 alors vous aurez des erreurs à l’affichage de ces nouveaux caractères.
Il existe 2 solutions simples pour corriger ce problème :
Vous configurez votre éditeur pour qu’il enregistre toujours les fichiers en UTF-8. Ce qui n’est pas toujours possible.
Vous faites en sorte que vos fichiers contiennent toujours au moins un caractère UTF-8. Par exemple le caractère « é ». Pour vos fichiers PHP c’est très facile à mettre en place, il suffit de rajouter ce caractère dans un commentaire au début de chaque fichier : <?php /* force utf-8: é */ ?>.
Les entêtes UTF-8
Pour que le client (en général un navigateur Web) reconnaisse à coup sûr les données qu’il reçoit comme étant codé en UTF-8 il faut lui envoyer des entêtes déclarant ce codage.
L’entête HTTP
Pour envoyer l’entête HTTP vous avez 2 possibilités : l’envoyer depuis le script PHP ou l’envoyer depuis le serveur HTTP (Apache). Pour être sûr que votre script soit portable d’une configuration à une autre ce n’est pas un mal de toujours envoyer l’entête depuis PHP.
Pour envoyer l’entête depuis votre script PHP il suffit d’ajouter la ligne suivante au tout début de votre script (avant l’affichage de n’importe quel caractère) :
header('Content-type: text/html; charset=UTF-8');
Si vous avez un script commun inclus à toutes vos pages, il est judicieux de placer ce code au début de script.
Si vous envoyez des emails depuis un script PHP, pensez aussi à déclarer le jeu de caractères UTF-8 dans l’entête des emails.
Si vous souhaitez laisser le serveur envoyer l’entête UTF-8 vous pouvez définir ce codage comment étant celui par défaut. Ajoutez simplement la directive suivante dans votre fichier de configuration (httpd.conf) ou dans votre fichier .htaccess :
AddDefaultCharset UTF-8
L’entête HTML
Vos fichiers HTML doivent aussi être déclarés en UTF-8. Pour cela c’est très simple, ajoutez simplement la balise meta suivante entre <head> et </head> :
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Oui si vous utilisez le Doctype HTML 5 :
<meta charset="utf-8">
Utiliser de l’UTF-8 dans vos scripts PHP
PHP 5.x ne travaillent pas avec le standard Unicode, il ne supporte pas nativement le traitement de chaines de caractères UTF-8. Ces fonctions supportant uniquement les caractères codés sur un octet et UTF-8 permettant de coder les caractères sur un nombre variable d’octets, elles ne fonctionneront pas correctement.
Par exemple le caractère “é” est encodé sur 2 octets en UTF-8. Si nous testons avec la fonction strlen() (qui renvoi le nombre de caractères d’une chaine) nous aurons un résultat erroné :
echo strlen("é"); // affiche 2
Par chance PHP dispose d’une extension officielle (donc incluse par défaut dans l’installation de PHP) qui supporte les caractères codés sur un nombre d’octets variable. Il s’agit de l’extension mbstring.
L’utilisation de cette extension est extrêmement simple puisque qu’elle ne fait rien de plus qu’implémenter des équivalents multioctet des fonctions de manipulation de chaines natives de PHP.
La seule chose à faire et de préfixer les fonctions natives par « mb_ ».
Exemple:
strlen($text); // devient : mb_strlen($text);
La liste des fonctions à utiliser en place des fonctions natives de PHP est disponible sur la documentation officielle :
http://fr.php.net/manual/en/book.mbstring.php
Il suffit ensuite de déclarer à l’extension mbstring que vous souhaitez travailler en UTF-8. Pour cela il suffit de rajouter la ligne suivante dans le script commun à toutes vos pages :
mb_internal_encoding('UTF-8');
NOTE : mbstring contient des versions multioctet des fonctions ereg/eregi. L’utilisation de ces dernières n’est pas recommandée, car leurs équivalents natifs sont dépréciés en PHP 5. Donc utilisez les fonctions preg natives, car elles supportent bien l’UTF-8.
UTF-8 avec MySQL
Quand on veut travailler en UTF-8 avec MySQL il faut observer plusieurs points :
Encodage des données dans la base
Vos bases de données, tables et colonnes doivent être déclarées en UTF-8. Vous devez déclarer le jeu de caractères et la collation qui correspond.
En général, on utilisera le jeu de caractères utf8 et la collation utf8_general_ci. Utf8_general_ci est une collation rapide et suffisante pour la plupart des cas. Pour voir en détail les autres types de collations, reportez-vous à la documentation de MySQL.
CREATE DATABASE `ma_base` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Déclarer le jeu de caractères lors de la connexion
Quand vous vous connectez à votre base de données, la première chose à faire et de déclarer le jeu de caractères comme étant de l’UTF-8.
Si vous utilisez l’extension mysqli il vous suffit d’exécuter cette fonction juste après la connexion à la base de données :
mysqli_set_charset($link, 'utf8'); // procédural $mysqli->set_charset('utf8'); // orienté objet
Si vous utilisez PDO, il n’y a pas de fonction équivalente, donc il vous suffit d’exécuter la requête suivante juste après la connexion à la base de données :
SET NAMES 'utf8';
NOTE : Si vous utilisez l’extension mysql vous devriez penser à mettre à jour vos scripts pour utiliser au moins mysqli.
Travailler avec des données externes
Parfois vous devez travailler avec des données provenant de l’extérieur et sur lesquelles vous n’avez pas de contrôle.
Par exemple :
- Des flux RSS, Json ou XML
- Des fichiers
- Des bases de données distantes
Quand vous recevez ces données, vous devez vérifier si elles sont bien encodées en UTF-8 et si ce n’est pas le cas les convertir dans ce jeu de caractères.
Pour déterminer si des données sont encodées en UTF-8 vous pouvez utiliser la fonction mb_detect_encoding() de l’extension mbstring :
if (mb_detect_encoding($data, 'UTF-8', true) == 'UTF-8') echo "C'est bien de l'UTF-8"; else echo "Ce n'est pas de l'UTF-8";
Si les données sont bien en UTF-8 vous pouvez les utiliser directement sur votre site. Sinon il vous suffit de les convertir avec la fonction mb_convert_encoding().
Vous pouvez aussi regarder les fonctions utf8_encode() et utf8_decode() qui permettent respectivement d’encoder et décoder UTF-8 de et vers le jeu de caractères ISO-8859-1.
Repérer et corriger les erreurs d’affichage des caractères
Il existe 2 cas de figure classiques :
Les caractères accentués sont remplacés par des caractères du genre : é, Ã, etc :
Problème :
Vos données sont bien encodées en UTF-8 mais le navigateur tente de les afficher en ISO-8859-1.
Solutions :
- Vérifiez que vous envoyez bien l’entête HTTP pour déclarer les données en UTF-8.
- Vérifiez que le jeu de caractères est bien déclaré en UTF-8 dans votre entête HTML (meta charset).
- Vérifiez que vous avez bien déclaré le jeu de caractères après la connexion à la base de données (SET NAME).
Les caractères accentués sont remplacés par des losanges contenant un point d’interrogation :
Problème :
Vos données sont encodées en ISO-8859-1 mais le navigateur tente de les afficher en UTF-8.
Solutions :
S’il s’agit d’un texte contenu en dur dans votre page :
- Convertissez votre fichier en UTF-8 depuis votre éditeur de texte.
- Vérifiez que vous envoyez bien l’entête HTTP pour déclarer les données en UTF-8.
- Vérifiez que le jeu de caractères est bien déclaré en UTF-8 dans votre entête HTML (meta charset).
Si le texte provient de la base de données :
- Vérifiez l’encodage de la base de données et les collations.
- Vérifiez que vous avez bien déclaré le jeu de caractères après la connexion à la base de données (SET NAME).
Si le texte provient d’une source externe (fichier, flux RSS, etc.) :
- Utilisez mbstring ou utf8_decode()/utf8_encode() pour convertir les données dans le bon jeu de caractères.
En effet, il est bien plus pratique aujourd’hui d’utiliser ce codage, merci pour ces explications.
Je rencontre actuellement un problème d’encodage sur mon site WordPress : quand j’utilise certains plugins, les caractères spéciaux ne s’affichent pas correctement. Je pense que le souci vient du fait que, pour des raisons que j’ignore, une partie de ma base de données est encodée en latin1. Quelle serait la solution la plus simple ? Convertir la totalité de ma base en utf-8 me fait un peu peur… (à tort ?)
C’est pourtant la solution qui parait la plus logique.