Accueil du Forum  >>  Programmation php et html  >>  passage en UTF-8

Sujet n°17 : passage en UTF-8 - par monTdM le 23/08/2016 à 00h33, lu 51 fois
Pour ce second sujet de la catégorie 'programmation', je tiens à vous parler de la difficulté pour passer son site en UTF-8 et des démarches indispensables à faire avant de lancer la procédure.

Comme la plupart des gens utilisant le français comme langue principale, vous avez probablement commencé votre site en utilisant l'encodage ISO-8859-1. Et, souhaitant répondre aux normes de l'html5, vous vous dites un jour que passer en encodage UTF-8 est devenu indispensable.

Toutes vos pages actuelles contiennent un magnifique :

Code

<meta charset="iso-8859-1">


ou son équivalent un peu plus ancien dans le style :

Code

<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">


ou encore son équivalent avec la fonction php header() :

Code

header("Content-type: text/html; charset=iso-8859-1");


voire votre fichier .htaccess contient une ligne :

Code

AddDefaultCharset iso-8859-1



Donc aucune hésitation, vous foncez sur la fonction php adéquate 'utf8_encode($str)' dédiée spécifiquement au basculement des chaînes de caractères en encodage ISO-8859-1 vers l'encodage UTF-8.

Et là catastrophe. Vous vous retrouvez dans vos fichiers avec une multitude de caractéres
ST
, de caractères
PAD
et j'en passe qui, à l'affichage ne donnent rien : et on ne comprend plus rien à vos si passionnants récits. Sans parler du fait que toutes vos images sont à jeter à la poubelle car tous vos fichiers gif, png, jpg et autres ont été aussi transformés, ajoutant ainsi plein de bruits parasites à vos splendides images !!

Pourquoi ces caractères sont-ils là ? Très simple mais difficile à admettre : malgré vos précieuses déclarations dans vos balises meta et dans votre fichier .htaccess, vos pages ne sont pas en ISO-8859-1 !

Vous allez me répondre : "Bien sûr que si ! Cela fait 5 ans que je programme mon site ainsi, je sais ce que je fais quand même !"

Sauf que comme tout le monde vous utilisez des éditeurs de texte, comme tout le monde vous utilisez des correcteurs orthographiques et comme tout le monde vous avez dans vos textes une multitude de oe (e dans l'o séparés) qui sont devenus des œ (e dans l'o accolés), que vous avez à un moment ou un autre parlé d'argent en mettant de magnifiques signes .

Oui mais le e dans l'o accolés et l'euro n'existent pas en ISO-8859-1 !! Ce que vous pouvez facilement vérifier sur cette page.

Et pourtant vos caractères spéciaux sont bien là, ils s'affichent impeccablement sur votre site. Pourquoi ? Parce que les navigateurs ne vous croient pas quand vous leur dites que votre page est en ISO-8859-1 et qu'ils ont bien compris, eux, comment vous avez rédigé vos textes : en utilisant l'encodage ANSI, un terme qu'on retrouve dans la plupart des éditeurs de texte pour parler de l'encodage windows-1252.

Conséquence, il ne faut surtout pas utiliser la fonction php 'utf8_encode($str)' mais la fonction 'mb_convert_encoding($str, "UTF-8", "Windows-1252")' qui va transformer la chaîne de caractères $str de l'encodage windows-1252 vers l'encodage utf-8.

****************************************

Après cette introduction j'espère instructive, voici les étapes que je vous suggère pour passer tranquillement ou presque en encodage UTF-8.

1ère étape :

- faites une recherche dans tous vos fichiers des lignes où apparait 'iso-8859-1'
- remplacez ce terme par une variable php et insérer juste avant un 'include()' pointant vers un unique fichier contenant cette variable
- donnez à cette variable la bonne valeur : windows-1252 !
- les fonctions php manipulant les chaînes de caractères, type strlen, strpos, substr ou strtolower ne fonctionnent pas toujours bien avec utf-8 et il est préférable de les transformer en mb_strlen, mb_strpos, mb_substr, mb_strtolower, etc. Il serait mieux de faire le changement dès cette étape car cela ne changera pas le fonctionnement en encodage windows-1252 et lorsque vous passerez vos fichiers en utf-8 tout sera impeccable. Le problème est qu'il y a énormément de fonctions manipulant les chaînes (une liste est diponible sur le site de php.net) et le basculement serait très long. De plus dans beaucoup de cas ce n'est pas nécessaire si vos manipulations de chaînes ne concernent pas des caractères spéciaux (remplacer un espace par la chaîne %20 par exemple). Je vous conseillerais donc de traiter uniquement les fonctions strtolower et strtoupper qui ne fonctionnent pas bien avec les accents et de reporter à plus tard les autres fonctions, vous les traiterez au cas par cas.
- ajouter cependant au début des pages php les instructions 'mb_internal_encoding("windows-1252");' et 'mb_regex_encoding("windows-1252");' nécessaires pour le bon fonctionnement des fonctions mb_ (le mieux étant de les inclure directement dans votre fichier où vous avez défini votre charset)

