UTF-8 PHP MYSQL (histoire d’encodage)

UTF-8 PHP MYSQL (histoire d’encodage)

Encodage et programmation

Les caractères qui s’affichent sur les écrans d’ordinateur, comme toute donnée informatique, ne sont qu’une sucession de 0 et de 1 du point de vue de la machine. C’est le nombre et l’ordonnance de ces bits qui définissent la norme d’un encodage. Plus le nombre de bit sera élevé, plus l’encodage supportera de caractères.

Les problèmes que l’on peut rencontrer lors du passage à l’UTF-8 viennent de cette différence de norme avec l’encodage européen ISO. Entre ces deux normes les problèmes vont se situer au niveau des caractères “spéciaux” comme les caractères accentués.

A côté des problèmes que cela peut impliquer, l’UTF-8 permet de gérer un plus grand nombre de caractères, donc de gérer des langues aux glyphes exotiques, ce que ne permet pas l’iso avec ses 256 possibilités.
Mais si l’UTF-8 permet de telles choses c’est qu’il est codé sur plus de bits que l’ISO, et si cela influe sur l’affichage, cela influe forcément sur le traitement des chaînes au niveau de la programmation et du stockage en base de données.

Imaginons que l’on veuille connaître la longueur de cette chaîne : ‘éé’. Basiquement un langage comptera le nombre de bits que contient cette chaîne.
Une fonction dédié à cette tâche trouvera 16 bits, soit deux octets, soit deux caractères en ce qui concerne l’ISO. En revanche cette même fonction trouvera 32 bits sur un encodage UTF-8, donc renverra une valeur de 4 caractères si elle croit avoir affaire à de l’ISO…tel est le problème.

Ce tutoriel couvrira donc la mise en place d’un environnement conforme, son utilisation ainsi qu’une reconnaissance rapide des problèmes d’affichage entre l’UTF-8 et l’ISO.

Plus d’infos sur l’encodage -> les bases
Plus d’infos sur l’encodage -> UTF-8


Préparation de l’environnement

Pour être sûr que tout fonctionne correctement il est impératif que l’ensemble de l’environnement soit aux normes afin de ne pas tout mélanger, oublier d’enregistrer ses sources au bon format et toutes les configurations du serveur deviennent aussi efficaces que le néant.

Editeurs et BOM

Les fichiers doivent être encodés en utf-8. A priori simple, cela dépendra du bon vouloir de l’éditeur de texte.

Certains éditeurs spécifient en début de fichier un marqueur d’ordre des octets (bom en anglais), qui plus est inutile pour l’utf-8.
Le fait d’insérer ce caractère au début d’un fichier php (donc avant la balise d’ouverture <?php) pourra provoquer une erreur du type “headers already sent”.
Il faut donc veiller à ne pas laisser l’éditeur insérer un tel caractère (notepad ou encore scite si l’on ne spécifie pas “UTF-8 Cookie”).

Plus d’infos sur le BOM (Merci à Damien pour la remarque)

Code HTML

Pour le code HTML il suffit de spécifier l’encodage à l’aide de cette balise :

Apache

Historiquement apache travail en ISO-8859-1, c’est donc dans cette norme qu’il risque d’envoyer ses entêtes.

L’instruction à modifier dans le httpd.conf ou dans un .htaccess :

Sinon via php :


header('Content-type: text/html; charset=UTF-8'); 


Pour connaître l’entête utilisé par un serveur apache il suffit de regarder l’encodage lors de la réception d’une page à l’aide de son navigateur (à peu de choses près en fonction de la famille : affichage -> encodage).
Sinon ici.

! L’entête http fait autorité face à la balise meta !

MySQL

Mysql supporte pleinement l’UTF-8 depuis la version 4.1. Les instructions données ici fonctionneront à partir cette architecture et un développement sérieux en UTF-8 se fera à l’aide d’un milésimme égale ou postèrieur à celle-ci.
Donc oui il est possible de stocker des données unicode dans une base 3.23, mais il faut s’attendre à ce qu’une chaîne de 25 caractères cyrilliques soit tronqué dans un champs varchar de 40 (sans parler des problèmes liés aux fonctions SQL).

Dans le cas présent l’ensemble des instructions se fera à l’aide de commandes sql et non pas à partir de directives de compilation ou d’instructions du my.cnf.

Exemple de la création d’une base :

CHARACTER SET -> spécifie l’encodage

COLLATE -> spécifie la collation (“l’attitude” de mysql envers les données)
utf8 -> orthographe propre à mysql (absence du “-” entre utf et 8)
utf8_bin -> cette collation rend la comparaison de chaîne sensible à la casse (au contraire de utf8_general_ci)

Chaque table d’une base peut avoir son propre jeu de caractère/collation, de même que chaque colonne.

Exemple de création de table:

