Nous vous expliquons ci-dessous le contexte des polices de caractères, les problèmes qu’elles entraînent et les solutions.
Soupe aux lettres: bases de données et polices de caractères
L’époque à laquelle les ordinateurs étaient des appareils onéreux et volumineux est révolue. Ce qui, au départ, n’était accessible qu’à une petite élite et uniquement en langue anglaise, est maintenant disponible à tous, dans presque toutes les langues. Cependant, le grand nombre de langues et donc de polices de caractères différant de celles de l’anglais standard de départ, continue de poser problème.
Le présent article décrit comment la base de données MySQL aborde le problème et comment il est possible d’éviter et de résoudre les problèmes liés aux voyelles infléchies et aux caractères spéciaux.
Création et formation des polices de caractères
Au commencement, tout était US-ASCII. Ou presque. Depuis les années 60, les ordinateurs utilisent 8 bits (8 bits = 1 octet) comme plus petite unité d’enregistrement. 8 bits correspondent aux chiffres de 0 à 255. Pour que les ordinateurs puissent représenter des textes, ces chiffres ont été attribués à des caractères d’écriture. Pour assurer la compatibilité entre les différents systèmes utilisés à l’époque, le format ASCII fut standardisé en 1969 : des caractères furent attribués aux 7 premières combinaisons de bits. Le premier codage de caractères, dit « charset » était né (« Character Set » signifiant chaîne de caractères en anglais). Ainsi, le chiffre 65 correspond par exemple à la lettre « A ».
Afin de conserver une possibilité d’ajouter de nouveaux caractères (comme le symbole de l’euro), seule la moitié des 256 caractères fut définie comme US-ASCII. Ces caractères reprenaient l’ensemble de la police de caractères de la langue anglaise. Les symboles, les voyelles infléchies et les caractères spéciaux d’autres langues durent être étendus avec la seconde moitié des 256 caractères. Cependant, étant donné qu’il existe bien plus que 256 caractères dans le monde (évoquons par exemple le chinois), il existe aujourd’hui de nombreuses extensions de ce type pour toutes les langues possibles. Les polices de caractères européennes font partie de la famille ISO-8859. Ce n’est qu’au début des années 90 qu’un concept permettant de répliquer toutes les polices de caractères fut introduit : Unicode. Cependant, aujourd’hui encore, Unicode n’est pas utilisé de manière rigoureuse sur tous les systèmes d’exploitation.
Illustration 1 : Tables de caractères avec exemples issus des polices de caractères ISO-8859-1, ISO-8859-6 et UTF-8
Polices de caractères les plus courantes
Le paragraphe suivant présente un aperçu des polices de caractères les plus courantes pour les langues d’Europe de l’Ouest.
ISO-8859-1 ou latin-1
Cette police de caractères utilise une largeur fixe de 8 bits pour coder les caractères. Les caractères pouvant être codés avec les 7 premiers bits (0–127) correspondent à la police de caractères US-ASCII. La seconde moitié (128–255) comprend les caractères courants en Europe de l’Ouest, en Amérique, en Australie et dans certaines parties de l’Afrique. Elle ne comprend pas le symbole de l’euro.
ISO-8859-15 ou latin-9
Cette police de caractères utilise une largeur fixe de 8 bits pour coder les caractères. Les caractères pouvant être codés avec les 7 premiers bits (0–127) correspondent à la police de caractères US-ASCII. La seconde moitié (128–255) comprend les caractères courants en Europe de l’Ouest, ainsi que le symbole de l’euro, et prend entièrement en charge le français, l’anglais (États-Unis), ainsi que les caractères courants en Australie et dans certaines parties de l’Afrique.
UTF-8
Cette police de caractères fut développée pour pouvoir utiliser une police de caractères commune pour toutes les langues. C’est pourquoi son codage est quelque peu compliqué.
UTF-8 utilise une largeur variable pour l’enregistrement des caractères. US-ASCII est compris dans les 7 premiers bits. Les caractères US-ASCII peuvent donc être enregistrés dans un bit. L’ensemble des autres caractères, tels que les voyelles infléchies, requiert 2 ou plus d’octets (pour 1 octet avec ISO-8859-x).
UTF-8 prend en charge presque tous les caractères utilisés dans le monde.
Problèmes
Grâce ce jeu de caractères de base US-ASCII et aux nombreuses extensions différentes spécifiques à telle ou telle langue, la majorité des caractères existants peuvent maintenant être répliqués. La condition est cependant que la police de caractères dans laquelle le texte a été écrit ait été définie. Si cette information n’est pas disponible, l’ordinateur ne peut pas savoir si le caractère correspondant à 196 correspond à un «Ä» ISO-8859-1 ou à un «?» ISO-8859-6. Les utilisateurs MS-DOS peuvent connaître le problème similaire dans le contexte des cadres de texte d’applications qui ne sont pas toujours affichées comme un cadre, mais également comme un enchevêtrement de lettres carrées. Le même problème se pose avec Unicode: si un texte n’est pas identifiable comme Unicode, un hiéroglyphe composé de deux caractères bizarres (étant donné qu’Unicode enregistre tous les caractères non US-ASCII en 2 ou plus d’octets) remplacera soudainement le caractère «Ä».
Texte de bases de données
Des bases de données peuvent également enregistrer des textes. Dans le cas des pages Web basées sur une base de données, c’est même leur usage premier. Pour résoudre le problème lié à l’enchevêtrement de caractères, les bases de données proposent de définir le « charset » de chaque champ de texte. Cela permet d’entrer et de lire le caractère correct. Illustration:
/*!40101 SET NAMES utf8 */;
CREATE TABLE `user` (
`Id` INT NOT NULL AUTO_INCREMENT,
`User` VARCHAR(255) CHARSET=latin1 NOT NULL default ,
`Occupation` VARCHAR(255) NOT NULL default ,
PRIMARY KEY (`Id`,`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users';
Cette base de données simple stocke trois champs dans une table:
Intitulé du champ | Type | Police de caractères |
---|---|---|
Id | INT (nombre) | aucun (nombre) |
User | VARCHAR (Text) | latin-1 (exclusivment pour ce champ) |
Occupation | VARCHAR (Text) | standard UTF-8 pour cette table |
- Cette table utilise de manière standard UTF-8 comme police de caractères. (DEFAULT CHARSET=utf8 à la dernière ligne.)
- Le champ « User » est cependant enregistré comme latin-1. (CHARSET=latin1 à la 4e ligne.)
- L’ensemble du dump est disponible en UTF-8. (Défini par l’instruction « SET NAMES utf8 » au commentaire, 1religne.)
- Le classement alphabétique (« collation ») définit l’ordre de tri de l’alphabet et non la police de caractères, comme le supposent beaucoup. (COLLATE=utf8_bin sur la dernière ligne.)
Pour ce dump, le champ « User » a été converti de la représentation interne à la base de données en latin-1 vers UTF-8. latin-1 peut être entièrement répliqué en UTF-8. Le champ « User » sera reconverti lors de l’importation du dump d’UTF-8 en latin-1 d’origine.
Accès à des textes dans des bases de données: la bibliothèque de la base de données
Le texte contenu dans des bases de données peut donc être enregistré avec une police de caractères bien définie. Entre la base de données et l’application, une bibliothèque programmes (« client library » ou « library ») transmet et règle l’échange de données.
Illustration 2 : déroulement schématique et interactions des composants d’un site Internet avec base de données.
Cette bibliothèque de programmes peut soit transmettre les données telles qu’elles sont contenues dans la base de données, soit les convertir d’un charset dans un autre (par exemple de latin-1 vers UTF-8). Si le programme qui utilise la bibliothèque ne définit pas le comportement à adopter, vous devez vous attendre à ce qu’il en choisisse un arbitrairement. Si la police de caractères de l’échange de données n’est pas définie, il ne peut être garanti que les textes soient affichés et enregistrés correctement.
La police de caractères utilisée pour la connexion est déterminée dans MySQL avec l’instruction suivante:
/*!40101 SET NAMES utf8 */;
Dans votre code PHP, cela pourrait avoir l’allure suivante:
$DB->query("SET NAMES 'utf8'");
ou encore:
mysql_query("SET NAMES 'utf8'",$connection);
L’application Web
Si le processus de la base de données via la « library » a eu lieu avec la police de caractères correcte jusqu’ici, l’application Web doit transmettre les données au navigateur avec le charset correct. La police de caractères utilisée dans l’HTML généré doit être déclarée dans l’en-tête HTML par méta-tag ou dans l’en-tête HTTP lors de la transmission des données. Ici aussi, une déclaration erronée entraîne un problème de jeux de caractères avec tous les caractères non US-ASCII, tels que les voyelles infléchies.
Définir la police de caractères dans l’en-tête HTTP
Généralement, le charset est indiqué dans l’en-tête HTTP lors du transfert de données. UTF-8 est défini comme charset avec l’en-tête HTTP suivant:
Content-Type: text/html; charset=utf-8
Dans votre application PHP, le code PHP apparaît comme suit pour la définition:
header('Content-Type: text/html; charset=utf-8');
Définir le charset en HTML
Le charset peut également être directement défini en HTML par méta-tag http-equiv. Le code HTML est alors le suivant:
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-15">
</head>
Définition du charset de formulaires
Inversement, le charset accepté doit être clairement défini lors de la transmission de textes de formulaires vers votre application. Si ce n’est pas le cas, le texte envoyé par le navigateur peut avoir n’importe quelle police de caractères. Dans ce cas, si votre application Web n’analyse pas minutieusement, voire ne convertit pas les caractères, l’affichage de la chaîne de caractères dans la base de données, dans le charset de la base de données, est une pure question de chance.
Exemple de formulaire assorti d’un charset précisément défini pour les champs de texte:
<form action="action.php" accept-charset="ISO-8859-15">
Name: <input type="text" name="name" />
Nachname: <input type="text" name="nachname" />
<input type="submit" value="Senden!" />
</form>
Cas d’erreur
Les variantes produisant des problèmes au niveau des polices de caractères sont pour ainsi dire inépuisables. On distingue cependant les trois catégories suivantes:
La police de caractères déclarée ne correspond pas à la police de caractères réelle
Ce type de données survient par exemple dans la base de données lorsqu’un navigateur transmet comme UTF-8 les données d’un champ de texte dans un formulaire en raison d’une instruction accept-charset="ISO-8859-15" manquante et que l’application enregistre les données sans les contrôler dans un champ de texte déclaré latin-1 de la base de données. Cela fonctionne tant que le charset de la connexion de la base de données reste le même. Si celui-ci n’est pas défini, des problèmes peuvent survenir lors d’un changement de fournisseur de services, de version de base de données ou de mise à jour du serveur.
Les données sont converties deux fois ou de manière erronée
Les données de texte issues d’un formulaire sont transmises au format UTF-8 (comme défini en HTML) dans la police de caractères et doivent être enregistrées dans un champ déclaré UTF-8 dans la base de données. Cependant, aucun charset contenant SET NAMES ou un charset erroné n’a été défini lors de la connexion à la base de données. Ainsi, les caractères UTF-8 d’une autre police de caractères sont reconvertis en une autre police de caractères UTF-8. Dans le pire des cas, l’ensemble des caractères non US-ASCII est détruit.
Cela peut également survenir à la sortie de textes de la base de données : des textes UTF-8 sont enregistrés par erreur dans une base de données déclarée latin-1. Lorsque la connexion de la base de données est configurée de telle manière que l’ensemble des textes en UTF-8 soit livré, la bibliothèque tente de reconvertir le texte prétendument latin-1 en UTF-8. Dans ce cas également, nous sommes confrontés à un enchevêtrement de caractères.
Le charset d’affichage des données dans le navigateur n’est pas défini ou est mal défini
L’erreur la plus simple à corriger. Les données sont enregistrées et lues avec un charset toujours défini, mais le charset utilisé n’est pas défini dans l’en-tête HTTP ou HTML. Dans ce cas, la plupart des navigateurs tentent de deviner le charset avec plus ou moins de succès. Étant donné que les données dans l’application et dans la base de données sont enregistrées de manière cohérente, ce problème peut être résolu avec une instruction PHP ou HTML simple (voir ci-dessus).
Récapitulatif: meilleures pratiques
Pour résumer, les directives suivantes permettent une utilisation des bases de données exempte de problèmes liés aux polices de caractères:
- Déclarez une police de caractères pour chaque champ de texte, chaque table ou chaque base de données ! Aucun champ de texte ne doit rester sans définition du charset.
- Déclarez la police de caractères pour chaque connexion MySQL avec SET NAMES.
- Déclarez le charset de vos pages par l’en-tête HTTP ou HTML.
- Déclarez pour chaque formulaire les polices de caractères acceptées. Soyez cependant avertis qu’un navigateur peut tout de même envoyer les données avec une police de caractères erronée.
- Veillez à ce qu’une seule police de caractères soit indiquée avec SET NAMES, tant pour l’importation que pour la création d’un dump.
Résolution des problèmes: lorsque le mal est fait
Pour tenter de résoudre tout problème, il convient de l’analyser : vous devez savoir à quelle erreur vous faites face dans votre application ou dans les données de la base de données. Si l’erreur ne se présente qu’en un seul des endroits possibles, procédez comme suit, en respectant l’ordre des étapes, pour trouver et résoudre le problème.
Le navigateur utilise un charset erroné
Contrôlez d’abord si votre navigateur choisit le bon charset. La plupart des navigateurs permettent de visualiser le charset utilisé et de le modifier manuellement. Le charset est le bon ? Pour les pages Web européennes, les charsets de la famille ISO-8859, et notamment ISO-8859-1, ISO-8859-15 et UTF-8, sont courants et judicieux.
Illustration 3 : présentation du site Internet Hostpoint avec un charset erroné : ISO-8859-1 (latin-1) au lieu d’UTF-8.
Illustration 4 : présentation du site Internet Hostpoint avec le bon charset : UTF-8.
Si, au lieu des voyelles infléchies, aucun caractère ou des caractères ressemblant à des virgules sont utilisés, il s’agit probablement du cas contraire: les caractères des polices ISO-8859 sont représentés comme UTF-8.
Solution: assurez-vous que le charset correct est indiqué dans l’en-tête HTTP et dans le code HTML.
Pour envoyer une demande d'assistance au support, merci d'utiliser ce formulaire-ci.