Résoudre les problèmes d'encodage

Parent Previous Next


Résoudre les problèmes d'encodage



Avant de commencer, disons-le purement et simplement : vous allez détester cette sous-partie ! Pourquoi ? Tout simplement parce que nous allons aborder un problème qui gêne un grand nombre d'apprentis développeurs Web : l'encodage des caractères. Nous allons toutefois essayer d'aborder la chose de la manière la plus efficace possible afin que vous n'ayez pas trop de mal à comprendre le problème.


L'encodage pour les nuls

Nombreux sont les développeurs débutants qui préfèrent ignorer le principe de l'encodage des caractères, car le sujet est un peu difficile à assimiler. Nous allons ici l'étudier afin que vous puissiez comprendre pourquoi vous allez un jour ou l'autre rencontrer des erreurs assez étranges avec l'AJAX. Tout d'abord, qu'est-ce que l'encodage des caractères ?


Il s'agit d'une manière de représenter les caractères en informatique. Lorsque vous tapez un caractère sur votre ordinateur, il est enregistré au format binaire dans la mémoire de l'ordinateur. Ce format binaire est un code qui représente votre caractère, ce code ne représente qu'un seul caractère, mais peut très bien désigner des caractères très différents selon les normes utilisées.


Si vous êtes intéressés par l'étude de l'encodage des caractères, nous vous conseillons de jeter un coup d’œil à l'article sur Wikipédia, qui explique plutôt bien le concept et l'histoire des normes d'encodage.


Une histoire de normes


Comme vous l'avez compris, chaque caractère est représenté par un code binaire, qui n'est au final qu'un simple nombre. Ainsi, lorsque l'informatique a fait ses débuts, il a fallu attribuer un nombre à chaque caractère utilisé, ce qui donna naissance à la norme ASCII. Cette norme n'était pas mal pour un début, mais était codée sur seulement 7 bits, ce qui limitait le nombre de caractères représentables par cette norme à 128. Alors, dit comme ça, cela peut paraître suffisant pour notre alphabet de 26 lettres, mais que fait-on des autres caractères, comme les caractères accentués ? En effet, ces trois lettres sont bien trois caractères différents : eéè. Tout ça sans compter les différents caractères comme les multiples points de ponctuation, les tirets, etc. Bref, tout ça fait que la norme ASCII pouvait convenir pour un américain, mais de nombreuses autres langues que l'anglais ne pouvaient pas s'en servir en raison de son manque de « place ».


La solution à ce problème s'est alors imposée avec l'arrivée des normes ISO 8859. Le principe est simple, la norme ASCII utilisait 7 bits, alors que l'informatique de nos jours stocke les informations par octets ; or 1 octet équivaut à 8 bits, ce qui fait qu'il reste 1 bit non utilisé. Les normes ISO 8859 ont pour but de l'exploiter afin de rajouter les caractères nécessaires à d'autres langues. Cependant, il n'est pas possible de stocker tous les caractères de toutes les langues dans seulement 8 bits (qui ne font que 256 caractères après tout), c’est pourquoi il est écrit « les normes 8859 » : il existe une norme 8859 (voire plusieurs) pour chaque langue. Pour information, la norme française est l'ISO 8859-1.


Avec ces normes, n'importe qui peut maintenant rédiger un document dans sa langue maternelle. Les normes sont encore utilisées de nos jours et rendent de fiers services. Cependant, il y a un problème majeur ! Comment faire pour utiliser deux langues radicalement différentes (le français et le japonais, par exemple) dans un même document ? Une solution serait de créer une nouvelle norme utilisant plus de bits afin d'y stocker tous les caractères existants dans le monde, mais il y a un défaut majeur : en passant à plus de 8 bits, le stockage d'un seul caractère ne se fait plus sur 1 octet mais sur 2, ce qui multiplie le poids des fichiers textes par deux, et c'est absolument inconcevable !


