J'ai rencontré un problème qui a été révélé par notre campagne de marketing Google axée sur les adwords. L'un des paramètres standard utilisés est "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 de nombreuses informations dans le référent. Nous capturons cela pour nos enregistrements et nous avons remarqué que le paramètre "Région" ne fonctionne pas correctement. Quel devrait être
http://ravercats.com/meow?foo=bar®ion=catnip
au lieu de cela passe comme:
http://ravercats.com/meow?foo=bar®ion=catnip
J'ai vérifié que cela se produit dans tous les navigateurs. Je crois comprendre que la syntaxe d'entité HTML est définie comme suit:
&VALUE;
où la limite principale est l'esperluette et la limite de fermeture est le point-virgule. Cela semble assez simple. Le problème est que cela n'est pas respecté pour l'entité ® et que cela cause toutes sortes de dégâts dans notre système.
Est-ce que quelqu'un sait pourquoi cela se produit? Est-ce un bug dans la DTD? (Je cherche la DTD HTML actuelle pour voir si je peux la comprendre) J'essaie de comprendre ce qui serait commun entre les navigateurs pour que cela se produise, et donc ma recherche de la DTD.
Voici une preuve que vous pouvez utiliser. Prenez ce code, faites-en un fichier HTML et rendez-le dans un navigateur:
<html>
<a href="http://foo.com/bar?foo=bar®ion=US®ister=lowpass®_test=fail&trademark=correct">http://foo.com/bar?foo=bar®ion=US®ister=lowpass®_test=fail&trademark=correct</a>
</html>
EDIT: Pour tous ceux qui suggèrent que je dois échapper à l'URL complète, les exemples d'URL ci-dessus sont exactement cela, des exemples. La véritable URL 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".
Bien que les références de caractères valid aient toujours un point-virgule à la fin, certaines références de caractères nommés non valides sans point-virgule sont, pour des raisons de compatibilité ascendante, reconnues par les analyseurs HTML des navigateurs modernes.
Soit vous connaissez la liste complète, soit vous suivez les règles HTML5 lorsque &
est valide sans être échappé (e, g, lorsque suivi d'un espace) ou vous échappez toujours toujours &
en tant que &
en cas de doute.
Pour référence, la liste complète des références de caractères nommés reconnues sans point-virgule est la suivante:
AElig, AMP, Aacute, Acirc, Agrave, Ating, Atilde, Auml, COPIE, Ccedil, ETH, Eacute, Ecirc, Egrave, Euml, GT, Iacute, Icrave, Igrave, Iuml, LT, Ntilde, Oacute, Ocac, Ograve, Oslash, Otilde, Ouml, COTATION, REG, THORN, Uacute, Ucirc, Ugrave, Uuml, Yacute, Aacute, acirc, aiguë, aelig, agrave, ampli, atilde, auml, brvbar, ccedil, cedil, cent, copie, curren, deg, divide, eacute, ecirc, egrave, eth, euml, frac12, frac14, frac34, gt, iacute, icirc, iexcl, igrave, iquest, iuml, laquo, lt, macr, micro, middot, nbsp, non, ntilde, eacute, ocirc, ograve, ordf, ordm, oslash, otilde, ouml, para, plusmn, livre, ', raquo, reg, secte, timide, sup1, sup2, supz, szlig, thorn, fois, uacute, ucirc, ugrave, uml, uuml, yacute, yen, yuml
Toutefois, il convient de noter que, uniquement dans une valeur d'attribut, les références de caractères nommés figurant dans la liste ci-dessus ne sont pas traitées en tant que telles par des analyseurs syntaxiques HTML5 conformes si le caractère suivant est un =
ou un caractère alphanumérique ASCII.
Pour le liste complète des références de caractères nommés avec ou sans point-virgule, voir ici
C’est une entreprise très confuse qui dépend du contexte (contenu du texte par rapport à la valeur de l’attribut).
Formellement, selon les spécifications HTML jusqu'au HTML 4.01 inclus, une référence à une entité peut apparaître sans point-virgule final, si le caractère suivant n'est pas un caractère de nom. Donc, par exemple ®ion=
serait syntaxiquement correct mais non défini, car l'entité region
n'a pas été définie. XHTML rend le point-virgule final requis.
Les navigateurs ont traditionnellement joué par d’autres règles. En raison de la syntaxe commune des URL de requête, ils analysent, par exemple, href="http://ravercats.com/meow?foo=bar®ion=catnip"
pour que ®ion
ne soit pas traité comme une référence d'entité, mais simplement comme une donnée texte. Et les auteurs ont principalement utilisé de telles constructions, même si elles sont formellement incorrectes.
Contrairement à ce que semble dire la question, href="http://ravercats.com/meow?foo=bar®ion=catnip"
fonctionne bien. Des problèmes se posent lorsque la chaîne ne se trouve pas dans une valeur d’attribut mais dans un contenu textuel, ce qui est plutôt rare: nous n’écrivons pas normalement d’URL dans du texte. Dans le texte, ®ion=
est traité de manière à ce que ®
soit reconnu comme une référence d'entité (pour «®») et le reste ne soit que des données de caractères. Un tel comportement étrange est officialisé dans HTML5 CR, où la clause 8.2.4.69 Tokeniser les références de caractère décrit le «double standard»:
Si la référence de caractère est utilisée en tant qu'élément d'un attribut, et le dernier caractère correspondant n'est pas un ";" (U + 003B) caractère et le caractère suivant est soit un "=" (U + 003D), soit compris dans la plage ASCII chiffres, lettres majuscules ASCII ou lettres minuscules ASCII, puis, pour des raisons historiques, tous les personnages qui ont été mis en correspondance après le caractère U + 0026 AMPERSAND (&) ne doit pas être utilisé, et rien n'est retourné.
Ainsi, dans une valeur d'attribut , même ®=
ne serait pas traité comme contenant une référence de caractère, et encore moins ®ion=
. (Mais reg_test=
est un cas différent, à cause du caractère de soulignement.)
Dans text content, d'autres règles s'appliquent. La construction ®ion=
provoque ensuite une erreur d’analyse (par les règles de HTML5 CR), mais avec une gestion des erreurs bien définie: ®
est reconnu en tant que référence de caractère.
Peut-être essayez-vous de remplacer votre &
par &
? Les esperluettes sont des caractères qui doivent également être échappés en HTML, car ils sont réservés pour être utilisés en tant que parties d'entités.
1: Le balisage suivant est d'abord invalide (utilisez le service de validation du balisage du W3C pour vérifier):
<a href="http://foo.com/bar?foo=bar®ion=US®ister=lowpass®_test=fail&trademark=correct"></a>
Dans l'exemple ci-dessus, le caractère &
doit être codé en tant que &
, comme suit:
<a href="http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct"></a>
2: Les navigateurs sont tolérants. ils essaient de comprendre le HTML cassé. Dans votre cas, toutes les entités HTML éventuellement valides sont converties en entités HTML.
Assez simplement, vous devez encoder le format url au format html pour une représentation précise (idéalement, vous le feriez avec une fonction d'échappement de variable de moteur de gabarit, mais ceci avec, avec htmlspecialchars($url)
ou htmlentities($url)
en php).
Consultez votre scénario de test, puis le code HTML correctement codé sur ce jsfiddle: http://jsfiddle.net/tchalvakspam/Fp3W6/
Code inactif ici:
<div>
Unescaped:
<br>
<a href="">http://foo.com/bar?foo=bar®ion=US®ister=lowpass®_test=fail&trademark=correct</a>
</div>
<div>
Correctly escaped:
<br>
http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct
</div>
Voici une solution simple qui peut ne pas fonctionner dans tous les cas.
Donc à partir de cela:
http://ravercats.com/meow?status=Online®ion=Atlantis
Pour ça:
http://ravercats.com/meow?region=Atlantis&status=Online
Parce que le ®
, comme nous le savons, déclenche le caractère spécial ®
Avertissement: Si vous n'avez aucun contrôle sur l'ordre de vos paramètres de chaîne de requête d'URL, vous devrez changer le nom de votre variable en autre chose.
Il me semble que ce que vous avez reçu de Google n'est pas une URL réelle mais une variable qui fait référence à une URL (chaîne de requête). Donc, c’est pourquoi il est analysé comme marque d’enregistrement lorsqu’il est rendu.
Je dirais que vous devez le coder en URL et le décoder à chaque traitement. Comme toute autre variable contenant des entités spéciales.