web-dev-qa-db-ja.com

encodeURI / encodeURIComponentの代わりにescapeを使用することになっていますか?

Webサーバに送信されるクエリ文字列をエンコードするとき - いつescape()を使うのか、そしていつencodeURI()またはencodeURIComponent()を使うのか:

エスケープを使う:

escape("% +&=");

OR

encodeURI()/ encodeURIComponent()を使用してください。

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

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

エスケープ()

使用しないでください。 escape()は付録 で定義されています。B.2.1.2エスケープ および のAnnex B の導入テキストでは、

...この附属書に明記されているすべての言語機能および振る舞いは、1つまたは複数の望ましくない特性を持っており、従来の用法がない場合はこの仕様から削除されます。 ...
...プログラマーは、新しいECMAScriptコードを書くときに、これらの機能や動作の存在を使用または想定しないでください。

動作:

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

特殊文字は、@ * _ + - を除いてエンコードされます。

コード単位の値が0xFF以下の文字の16進形式は、2桁のエスケープシーケンス、%xxです。

より大きいコード単位を持つ文字の場合は、4桁のフォーマット%uxxxxが使用されます。これは、クエリ文字列内では許可されません( RFC3986 で定義されているとおり)。

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

パーセント記号は、その直後に2つの16進数字が続く場合にのみ許可され、パーセントの後にuが続くことは許可されません。

encodeURI()

実用的なURLが欲しいときにencodeURIを使用してください。この電話をかける:

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

取得するため:

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

URLを破壊して戻るので、encodeURIComponentを呼び出さないでください。

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

encodeURIComponent()

URLパラメータの値をエンコードする場合は、encodeURIComponentを使用してください。

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

それからあなたはあなたが必要とするURLを作成することができます:

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

そして、あなたはこの完全なURLを手に入れるでしょう:

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

EncodeURIComponentは'文字をエスケープしないことに注意してください。よくあるバグはそれを使ってhref='MyUrl'のようなhtml属性を作成することです。これはインジェクションのバグを被る可能性があります。文字列からhtmlを作成する場合は、属性の引用符に"の代わりに'を使用するか、または追加のエンコード層を追加します('は%27としてエンコードできます)。

このタイプのエンコーディングの詳細については、次のものを確認できます。 http://en.wikipedia.org/wiki/Percent-encoding

1866
Arne Evertsson

encodeURI()encodeURIComponent()の違いは、encodeUICではなくencodeURIComponentによってエンコードされた11文字です。

Table with the ten differences between encodeURI and encodeURIComponent

このコードを使ってGoogle Chromeでconsole.tableを使って簡単にこのテーブルを生成しました。

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);
416

私はこの記事が啓発を見つけた: Javascriptの狂気:クエリ文字列の解析

DecodeURIComponentが '+'を正しくデコードしていなかった理由を理解しようとしたときに見つけました。これが抜粋です。

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!
46
Damien

encodeURIComponentは-_.!~*'()をエンコードしないため、XML文字列でphpにデータを投稿する際に問題が発生します。

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

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

ご覧のとおり、一重引用符はエンコードされていません。問題を解決するために、私は自分のプロジェクトの問題を解決するために2つの関数を作成しました。URLのエンコード:

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");
}

デコードURLの場合:

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 "";
}
40

encodeURI() - escape()関数はHTTPではなくJavaScriptエスケープ用です。

38
Daniel Papasian

小さな比較表Java対JavaScript対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
17
30thh

これらの方法をそのまま使用しないことをお勧めします。正しいことをするあなた自身の関数を書いてください。

MDNは、次に示すURLエンコードの良い例を示しています。

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

また、それらはすべて異なる文字セットをエンコードしているので、必要なものを適切に選択してください。 encodeURI()は、encodeURIComponent()よりも少ない文字数をエンコードします。これは、escape()よりも少ない文字数(dannypの観点とは異なります)をエンコードします。

10

Javascriptをエンコードする目的で3つの作り付けの関数を与えました -

  1. escape() - @*/+をエンコードしませんこのメソッドはECMA 3以降は推奨されていないので、避けるべきです。

  2. encodeURI() - ~!@#$&*()=:/,;?+'をエンコードしませんURIは完全なURIであると想定しているため、URIで特別な意味を持つ予約文字はエンコードしません。このメソッドは、URLの特別なセグメントではなく、完全なURLを変換することを目的としている場合に使用されます。例 - encodeURI('http://stackoverflow.com');は - http://stackoverflow.comを与えます

  3. encodeURIComponent() - - _ . ! ~ * ' ( )をエンコードしないこの関数は、特定の文字の各インスタンスを、文字のUTF-8エンコードを表す1、2、3、または4つのエスケープシーケンスで置き換えることによって、URI(Uniform Resource Identifier)コンポーネントをエンコードします。このメソッドはURLのコンポーネントを変換するために使われるべきです。例えば、いくつかのユーザ入力を追加する必要があります。例 - encodeURI('http://stackoverflow.com');は与える - http%3A%2F%2Fstackoverflow.com

このエンコーディングはすべてUTF 8で実行されます。つまり、文字はUTF-8形式に変換されます。

encodeURIComponentは、エンコードされた文字とencodeURIのシャープ記号をエンコードするという点でencodeURIと異なります

7
Gaurav Tiwari

さまざまな方法を試してみることは、さまざまな用途や機能が何であるかをよく理解した後でも、健全性を確認するのに適していることがわかりました。

その目的のために私は このウェブサイト が私が何かを適切にしているという私の疑いを確認するために非常に有用であることを見つけました。それは、解釈するのがかなり難しい場合があるencodeURIComponentの文字列をデコードするのにも有用であることが証明されています。持っているのに最適なブックマーク:

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

3
veeTrain

Johannのテーブル に触発されて、私はテーブルを拡張することにしました。どの[ASCII文字がエンコードされるのかを見たかったのです。

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);

表はエンコードされた文字のみを示しています。空のセルは、元の文字とエンコードされた文字が同じであることを意味します。


念のため、 urlencode() vs rawurlencode() 唯一の違いはスペース文字のエンコーディングです。

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>
2
akinuri

私はこの機能を持っています...

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

受け入れられた答えは良いです。最後の部分を拡張するには

EncodeURIComponentは '文字をエスケープしないことに注意してください。よくあるバグはこれを使ってhref = 'MyUrl'のようなHTML属性を作成することです。文字列からhtmlを作成している場合は、属性の引用符に "の代わりに"を使用するか、またはエンコーディングのレイヤを追加します( '%27としてエンコードできます)。

あなたが安全側になりたいのであれば、 パーセントエンコーディング予約されていない文字 もエンコードする必要があります。

あなたはそれらをエスケープするためにこのメソッドを使うことができます(source Mozilla

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

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

@ 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
        )
)

あるいは、テーブルを使用できる場合は、(きれいな出力のために)console.logconsole.tableに置き換えます。

1
ryanpcmcquen