2de étape :

Vous trouverez ci-dessous un exemple de programme php pour vous aider à transformer vos pages en utf-8 :

Code

<!DOCTYPE html>
<html>
<head>
<title>ANSI vers UTF-8</title>
<meta charset="windows-1252">
</head>

<body>
<?php
$tt_ext = array();
$nbfichfait = 0;

function ValUnique($tableau)
{
  $tabtmp = array();
  for ($i = 0, $nbi = count($tableau); $i < $nbi; $i++)
    $tabtmp[$tableau[$i]] = "";
  $tabres = array();
  foreach ($tabtmp as $v => $val) $tabres[] = $v;
  return $tabres;
}

function ansi_vers_utf($dir) {
  global $tt_ext, $nbfichfait;
  echo "<br><div style=\"font-size:1.5em\">encodage du dossier ".($dir == "./" ? "racine" : substr($dir,2))." :</div>";
  $rep = array();
  if ($dossier = opendir($dir)) {
    while (false !== ($fichier = readdir($dossier))) {
      if ($fichier != "." && $fichier != "..") {
        if (is_file($dir.$fichier)) {
          $ext = strtolower(pathinfo($fichier, PATHINFO_EXTENSION));
          if ($ext == "php" || $ext == "htaccess" || $ext == "css" || $ext == "js" || $ext == "html" || $ext == "htm" || $ext == "txt") {
            $contenu = file_get_contents($dir.$fichier);
            $encodage = mb_detect_encoding($contenu, "UTF-8, Windows-1252, ISO-8859-1");
            if ($encodage != "UTF-8") {
              /*$heure = filemtime($dir.$fichier);
              $fic = fopen($dir.$fichier, 'w');
              $contenu = mb_convert_encoding($contenu, "UTF-8", "Windows-1252");
              fputs($fic, $contenu);
              fclose($fic);
              touch($dir.$fichier, $heure);*/

              $nbfichfait++;
              echo "<div style=\"padding-left:10px\"><span style=\"color:#0A0\">".$fichier." fait</span></div>";
            }
            else echo "<div style=\"color:#00F;padding-left:10px\">".$fichier." n'a pas été encodé car est déjà en UTF-8</div>";
          } else {
            echo "<div style=\"padding-left:10px\">".$fichier." n'a pas été encodé car a une extension incompatible : ";
            echo "<span style=\"color:red\">".$ext."</span></div>";

            $tt_ext[] = $ext;
          }
        } else $rep[] = $dir.$fichier."/";
      }
    }
    closedir($dossier);
  }
  natcasesort($rep);
  $rep = array_values($rep);
  while ($rep != null) ansi_vers_utf(array_shift($rep));
}

ansi_vers_utf("./");
$tt_ext = ValUnique($tt_ext);
natcasesort($tt_ext);
$tt_ext = array_values($tt_ext);
$nbi = count($tt_ext);
echo "<br><div style=\"font-size:1.5em\">synthèse des extensions non traitées (".$nbi.") :</div>";
for ($i=0;$i<$nbi;$i++) echo ".".($tt_ext[$i] != "" ? $tt_ext[$i] : "&nbsp;&nbsp;&nbsp;")." ";

echo "<br><br><div style=\"font-size:1.5em\">".$nbfichfait." fichier".($nbfichfait > 1 ? "s ont été traités" : " a été traité")."</div>";
?>
</body>
</html>


Explications (lignes jaunes et vertes) :

- la variable $tt_ext est un tableau qui contiendra toutes les extensions de fichiers qui n'ont pas été encodés (voir plus loin pour plus de détails)
- la variable $nbfichfait contiendra le nombre de fichiers qui ont été encodés
- la fonction ValUnique() est une fonction qui ne conserve qu'un élément des doublons ou plus que vous avez dans un tableau. Par exemple si vous avez un tableau avec 7 éléments : array('toto', 'tata', 'titi', 'toto', 'titi', 'tutu', 'toto') le résultat sera un tableau avec seulement 4 éléments : array('toto', 'tata', 'titi', 'tutu'), les doublons 'titi' et le triple 'toto' sont devenus uniques
- la fonction ansi_vers_utf est bien sûr le centre ce code. Sans entrer dans les détails :
- à la fin de l'exécution, une synthèse des extensions de fichiers non traitées est indiquée. Au cours de l'exécution, tous les fichiers qui avaient une de ses extensions ont été mis en évidence en affichant l'extension en rouge
- remarquez également que je n'ai pas utilisé les fonctions en mb_ dans ce programme car inutiles dans le cas présent : comme déjà expliqué, ces fonctions sont nécessaires pour travailler correctement des chaînes contenant des caractères spéciaux, les utilisations que je fais ici ne les rendent pas indispensables

