変数を使用してURLを作成したい場合は、文字列をエンコードする方法が2つあります。 urlencode()
とrawurlencode()
。
その違いは、正確にはどのようなものですか。
それはあなたの目的によります。他のシステムとの相互運用性が重要な場合は、rawurlencodeを使用することをお勧めします。 1つの例外は、クエリ文字列が%20ではなく+としてエンコードされたフォームエンコード形式のスペースに従うことを想定している従来のシステムです(この場合はurlencodeが必要です)。
rawurlencodeは、PHP 5.3.0以前のRFC 1738、およびその後のRFC 3986に準拠しています( http:// us2を参照)。 php.net/manual/en/function.rawurlencode.php )
-_。〜を除くすべての英数字以外の文字がパーセント(%)記号とそれに続く2つの16進数で置き換えられたストリングを返します。これは、リテラル文字が特殊なURLデリミタとして解釈されるのを防ぐため、および文字変換を使用して伝送メディアによってURLが破壊されるのを防ぐための"RFC 3986で説明されているエンコーディングです。
Php 5.3より前のrawurlencodeでは、RFC 1738に従ってチルダ文字(~
)がエンコードされていました。ただし、PHP 5.3以降、rawurlencodeは、チルダ文字のエンコードを必要としないRFC 3986に準拠しています。
urlencodeはスペースをプラス記号としてエンコードします(rawurlencodeのように%20
としてではありません)( http://us2.php.net/manualを参照) /en/function.urlencode.php )
-_以外のすべての英数字以外の文字を含むストリングを返します。パーセント(%)記号の後に2つの16進数字とスペースをプラス(+)記号としてエンコードしたものに置き換えられました。 WWWフォームからの投稿データがエンコードされるのと同じ方法でエンコードされます。つまり、application/x-www-form-urlencodeされたメディアタイプと同じ方法です。これは"RFC 3986エンコーディング(rawurlencode()を参照)とは歴史的な理由でスペースがプラス(+)記号としてエンコードされるという点で異なります。
これは RFC 1866 にあるapplication/x-www-form-urlencodeの定義に対応しています。
追加の読書:
また、 http://bytes.com/groups/php/5624-urlencode-vs-rawurlencode で議論を見たいと思うかもしれません。
また、 RFC 2396 は一見の価値があります。 RFC 2396は有効なURI構文を定義しています。私たちが興味を持っている主な部分は3.4クエリコンポーネントからです。
クエリコンポーネント内では、文字
";", "/", "?", ":", "@",
は予約されています。
"&", "=", "+", ",", and "$"
ご覧のとおり、+
はクエリ文字列内の予約文字なので、(rawurlencodeの場合と同様に)RFC 3986に従ってエンコードする必要があります。
証明は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_encodeおよびphp_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);
}
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バイトがASCIIのL
ではなく、実際には<
であることを意味します。ここで混乱が生じると思います。
Webサーバーで定義されている場合、これらの機能は両方ともEBCDICを管理します。
また、両方ともcharの配列(文字列型と考えてください)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で説明します。
URLENCODE:
+
記号を出力文字列に追加します。isalnum(c)
)でもなく、_
、-
、または.
文字でもない場合、配列位置0に%
記号を出力し、配列を検索しますhexchars
(現在の文字)のキーのos_toascii
配列( Apacheが変換する charから16進コードへの配列)のルックアップのためのc
配列に、4ビットずつ右にシフトします。値を文字1に、位置2に同じルックアップを割り当てます。ただし、論理を実行し、値が15(0xF)であるかどうかを確認し、その場合は1を返します。最後に、エンコードされたものになります。_-.
文字のいずれかである場合、正確にそれが何であるかを出力します。RAWURLENCODE:
注:多くのプログラマーは、おそらくforループがこの方法で繰り返されるのを見たことがないでしょう。これはややハック的で、ほとんどのforループで使用される標準の規則ではなく、注意を払って、x
とy
を割り当て、 len
が0に到達すると終了し、x
とy
の両方をインクリメントします。私は知っている、それはあなたが期待するものではありませんが、それは有効なコードです。
str
の一致する文字位置に割り当てます。_-.
文字の1つかをチェックし、そうでない場合は、ルックアップを実行するURLENCODEとほぼ同じ割り当てを行いますが、y++
ではなくto[1]
を使用して、インクリメントします。文字列はさまざまな方法で構築されていますが、いずれにしても最終的には同じ目標に到達するからです。\0
バイトを割り当てます。違い:
\0
バイトを文字列に割り当てませんが、RawUrlEncodeは割り当てます(これは重要なポイントかもしれません)基本的に異なる方法で繰り返され、ASCII 20のイベントに+記号を割り当てます。
URLENCODE:
0
の前の文字かどうかをチェックします。ただし、.
または-
、、またはA
よりも小さいがCHAR 9
よりも大きいである場合は例外ですまたはZ
より大きく、a
より小さいが、_
ではない。 またはz
より大きい(ええ、EBCDICは動作するように少し混乱しています)。それらのいずれかに一致する場合は、ASCIIバージョンにあるのと同様の検索を実行します(os_toasciiでの検索は不要です)。RAWURLENCODE:
z
より大きい場合は、~
がURLエンコードから除外されます。\0
バイトを追加します。~
を管理するため、RawUrlEncodeを使用することをお勧めします( これは報告された問題です )。 ASCIIとEBCDIC 0x20は両方ともスペースであることに注意してください。+
にスペースを作り、RawUrlEncodeは配列ルックアップを介して%20
にスペースを作ります。免責事項:私は何年もCに触れたことがなく、本当に長い間EBCDICを見ていない。私がどこか間違っているなら、私に知らせてください。
これらすべてに基づいて、rawurlencodeはほとんどの場合に使用できます。ジョナサンフィンランドの答えをご覧ください。ほとんどの場合、それを守ってください。 urlencodeがオールドスクールのやり方で行うように、URIコンポーネントの最新のスキームを扱います。ここで、+は「スペース」を意味します。
古い形式と新しい形式の間で変換しようとしている場合は、コードが上手く行かないようにし、誤って二重エンコードするか、これに関する同様の「おっと」シナリオによって、デコードされた+記号であるものをスペースに変えないようにしてくださいスペース/ 20%/ +の問題。
新しい形式を好まない古いソフトウェアを使用して古いシステムで作業している場合は、urlencodeに固執しますが、%20は実際には下位互換性があると思います。望ましい。あなたが遊んでいるなら、それを試してみてください、それがあなたのためにどのように働いたか教えてください。
基本的に、EBCDICシステムが本当に嫌な場合を除き、rawのままにしてください。ほとんどのプログラマーは、2000年以降、おそらくは1990年以降に作成されたシステムでEBCDICに遭遇することはありません(それはプッシュですが、それでも私の意見ではそうです)。
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は、スペースを+
ではなく%20
としてエンコードする点でRFC 1738と異なります
一方を選択する実際的な理由の1つは、JavaScriptなどの別の環境で結果を使用する場合です。
結果として、PHP urlencode('test 1')
は'test+1'
を返し、rawurlencode('test 1')
は'test%201'
を返します。
しかし、JavaScriptでdecodeURI() functionを使用してこれを「デコード」する必要がある場合、decodeURI("test+1")
から"test+1"
が返され、decodeURI("test%201")
から"test 1"
が返されます。
つまり、PHP内のrlencodeからプラス( "+")にエンコードされたスペース( "")は、JavaScriptではdecodeURIによって正しくデコードされません。 。
そのような場合はrawurlencode PHP関数を使うべきです。
スペースは次のようにエンコードする必要があると思います。
%20
+
( 17.13.4フォームコンテンツタイプ を参照)次の例は、 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
が含まれます。唯一の違いはスペースの扱い方です。
urlencode - 従来の実装に基づき、スペースを+に変換します
rawurlencode - RFC 1738 に基づいて、スペースを%20に変換します。
違いがあるのは、+がURLで予約されていて有効(エンコードされていない)だからです。
私は本当に1つを他のものよりも選ぶためのいくつかの理由を見たいと思います...私はただ1つを選びそして最小の煩わしさで永遠にそれを使用できるようにしたいです。
私はこれらの決定を下す際に従うという単純な戦略を持っています。
私はそれがを要求したHTTP/1.1仕様 RFC 2616 だと思います--- アプリケーションの許容範囲 "
クライアントはStatus-Lineの解析に寛容であり、サーバーはRequest-Lineの解析に寛容であるべきです(SHOULD)。
このような質問に直面したときの最良の戦略は、常にできるだけ多くを消費して、標準に準拠したものを作成することです。
ですから私のアドバイスは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つの形式のどちらも拒否している人はいませんが、事実上の戦略として採用するより良い戦略を考えることはできませんか。
nジョイ!
違いは戻り値にあります。
-_以外のすべての英数字以外の文字を含むストリングを返します。パーセント(%)記号の後に2つの16進数字とスペースをプラス(+)記号としてエンコードしたものに置き換えられました。 WWWフォームからの投稿データがエンコードされるのと同じ方法でエンコードされます。つまり、application/x-www-form-urlencodeされたメディアタイプと同じ方法です。これは"RFC 1738エンコーディング(rawurlencode()を参照)とは歴史的な理由でスペースがプラス(+)記号としてエンコードされるという点で異なります。
-_以外のすべての英数字以外の文字を含むストリングを返します。パーセント(%)記号とそれに続く2桁の16進数に置き換えられました。これは、リテラル文字が特殊なURLデリミタとして解釈されるのを防ぐため、および文字変換を使用して伝送メディアによってURLが破壊されるのを防ぐための"RFC 1738で説明されているエンコーディングです。
この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%[email protected]/x.txt">
rlencode :これは"RFC 1738エンコーディング(rawurlencode()を参照)とは歴史的な理由でスペースがプラス(+)記号としてエンコードされているという点で異なります。
%20
対+
としてエンコードされたスペース私がほとんどの場合rawurlencode()
を使用するのを見た最大の理由は、urlencode
がテキストスペースを+
(プラス記号)としてエンコードするのに対し、rawurlencode
は一般的に見られる%20
としてエンコードするからです。
echo urlencode("red shirt");
// red+shirt
echo rawurlencode("red shirt");
// red%20shirt
エンコードされたテキストクエリを受け付ける特定のAPIエンドポイントでは、スペースに%20
が表示されることを期待しています。その結果、代わりにプラス記号を使用すると失敗します。明らかにこれはAPI実装の間で異なり、あなたの走行距離は変わるかもしれません。
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を比較する場合は、一貫性があるものを選択してください。
simple * rawurlencodeパス - パスは "?"の前の部分です。 - スペースは%20 *としてエンコードする必要があります。*クエリ文字列のURLエンコード - クエリ文字列は "?"の後の部分です。 "+" = rawurlencodeの方が一般的により互換性があるので、スペースはよりよくエンコードされます。