web-dev-qa-db-fra.com

Quand êtes-vous censé utiliser échappement au lieu d'encodureURI/encodeURIComponent?

Lors du codage d'une chaîne de requête à envoyer à un serveur Web, utilisez-vous escape() et quand utilisez-vous encodeURI() ou encodeURIComponent():

Utilisez escape:

escape("% +&=");

OR

utiliser encodeURI ()/encodeURIComponent ()

encodeURI("http://www.google.com?var1=value1&var2=value2");

encodeURIComponent("var1=value1&var2=value2");
1323
Adam

échapper()

Ne l'utilisez pas! escape() est défini dans la section B.2.1.2 échappement et le texte d'introduction de l'Annexe B indique:

... Toutes les caractéristiques et tous les comportements de langage spécifiés dans cette annexe ont une ou plusieurs caractéristiques indésirables et, en l'absence d'utilisation héritée, seraient supprimés de cette spécification. ...
... Les programmeurs ne doivent pas utiliser ou supposer l'existence de ces caractéristiques et comportements lors de l'écriture de nouveau code ECMAScript ....

Comportement:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape } _

Les caractères spéciaux sont codés à l'exception de: @ * _ + -. /

La forme hexadécimale des caractères dont l'unité de code est égale ou inférieure à 0xFF est une séquence d'échappement à deux chiffres: %xx.

Pour les caractères avec une plus grande unité de code, le format à quatre chiffres %uxxxx est utilisé. Ceci n'est pas autorisé dans une chaîne de requête (comme défini dans RFC3986 ):

query       = *( pchar / "/" / "?" )
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded   = "%" HEXDIG HEXDIG
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
              / "*" / "+" / "," / ";" / "="

Un signe de pourcentage n'est autorisé que s'il est directement suivi de deux chiffres hexadécimaux, le pourcentage suivi de u n'est pas autorisé.

encodeURI ()

Utilisez encodeURI lorsque vous voulez une URL fonctionnelle. Faites cet appel:

encodeURI("http://www.example.org/a file with spaces.html")

obtenir:

http://www.example.org/a%20file%20with%20spaces.html

N'appelez pas encodeURIComponent car cela détruirait l'URL et renverrait

http%3A%2F%2Fwww.example.org%2Fa%20file%20with%20spaces.html

encodeURIComponent ()

Utilisez encodeURIComponent lorsque vous souhaitez coder la valeur d'un paramètre d'URL.

var p1 = encodeURIComponent("http://example.org/?a=12&b=55")

Ensuite, vous pouvez créer l'URL dont vous avez besoin:

var url = "http://example.net/?param1=" + p1 + "&param2=99";

Et vous obtiendrez cette URL complète:

http://example.net/?param1=http%3A%2F%2Fexample.org%2F%Ffa%3D12%26b%3D55&param2=99