La solution se nomme UTF-8. Cette norme est très particulière, dans le sens où elle stocke les caractères sur un nombre variable de bits. Autrement dit, un caractère classique, comme la lettre A, sera stocké sur 8 bits (1 octet donc), mais un caractère plus exotique comme le A en japonais () est stocké sur 24 bits (3 octets), le maximum de bits utilisables par l'UTF-8 étant 32, soit 4 octets. En clair, l'UTF-8 est une norme qui sait s'adapter aux différentes langues et est probablement la norme d'encodage la plus aboutie de notre époque.


Pour information, si vous avez été capables de lire le caractère japonais , c'est parce que le Site du Zéro utilise l'UTF-8 comme norme d'encodage. Et cela se voit bien, car vous lisez ici du français et pourtant il y a aussi un caractère japonais affiché, le tout sur la même page.


L'encodage et le développement Web


Comprendre l'encodage des caractères est une chose, mais savoir s'en servir en est une autre. Nous allons faire simple et rapide, et étudier quelles sont les étapes pour bien définir son encodage des caractères sur le Web.


Le monde du Web est stupide, il faut spécifier quel est l'encodage que vous souhaitez utiliser pour vos fichiers, alors que les navigateurs pourraient le détecter d'eux-mêmes. Prenons l'exemple d'un fichier PHP contenant du HTML et listons les différentes manières pour définir le bon encodage sur la machine du client :


Bref, beaucoup de manières de faire pour pas grand-chose, un bon paramétrage du serveur HTTP (Apache dans notre cas) est généralement suffisant, à condition d'avoir des fichiers encodés avec la norme spécifiée par le serveur, bien sûr.


Alors, pourquoi vous avoir montré ça ? Parce que vous risquez d'avoir des problèmes d'encodage avec l'AJAX et que ce petit récapitulatif des manières de faire pour la spécification d'un encodage pourra sûrement vous aider à les résoudre.


Attention à une chose ! Dans votre éditeur de texte, lorsque vous voudrez spécifier l'encodage, il se peut que vous ayez deux types d'encodage UTF-8 proposés : un nommé « UTF-8 avec BOM », et l'autre nommé « UTF-8 sans BOM ».


Utilisez en permanence l'encodage sans BOM !


Le BOM est une indication de l'ordre des octets qui est ajoutée au tout début du fichier, ce qui fait que, si vous souhaitez appeler la fonction header() en PHP, vous ne pourrez pas, car des caractères auront déjà été envoyés, en l’occurrence les caractères concernant le BOM.


L'AJAX et l'encodage des caractères


Enfin nous y sommes ! Entrons dans le vif du sujet et voyons ce qui ne va pas !


Le problème


Eh oui, il n'y a qu'un seul problème, mais il est de taille, bien que facile à régler une fois que l'on a bien compris le concept. Le voici : lorsque vous faites une requête AJAX, toutes les données sont envoyées avec un encodage UTF-8, quel que soit l'encodage du fichier HTML qui contient le script pour la requête AJAX !


Mais en quoi est-ce un problème ?


Eh bien, cela pose problème si vous travaillez autrement qu'en UTF-8 côté serveur. Car si le fichier PHP appelé par la requête AJAX est encodé, par exemple, en ISO 8859-1, alors il se doit de travailler avec des données ayant le même encodage, ce que ne fournira pas une requête AJAX.


Concrètement, quel problème cela pose-t-il ? Le serveur tombe en rade ?


Non, loin de là ! Mais vous allez vous retrouver avec des caractères étranges en lieu et place de certains caractères situés dans le texte d'origine, tout particulièrement pour les caractères accentués.


Comme vous le savez, l'ISO 8859-1 n'utilise que 8 bits pour l'encodage des caractères, tandis que l'UTF-8 peut aller jusqu'à 32. À première vue, ces deux normes n'ont aucune ressemblance, et pourtant si ! Leurs 7 premiers bits respectifs assignent les mêmes valeurs aux caractères concernés, ainsi la lettre A est représentée par ces 7 bits quelle que soit la norme utilisée, celle de l'ISO ou l'UTF-8 : 100 0001.


La différence se situe en fait pour les caractères que l'on va qualifier « d'exotiques », comme les caractères accentués. Ainsi, un e avec accent circonflexe (ê) a la valeur binaire suivante en ISO 8859-1 : 1110 1010, ce qui en UTF-8 équivaut à un caractère impossible à afficher. Bref, pas très pratique.


