htmlentities() ne suffit pas

Mammouth du PHP | 2937 Messages

18 juil. 2006, 20:56

Salut à tous!

Afin que les caractères spéciaux contenus dans une chaîne de caractères soient correctement interprétés par les navigateurs, on recourt à la fonction htmlentities(), qui les convertit dans le code HTML correspondant (ce qui permet, soit dit en passant, de coder conformément aux standards).

Or, cette fonction pèche par insuffisance, en ce sens que certains caractères spéciaux ne sont pas convertis et demeurent affichés tels quels dans le code de la page. Ces caractères spéciaux "récalcitrants" sont ceux dont le code ISO est inférieur à 160 (code correspondant à l'espace insécable  ), parmi lesquels deux caractères que nous, développeurs francophones, sommes appelés à utiliser: "Œ" et "œ", sans compter le symbole euro "€".

La solution que je propose consiste à créer une fonction qui complète htmlentities() en palliant ses insuffisances.
<?php 
function encodage_html($chaine){
  // Utilisation de la fonction htmlentities() pour convertir les caractères spéciaux qu'elle peut faire
  $chaine=htmlentities($chaine);
  // Création d'un tableau groupant les caractères spéciaux problématiques (j'en ai sélectionné 20, mais d'autres peuvent compléter ce tableau)
  $caracteres_non_codes=array('Œ', 'œ', 'Ÿ', '–', '—', '‘', '’', '‚', '“', '”', '„', '†', '‡', '•', '…', '‰', '‹', '›', '€', '™');
  // Création d'un autre tableau groupant les codes HTML respectifs de ces caractères
  $caracteres_codes=array('&OElig;', '&oelig;', '&Yuml;', '&ndash;', '&mdash;', '&lsquo;', '&rsquo;', '&sbquo;', '&ldquo;', '&rdquo;', '&bdquo;', '&dagger;', '&Dagger;', '&bull;', '&hellip;', '&permil;', '&lsaquo;', '&rsaquo;', '&euro;', '&trade;');
  // On remplace les valeurs du premier tableau par ceux du second avec la fonction str_replace()
  $encodage_html=str_replace($caracteres_non_codes, $caracteres_codes, $chaine);
  // On retourne le résultat
  return $encodage_html;
}
?>
Un exemple montrant la différence entre une chaîne non convertie, convertie avec htmlentities() seule et convertie avec la fonction créée.
<?php 
$phrase='Quand je fais du PHP, je n’écoute que mon cœur…'; // La phrase se finit par de vrais points de suspension, ceux qu'affiche automatiquement Word

echo $phrase; // Affiche dans le code source de la page 'Quand je fais du PHP, je n’écoute que mon cœur…'

echo htmlentities($phrase); // Affiche dans le code source de la page 'Quand je fais du PHP, je n’&eacute;coute que mon cœur…'

echo encodage_html($phrase); // Affiche dans le code source de la page 'Quand je fais du PHP, je n&rsquo;&eacute;coute que mon c&oelig;ur&hellip;'
?>
Voyez-vous la différence? :wink:

Cela est valable avec l'encodage de caractères par défaut (iso-8859-1). Il est possible qu'il n'en soit pas de même avec d'autres encodages (iso-8859-15, utf-8, etc.).

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

19 juil. 2006, 06:11

Il est possible qu'il n'en soit pas de même avec d'autres encodages (iso-8859-15, utf-8, etc.).
Si mes souvenirs sont bons, iso-8859-1 ne possède ni le symbole euro ni la ligature "oe", donc ce que tu as posté est soit cp1252 soit iso-8559-15. La confusion est courante car dans la pratique, les navigateurs mélangent un peu les trois.

Je confirme que ça ne peut pas fonctionner en UTF-8 (ça corromprait la chaîne). Il existe des fonctions similaires qui fonctionne en UTF-8 pour encoder/décoder les caractères non-ASCII en entités dans la prochaine version de phpBB. Voici le fichier en question : utf_tools.php (cliquez sur le premier lien "download")