urlencode vs rawurlencode?

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 les différences et quelles sont les préférences?

349
demandé sur teynon 2009-06-15 17:33:35

11 réponses

Cela dépendra de votre objectif. Si l'interopérabilité avec d'autres systèmes est importante, il semble que rawurlencode soit la solution. La seule exception est les systèmes traditionnels qui s'attendent à ce que la chaîne de requête suive le style d'encodage des formes des espaces encodés en + au lieu de %20 (dans ce cas, vous avez besoin du urlencode).

rawurlencode suit RFC 1738 avant PHP 5.3.0 et RFC 3986 après (voir http://us2.php.net/manual/en/function.rawurlencode.php )

Renvoie une chaîne dans laquelle tous les caractères non-alphanumériques sauf -_.~ ont été remplacés par un pourcentage (%) signe suivi de deux chiffres hexadécimaux. Il s'agit de l'encodage décrit dans " RFC 3986 pour protéger les caractères littéraux d'être interprétés comme des délimiteurs D'URL spéciaux, et pour protéger les URLs d'être altérés par des supports de transmission avec des conversions de caractères (comme certains système.)

Note sur RFC 3986 vs 1738. rawurlencode avant php 5.3 codait le caractère tilde ( ~ ) selon la RFC 1738. En PHP 5.3, cependant, rawurlencode suit RFC 3986 qui ne nécessite pas d'encodage des caractères tilde.

urlencode code les espaces en plus des signes (pas comme %20 comme fait en rawurlencode)(voir http://us2.php.net/manual/en/function.urlencode.php )

Renvoie une chaîne dans laquelle tous les caractères non-alphanumériques sauf -_. ont été remplacés par un signe pour cent (%) suivi de deux chiffres hexadécimaux et d'espaces encodés en signes plus ( + ). Il est encodé de la même manière que les données postées d'un formulaire WWW sont encodées, c'est-à-dire de la même manière que dans le type application/x-www-form-urlencoded media. Ceci diffère de l'encodage " RFC 3986 (voir rawurlencode()) en ce que pour des raisons historiques, les espaces sont encodés comme signes plus ( + ).

correspond à la définition de application/x-www-form-urlencoded in RFC 1866 .

Mention Supplémentaire:

vous pouvez également vouloir voir la discussion à http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode .

Aussi, RFC 2396 vaut le coup d'oeil. RFC 2396 définit la syntaxe URI valide. La partie principale qui nous intéresse est du composant de requête 3.4:

dans un composant de requête, les caractères ";", "/", "?", ":", "@",

"&", "=", "+", ",", and "$"
sont réservés.

comme vous pouvez le voir, le + est un caractère réservé dans la chaîne de requête et devrait donc être encodé selon la RFC 3986 (comme dans rawurlencode).

297
répondu Jonathan Fingland 2011-08-04 11:03:11

la preuve est dans le code source de PHP.

je vous montrerai comment découvrir ce genre de choses par vous-même à l'avenir quand vous voulez. Soyez indulgents, il y aura beaucoup de code source C que vous pouvez parcourir (Je l'explique). si vous voulez rafraîchir sur un C, Un bon endroit pour commencer est notre wiki .

Téléchargez la source (ou utilisez http://lxr.php.net / à parcourir en ligne), grep tous les fichiers pour le nom de la fonction, vous trouverez quelque chose comme ceci:

PHP 5.3.6 (le plus récent au moment de la rédaction) 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, qu'est-ce qui est différent ici?

ils appellent tous deux essentiellement deux fonctions internes différentes respectivement: php_raw_url_encode et php_url_encode

alors allez chercher ces fonctions!

regardons php_raw_url_encode

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] = '"151920920"';
    if (new_length) {
        *new_length = y;
    }
    return ((char *) str);
}

et bien sûr, php_url_encode:

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 petit peu de connaissance avant d'aller de l'avant, EBCDIC est un autre jeu de caractères , similaire à ASCII, mais un concurrent total. PHP tente de traiter les deux. Mais en gros, cela signifie que byte EBCDIC 0x4c byte 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.

aussi, ils utilisent tous les deux un tableau de caractères (penser le type de chaîne) hexchars chercher obtenez de certaines valeurs, le tableau est décrit comme tel:

/* 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 en ASCII et en EBCDIC.

Différences en ASCII:

URLENCODE:

  • calcule une longueur début / fin de la chaîne d'entrée, attribue de la mémoire
  • marche à travers une boucle de temps, incréments jusqu'à ce que nous atteindre la fin de la chaîne
  • saisit le caractère actuel
  • si le caractère est égal à ascii Char 0x20 (c'est-à-dire un" espace"), ajouter un signe + à la chaîne de sortie.
  • si ce n'est pas un espace, et ce n'est pas non plus alphanumérique ( isalnum(c) ), et n'est pas non plus et _ , - , ou . caractère, alors nous , sortie d'un % signe à la position du tableau 0, faire un tableau regarder à la hexchars tableau pour une recherche de os_toascii tableau (un tableau de Apache qui traduit char en code hexadécimal) pour la clé de c (le caractère actuel), nous puis bifurquons à droite par 4, assignons cette valeur au caractère 1, et à la position 2 nous assignons la même recherche, sauf que nous préformons une logique et pour voir si la valeur est 15 (0xF), et retourner un 1 dans ce cas, ou un 0 autrement. À la fin, tu finiras avec quelque chose d'encodé.
  • si elle finit ce n'est pas un espace, c'est alphanumérique ou l'un des _-. chars, il génère exactement ce que c'est.

RAWURLENCODE:

  • Alloue de la mémoire pour la chaîne
  • Parcourt-il en fonction de la durée prévue dans l'appel de fonction (pas calculé en fonction avec la fonction URLENCODE).

Note: Beaucoup les programmeurs n'ont probablement jamais vu un pour boucle iterate de cette façon, il est quelque peu hackish et pas la convention standard utilisée avec la plupart des for-loops, attention, il assigne x et y , les vérifications de sortie sur len atteindre 0, et les incréments à la fois x et y . Je sais, ce n'est pas ce à quoi tu t'attendais, mais c'est un code valide.

  • attribue le caractère actuel à une position de caractère correspondant dans str .
  • il vérifie si le caractère actuel est alphanumérique, ou l'un des caractères _-. , et si ce n'est pas le cas, nous faisons presque la même tâche qu'avec URLENCODE où il préformes les recherches, cependant, 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 façons, mais atteignent le même but à la fin de toute façon.
  • quand la boucle est terminée et que la longueur a disparu, elle se termine en fait la chaîne, assignant le byte " 1519270920" .
  • renvoie la chaîne encodée.

différences:

  • UrlEncode vérifie l'espace, assigne un signe+, RawURLEncode ne le fait pas.
  • UrlEncode n'attribue pas un octet "1519270920" à la chaîne, RawUrlEncode le fait (ceci peut être un point discutable)
  • peut être enclin à déborder avec des cordes malformées, je suis simplement suggérant ceci et je n'ont pas réellement étudié.

ils itèrent fondamentalement différemment, on assigne un signe + dans le cas de ASCII 20.

différences dans L'EBCDIC:

URLENCODE:

  • même configuration d'itération qu'avec ASCII
  • traduisant toujours le caractère" espace "en un signe + . Note-- je pense que cela doit être compilé dans EBCDIC ou vous finirez avec un bug? Quelqu'un peut-il modifier et confirmer cela?
  • il vérifie si le présent code est un code avant 0 , à l'exception des codes . ou - , ou inférieur à A mais supérieur à 9 , ou supérieur à Z et inférieur à a mais non un _ . ou plus grand que z (ouais, EBCDIC est un peu dérangé de travailler avec). S'il correspond à l'un de ceux-ci, faites une recherche similaire à celle trouvée dans la version ASCII (elle ne nécessite pas de recherche dans os_toascii).

RAWURLENCODE:

  • même configuration d'itération qu'avec ASCII
  • même vérification que celle décrite dans la version EBCDIC de L'encodage D'URL, à l'exception que si elle est supérieure à z , elle exclut ~ de l'encodage D'URL.
  • même affectation que le RawUrlEncode ASCII
  • toujours en ajoutant le byte " 1519270920 " à la chaîne avant le retour.

Grand Résumé

  • les deux utilisent la même recherche d'hexchars tableau 1519980920"
  • URIEncode ne termine pas une chaîne avec \0, raw le fait.
  • si vous travaillez dans EBCDIC, je vous suggérerais D'utiliser RawUrlEncode, car il gère le ~ que UrlEncode ne fait pas ( il s'agit d'un problème rapporté ). Il est intéressant de noter que ASCII et EBCDIC 0x20 sont deux espaces.
  • ils itèrent différemment, l'un peut être plus rapide, l'autre peut être enclin à des exploits basés sur la mémoire ou la chaîne.
  • URIEncode fait un espace dans + , RawUrlEncode fait un espace dans %20 via des recherches de réseau.

avis de non-responsabilité: Je n'ai pas touché C depuis des années, et je n'ai pas regardé EBCDIC depuis vraiment très longtemps. Si je me trompe quelque part, prévenez-moi.

suggestions de mise en œuvre

basé sur tout cela, rawurlencode est la voie à suivre la plupart du temps. Comme vous le voyez dans la réponse de Jonathan Fingland, il faut s'y tenir dans la plupart des cas. Il traite du schéma moderne pour les composants URI, où comme urlencode fait les choses à l'ancienne, où + signifiait "espace."

si vous essayez de convertir entre l'ancien format et les nouveaux formats, assurez-vous que votre code ne dérape pas et ne transforme pas quelque chose qui est un signe + décodé dans un espace par un double encodage accidentel, ou des scénarios" oops " similaires autour de cet espace/20%/+ problème.

Si vous travaillez sur un système plus ancien avec des logiciels plus anciens qui ne préfèrent pas le nouveau format, collez avec urlencode, cependant, je crois que %20 sera en fait rétrocompatible, comme sous l'ancienne norme %20 travaillé, juste n'a pas été préféré. Tentez votre chance si vous êtes prêt à jouer, Faites-nous savoir comment ça a marché pour vous.

fondamentalement, vous devriez rester avec raw, à moins que votre système EBCDIC vous déteste vraiment. La plupart des programmeurs ne tomberont jamais dans EBCDIC sur n'importe quel système après l'an 2000, peut-être même 1990 (c'est poussant, mais encore probable à mon avis).

201
répondu Incognito 2017-05-23 12:02:29
echo rawurlencode('http://www.google.com/index.html?id=asd asd');

rendements

http%3A%2F%2Fwww.google.com%2Findex.html%3Fid%3Dasd%20asd

alors que

echo urlencode('http://www.google.com/index.html?id=asd asd');

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 RFC 1738 en encodant des espaces comme + au lieu de %20

31
répondu jitter 2009-06-15 13:44:47

une raison pratique de choisir l'un par rapport à l'autre est si vous allez utiliser le résultat dans un autre environnement, par exemple JavaScript.

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 () fonction alors decodeURI("test+1") vous donnera "test+1" tandis que decodeURI("test%201") vous donnera "test 1" comme résultat.

en D'autres termes, L'espace ( " ") encodé par urlencode à plus (" + ") en PHP ne sera pas correctement décodé par decodeURI en JavaScript.

dans ces cas, la fonction rawurlencode PHP doit être utilisée.

25
répondu Neven Boyanov 2011-12-21 14:04:37

je crois espaces doit être codé comme:

  • %20 lorsqu'il est utilisé à l'intérieur du composant de chemin D'URL
  • + lorsqu'il est utilisé à l'intérieur de la chaîne de requête D'URL ou de données de forme (voir 17.13.4 types de contenu de forme )

L'exemple suivant montre l'utilisation correcte de rawurlencode et 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 les composants chemin et chaîne de requête dans l'autre sens? Pour l'exemple suivant:

http://example.com/category/latest+songs/search?q=lady%20gaga
  • le serveur web recherchera le répertoire latest+songs au lieu de latest songs
  • le paramètre de la chaîne de requête q contiendra lady gaga
19
répondu Salman A 2013-01-07 12:34:30

la différence est dans les valeurs de retour, I. e:

urlencode () :

renvoie une chaîne dans laquelle tous caractères non alphanumériques sauf -_. ont été remplacés par un pourcentage (%) signe suivi de deux chiffres hexadécimaux et espaces encodés en signes plus ( + ). Il est codé de la même façon que le les données postées à partir d'un formulaire WWW est codé, qui est de la même manière que dans application / x-www-form-urlencoded type de support. Cela diffère de la " Encodage RFC 1738 (voir rawurlencode()) pour des raisons historiques, les espaces sont codés comme des signes plus ( + ).

rawurlencode () :

renvoie une chaîne dans laquelle tous caractères non alphanumériques sauf -_. ont été remplacés par un pourcentage (%) signe suivi de deux chiffres hexadécimaux. Ce est l'encodage décrit dans " RFC 1738 pour la protection littérale caractère interprétés comme des URL délimiteurs, et pour la protection des URLs d'être mutilé par la transmission médias avec conversion de caractères (comme certains systèmes de messagerie).

les deux sont très similaires, mais ce dernier (rawurlencode) remplacera les espaces avec un ' % 'et deux chiffres hexadécimaux, ce qui est approprié pour encoder des mots de passe ou tels, 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%2F@ftp.example.com/x.txt">
5
répondu karim79 2009-06-15 13:46:22

1. Quelles sont exactement les différences et

la seule différence réside dans la façon dont les espaces sont traités:

urlencode basé sur l'héritage de la mise en œuvre convertit les espaces à +

rawurlencode - basé sur RFC 1738 traduit les espaces par %20

la raison de la différence est que + est réservé et valide (Non-codé) dans les urls.

2. qui est préféré?

j'aimerais vraiment voir quelques raisons de choisir l'une plutôt que l'autre ... Je veux pouvoir en choisir un et l'utiliser pour toujours avec le moins de tracas.

très bien, j'ai une stratégie simple que je suis en prenant ces décisions que je partagerai avec vous dans l'espoir qu'elle puisse aider.

je pense que C'était la spécification HTTP/1.1 RFC 2616 qui appelé pour applications tolérantes

les Clients doivent être tolérants dans l'analyse de la ligne de statut et des serveurs tolérant lors de l'analyse de la ligne de demande.

face à des questions comme celles-ci, la meilleure stratégie est toujours de consommer autant que possible et de produire ce qui est conforme aux normes.

mon conseil est donc d'utiliser rawurlencode pour produire des chaînes codées RFC 1738 conformes aux normes et d'utiliser urldecode pour être rétrocompatible et accommoder tout ce que vous pourriez rencontrer pour consommer.

vous pouvez me croire sur parole, mais prouvons-le...

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é quelqu'un refusant l'un ou l'autre des deux formats, Je ne peux pas penser à un meilleure stratégie à adopter comme stratégie de fait, pouvez-vous?

nJoy!

5
répondu nickl- 2013-09-18 21:49:31

urlencode : cela diffère de la "Encodage RFC 1738 (voir rawurlencode()) pour l'historique raisons, les espaces sont encodés en plus (+) signer.

4
répondu Remus Rusanu 2009-06-15 13:38:02

je crois que urlencode est pour les paramètres de requête, alors que le rawurlencode est pour les segments de chemin. Ceci est principalement dû à %20 pour les segments de chemin vs + pour les paramètres de requête. Voir cette réponse qui parle des espaces: quand encoder espace à plus ( + ) ou %20?

cependant %20 fonctionne maintenant dans les paramètres de requête aussi bien, c'est pourquoi rawurlencode est toujours plus sûr. Cependant le signe tend à être utilisée lorsqu' l'expérience de l'utilisateur de l'édition et la lisibilité des paramètres de requête importe.

noter que cela signifie rawurldecode ne décode pas + dans les espaces ( http://au2.php.net/manual/en/function.rawurldecode.php ). C'est pourquoi le $_GET est toujours automatiquement passé par urldecode , ce qui signifie que + et %20 sont tous deux décodés dans des espaces.

si vous voulez que l'encodage et le décodage soit cohérent entre les entrées et les sorties et vous avez sélectionné d'utiliser toujours + et non %20 pour les paramètres de requête, puis urlencode est très bien pour les paramètres de requête (clé et valeur).

la conclusion est:

segments de chemin - toujours utiliser rawurlencode / rawurldecode

paramètres de requête - pour le décodage toujours utiliser urldecode (fait automatiquement), pour le codage, à la fois rawurlencode ou urlencode est très bien, il suffit de choisir un pour être cohérent, surtout quand on compare les URLs.

1
répondu CMCDragonkai 2017-05-23 12:17:53

espaces codés comme %20 vs. +

la raison la plus importante que j'ai vu pour utiliser rawurlencode() dans la plupart des cas est parce que urlencode encode les espaces de texte comme + (plus les signes) où rawurlencode les encode comme le plus souvent vu %20 :

echo urlencode("red shirt");
// red+shirt

echo rawurlencode("red shirt");
// red%20shirt

j'ai vu spécifiquement certains paramètres de L'API qui acceptent les requêtes texte encodées s'attendre à voir %20 pour un espace et par conséquent, échouer si un plus le signe est utilisé à la place. Évidemment, cela va différer entre les implémentations de l'API et votre kilométrage peut varier.

1
répondu Jake Wilson 2016-07-27 21:21:46

simple * rawurlencode le chemin - chemin d'accès est la partie avant le "?" - les espaces doivent être codés en %20 * urlencode la chaîne de requête - Chaîne de requête est la partie après le "?" -les espaces sont mieux codé comme "+" = rawurlencode est généralement plus compatible

0
répondu haysam elmasry 2017-03-14 11:40:46