Si MySQL n’est pas configuré par défaut pour l’UTF-8 il faut lui préciser la manière dont elle doit traiter les caractères contenus dans une requête SQL à l’aide de cette instruction :

PHP

PHP travail nativement en ISO, ce n’est qu’à partir de la v6 qu’il basculera entièrement en UTF-8.
Deux modules permettent de gérer différents types d’encodages, mbstring et iconv.

mbstring s’occupe de la manipulation de chaînes tandis qu’iconv permet de convertir différents types d’encodages. Les conversions entre ISO et UTF-8 peuvent se réaliser à l’aide des fonctions utf8_encode() et utf8_decode(). Une conversion à partir ou à destinations d’une autre norme nécessitera les fonctions du module iconv.

D’autres fonctions supportent différents charsets sous réserve de l’indiquer, tel que html_entities() (dont on pourra se passer au profit de htmlspecialschar() une fois les problématiques d’encodage apréhendées…html_entities ne s’occupe que de des caractères latins).

mbstring

Une fois le module activé et correctement configuré à l’aide du php.ini mbstring permettra la manipulation de chaînes en UTF-8. Plusieurs fonctions qui reprennent les fonctions usuelles de PHP lui sont associés.
Il faudra utiliser par exemple mb_strlen() au lieu de strlen() (une autre méthode plus pénalisante au niveau performance existe pour continuer à utiliser les fonctions standarts tout en se servant de mbstring -> voir lien ci dessous).

Une configuration fonctionnel pour l’UTF-8 (dans l’ordre) :

A défaut d’avoir accès au php.ini les directives de configuration peuvent être spécifiées dans le http.conf-.htaccess (ex: php_value mbstring.language “UTF-8”) ou à l’aide de la fonction ini_set() (sauf pour mbstring.language qui est une configuration de type PHP_INI_PERDIR => à stipuler dans un php.ini, httpd.conf ou un .htaccess) ou bien encore des fonctions propres à mbstring (mb_internal_encoding(), mb_http_output(), …)

Ne pas passer par le php.ini permet également de travailler avec des configurations différentes sur son poste de travail, donc d’éviter des incompatibilités.
A tire d’exemple la directive “mbstring.http_input=UTF-8” semblera ne pas faire passer les données $_GET et $_POST sur un site en ISO (réception d’une chaîne vide).

Plus d’infos sur mbstring

iconv

A part l’activation du module il n’y a pas de configuration particulière pour ce qui est de la conversion entre différents encodages (pour ce qui est du traitement de chaîne mbstring est plus complet).

Plus d’infos sur iconv

Utilisation

Une fois mis en place les bonnes configurations et les scripts sql exécutés (création de la base et d’une table) , vous pouvez commencer par tester ce script :

<?php


mysql_connect

("serveur","login","pass");
mysql_select_db("toto_utf");



//necessaire seulement après la connection
mysql_query("SET NAMES 'utf8'");



mysql_query("insert into tutu values('tдtд','tдtд')");
mysql_query("insert into tutu values('Tдtд','Tдtд')");



//difference des collations en ce qui concerne la casse
$res=mysql_query("select * from tutu where bin='tдtд'");
echo
'nombre de "tдtд" trouvé avec utf8_bin : '.mysql_num_rows($res).'<br />';



$res=mysql_query("select * from tutu where gen_ci='tдtд'");
echo
'nombre de "tдtд" trouvé avec utf8_general_ci : '.mysql_num_rows($res).'<br />';



//utilisation d'une fonction mbstring
$chaine=mysql_fetch_row($res);
echo
'longueur de "tдtд" sans mbstring : '.strlen($chaine[0]).'<br />';
echo
'longueur de "tдtд" avec mbstring : '.mb_strlen($chaine[0]).'<br />';



?>

Reconnaissance rapide des problèmes d’affichage UTF-8 ISO

Si la page affiche des caractères de ce type : “é”, “î”, “Ô, …
=> Les données ont été enregistrées au format UTF-8, et le navigateur les affiche en pensant avoir affaire à de l’ISO.

Si la page affiche des caractères de ce type : “�”
=> Les données ont été enregistrées au format ISO, et le navigateur les affiche en pensant avoir affaire à de l’UTF-8.

Si les données sont codées en dur dans la page, voir l’encodage de l’éditeur de texte, l’header apache et la balise meta “charset”.
Si les données proviennent de la base, vérifier le format de stockage et les méthodes de lecture et d’insertion (SET NAMES et charset).
Si les données proviennent de l’extérieur (web services, rss, …), penser à convertir les chaînes de caractère (utf8_encode-decode et fonctions du module iconv).

Erreurs, suggestions, commentaires, … -> thierry at fassnet dot net

Fassnet.net – Création de site Internet à Nice, PACA – Développeur Internet Indépendant

PhpMyvisites – Compteur de visites

Author: stratus

Laisser un commentaire