Encodage

Version imprimableEnvoyer par emailversion PDF

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.

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.

Pour plus d'informations, vous pouvez visiter :

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

Voici une chaine de caractère accentuée, qui peut poser problème : é - è - ê - à - â - î - ï

  1. Si la page affiche des caractères de ce type : é - è - ê - à - â - î - ï Les données sont encodés en UTF-8 et affichées par le navigateur en ISO-8859-1 (Latin 1).
  2. Si la page affiche des caractères de ce type : � - � - � - � - � - � - � Les données sont encodés en ISO-8859-1 et affichées par le navigateur en UTF-8.
  3. Si la page affiche des caractères de ce type :  -  -  -  -  -  - 

Les données sont (normalement) encodées en WINDOWS-1252 et affichées par le navigateur en UTF-8.

Si vous rencontrez un problème de ce type, vérifiez les points suivants (et donc les catégories ci-dessous) :

  • Si les données sont codées en dur dans la page : vérifiez l'encodage de l'éditeur de texte (Editeur et BOM, ci-dessous), puis l'header d'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). 

Les navigateurs ont des priorités sur l'encodage, les voici :

  • Préférence utilisateur (pour forcer l'encodage).
  • Header HTTP.
  • Prologue XML (si présent).
  • Balises "meta" de la page web.

Taper la commande suivante sous linux :

locale charmap

pour connaitre le charset utilisé par le système, en général il s'agit d'UTF-8 par défaut sur les systèmes récents. Dans d'autre cas, vous pouvez effectuer un dpkg-reconfigure locales sous Debian.

Éditeurs et BOM

En unicode, une Marque d'ordre des octets ou BOM (pour l'anglais Byte Order Mark) est un caractère unicode de code point U+FEFF (espace insécable de largeur nulle "zero-width no-break space"), quand ce caractère est utilisé pour marquer l'endianness d'une chaîne de caractères UCS/Unicode codée en UTF-16 ou UTF-32 et/ou comme marqueur pour indiquer que le texte est codé en UTF-8, UTF-16 ou UTF-32.

Visitez cette page de Wikipedia pour plus d'informations sur le BOM. Lorsqu'il est correctement interprété, le BOM n'est pas vu par l'utilisateur final du texte codé. Dans le cas contraire, l'utilisateur est confronté à une courte séquence de caractères incompréhensibles. Si les fichiers doivent être encodés en utf-8, cela dépendra du bon vouloir de l'éditeur de texte. Ce BOM est inutile pour l'utf-8.

Le fait d'insérer ce BOM 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. Il est alors conseillé d'utiliser Notepad++ si vous utilisez Windows.

Choisissez UTF-8 sans BOM (parfois noté "sans signature" ou "UTF-8 sans Cookie").

Utilisation d'iconv

Convertir en UTF-8

Convertir un fichier encodé en ISO8859-1 vers un fichier encodé en UTF-8 :

iconv nom_fichier -f ISO-8859-1 -t UTF-8

 

Convertir en ISO-8859-1

Convertir un fichier encodé en UTF-8 vers un fichier encodé en ISO-8859-1 :

iconv nom_fichier -f UTF-8 -t ISO-8859-1

 

Déclaration HTML / XML / CSS / PHP

HTML

Le code HTML peut spécifier l'encodage par la balise suivante (ici en UTF-8) :

<meta content="text/html; charset=UTF-8" http-equiv="Content-type" />

 

Il est important de noter que l'entête HTTP est prioritaire face à la balise HTML meta !

XML

Si votre page comporte un prologue XML il peut être intéressant de préciser également l'encodage :

<?xml version="1.0" encoding="UTF-8" ?>

 

Ou laisser le header du serveur web décider :

<?xml version="1.0" ?>

 

CSS

Avant tout caractère dans votre fichier CSS, vous pouvez spécifier son encodage de la manière suivante :

@charset "UTF-8";

 

Utilisation de PHP

PHP travail nativement en ISO, ce n'est qu'à partir de la version 6 qu'il basculera entièrement en UTF-8. Si vous n'avez pas accès à la configuration d'Apache, vous pouvez utiliser PHP pour fournir un autre header :

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

 

Configuration de PHP

Éditez le fichier /etc/php5/apache2/php.ini, puis vérifiez l'encodage utilisé par PHP, à la ligne suivante :

default_charset = "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 appréhendées... html_entities() ne s'occupe que de des caractères latins).

mbstring

Il faut activer le module mbstring dans php.ini.

Ce module est visiblement activé par défaut sous Debian, vous pouvez tout de même vérifier son activation avec un phpinfo().

Il permettra la manipulation de chaînes en UTF-8. Plusieurs fonctions "classiques" de PHP lui son associées.

Par exemple il faut utiliser mb_strlen() au lieu de strlen().

Une autre méthode plus pénalisante au niveau performance existe pour continuer à utiliser les fonctions standards tout en se servant de mbstring.

Voir la page du manuel PHP ici, et la documentation de mbstring.func_overload.

mbstring.overload

Il faut déclarer de la manière suivante dans php.ini :

mbstring.func_overload = 7

La valeur 7 permet de changer toute les fonctions qui ont quelque chose à voir avec les chaînes de caractères.
0 désactive l'interception ;
1 intercepte uniquement mail() ;
2 intercepte str*() ;
4 intercepte ereg*().

Vous pouvez également combiner ces valeurs. Voici une configuration de mbstring / php.ini pour l'UTF-8 :

; 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

Si vous n'avez pas accès au fichier php.ini, les directives de configuration peuvent être spécifiées par le fichier httpd.conf, voir par fichier .htaccess. Par exemple :

php_value mbstring.language "UTF-8"

