urlencode対rawurlencode?


380

変数を使用してURLを作成する場合、文字列をエンコードする方法は2つあります。urlencode()rawurlencode()

違いは何ですか?どちらが好ましいですか?


1
私は本当にどちらか一方を選択するいくつかの理由を見たいと思います(たとえば、どちらかで発生する可能性のある問題)、私(と私は他の人が期待する)を選択して、それを永遠に使用できるようにしたいです少なくとも大騒ぎなので、この質問について賞金を獲得しました。
Kzqai 2011

29
@Tchalvak:1つだけ選択する場合は、を選択しますrawurlencode。あなたはめったにチョーク与えられたスペースとしてエンコードすることをシステムに実行していないだろう%20システムにスペース上のチョークのようにエンコードされていることが、+より一般的です。
Anomie、2011

回答:


326

それはあなたの目的に依存します。他のシステムとの相互運用性が重要な場合は、rawurlencodeが適しています。1つの例外は、クエリ文字列が%20ではなく+としてエンコードされたスペースのフォームエンコーディングスタイルに従うことを期待するレガシーシステムです(この場合、urlencodeが必要です)。

rawurlencodeは、PHP 5.3.0以前のRFC 1738およびその後のRFC 3986に準拠しています(http://us2.php.net/manual/en/function.rawurlencode.phpを参照)

-_。〜を除くすべての非英数字がパーセント(%)記号とそれに続く2桁の16進数で置き換えられた文字列を返します。これは»RFC 3986で説明されているエンコーディングであり、リテラル文字が特殊なURL区切り文字として解釈されないように保護し、URLが文字変換のある送信メディア(一部の電子メールシステムなど)によって変換されないようにします。

RFC 3986と1738の比較。php5.3より前のrawurlencodeは~、RFC 1738に従ってチルダ文字()をエンコードしていました。ただし、PHP 5.3以降、rawurlencodeは、チルダ文字のエンコードを必要としないRFC 3986に従っています。

urlencodeはスペースをプラス記号としてエンコードします(%20rawurlencodeの場合とは異なります)(http://us2.php.net/manual/en/function.urlencode.phpを参照)

-_を除くすべての非英数字が含まれる文字列を返します。パーセント(%)記号とそれに続く2つの16進数とプラス(+)記号としてエンコードされたスペースに置き換えられました。WWWフォームからポストされたデータがエンコードされるのと同じ方法でエンコードされます。つまり、application / x-www-form-urlencodedメディアタイプの場合と同じです。これは»RFC 3986エンコーディング(rawurlencode()を参照)とは異なります。歴史的な理由から、スペースはプラス(+)記号としてエンコードされます。

これは、RFC 1866の application / x-www-form-urlencodedの定義に対応しています。

追加の読み:

http://bytes.com/groups/php/5624-urlencode-vs-rawurlencodeでディスカッションを確認することもできます。

また、RFC 2396も一見の価値があります。RFC 2396は有効なURI構文を定義しています。私たちが興味を持っている主要な部分は3.4クエリコンポーネントからです:

クエリコンポーネント内では、文字は予約されています。";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$"

ご覧のとおり+、これはクエリ文字列の予約文字であるため、RFC 3986に従ってエンコードする必要があります(rawurlencodeなど)。


27
それでどちらが優先されますか?
ゲーリーウィロビー

79
rawurlencode。この場合は標準で行ってください。urlencodeはレガシー使用のためにのみ保持されます
Jonathan Fingland '15

2
たくさんのコードを更新する前に、セカンドオピニオンが欲しかったのです。
ゲイリーウィロビー

3
スペースをプラス記号としてではなく%20sとしてエンコードするのはrawurlencodeだと思います
BigName

2
@Pindatjuh:引用した部分1つの例外は、クエリ文字列が%20ではなく+としてエンコードされたスペースのフォームエンコーディングスタイルに従うことを期待するレガシーシステムです(この場合、urlencodeが必要です)は、rawurlencodeがほとんどの状況に適していることを意味します、一部のシステムでは、スペースが+(正符号)としてエンコードされることを想定しています。そのようなシステムでは、urlencodeがより良い選択です。
ジョナサンフィンランド、2011

213

プルーフはPHPのソースコードにあります。

いつでも自分でこの種のことを自分で見つける方法の簡単なプロセスを説明します。気を付けてください。Cソースコードはたくさん読み飛ばすことができます(説明します)。Cをブラッシュアップしたい場合は、SO wikiから始めるのが良いでしょう

ソースをダウンロードして(またはhttp://lxr.php.net/を使用してオンラインで閲覧します)、関数名のすべてのファイルをgrepすると、次のようなものが見つかります。

PHP 5.3.6(執筆時点で最新)は、ファイルurl.cのネイティブCコードの2つの関数について説明しています。

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

では、ここで何が違うのですか?

どちらも本質的に、2つの異なる内部関数をそれぞれ呼び出しています:php_raw_url_encodephp_url_encode

だから、それらの関数を探しに行ってください!

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

そしてもちろん、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;
}

次に進む前に、EBCDICは ASCIIに似た別の文字セットですが、完全な競争相手です。PHPは両方を処理しようとします。しかし基本的に、これはバイトEBCDIC 0x4cバイトがLASCIIではなく、実際にはであることを意味します<。きっとあなたはここで混乱を目にするでしょう。

Webサーバーで定義されている場合、これらの関数はどちらもEBCDICを管理します。

また、どちらも文字の配列(文字列型と考えます)のhexcharsルックアップを使用していくつかの値を取得します。配列は次のように記述されます。

/* 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";

それ以外は、機能が本当に異なるので、ASCIIとEBCDICで説明します。

ASCIIの違い:

URLENCODE:

  • 入力文字列の開始/終了の長さを計算し、メモリを割り当てます
  • 文字列の終わりに達するまで、whileループをインクリメントします
  • 現在のキャラクターをつかむ
  • 文字がASCII Char 0x20(つまり、「スペース」)に等しい場合は+、出力文字列に符号を追加します。
  • それはスペースはありません、それはまた、(英数字ではない場合isalnum(c))、またしていない_-または.文字は、我々は、出力%配列の位置0に記号を、に配列ルックアップを行うhexcharsためのルックアップのための配列os_toascii(配列(現在の文字)のキーに対して、charを16進コードに変換するApacheの配列。c次に、ビット単位で右に4シフトし、その値を文字1に割り当て、位置2に、プリフォームを除いて同じルックアップを割り当てます。論理値で、値が15(0xF)かどうかを確認し、その場合は1を返し、そうでない場合は0を返します。最後に、エンコードされたものになります。
  • 最終的にスペースではない場合、それは英数字または文字の1つであり、_-.正確に何であるかを出力します。

RAWURLENCODE:

  • 文字列にメモリを割り当てます
  • 関数呼び出しで提供された長さに基づいて反復します(URLENCODEのように関数で計算されません)。

注:多くのプログラマは、おそらくループの反復処理をこのように見たことがない、それは、注意を払うループのために最もに使用される標準的な慣習ややハックだといない、それが割り当てxy、上の終了をチェックlen0に到達し、インクリメントの両方xy。それはあなたが期待するものではありませんが、それは有効なコードです。

  • 現在の文字をの一致する文字位置に割り当てstrます。
  • これは、現在の文字が英数字または文字の1つであるかどうかをチェックし_-.、そうでない場合は、ルックアップを実行するURLENCODEとほぼ同じ割り当てを行いますが、y++ではなくを使用して、異なる方法でインクリメントしますto[1]。これは、文字列はさまざまな方法で構築されていますが、いずれにしても最終的に同じ目標に到達します。
  • ループが終了して長さがなくなったとき、実際には文字列を終了して\0バイトを割り当てます。
  • エンコードされた文字列を返します。

違い:

  • UrlEncodeはスペースをチェックし、+記号を割り当てますが、RawURLEncodeはしません。
  • UrlEncodeは\0文字列にバイトを割り当てませんが、RawUrlEncodeは割り当てます(これは問題になる可能性があります)
  • 彼らは異なって反復します、1つは不正な形式の文字列でオーバーフローする傾向があるかもしれません、私はこれを示唆しているだけで、実際には調査していません

それらは基本的に異なって反復し、ASCII 20のイベントでは+記号を割り当てます。

EBCDICの違い:

URLENCODE:

  • ASCIIと同じ反復セットアップ
  • それでも「スペース」文字を+ 記号に変換します。注-これはEBCDICでコンパイルする必要があると思います。そうしないと、バグが発生しますか?誰かがこれを編集して確認できますか?
  • それチェック本チャーは前チャーであるか0であることを除いて、.または-OR未満Aしかしチャーより大きい9ORより大きいZ未満aではありません_またはより大きいz(そうです、EBCDICは動作するように少し混乱しています)。それらのいずれかに一致する場合は、ASCIIバージョンにあるのと同様のルックアップを実行します(os_toasciiでのルックアップは必要ありません)。

RAWURLENCODE:

  • ASCIIと同じ反復セットアップ
  • EBCDICバージョンのURLエンコードで説明されているものと同じチェックですが、それがより大きい場合z~URLエンコードから除外されます。
  • ASCII RawUrlEncodeと同じ割り当て
  • \0返される前に、バイトを文字列に追加します。

グランドサマリー

  • どちらも同じhexcharsルックアップテーブルを使用します
  • URIEncodeは文字列を\ 0で終了しませんが、rawは終了します。
  • EBCDICで作業している場合は~、UrlEncodeが管理しないRawUrlEncode を使用することをお勧めします(これは報告されている問題です)。ASCIIとEBCDIC 0x20はどちらもスペースであることは注目に値します。
  • それらは異なる方法で反復し、1つはより速く、1つはメモリまたは文字列ベースのエクスプロイトになりやすいかもしれません。
  • URIEncodeはスペースを+に作り、RawUrlEncodeは%20配列ルックアップを介してスペースを作ります。

免責事項:私は何年もCに触れていません。また、EBCDICを本当に長い間見ていません。どこか間違っている場合はお知らせください。

推奨される実装

これらすべてに基づいて、rawurlencodeはほとんどの場合に行く方法です。Jonathan Finglandの答えに見られるように、ほとんどの場合それを使います。これは、URIコンポーネントの最新のスキームを扱います。urlencodeは昔ながらの方法で+は「スペース」を意味します。

古い形式と新しい形式の間で変換しようとしている場合は、コードが失敗して、デコードされた+記号であるものを誤ってダブルエンコードすることによってスペースに変換しないようにしてください。スペース/ 20%/ +問題。

新しいフォーマットを好まない古いソフトウェアを備えた古いシステムで作業している場合は、urlencodeを使用してください。ただし、古い標準では%20が機能していたので、%20は実際には下位互換性があると思います優先。あなたが遊んでいるなら、それを試してみてください、それがあなたのためにどのようにうまくいったかを教えてください。

基本的に、EBCDICシステムが本当に嫌いでない限り、生のままにしておくべきです。ほとんどのプログラマーは、2000年以降、おそらく1990年以降に作成されたシステムでEBCDICに出くわすことはありません(これは推進中ですが、おそらく私の考えではそうです)。


ダブルエンコーディングについて心配する必要はありませんでした。結局、自分が考えているエンコーディングを実行するので、何をエンコードしたかを知る必要があります。スペースの+の扱い方を知っている互換モードで受け取ったすべてをデコードするので、ここで警告しようとしている問題に遭遇することはありません。何かがわからない場合でもソースを見ると理解できますが、単に両方の関数を実行しただけではまだ知らなかった、ここで正確に何を学んだのでしょう。私は偏見があることを知っていますが、これはあまりにも行き過ぎだと思わずにはいられません。努力の功績も!=)
nickl- 2012年

2
+1、この部分:「%20は実際には下位互換性があると思います。古い標準では%20が機能しましたが、好まれませんでした」
Gras Double

3
良い答えですが、少しやり過ぎかもしれません。
rinogo

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

収量

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

ながら

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

収量

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

asd%20asd対の違いasd+asd

urlencodeは、+代わりにスペースをエンコードする点でRFC 1738と異なります%20


28

どちらかを選択する実用的な理由の1つは、JavaScriptなどの別の環境で結果を使用する場合です。

PHPにurlencode('test 1')返し'test+1'ながら、rawurlencode('test 1')戻り'test%201'結果。

あなたが使用してJavaScriptで「デコード」にこれを必要とする場合でも、decodeURI()関数を、次にdecodeURI("test+1")あなたを与えるだろう"test+1"しながら、decodeURI("test%201")あなたを与える"test 1"結果として。

言い換えると、PHPでurlencodeによってプラス( "+")にエンコードされたスペース( "")は、JavaScriptのdecodeURIによって適切にデコードされません。

このような場合は、rawurlencode PHP関数を使用する必要があります。


6
これは私が見た中で断然最高の答えです。これは、実際の例に戻って、使用のための提案を提供します。さらに、それは簡潔です。
dotancohen

私が好むけれどもそれは、良い例であるjson_encodeJSON.parse、その目的のために。
ファブリシオマッテ2013

21

スペースは次のようにエンコードする必要があると思います。

次の例は、rawurlencodeおよびの正しい使用法を示していますurlencode

echo "http://example.com"
    . "/category/" . rawurlencode("latest songs")
    . "/search?q=" . urlencode("lady gaga");

出力:

http://example.com/category/latest%20songs/search?q=lady+gaga

パスとクエリ文字列コンポーネントを逆にエンコードするとどうなりますか?次の例の場合:

http://example.com/category/latest+songs/search?q=lady%20gaga
  • ウェブサーバーはlatest+songs代わりにディレクトリを探しますlatest songs
  • クエリ文字列パラメーターqにはlady gaga

2
「クエリ文字列パラメータにqは、次のlady gagaものが含まれます」クエリパラメータがq渡さ同じ価値があるようです$_GETかかわらず、使用しての配列rawurlencodeまたはurlencodePHP 5.2+では。ただし、GETリクエストのデフォルトurlencodeapplication/x-www-form-urlencoded形式でエンコードするため、私はあなたのアプローチを採用します。+1
ファブリシオマッテ2013

2
私は両方のことを明確にしたかった+し、%20クエリ文字列で使用する場合スペースとしてデコードされています。
Salman A

5

違いは戻り値、すなわち:

urlencode()

-_を除くすべての非英数字が含まれる文字列を返します。パーセント(%)記号とそれに続く2つの16進数とプラス(+)記号としてエンコードされたスペースに置き換えられました。WWWフォームからポストされたデータがエンコードされるのと同じ方法でエンコードされます。つまり、application / x-www-form-urlencodedメディアタイプの場合と同じです。これは»RFC 1738エンコーディング(rawurlencode()を参照)とは異なり、歴史的な理由から、スペースはプラス(+)記号としてエンコードされます。

rawurlencode()

-_を除くすべての非英数字が含まれる文字列を返します。パーセント(%)記号とそれに続く2桁の16進数で置き換えられています。これは»RFC 1738で説明されているエンコーディングであり、リテラル文字が特殊なURL区切り文字として解釈されないように保護し、URLが文字変換のある送信メディア(一部の電子メールシステムなど)によって変換されないようにします。

2つは非常に似ていますが、後者(rawurlencode)はスペースを「%」と2つの16進数字で置き換えます。これは、パスワードのエンコードなどに適しています。

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">

2
OPは、どちらをいつ使用するかを知る方法を尋ねます。OPが異なる戻り値の重要性を知らない場合、それぞれがスペースで何をするかを知っていても、OPが決定を下すのに役立ちません。
dotancohen

5

1.正確に何が違うのか

唯一の違いは、スペースの処理方法です。

urlencode-レガシー実装に基づいてスペースを+に変換します

rawurlencode- RFC 1738に基づき、スペースを%20に変換します

違いは、+が予約されており、URLで有効(エンコードされていない)であるためです。

2.どちらが好ましいですか?

私は本当にどちらかを選択するいくつかの理由を見たいと思っています...私はただ1つを選んでそれを最小限の手間で永遠に使用できるようにしたいです。

十分に公平ですが、私はこれらの決定を行うときに従う簡単な戦略を持っています。それが役立つことを期待して、私はあなたと共有します。

寛容なアプリケーション」を要求したのはHTTP / 1.1仕様RFC 2616だったと思います

クライアントは、ステータスラインの解析に耐性があり、サーバーはリクエストラインの解析に耐性があるべきです。

このような質問に直面したときの最善の戦略は、常にできるだけ多くを消費し、標準に準拠したものを作成することです。

ですから、私のアドバイスは、を使用rawurlencodeして標準に準拠したRFC 1738エンコードされた文字列を生成urldecodeし、下位互換性を保ち、消費する可能性のあるすべてのものに対応することです。

さて、あなたは私の言葉をそれで受け止めることができますが、それを証明しましょう...

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

PHPはまさにこれを念頭に置いていたように思われますが、2つの形式のいずれかを拒否する人に出くわしたことはありませんが、事実上の戦略として採用するより良い戦略を考えることができませんか?

nJoy!


4

urlencode:これは»RFC 1738エンコーディング(rawurlencode()を参照)とは異なります。歴史的な理由から、スペースはプラス(+)記号としてエンコードされます。


2

%20対としてエンコードされたスペース+

私が使用に見てきた最大の理由はrawurlencode()、ほとんどの場合には、理由はあるurlencodeとしてエンコードテキストスペース+(プラス記号)ここで、rawurlencode一般的に見られるように、それらをエンコード%20

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

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

エンコードされたテキストクエリを受け入れる特定のAPIエンドポイントが%20スペースを参照することを期待しているため、プラス記号が代わりに使用された場合に失敗することがわかりました。明らかに、これはAPI実装間で異なり、マイレージは異なる場合があります。


1

urlencodeはクエリパラメータ用であるのに対し、rawurlencodeはパスセグメント用であると思います。これは主に%20、パスセグメント+とクエリパラメーターの違いによるものです。スペースについて説明しているこの回答を参照してください:スペースをプラス(+)または%20にエンコードするタイミングは?

ただし%20、クエリパラメータでも機能するようになったため、rawurlencodeの方が常に安全です。ただし、プラス記号は、編集のユーザーエクスペリエンスとクエリパラメーターの読みやすさが重要な場合に使用される傾向があります。

これは、スペースにrawurldecodeデコード+されないことを意味することに注意してくださいhttp://au2.php.net/manual/en/function.rawurldecode.php)。これが$ _GETが常に自動的に渡される理由です。urldecodeつまり、+との%20両方がスペースにデコードされます。

エンコーディングとデコーディングを入力と出力の間で一貫させる必要が+あり%20、クエリパラメータではなく常に使用することを選択した場合urlencode、クエリパラメータ(キーと値)は問題ありません。

結論は:

パスセグメント-常にrawurlencode / rawurldecodeを使用

クエリパラメータ-デコードには常にurldecode(自動的に行われます)を使用し、エンコードにはrawurlencodeまたはurlencodeのどちらでも問題ありません。特にURLを比較する場合は、一貫性のあるものを選択してください。


0

simple * rawurlencode the path-パスは「?」の前の部分です -スペースは%20としてエンコードする必要があります*クエリ文字列をurlencodeします-クエリ文字列は「?」の後の部分です -スペースは「+」としてより適切にエンコードされます= rawurlencodeは一般により互換性があります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.