51 votes

Pourquoi "&reg" est-il rendu par "®" sans le point-virgule qui le délimite ?

J'ai rencontré un problème qui a été révélé par notre campagne de marketing basée sur Google adwords. L'un des paramètres standard utilisés est la "région". Lorsqu'un utilisateur effectue une recherche et clique sur un lien sponsorisé, Google génère une longue URL pour suivre le clic et envoie un tas d'informations dans le référent. Nous capturons ces données pour nos dossiers et nous avons remarqué que le paramètre "région" n'est pas correctement pris en compte. Ce qui devrait être

http://ravercats.com/meow?foo=bar&region=catnip

est en train de s'imposer comme :

http://ravercats.com/meow?foo=bar®ion=catnip

J'ai vérifié que cela se produit dans tous les navigateurs. Je crois savoir que Syntaxe des entités HTML est défini comme suit :

&VALUE;

où la limite avant est l'esperluette et la limite arrière est le point-virgule. Cela semble assez simple. Le problème est que cela n'est pas respecté pour l'entité ®, et que cela provoque toutes sortes de dégâts dans notre système.

Quelqu'un sait-il pourquoi cela se produit ? S'agit-il d'un bogue dans la DTD ? (Je cherche la DTD HTML actuelle pour voir si je peux la comprendre) J'essaie de comprendre ce qui serait commun à tous les navigateurs pour que cela se produise, d'où ma recherche de la DTD.

Voici une preuve que vous pouvez utiliser. Prenez ce code, créez un fichier HTML à partir de celui-ci et affichez-le dans un navigateur :

<html>
<a href="http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct">http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct</a>
</html>

EDIT : Pour tous ceux qui suggèrent que je dois échapper l'intégralité de l'URL, les exemples d'URL ci-dessus sont exactement cela, des exemples. L'URL réelle provient directement de Google et je n'ai aucun contrôle sur la façon dont elle est construite. Ces suggestions, bien que valables, ne répondent pas à la question : "Pourquoi cela se produit-il".

3 votes

Essayez peut-être de remplacer votre & par &amp; ou l'esperluette codée en URL %26 ?

6 votes

Votre sans-capture & est illégal en HTML en premier lieu. Essayer de légiférer sur le langage du navigateur permissif après cela est un peu stupide. (BTW, cela fonctionne bien dans Firefox ; c'était un bug corrigé en 2005).

5 votes

Il s'agit d'exemples d'URL. L'URL réelle provient directement de Google, je n'ai donc aucun contrôle sur elle. J'apprécie les suggestions, mais elles ne répondent pas à la question de savoir POURQUOI cela se produit, spécifiquement pour l'entité "reg" et aucune autre.

44voto

Alohci Points 30645

Bien que valide Les références de caractères ont toujours un point-virgule à la fin, certaines références de caractères nommés invalides sans point-virgule sont, pour des raisons de rétrocompatibilité, reconnues par les analyseurs HTML des navigateurs modernes.

Soit vous savez ce qu'est cette liste entière, soit vous suivez les règles HTML5 pour savoir quand & est valide sans être échappé (par exemple lorsqu'il est suivi d'un espace) ou sinon toujours échappé. & como &amp; en cas de doute.

Pour référence, la liste complète des références de personnages nommés qui sont reconnus sans point-virgule est :

AElig, AMP, Aacute, Acirc, Agrave, Aring, Atilde, Auml, COPY, Ccedil, ETH, Eacute, Ecirc, Egrave, Euml, GT, Iacute, Icirc, Igrave, Iuml, LT, Ntilde, Oacute, Ocirc, Ograve, Oslash, Otilde, Ouml, QUOT, REG, THORN, Uacute, Ucirc, Ugrave, Uuml, Yacute, aacute, acirc, acute, aelig, agrave, amp, aring, atilde, auml, brvbar, ccedil, cedil, cent, copy, curren, deg, divide, eacute, ecirc, egrave, eth, euml, frac12, frac14, frac34, gt, iacute, icirc, iexcl, igrave, iquest, iuml, laquo, lt, macr, micro, middot, nbsp, not, ntilde, oacute, ocirc, ograve, ordf, ordm, oslash, otilde, ouml, para, plusmn, pound, quot, raquo, reg, sect, shy, sup1, sup2, sup3, szlig, thorn, times, uacute, ucirc, ugrave, uml, uuml, yacute, yen, yuml

Toutefois, il convient de noter que, uniquement lorsqu'elles figurent dans une valeur d'attribut, les références aux caractères nommés de la liste ci-dessus ne sont pas traitées en tant que telles par les analyseurs HTML5 conformes si le caractère suivant est un caractère = ou un caractère alphanumérique ASCII.

Pour la liste complète des références de caractères nommés avec ou sans point-virgule final, voir aquí .

2 votes

Je ne savais pas qu'il existait des entités qui pouvaient "s'en sortir" sans point-virgule. Merci d'avoir répondu à la question et de m'avoir orienté vers une bonne référence.

6 votes

J'ai rencontré un cas intéressant où &provider=XXX&reg=1 dans l'URL a été remplacé par un navigateur obsolète ou peu courant en provider=XXX®=1 brisant complètement le script.

2 votes

13voto

Jukka K. Korpela Points 71599

C'est une affaire très compliquée qui dépend du contexte (contenu du texte ou valeur de l'attribut).