La fonction ini_set() peut aussi être utilisée, pour ce faire, consultez la page du manuel PHP.

Seules exception à l'utilisation d' ini_set():

  • mbstring.language qui est une configuration de type PHP_INI_PERDIR - c'est à dire à spécifier dans php.ini / httpd.conf ou un fichier .htaccess.
  • Toutes fonctions propres à mbstring (mb_internal_encoding(), mb_http_output(), ...) Ne pas utiliser php.ini permet de travailler avec des configurations différentes, afin d'évoter toute incompatibilité. Par 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).
     

iconv

Il faut activer le module iconv dans le fichier php.ini. Vous pouvez vérifier les valeurs suivantes (ici mises en commentaire par la présente de ";") :

iconv ;iconv.input_encoding = ISO-8859-1 ;
iconv.internal_encoding = ISO-8859-1 ;
iconv.output_encoding = ISO-8859-1;

Pour plus d'information, reportez vous au manuel PHP.
Il est aussi fortement conseillé de lire la documentation sur utf8_encode() et utf8_decode().

Apache

Historiquement Apache travail en ISO-8859-1. Dans la suite de ce document il est fait référence au fichier httpd.conf, sous Debian il s'agit du ficher /etc/apache2/apache2.conf . A chaque modification de ce fichier, il faut redémarrer ou recharger Apache.

Exemple d'entête

Voici un header spécifiant l'encodage iso-8859-1. Remarquez la dernière ligne :

Date: Sat, 01 Aug 2009 00:07:33 GMT Server: Apache X-Powered-By: PHP/5.2.6-1+lenny3 Expires:
 Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-
check=0, pre-check=0 Pragma: no-cache Keep-Alive: timeout=15, max=100 Connection: Keep-Alive
 Transfer-Encoding: chunked Content-Type: text/html; charset=iso-8859-1

Pour vérifier les headers envoyés par Apache à votre navigateur, il est possible d'utiliser diverses extensions Firefox, comme Live HTTP Headers ou FireBug (Réseau > HTML).

L'encodage peut aussi se vérifier par l'utilisation d'une validation sur le site du W3C : http://validator.w3.org/ , ou encore par votre navigateur (Affichage > Encodage).

Il est important de noter que l'entête HTTP est prioritaire face à la balise HTML meta ! L'encodage au niveau d'Apache peut se spécifier de différente manières, par votre fichier de configuration d'Apache (httpd.conf) ou par fichier .htaccess.

httpd.conf

L'instruction à modifier dans httpd.conf est la suivante : AddDefaultCharset. Afin d'avoir un encodage UTF-8, l'instruction doit être la même que celle ci-dessous :

AddDefaultCharset UTF-8

.htaccess

A condition que la configuration d'apache permette certains AllowOverride, un fichier .htaccess peut être crée, contenant cette information :

 AddDefaultCharset UTF-8

Dans cet exemple, l'encodage sera spécifié en UTF-8 pour tous les fichiers et tous les sous-répertoire contenant le fichier .htaccess.

Autres exemples

Utilisation de FilesMatch dans un fichier .htaccess. Ici un filtre sur les fichiers .htm, .html, .css, .js :

 

<FilesMatch "\.(htm|html|css|js)$">
ForceType 'text/html; charset=UTF-8'
</FilesMatch>

Une autre solution serait :

 

<FilesMatch "\.(htm|html|css|js)$">
AddDefaultCharset UTF-8
</FilesMatch>

Pour spécifier le charset uniquement aux fichiers .html :

 

AddCharset UTF-8 .html

Une autre solution :

 

AddType 'text/html; charset=UTF-8' html

Pour les cas les plus compliqués, vous pouvez créer des fichiers ayant votre propre extension (ici des .utf8), et afficher ceux-ci dans l'encodage de votre choix :

 

AddCharset UTF-8 .utf8
AddCharset windows-1252 .html

Dans ce dernier exemple, les fichiers .html sont encodés en Windows-1252, et les fichiers .utf8 sont encodés en UTF-8.

MySQL

L'UTF-8 est supporté depuis MySQL 4.1.

Nouvelle base

Création d'une base UTF-8 :

CREATE DATABASE MaBDD_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 encodage, de même que chaque colonne. Voici un exemple de création de table :

CREATE TABLE MaTable ( 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';

L'ordre d'importance des CHARSET & COLLATE est la suivante :

  • S'il y a une définition pour un champs, MySQL l'applique ;
  • Sinon il opte pour la définition de la table ;
  • Sinon pour la définition de la base.

Conversion d'une base existante

Une technique existe pour convertir les données d'une base, depuis l'ISO-8859-1 vers l'UTF-8.

Étape 1 : Faire un dump de la BDD.

Étape 2 : Créez une nouvelle base en UTF-8.

Étape 3 : Changez les charset et collate, si vous avez un gros dump cette commande sous Linux peut vous aider :

sed -i 's/CHARSET=latin1/CHARACTER SET utf8 COLLATE utf8_bin/' dump.sql 

Bien sûr remplacez latin1 par les charset actuel de votre structure.

Étape 4 : Convertir le fichier en UTF-8 (étape 2) :

iconv -f ISO8859-1 -t UTF-8 -o dump_encoded.sql dump.sql

Remplacez ISO8859-1 par l'encodage actuel de votre fichier.

Étape 5 : Importez dump_encoded.sql dans votre base en UTF-8.

Script PHP de test

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

<?php

mysql_connect("serveur","login","pass");
mysql_select_db("MaBDD_utf");

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

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

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

$res=mysql_query("select * from Bidule 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 />';

?>

Liens

Internes

Apache

PHP

MySQL

.htaccess

Externes

http://electron-libre.fassnet.net/utf8.php

Sponsors