Procédure :

- le programme est prévu pour traiter tous les fichiers du répertoire où il se trouve ainsi que les sous-répertoires grâce aux deux lignes oranges. Si vous supprimez (ou transformez en commentaire) la première ligne, seul le répertoire courant sera traité. Si vous modifiez la seconde ligne sans toucher à la première, le programme démarrera dans le répertoire que vous aurez mis dans la seconde ligne et traitera également les sous-répertoires.
- lancez une première fois le programme tel quel. Il ne fera aucun encodage du fait de la zone en vert. Lorsqu'il aura terminé, verifiez tout en bas de la page quelles sont les extensions qui n'ont pas été traitées
- ajustez alors la première ligne jaune à l'intérieur de la fonction ansi_vers_utf en ajoutant (et éventuellemnt enlevant) les extensions qui doivent être finalement encodées : vous seul connaissez comment vous avez construit votre site et vous seul pouvez ajuster mon code pour qu'il corresponde parfaitement à vos besoins
- quand vous vous sentirez près, je vous recommande de faire une copie d'un des répertoires en un endroit sûr, d'ajuster les lignes oranges pour que le programme ne traite que ce répertoire, de lancer une dernière fois à vide le programme avant d'enlever les marques de commentaires entourant la zone verte. L'idéal est évidemment de traiter des fichiers contenant des caractères avec accent, des e dans l'o accolés, des €, etc. Ouvrez alors ces fichiers avec votre éditeur de texte préféré et vérifiez qu'ils sont bien indiqués en encodage UTF-8 et que tous les caractères spéciaux ont bien été conservés
- une fois rassuré, traitez tous les répertoires de votre site

3ème étape :

- changer les balises meta de toutes vos pages en modifiant uniquement le contenu de la variable créée à l'étape 1
- changer votre fichier .htaccess en remplaçant l'encodage (la ligne n'est pas indispensable la plupart du temps mais si vous testez votre site avec le validator html5 l'absence de ligne entraînerait une erreur)
- changer vos mb_internal_encoding("windows-1252"); en mb_internal_encoding("utf-8"); et vos mb_regex_encoding("windows-1252"); et mb_regex_encoding("utf-8");

3 cas particuliers à traiter :

Le premier cas est l'envoi d'e-mail à partir de votre site, si cela vous concerne. La fonction php 'mail' nécessite des caractéristiques d'encodage qu'il a fallu que vous preniez en compte lorsque votre site était en windows-1252. Le passage en utf-8 implique que vous devez faire des ajustements pour éviter que vos destinataires reçoivent des caractères étranges.

Le second cas est plus complexe, il s'agit de la gestion des répertoires et fichiers (création, suppression, téléchargement) si vous utilisez (ou voulez utiliser) des accents dans leur nom. Si vous avez un simulateur apache/php sur votre ordinateur fonctionnant sous windows (type wampserver), les répertoires/fichiers sont en encodage windows-1252 alors que ceux sur le serveur de votre hébergeur sont probablement en utf-8. En conséquence la gestion sur votre PC et sur votre site est différente et les caractères accentués dans vos fichiers/répertoires ne fonctionneront pas sur l'un ou sur l'autre si vous ne différenciez pas le code. Je vous conseille donc de créer une variable :

Code

$repwindows = strpos($_SERVER["SERVER_NAME"], "localhost") !== false;


qui vaudra true sur votre ordinateur et false sur votre site. Puis de dédoubler vos variables répertoires et fichiers, par exemple $rep + $reputf et $fic + $ficutf. Les variables $...utf seront utilisées à l'identique sur votre ordinateur et votre site pour l'affichage, les liens, les valeurs des balises input etc. Les variables sans utf seront utilisées pour la gestion des fichiers et répertoires dans les fonctions adéquates (chmod, is_dir, rmdir, mkdir, is_file, filesize, readfile, filemtime, copy, touch, unlink, move_uploaded_file, etc) en convertissant les répertoires/fichiers utf-8 en répertoires/fichiers windows-1252 avec les fonctions mb_convert_encoding($..., "Windows-1252", "UTF-8") mais uniquement quand la variable $repwindows vaut true (c'est-à-dire sur votre ordinateur). Je ne rentre pas dans le détail mais c'est assez complexe et long à mettre en œuvre.

Le troisième cas est la gestion des bases de données sql. Il vous faudra probablement faire des ajustements mais je ne connais pas le problème car je n'ai pas de base donc je ne peux pas vous aider sur ce point.

Bon courage et n'hésitez pas à laisser vos commentaires.

[ Retour à la liste des sujets ]

upHautup


Site propulsé par GuppY - © 2004-2011 - Licence Libre CeCILL
Document généré en 5.986 secondes