Mais les choses se corsent encore plus lorsque la conversion est faite depuis l'UTF-8 vers une autre norme, comme l'ISO 8859-1, car l'UTF-8 utilisera parfois 2 octets (voire plus) pour stocker un seul caractère, ce que les autres normes interprèteront comme étant deux caractères. Par exemple, la même lettre ê encodée en UTF-8 donne le code binaire suivant : 1100 0011 1010 1010. L'ISO 8859-1 va y voir 2 octets puisqu'il y a 16 bits, la première séquence de 8 bits (1100 0011) va donc être traduite avec le caractère Ã, et la deuxième séquence (1010 1010) avec ª.


Bref, tout cela signifie que si votre fichier HTML client est en ISO 8859-1 et qu'il envoie par l'AJAX le caractère ê à une page PHP encodée elle aussi en ISO 8859-1, alors les données qui seront lues par le serveur seront les suivantes : Ãª.


Comprendre la démarche de l'AJAX


Afin que vous compreniez encore mieux le problème posé par l'AJAX, il est bon de savoir quelles sont les étapes d'encodage d'une requête avec des fichiers en ISO 8859-1 (que nous allons abréger ISO) :


Ces trois points doivent vous faire comprendre qu'une requête AJAX n'opère en UTF-8 que lors de l'envoi des données, le problème d'encodage ne survient donc que lorsque les données sont réceptionnées par le serveur, et non pas quand le client reçoit les données renvoyées par le serveur.


Deux solutions


Il existe deux solutions pour éviter ce problème d'encodage sur vos requêtes AJAX.

La première, qui est de loin la plus simple et la plus pérenne, consiste à ce que votre site soit entièrement encodé en UTF-8, comme ça les requêtes AJAX envoient des données en UTF-8 qui seront reçues par un serveur demandant à traiter de l'UTF-8, donc sans aucun problème. Un site en UTF-8 implique que tous vos fichiers textes soient encodés en UTF-8, que le serveur indique au client le bon encodage, et que vos ressources externes, comme les bases de données, soient aussi en UTF-8.


Cette solution est vraiment la meilleure dans tous les sens du terme, mais est difficile à mettre en place sur un projet Web déjà bien entamé. Si vous souhaitez vous y mettre (et c'est même fortement conseillé), nous vous conseillons de lire le cours « Passer du latin1 à l'unicode » écrit par vyk12 sur le Site du Zéro.


La deuxième solution, encore bien souvent rencontrée, est plus adaptée si votre projet est déjà bien entamé et que vous ne pouvez vous permettre de faire une conversion complète de son encodage. Il s'agit de décoder les caractères reçus par le biais d'une requête AJAX avec la fonction PHP utf8_decode().


Admettons que vous envoyiez une requête AJAX à la page suivante :

<?php

 

  header('Content-Type: text/plain; charset=iso-8859-1'); // On précise bien qu'il s'agit d'une page en ISO 8859-1

 

  echo $_GET['parameter'];

 

?>


Si la requête AJAX envoie en paramètre la chaîne de caractères « Drôle de tête », le serveur va alors vous renvoyer ceci :

Drôle de tête


La solution consiste donc à décoder l'UTF-8 reçu pour le convertir en ISO 8859-1, la fonction utf8_decode()intervient donc ici :

<?php

 

  header('Content-Type: text/plain; charset=iso-8859-1'); // On précise bien qu'il s'agit d'une page en ISO 8859-1

 

  echo utf8_decode($_GET['parameter']);

 

?>


Et là, aucun problème :

Drôle de tête


Et quand je renvoie les données du serveur au client, je dois encoder les données en UTF-8 ?


Absolument pas, car l'AJAX applique une conversion UTF-8 uniquement à l'envoi des données, comme étudié un peu plus haut. Donc si vous affichez des données en ISO 8859-1, elles arriveront chez le client avec le même encodage.

Si vous travaillez dans un encodage autre que l'ISO 8859-1, utilisez alors la fonction mb_convert_encoding().


Créé avec HelpNDoc Personal Edition: Générateur d'aide complet

Site à deux balles