Notez qu'encodeURIComponent n'échappe pas au caractère '. Un bug courant consiste à l’utiliser pour créer des attributs HTML tels que href='MyUrl', qui pourraient être affectés par un bug d’injection. Si vous construisez du code HTML à partir de chaînes, utilisez " au lieu de ' pour les guillemets d'attributs ou ajoutez une couche d'encodage supplémentaire (' peut être codé sous la forme% 27).

Pour plus d'informations sur ce type d'encodage, vous pouvez vérifier: http://en.wikipedia.org/wiki/encercing-percent

1847
Arne Evertsson

La différence entre encodeURI() et encodeURIComponent() correspond exactement à 11 caractères codés par encodeURIComponent mais pas par encodeURI:

Table with the ten differences between encodeURI and encodeURIComponent

J'ai généré ce tableau facilement avec console.table dans Google Chrome avec ce code:

var arr = [];
for(var i=0;i<256;i++) {
  var char=String.fromCharCode(i);
  if(encodeURI(char)!==encodeURIComponent(char)) {
    arr.Push({
      character:char,
      encodeURI:encodeURI(char),
      encodeURIComponent:encodeURIComponent(char)
    });
  }
}
console.table(arr);

411

J'ai trouvé cet article éclairant: Javascript Madness: Query String Parsing

Je l'ai trouvé quand j'essayais de comprendre pourquoi decodeURIComponent ne décodait pas correctement le "+". Voici un extrait:

String:                         "A + B"
Expected Query String Encoding: "A+%2B+B"
escape("A + B") =               "A%20+%20B"     Wrong!
encodeURI("A + B") =            "A%20+%20B"     Wrong!
encodeURIComponent("A + B") =   "A%20%2B%20B"   Acceptable, but strange

Encoded String:                 "A+%2B+B"
Expected Decoding:              "A + B"
unescape("A+%2B+B") =           "A+++B"       Wrong!
decodeURI("A+%2B+B") =          "A+++B"       Wrong!
decodeURIComponent("A+%2B+B") = "A+++B"       Wrong!
43
Damien

encodeURIComponent ne code pas -_.!~*'(), ce qui pose un problème pour la publication de données sur php dans une chaîne xml.

Par exemple:
<xml><text x="100" y="150" value="It's a value with single quote" /> </xml>

Evasion générale avec encodeURI
%3Cxml%3E%3Ctext%20x=%22100%22%20y=%22150%22%20value=%22It's%20a%20value%20with%20single%20quote%22%20/%3E%20%3C/xml%3E

Vous pouvez voir que les guillemets simples ne sont pas codés . Pour résoudre le problème, j’ai créé deux fonctions permettant de résoudre le problème dans mon projet:

function encodeData(s:String):String{
    return encodeURIComponent(s).replace(/\-/g, "%2D").replace(/\_/g, "%5F").replace(/\./g, "%2E").replace(/\!/g, "%21").replace(/\~/g, "%7E").replace(/\*/g, "%2A").replace(/\'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29");
}

Pour l'URL de décodage:

function decodeData(s:String):String{
    try{
        return decodeURIComponent(s.replace(/\%2D/g, "-").replace(/\%5F/g, "_").replace(/\%2E/g, ".").replace(/\%21/g, "!").replace(/\%7E/g, "~").replace(/\%2A/g, "*").replace(/\%27/g, "'").replace(/\%28/g, "(").replace(/\%29/g, ")"));
    }catch (e:Error) {
    }
    return "";
}
38

encodeURI () - la fonction escape () sert à l'échappement javascript, pas à HTTP.

37
Daniel Papasian

Petit tableau de comparaison Java vs. JavaScript vs. PHP.

1. Java URLEncoder.encode (using UTF8 charset)
2. JavaScript encodeURIComponent
3. JavaScript escape
4. PHP urlencode
5. PHP rawurlencode

char   Java JavaScript --PHP---
[ ]     +    %20  %20  +    %20
[!]     %21  !    %21  %21  %21
[*]     *    *    *    %2A  %2A
[']     %27  '    %27  %27  %27 
[(]     %28  (    %28  %28  %28
[)]     %29  )    %29  %29  %29
[;]     %3B  %3B  %3B  %3B  %3B
[:]     %3A  %3A  %3A  %3A  %3A
[@]     %40  %40  @    %40  %40
[&]     %26  %26  %26  %26  %26
[=]     %3D  %3D  %3D  %3D  %3D
[+]     %2B  %2B  +    %2B  %2B
[$]     %24  %24  %24  %24  %24
[,]     %2C  %2C  %2C  %2C  %2C
[/]     %2F  %2F  /    %2F  %2F
[?]     %3F  %3F  %3F  %3F  %3F
[#]     %23  %23  %23  %23  %23
[[]     %5B  %5B  %5B  %5B  %5B
[]]     %5D  %5D  %5D  %5D  %5D
----------------------------------------
[~]     %7E  ~    %7E  %7E  ~
[-]     -    -    -    -    -
[_]     _    _    _    _    _
[%]     %25  %25  %25  %25  %25
[\]     %5C  %5C  %5C  %5C  %5C
----------------------------------------
char  -Java-  --JavaScript--  -----PHP------
[ä]   %C3%A4  %C3%A4  %E4     %C3%A4  %C3%A4
[ф]   %D1%84  %D1%84  %u0444  %D1%84  %D1%84
16
30thh

Je recommande de ne pas utiliser l'une de ces méthodes telles quelles. Ecrivez votre propre fonction qui fait la bonne chose.

MDN a donné un bon exemple de codage d’URL présenté ci-dessous.

var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''" + encodeRFC5987ValueChars(fileName);

console.log(header); 
// logs "Content-Disposition: attachment; filename*=UTF-8''my%20file%282%29.txt"


function encodeRFC5987ValueChars (str) {
    return encodeURIComponent(str).
        // Note that although RFC3986 reserves "!", RFC5987 does not,
        // so we do not need to escape it
        replace(/['()]/g, escape). // i.e., %27 %28 %29
        replace(/\*/g, '%2A').
            // The following are not required for percent-encoding per RFC5987, 
            //  so we can allow for a little better readability over the wire: |`^
            replace(/%(?:7C|60|5E)/g, unescape);
}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent

11
Jerry Joseph

N'oubliez pas non plus qu'ils encodent tous différents jeux de caractères et sélectionnez celui dont vous avez besoin. encodeURI () encode moins de caractères que encodeURIComponent (), ce qui encode moins de caractères (et également différents, du point de dannyp) à l'échappement ().

10
Pseudo Masochist

Pour coder javascript, trois fonctions ont été intégrées:

  1. escape () - ne code pas @*/+ Cette méthode est obsolète après ECMA 3, elle devrait donc être évitée.

  2. encodeURI () - ne code pas ~!@#$&*()=:/,;?+'Il suppose que l’URI est un URI complet et ne code donc pas les caractères réservés qui ont une signification spéciale dans l’URI . Cette méthode est utilisée lorsque l’intention est de convertir le code complet. URL au lieu d’un segment spécial d’URL . Exemple - encodeURI('http://stackoverflow.com'); Donnera - http://stackoverflow.com

  3. encodeURIComponent () n'encode pas - _ . ! ~ * ' ( ) Cette fonction code un composant URI (Uniform Resource Identifier) ​​en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant le codage UTF-8 du caractère. Cette méthode doit être utilisée pour convertir un composant d'URL. Par exemple, certaines entrées utilisateur doivent être ajoutées Exemple - encodeURI('http://stackoverflow.com'); Donnera - http% 3A% 2F% 2Fstackoverflow.com

Tout cet encodage est effectué en UTF 8, c'est-à-dire que les caractères seront convertis au format UTF-8. 

encodeURIComponent diffère de encodeURI en ce qu'il code les caractères réservés et le numéro de signe # de encodeURI}

6
Gaurav Tiwari

J'ai constaté qu'expérimenter les différentes méthodes est un bon contrôle de la santé mentale même après avoir bien maîtrisé leurs utilisations et leurs capacités.

À cette fin, j'ai trouvé ce site Web extrêmement utile pour confirmer mes soupçons selon lesquels je suis en train de faire quelque chose de bien. Il s’est également avéré utile pour décoder une chaîne encodée par l’URG qui peut être assez difficile à interpréter. Un super bookmark à avoir:

http://www.the-art-of-web.com/javascript/escape/

3
veeTrain

J'ai cette fonction ...

var escapeURIparam = function(url) {
    if (encodeURIComponent) url = encodeURIComponent(url);
    else if (encodeURI) url = encodeURI(url);
    else url = escape(url);
    url = url.replace(/\+/g, '%2B'); // Force the replacement of "+"
    return url;
};
1
molokoloco

La réponse acceptée est bonne… .. Pour prolonger la dernière partie:

Notez qu'encodeURIComponent n'échappe pas au caractère '. Un commun le bogue est de l’utiliser pour créer des attributs HTML tels que href = 'MyUrl', qui pourrait souffrir d'un bug d'injection. Si vous construisez du HTML à partir de chaînes, utilisez "au lieu de" pour les guillemets d'attributs ou ajoutez une couche d'encodage supplémentaire .__ (peut être codé sous la forme% 27).

Si vous voulez être sûr, coder pour cent les caractères non réservés doit également être encodé. 

Vous pouvez utiliser cette méthode pour les échapper (source Mozilla )

function fixedEncodeURIComponent(str) {
  return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
    return '%' + c.charCodeAt(0).toString(16);
  });
}

// fixedEncodeURIComponent("'") --> "%27"
1
Michael

Réécriture moderne de la réponse de @ johann-echavarria:

console.log(
    Array(256)
        .fill()
        .map((ignore, i) => String.fromCharCode(i))
        .filter(
            (char) =>
                encodeURI(char) !== encodeURIComponent(char)
                    ? {
                          character: char,
                          encodeURI: encodeURI(char),
                          encodeURIComponent: encodeURIComponent(char)
                      }
                    : false
        )
)

Ou, si vous pouvez utiliser une table, remplacez console.log par console.table (pour une sortie plus jolie).

1
ryanpcmcquen

Inspiré par la table de Johann , j'ai décidé d'étendre la table. Je voulais voir quels caractères ASCII étaient codés.

 screenshot of console.table

var ascii = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";

var encoded = [];

ascii.split("").forEach(function (char) {
    var obj = { char };
    if (char != encodeURI(char))
        obj.encodeURI = encodeURI(char);
    if (char != encodeURIComponent(char))
        obj.encodeURIComponent = encodeURIComponent(char);
    if (obj.encodeURI || obj.encodeURIComponent)
        encoded.Push(obj);
});

console.table(encoded);

Le tableau montre uniquement les caractères encodés. Les cellules vides signifient que l'original et les caractères encodés sont les mêmes.


Juste pour être extra, j'ajoute une autre table pour urlencode() vs rawurlencode() . La seule différence semble être l'encodage du caractère d'espace.

 screenshot of console.table

<script>
<?php
$ascii = str_split(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", 1);
$encoded = [];
foreach ($ascii as $char) {
    $obj = ["char" => $char];
    if ($char != urlencode($char))
        $obj["urlencode"] = urlencode($char);
    if ($char != rawurlencode($char))
        $obj["rawurlencode"] = rawurlencode($char);
    if (isset($obj["rawurlencode"]) || isset($obj["rawurlencode"]))
        $encoded[] = $obj;
}
echo "var encoded = " . json_encode($encoded) . ";";
?>
console.table(encoded);
</script>
0
akinuri