Si je veux créer une URL en utilisant une variable, j'ai deux choix pour encoder la chaîne. urlencode()
et rawurlencode()
.
Quelles sont exactement les différences et lesquelles sont préférées?
Cela dépendra de votre but. Si l'interopérabilité avec d'autres systèmes est importante, il semble alors qu'il soit préférable d'utiliser du code rawurlencod La seule exception concerne les systèmes hérités qui s'attendent à ce que la chaîne de requête suive le style de codage de formulaire des espaces codés sous la forme + au lieu de% 20 (auquel cas vous avez besoin d'un code urlencode).
rawurlencode suit la RFC 1738 avant le PHP 5.3.0 et la RFC 3986 ensuite (voir http: // us2. php.net/manual/en/function.rawurlencode.php )
Renvoie une chaîne dans laquelle tous les caractères non alphanumériques, à l'exception de -_. ~, Ont été remplacés par un signe de pourcentage (%) suivi de deux chiffres hexadécimaux. Il s'agit de l'encodage décrit dans la "RFC 3986 pour empêcher les caractères littéraux d'être interprétés en tant que délimiteurs d'URL spéciaux et pour protéger les URL contre les altérations causées par les supports de transmission avec conversion de caractères (comme certains systèmes de messagerie).
Note sur RFC 3986 vs 1738. rawurlencode avant PHP 5.3 encodait le caractère tilde (~
) conformément à RFC 1738. À partir de PHP 5.3, cependant, rawurlencode suit RFC 3986, qui ne nécessite pas d'encodage. caractères tilde.
urlencode code les espaces en tant que signes plus (et non en tant que %20
comme dans rawurlencode) (voir http: //us2.php .net/manual/en/function.urlencode.php )
Retourne une chaîne contenant tous les caractères non alphanumériques sauf -_. ont été remplacés par un signe de pourcentage (%) suivi de deux chiffres hexadécimaux et d'espaces codés sous la forme de signes plus (+). Il est codé de la même manière que les données postées d’un formulaire WWW, comme dans le type de média application/x-www-form-urlencoded. Cela diffère du codage "RFC 3986 (voir rawurlencode ()) en ce que, pour des raisons historiques, les espaces sont codés sous la forme de signes plus (+).
Cela correspond à la définition de l'application/x-www-form-urlencoded in RFC 1866 .
Lecture supplémentaire:
Vous voudrez peut-être aussi voir la discussion sur http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode .
En outre, RFC 2396 vaut le détour. La RFC 2396 définit la syntaxe URI valide. La partie principale qui nous intéresse est tirée du composant de requête 3.4:
Dans un composant de requête, les caractères
";", "/", "?", ":", "@",
sont réservés.
"&", "=", "+", ",", and "$"
Comme vous pouvez le constater, le +
est un caractère réservé dans la chaîne de requête et doit donc être codé conformément à la norme RFC 3986 (comme dans le code rawurlencode).
La preuve est dans le code source de PHP.
Je vais vous expliquer rapidement comment trouver ce genre de choses vous-même à l'avenir, quand vous le souhaitez. Ours avec moi, il y aura beaucoup de code source C que vous pouvez survoler (je l'explique). Si vous voulez rafraîchir un peu le langage C, un bon point de départ est notre wiki SO .
Téléchargez la source (ou utilisez http://lxr.php.net/ pour la parcourir en ligne), grep tous les fichiers pour le nom de la fonction, vous trouverez quelque chose comme ceci:
PHP 5.3.6 (la plus récente au moment de l'écriture) décrit les deux fonctions dans leur code C natif dans le fichier url.c .
RawUrlEncode ()
PHP_FUNCTION(rawurlencode)
{
char *in_str, *out_str;
int in_str_len, out_str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
&in_str_len) == FAILURE) {
return;
}
out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
RETURN_STRINGL(out_str, out_str_len, 0);
}
UrlEncode ()
PHP_FUNCTION(urlencode)
{
char *in_str, *out_str;
int in_str_len, out_str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
&in_str_len) == FAILURE) {
return;
}
out_str = php_url_encode(in_str, in_str_len, &out_str_len);
RETURN_STRINGL(out_str, out_str_len, 0);
}
Ok, alors qu'est-ce qui est différent ici?
Ils appellent tous deux deux fonctions internes différentes: php_raw_url_encode et php_url_encode
Alors allez chercher ces fonctions!
PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
{
register int x, y;
unsigned char *str;
str = (unsigned char *) safe_emalloc(3, len, 1);
for (x = 0, y = 0; len--; x++, y++) {
str[y] = (unsigned char) s[x];
#ifndef CHARSET_EBCDIC
if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
(str[y] < 'A' && str[y] > '9') ||
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
(str[y] > 'z' && str[y] != '~')) {
str[y++] = '%';
str[y++] = hexchars[(unsigned char) s[x] >> 4];
str[y] = hexchars[(unsigned char) s[x] & 15];
#else /*CHARSET_EBCDIC*/
if (!isalnum(str[y]) && strchr("_-.~", str[y]) != NULL) {
str[y++] = '%';
str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
#endif /*CHARSET_EBCDIC*/
}
}
str[y] = '\0';
if (new_length) {
*new_length = y;
}
return ((char *) str);
}
PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
{
register unsigned char c;
unsigned char *to, *start;
unsigned char const *from, *end;
from = (unsigned char *)s;
end = (unsigned char *)s + len;
start = to = (unsigned char *) safe_emalloc(3, len, 1);
while (from < end) {
c = *from++;
if (c == ' ') {
*to++ = '+';
#ifndef CHARSET_EBCDIC
} else if ((c < '0' && c != '-' && c != '.') ||
(c < 'A' && c > '9') ||
(c > 'Z' && c < 'a' && c != '_') ||
(c > 'z')) {
to[0] = '%';
to[1] = hexchars[c >> 4];
to[2] = hexchars[c & 15];
to += 3;
#else /*CHARSET_EBCDIC*/
} else if (!isalnum(c) && strchr("_-.", c) == NULL) {
/* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
to[0] = '%';
to[1] = hexchars[os_toascii[c] >> 4];
to[2] = hexchars[os_toascii[c] & 15];
to += 3;
#endif /*CHARSET_EBCDIC*/
} else {
*to++ = c;
}
}
*to = 0;
if (new_length) {
*new_length = to - start;
}
return (char *) start;
}
Un peu de connaissance avant de continuer, EBCDIC est un autre jeu de caractères , similaire à ASCII, mais un concurrent total. PHP tente de gérer les deux. En gros, cela signifie octet octet EBCDIC 0x4c octet n’est pas le L
en ASCII, c’est en fait un <
. Je suis sûr que vous voyez la confusion ici.
Ces deux fonctions gèrent EBCDIC si le serveur Web l'a défini.
En outre, ils utilisent tous deux un tableau de caractères (type de chaîne) hexchars
look-up pour obtenir des valeurs, le tableau est décrit comme suit:
/* rfc1738:
...The characters ";",
"/", "?", ":", "@", "=" and "&" are the characters which may be
reserved for special meaning within a scheme...
...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL...
For added safety, we only leave -_. unencoded.
*/
static unsigned char hexchars[] = "0123456789ABCDEF";
Au-delà de cela, les fonctions sont vraiment différentes, et je vais les expliquer dans ASCII et EBCDIC.
URLENCODE:
+
à la chaîne de sortie.isalnum(c)
), et n'est pas non plus et _
, -
ou .
caractère, alors nous produisons un %
signe à la position 0 du tableau, effectuez une recherche dans le tableau hexchars
pour une recherche de os_toascii
tableau (un tableau de Apache qui traduit char en code hexadécimal) pour la touche de c
(le caractère actuel), nous décalons ensuite de 4 bits à droite, assignons cette valeur au caractère 1, et à la position 2, nous assignons la même recherche, sauf que nous effectuons une pour voir si la valeur est 15 (0xF) et renvoyer un 1 dans ce cas, ou un 0 dans les autres cas. À la fin, vous obtiendrez quelque chose d'encodé._-.
, il affichera exactement ce que c'est.RAWURLENCODE:
Remarque: De nombreux programmeurs n'ont probablement jamais vu une boucle for itérer de cette façon, c'est un peu bidon et pas la convention standard utilisée avec la plupart des boucles for loops, faites attention , il affecte x
et y
, vérifie la sortie sur len
jusqu’à 0 et incrémente x
et y
. Je sais, ce n'est pas ce à quoi vous vous attendiez, mais c'est un code valide.
str
._-.
, et si ce n'est pas le cas, nous faisons presque la même affectation que pour URLENCODE, où il effectue des recherches, mais nous incrémentons différemment, en utilisant y++
plutôt que to[1]
, c'est parce que les chaînes sont construites de différentes manières, mais atteignent le même objectif à la fin.\0
.Différences:
\0
à la chaîne, contrairement à RawUrlEncode (cela peut être un point discutable)En gros, ils itèrent différemment, on attribue un signe + dans le cas de ASCII 20.
URLENCODE:
0
, à l'exception d'être .
ou -
, OU inférieur à A
mais supérieur à char 9
, OU supérieur à Z
et inférieur à a
mais pas à _
. OU supérieur à z
(ouais, EBCDIC est un peu foiré pour travailler avec). Si cela correspond à l'un de ceux-ci, effectuez une recherche similaire à celle trouvée dans la version ASCII (elle ne nécessite simplement pas de recherche dans os_toascii).RAWURLENCODE:
z
, elle exclut ~
de l’encodage URL.\0
à la chaîne avant le renvoi.~
, contrairement à UrlEncode ( c'est un problème signalé ). Il convient de noter que ASCII et EBCDIC 0x20 sont deux espaces.+
, RawUrlEncode crée un espace dans %20
via des recherches dans un tableau.Avertissement: Je n'ai pas touché à C depuis des années et je n'ai pas examiné EBCDIC depuis très longtemps. Si je me trompe quelque part, faites le moi savoir.
En se basant sur tout cela, rawurlencode est la voie à suivre la plupart du temps. Comme vous le voyez dans la réponse de Jonathan Fingland, respectez-le dans la plupart des cas. Il traite du schéma moderne pour les composants URI, où urlencode fait les choses à l'ancienne, où + voulait dire "espace".
Si vous essayez de convertir entre l'ancien et le nouveau format, assurez-vous que votre code ne va pas bien et transformez quelque chose qui est un signe décodé + en un espace par un double encodage accidentel, ou des scénarios similaires "oops" autour de cela. espace/20%/+ numéro.
Si vous travaillez sur un ancien système avec un logiciel plus ancien qui ne préfère pas le nouveau format, restez-en à l'urlencode. Cependant, je pense que% 20 sera rétro-compatible, comme sous l'ancien standard% 20 travaillé, ce n'était tout simplement pas le cas. préféré. Essayez si vous êtes prêt à jouer, dites-nous comment cela a fonctionné pour vous.
En gros, vous devriez vous en tenir à raw, à moins que votre système EBCDIC ne vous déteste vraiment. La plupart des programmeurs ne se heurteront jamais à l’EBCDIC sur un système créé après l’an 2000, voire 1990 (c’est poussant, mais toujours probable à mon avis).
echo rawurlencode('http://www.google.com/index.html?id=asd asd');
les rendements
http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd%20asd
tandis que
echo urlencode('http://www.google.com/index.html?id=asd asd');
les rendements
http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd+asd
La différence étant le asd%20asd
vs asd+asd
urlencode diffère de la RFC 1738 en codant les espaces comme +
au lieu de %20
Une raison pratique de choisir l’un sur l’autre est d’utiliser le résultat dans un autre environnement, par exemple JavaScript.
Dans PHP urlencode('test 1')
renvoie 'test+1'
alors que rawurlencode('test 1')
renvoie 'test%201'
comme résultat.
Mais si vous avez besoin de "décoder" cela en JavaScript en utilisant decodeURI () function alors decodeURI("test+1")
vous donnera "test+1"
tandis que decodeURI("test%201")
vous donnera "test 1"
à la suite.
En d'autres termes, l'espace ("") codé par rlencode en plus ("+") dans PHP ne sera pas correctement décodé par decodeURI en JavaScript .
Dans ce cas, utilisez la fonction rawurlencode PHP.
Je crois que les espaces doivent être encodés comme:
%20
lorsqu'il est utilisé à l'intérieur d'un composant de chemin d'URL+
lorsqu'il est utilisé à l'intérieur d'un composant de chaîne de requête d'URL ou de données de formulaire (voir 17.13.4 Types de contenu de formulaire )L'exemple suivant montre l'utilisation correcte de rawurlencode
et de urlencode
:
echo "http://example.com"
. "/category/" . rawurlencode("latest songs")
. "/search?q=" . urlencode("lady gaga");
Sortie:
http://example.com/category/latest%20songs/search?q=lady+gaga
Que se passe-t-il si vous encodez le chemin et interrogez les composants de chaîne de caractères à l'envers? Pour l'exemple suivant:
http://example.com/category/latest+songs/search?q=lady%20gaga
latest+songs
au lieu de latest songs
q
contiendra lady gaga
La seule différence réside dans la façon dont les espaces sont traités:
urlencode - basé sur une implémentation existante convertit les espaces en +
rawurlencode - basé sur RFC 1738 traduit les espaces en% 20
La raison de la différence est que + est réservé et valide (non codé) dans les URL.
J'aimerais vraiment voir des raisons de choisir l'une plutôt que l'autre ... Je veux pouvoir en choisir une et l'utiliser indéfiniment avec le moins de tracas possible.
Très bien, j'ai une stratégie simple que je suis en prenant ces décisions et que je partagerai avec vous dans l'espoir que cela puisse vous aider.
Je pense que c’est la spécification HTTP/1.1 RFC 2616 qui appelle " applications tolérantes "
Les clients DEVRAIENT être tolérants dans l'analyse de la ligne d'état et les serveurs lors de l'analyse de la ligne de demande.
Face à de telles questions, la meilleure stratégie consiste toujours à consommer le plus possible et à produire des produits conformes aux normes.
Mon conseil est donc d'utiliser rawurlencode
pour produire des chaînes codées conformes à la norme RFC 1738 et d'utiliser urldecode
pour être compatible avec les versions antérieures et accueillir tout ce que vous pouvez rencontrer.
Maintenant, vous pouvez juste prendre ma parole pour cela, mais prouvons que nous allons ...
php > $url = <<<'EOD'
<<< > "Which, % of Alice's tasks saw $s @ earnings?"
<<< > EOD;
php > echo $url, PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > echo urlencode($url), PHP_EOL;
%22Which%2C+%25+of+Alice%27s+tasks+saw+%24s+%40+earnings%3F%22
php > echo rawurlencode($url), PHP_EOL;
%22Which%2C%20%25%20of%20Alice%27s%20tasks%20saw%20%24s%20%40%20earnings%3F%22
php > echo rawurldecode(urlencode($url)), PHP_EOL;
"Which,+%+of+Alice's+tasks+saw+$s+@+earnings?"
php > // oops that's not right???
php > echo urldecode(rawurlencode($url)), PHP_EOL;
"Which, % of Alice's tasks saw $s @ earnings?"
php > // now that's more like it
Il semblerait que PHP avait exactement cela à l'esprit, même si je n'ai jamais rencontré personne refusant l'un des deux formats, je ne peux pas penser à une meilleure stratégie à adopter comme stratégie de facto, n'est-ce pas?
nonJoy!
La différence réside dans les valeurs de retour, à savoir:
Retourne une chaîne contenant tous les caractères non alphanumériques sauf -_. ont été remplacés par un signe de pourcentage (%) suivi de deux chiffres hexadécimaux et d'espaces codés sous la forme de signes plus (+). Il est codé de la même manière que les données postées d’un formulaire WWW, comme dans le type de média application/x-www-form-urlencoded. Cela diffère du codage "RFC 1738 (voir rawurlencode ()) en ce que, pour des raisons historiques, les espaces sont codés sous la forme de signes plus (+).
Retourne une chaîne contenant tous les caractères non alphanumériques sauf -_. ont été remplacés par un signe de pourcentage (%) suivi de deux chiffres hexadécimaux. Il s'agit de l'encodage décrit dans la "RFC 1738 pour empêcher les caractères littéraux d'être interprétés en tant que délimiteurs d'URL spéciaux et pour protéger les URL contre les altérations causées par les supports de transmission avec conversion de caractères (comme certains systèmes de messagerie).
Les deux sont très similaires, mais le dernier (rawurlencode) remplacera les espaces par un '%' et deux chiffres hexadécimaux, ce qui convient au codage de mots de passe ou autres, où un '+' n'est pas, par exemple:
echo '<a href="ftp://user:', rawurlencode('foo @+%/'),
'@ftp.example.com/x.txt">';
//Outputs <a href="ftp://user:foo%20%40%2B%25%[email protected]/x.txt">
rlencode : Ceci diffère du codage "RFC 1738 (voir rawurlencode ()) en ce que, pour des raisons historiques, les espaces sont codés sous la forme de signes plus (+).
%20
vs. +
La plus grande raison pour laquelle j’ai vu utiliser rawurlencode()
dans la plupart des cas est que urlencode
code les espaces de texte sous la forme +
(signes plus), où rawurlencode
les code sous la forme courante. %20
:
echo urlencode("red shirt");
// red+shirt
echo rawurlencode("red shirt");
// red%20shirt
J'ai spécifiquement vu certains points de terminaison d'API qui acceptent les requêtes de texte codé s'attendent à voir %20
pour un espace et échouent si un signe plus est utilisé à la place. Évidemment, cela va différer entre les implémentations d'API et votre kilométrage peut varier.
Je crois que urlencode est destiné aux paramètres de requête, alors que le rawurlencode est destiné aux segments de chemin. Ceci est principalement dû à %20
pour les segments de chemin d'accès vs +
pour les paramètres de requête. Voir cette réponse qui parle des espaces: Quand encoder de l’espace en plus (+) ou en% 20?
Cependant, %20
fonctionne désormais également dans les paramètres de requête. C'est pourquoi rawurlencode est toujours plus sûr. Toutefois, le signe plus a tendance à être utilisé lorsque l'expérience de l'utilisateur en matière d'édition et de lisibilité des paramètres de requête est importante.
Notez que cela signifie que rawurldecode
ne décode pas +
en espaces ( http://au2.php.net/manual/en/function.rawurldecode.php ). C'est pourquoi $ _GET est toujours automatiquement passé à travers urldecode
, ce qui signifie que +
et %20
sont tous deux décodés en espaces.
Si vous voulez que l'encodage et le décodage soient cohérents entre les entrées et les sorties et que vous avez choisi d'utiliser toujours +
et non %20
pour les paramètres de requête, alors urlencode
convient parfaitement aux paramètres de requête (clé et valeur).
La conclusion est:
Segments de chemin - utilisez toujours rawurlencode/rawurldecode
Paramètres de requête: pour le décodage, utilisez toujours urldecode (fait automatiquement). Pour le codage, rawurlencode ou urlencode convient, choisissez-en un qui soit cohérent, en particulier lorsque vous comparez des URL.
simple * rawurlencode le chemin - chemin est la partie avant le "?" - les espaces doivent être codés sous la forme% 20 * urlencode de la chaîne de requête - La chaîne de requête est la partie située après le "?" -les espaces sont mieux encodés car "+" = rawurlencode est généralement plus compatible