6 votes

Comment substituer des caractères non SGML dans une chaîne de caractères en utilisant PHP ?

J'ai programmé un livre d'or en utilisant PHP4 et HTML 4.01 (avec le charset ISO-8859-15, c'est-à-dire latin-9). Les données sont sauvegardées dans une base de données MySQL avec le charset (ISO-8859-1, c'est-à-dire latin-1).

Lorsque quelqu'un saisit des caractères d'un jeu de caractères différent, il semble que les navigateurs envoient les données encodées (en fait, je n'ai pas vérifié où elles sont encodées, ...).

Quoi qu'il en soit, dans certains cas, il semble que les caractères ne soient pas sauvegardés encodés dans la base de données. Ainsi, le validateur renvoie un message d'erreur lorsque j'ajoute l'affichage des données dans un document HTML4.01 :

numéro de caractère non SGML 146

Vous avez utilisé un caractère illégal dans votre texte. HTML utilise le répertoire de caractères standard du Consortium UNICODE, et il laisse non définis (entre autres) 65 codes de caractères (de 0 à 31 inclus et de 127 à 159 inclus) qui sont parfois utilisés pour les guillemets typographiques et similaires dans les jeux de caractères propriétaires. Le validateur a trouvé un de ces caractères non définis dans votre document. Le peut apparaître sur votre navigateur sous la forme d'un guillemet frisé, ou d'un symbole de marque déposée ou un symbole de marque, ou tout autre glyphe fantaisiste ; sur un autre ordinateur, cependant, il apparaîtra probablement comme une virgule, il apparaîtra probablement sous la forme d'un caractère complètement différent, ou rien du tout. rien du tout.

Le mieux est de remplacer le caractère par son équivalent le plus proche ASCII le plus proche, ou d'utiliser une entité de caractères appropriée. Pour plus d'informations informations sur le codage des caractères sur le web, voir l'ouvrage d'Alan Flavell, intitulé d'Alan Flavell.

Cette erreur peut également être déclenchée par des caractères de formatage intégrés dans les fichiers documents par certains traitements de texte. Si vous utilisez un traitement de texte pour éditer des vos documents HTML, veillez à utiliser l'option "Enregistrer sous ASCII" ou une option similaire. pour enregistrer le document sans les informations de formatage.

J'utilise maintenant PHP5.2.17, et j'ai joué un peu avec htmlspecialchars, mais rien n'a fonctionné. Comment puis-je encoder ces caractères, afin qu'il n'y ait plus d'erreurs de validation ?

3voto

hakre Points 102271

Dans les normes ISO-8859-1 et ISO-8859-15, le caractère numéro 146 est un caractère de contrôle. MW (Message en attente) à partir du Gamme C1 .

SGML fait référence à ISO 8859-1 (attention à l'espace entre ISO et 8859-1, qui n'est pas un trait d'union comme dans les jeux de caractères que vous utilisez). Il n'autorise pas les caractères de contrôle, mais trois (ici : SGML en HTML ):

Dans le jeu de caractères du document HTML, seuls trois caractères de contrôle sont autorisés : Horizontal tabulation horizontale, le retour chariot et le saut de ligne (positions de code 9, 13 et 10).

Vous avez donc transmis un caractère illégal. Il n'existe pas d'entité SGML/HTML pour le remplacer.

Je vous suggère de valider les données qui entrent dans votre application afin de vous assurer qu'elles n'autorisent pas les caractères de contrôle. Si vous pensez que ces caractères représentaient à l'origine quelque chose d'utile, comme une lettre qui peut être lue (c'est-à-dire pas un caractère de contrôle), il est probable que lorsque vous traitez les données, l'encodage est cassé à un moment donné.

D'après les informations fournies dans votre question, il est difficile de dire où, car vous ne spécifiez que l'encodage d'entrée et l'encodage de la base de données déposée - mais ces deux-là ne correspondent déjà pas (ce qui ne devrait pas produire le problème que vous demandez, mais qui peut en produire d'autres). En plus de ces deux endroits, il y a aussi le charset de connexion du client à la base de données (non spécifié dans votre question), l'encodage de sortie (non spécifié dans votre question) et l'encodage du contenu de la réponse (non spécifié dans votre question).

Il pourrait être logique de modifier votre encodage global en UTF-8 pour prendre en charge un plus grand nombre de caractères, mais il s'agit en réalité d'une pourrait .

Edita: La partie ci-dessus est en quelque sorte un point de vue strict. Il m'est venu à l'esprit que l'entrée que vous recevez n'est pas ISO-8859-1(5) mais quelque chose d'autre, comme une page de code Windows. Je dirais probablement que c'est Windows-1252 (cp1252) Wkipedia . Par rapport à la gamme C1 de l'ISO-8859-1 (128-159), il comporte plusieurs caractères de non-contrôle.

La page Wikipedia indique également que la plupart des navigateurs traitent ISO-8859-1 comme Windows-1252/CP1252/CP-1252. La page PHP htmlentities() fonction n'est pas en mesure de traiter ces caractères, le table de traduction pour les entités HTML ne couvre pas les points de code (PHP 5.3, non testé avec 5.4). Vous devez créer votre propre table de traduction et l'utiliser avec strtr pour remplacer les caractères non disponibles dans la norme ISO 8859-15 pour Windows-1252 :

/*
 * mappings of Windows-1252 (cp1252)  128 (0x80) - 159 (0x9F) characters:
 * @link http://en.wikipedia.org/wiki/Windows-1252
 * @link http://www.w3.org/TR/html4/sgml/entities.html
 */
$cp1252HTML401Entities = array(
    "\x80" => '€',    # 128 -> euro sign, U+20AC NEW
    "\x82" => '‚',   # 130 -> single low-9 quotation mark, U+201A NEW
    "\x83" => 'ƒ',    # 131 -> latin small f with hook = function = florin, U+0192 ISOtech
    "\x84" => '„',   # 132 -> double low-9 quotation mark, U+201E NEW
    "\x85" => '…',  # 133 -> horizontal ellipsis = three dot leader, U+2026 ISOpub
    "\x86" => '†',  # 134 -> dagger, U+2020 ISOpub
    "\x87" => '‡',  # 135 -> double dagger, U+2021 ISOpub
    "\x88" => 'ˆ',    # 136 -> modifier letter circumflex accent, U+02C6 ISOpub
    "\x89" => '‰',  # 137 -> per mille sign, U+2030 ISOtech
    "\x8A" => 'Š',  # 138 -> latin capital letter S with caron, U+0160 ISOlat2
    "\x8B" => '‹',  # 139 -> single left-pointing angle quotation mark, U+2039 ISO proposed
    "\x8C" => 'Œ',   # 140 -> latin capital ligature OE, U+0152 ISOlat2
    "\x8E" => 'Ž',    # 142 -> U+017D
    "\x91" => '‘',   # 145 -> left single quotation mark, U+2018 ISOnum
    "\x92" => '’',   # 146 -> right single quotation mark, U+2019 ISOnum
    "\x93" => '“',   # 147 -> left double quotation mark, U+201C ISOnum
    "\x94" => '”',   # 148 -> right double quotation mark, U+201D ISOnum
    "\x95" => '•',    # 149 -> bullet = black small circle, U+2022 ISOpub
    "\x96" => '–',   # 150 -> en dash, U+2013 ISOpub
    "\x97" => '—',   # 151 -> em dash, U+2014 ISOpub
    "\x98" => '˜',   # 152 -> small tilde, U+02DC ISOdia
    "\x99" => '™',   # 153 -> trade mark sign, U+2122 ISOnum
    "\x9A" => 'š',  # 154 -> latin small letter s with caron, U+0161 ISOlat2
    "\x9B" => '›',  # 155 -> single right-pointing angle quotation mark, U+203A ISO proposed
    "\x9C" => 'œ',   # 156 -> latin small ligature oe, U+0153 ISOlat2
    "\x9E" => 'ž',    # 158 -> U+017E
    "\x9F" => 'Ÿ',    # 159 -> latin capital letter Y with diaeresis, U+0178 ISOlat2
);

$outputWithEntities = strtr($output, $cp1252HTML401Entities);

Si vous voulez être encore plus sûr, vous pouvez éviter les entités nommées et ne prendre que les entités numériques, ce qui devrait également fonctionner dans les très vieux navigateurs :

$cp1252HTMLNumericEntities = array(
    "\x80" => '€',   # 128 -> euro sign, U+20AC NEW
    "\x82" => '‚',   # 130 -> single low-9 quotation mark, U+201A NEW
    "\x83" => 'ƒ',    # 131 -> latin small f with hook = function = florin, U+0192 ISOtech
    "\x84" => '„',   # 132 -> double low-9 quotation mark, U+201E NEW
    "\x85" => '…',   # 133 -> horizontal ellipsis = three dot leader, U+2026 ISOpub
    "\x86" => '†',   # 134 -> dagger, U+2020 ISOpub
    "\x87" => '‡',   # 135 -> double dagger, U+2021 ISOpub
    "\x88" => 'ˆ',    # 136 -> modifier letter circumflex accent, U+02C6 ISOpub
    "\x89" => '‰',   # 137 -> per mille sign, U+2030 ISOtech
    "\x8A" => 'Š',    # 138 -> latin capital letter S with caron, U+0160 ISOlat2
    "\x8B" => '‹',   # 139 -> single left-pointing angle quotation mark, U+2039 ISO proposed
    "\x8C" => 'Œ',    # 140 -> latin capital ligature OE, U+0152 ISOlat2
    "\x8E" => 'Ž',    # 142 -> U+017D
    "\x91" => '‘',   # 145 -> left single quotation mark, U+2018 ISOnum
    "\x92" => '’',   # 146 -> right single quotation mark, U+2019 ISOnum
    "\x93" => '“',   # 147 -> left double quotation mark, U+201C ISOnum
    "\x94" => '”',   # 148 -> right double quotation mark, U+201D ISOnum
    "\x95" => '•',   # 149 -> bullet = black small circle, U+2022 ISOpub
    "\x96" => '–',   # 150 -> en dash, U+2013 ISOpub
    "\x97" => '—',   # 151 -> em dash, U+2014 ISOpub
    "\x98" => '˜',    # 152 -> small tilde, U+02DC ISOdia
    "\x99" => '™',   # 153 -> trade mark sign, U+2122 ISOnum
    "\x9A" => 'š',    # 154 -> latin small letter s with caron, U+0161 ISOlat2
    "\x9B" => '›',   # 155 -> single right-pointing angle quotation mark, U+203A ISO proposed
    "\x9C" => 'œ',    # 156 -> latin small ligature oe, U+0153 ISOlat2
    "\x9E" => 'ž',    # 158 -> U+017E
    "\x9F" => 'Ÿ',    # 159 -> latin capital letter Y with diaeresis, U+0178 ISOlat2
);

J'espère que cela vous sera plus utile. Voir aussi la page Wikipedia liée ci-dessus pour quelques caractères qui sont dans Windows-1242 et ISO 8859-15 mais à différents endroits. Vous devriez probablement envisager d'utiliser UTF-8 sur votre site web.

2voto

Jukka K. Korpela Points 71599

Une page web comportant un champ de saisie de texte doit être codée en UTF-8, car c'est le seul moyen de garantir que tous les caractères saisis par l'utilisateur seront correctement transmis. La manière de les traiter côté serveur (par exemple, en rejetant les caractères en dehors d'une plage spécifique) est une autre question.

Si vous utilisez un autre codage et que l'utilisateur saisit un caractère qui n'est pas représenté dans ce codage, il s'agit d'une condition d'erreur que les navigateurs peuvent traiter comme ils l'entendent. Les navigateurs modernes font quelque chose de très étrange en principe, mais utile en pratique : ils représentent les caractères sous forme de références de caractères, comme ’ pour le guillemet simple droit ('). Dans ce cas, les données reçues sont les mêmes que si l'utilisateur avait effectivement tapé les caractères ’ (mais c'est tellement théorique que les vendeurs de navigateurs ignorent apparemment le problème).

Ce qui se passe côté serveur dans votre cas n'est pas clair, mais cela peut impliquer plusieurs types de traitement. En tout état de cause, vous ne pouvez pas stocker ISO-8859-15 dans le codage ISO-8859-1 (ISO-8859-15 a été conçu pour remplacer certains caractères de l'ISO-8859-1 par d'autres caractères). Il n'est pas clair ce que votre logiciel fait avec des références de caractères comme ’ . Il serait un peu étrange, mais sûrement possible, qu'un logiciel les remplace par des références de caractères comme ’ (qui reposent sur l'utilisation de Windows-1252 comme jeu de caractères du document, contrairement aux règles HTML ; ils sont techniquement indéfinis - et non illégaux - dans HTML, mais si largement pris en charge par les navigateurs que HTML5 en a fait une règle).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X