Formellement, selon les spécifications HTML jusqu'à HTML 4.01 inclus, une référence à une entité peut apparaître sans point-virgule de fin, si le caractère suivant n'est pas un caractère de nom. Ainsi, par exemple &region= serait syntaxiquement correct mais indéfini, comme l'entité region n'a pas été défini. Le XHTML rend le point-virgule de fin obligatoire.

Cependant, les navigateurs ont traditionnellement joué selon d'autres règles. En raison de la syntaxe commune des URL de requête, ils analysent, par exemple, les éléments suivants href="http://ravercats.com/meow?foo=bar&region=catnip" de sorte que &region n'est pas traitée comme une référence d'entité mais comme une simple donnée textuelle. Et les auteurs ont le plus souvent utilisé de telles constructions, même si elles sont formellement incorrectes.

Contrairement à ce que la question semble dire, href="http://ravercats.com/meow?foo=bar&region=catnip" fonctionne bien. Les problèmes surviennent lorsque la chaîne de caractères ne se trouve pas dans une valeur d'attribut mais dans un contenu textuel, ce qui est plutôt rare : nous n'écrivons normalement pas les URL dans du texte. Dans du texte, &region= est traité de manière à ce que &reg est reconnu comme une référence d'entité (pour "®") et le reste n'est que des données de caractères. Ce comportement étrange est rendu officiel dans le HTML5 CR, où la clause 8.2.4.69 Tokenisation des références de caractères décrit le "double standard" :

Si la référence de caractère est consommée comme partie d'un attribut, et que le dernier caractère correspondant n'est pas un caractère " ;" (U+003B), et que le caractère suivant est soit un caractère "=" (U+003D), soit un caractère de l'ordre de chiffres ASCII, lettres ASCII majuscules ou lettres ASCII minuscules, alors, pour des raisons historiques, tous les caractères qui ont été appariés après le caractère U+0026 AMPERSAND (&) doivent être ignorés et rien n'est renvoyé. rien n'est retourné.

Ainsi, dans un valeur de l'attribut même &reg= ne serait pas traitée comme contenant une référence de caractère, et encore moins &region= . (Mais reg_test= est un cas différent, en raison du caractère de soulignement).

Sur contenu du texte d'autres règles s'appliquent. La construction &region= provoque alors une erreur d'analyse (selon les règles du HTML5 CR), mais avec une gestion des erreurs bien définie : &reg est reconnu comme une référence de caractère.

3 votes

Ce qui est intéressant, c'est que dans le cas réel, je collecte essentiellement le HTTP_REFERER de Google et je l'analyse dans un cookie. L'URL que je reçois est déjà analysée de cette manière. Merci pour cette explication très concise avec les sources.

9voto

jchapa Points 1958

Essayez peut-être de remplacer votre & como &amp; ? Les esperluettes sont des caractères qui doivent être échappés en HTML également, car elles sont réservées pour être utilisées comme parties d'entités.

4voto

Salman A Points 60620

1 : Le balisage suivant n'est pas valide en premier lieu (utilisez la balise Service de validation du balisage du W3C à vérifier) :

<a href="http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct"></a>

Dans l'exemple ci-dessus, le & doit être encodé comme &amp; comme ça :

<a href="http://foo.com/bar?foo=bar&amp;region=US&amp;register=lowpass&amp;reg_test=fail&amp;trademark=correct"></a>

2 : Les navigateurs sont tolérants ; ils essaient de donner un sens à du HTML cassé. Dans votre cas, toutes les entités HTML valides possibles sont converties en entités HTML.

1voto

Kzqai Points 7484

Échappez à votre sortie !

Pour faire simple, vous devez encoder le format de l'url en format html pour une représentation précise (l'idéal serait de le faire avec une fonction d'échappement de variable du moteur de modèle, mais sinon, avec htmlspecialchars($url) o htmlentities($url) en php).

Voir votre cas de test et ensuite le html correctement encodé à ce jsfiddle : http://jsfiddle.net/tchalvakspam/Fp3W6/

Code inactif ici :

<div>
Unescaped:
<br>
<a href="">http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct</a>
</div>

<div>
Correctly escaped:
<br>
http://foo.com/bar?foo=bar&amp;region=US&amp;register=lowpass&amp;reg_test=fail&amp;trademark=correct
</div>

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