Tutoriel sur UTF-8 avec PHP et MySQL
UTF-8 PHP MYSQL (histoire d’encodage)
* Accueil
* UTF-8 PHP MySql
* Barre de progression d’upload en PHP
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
Code HTML
Pour le code HTML il suffit de spécifier l’encodage à l’aide de cette balise :
<meta http-equiv= »Content-type » content= »text/html; charset=UTF-8″/>
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 :
AddDefaultCharset UTF-8
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 :
CREATE DATABASE toto_utf
CHARACTER SET utf8
COLLATE utf8_bin;
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:
CREATE TABLE tutu (
bin VARCHAR(30) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
gen_ci VARCHAR(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
) CHARACTER SET utf8;
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 :
SET NAMES ‘utf8’;
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) :
; Langage par défaut
mbstring.language=UTF-8
; Jeu de caractère interne
mbstring.internal_encoding= UTF-8
; Jeu de caractères par défaut pour les données d’entrée HTTP
mbstring.http_input=UTF-8
; Jeu de caractères par défaut pour les données de sortie HTTP
mbstring.http_output=UTF-8
; Ordre de détection des jeux de caractères
mbstring.detect_order= auto
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).