変数を使用してURLを作成する場合、文字列をエンコードする方法は2つあります。urlencode()
とrawurlencode()
。
違いは何ですか?どちらが好ましいですか?
rawurlencode
。あなたはめったにチョーク与えられたスペースとしてエンコードすることをシステムに実行していないだろう%20
システムにスペース上のチョークのようにエンコードされていることが、+
より一般的です。
変数を使用してURLを作成する場合、文字列をエンコードする方法は2つあります。urlencode()
とrawurlencode()
。
違いは何ですか?どちらが好ましいですか?
rawurlencode
。あなたはめったにチョーク与えられたスペースとしてエンコードすることをシステムに実行していないだろう%20
システムにスペース上のチョークのようにエンコードされていることが、+
より一般的です。
回答:
それはあなたの目的に依存します。他のシステムとの相互運用性が重要な場合は、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はスペースをプラス記号としてエンコードします(%20
rawurlencodeの場合とは異なります)(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など)。
プルーフは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バイトがL
ASCIIではなく、実際にはであることを意味します<
。きっとあなたはここで混乱を目にするでしょう。
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で説明します。
URLENCODE:
+
、出力文字列に符号を追加します。isalnum(c)
)、またしていない_
、-
または.
文字は、我々は、出力%
配列の位置0に記号を、に配列ルックアップを行うhexchars
ためのルックアップのための配列os_toascii
(配列(現在の文字)のキーに対して、charを16進コードに変換するApacheの配列。c
次に、ビット単位で右に4シフトし、その値を文字1に割り当て、位置2に、プリフォームを除いて同じルックアップを割り当てます。論理値で、値が15(0xF)かどうかを確認し、その場合は1を返し、そうでない場合は0を返します。最後に、エンコードされたものになります。_-.
正確に何であるかを出力します。RAWURLENCODE:
注:多くのプログラマは、おそらくループの反復処理をこのように見たことがない、それは、注意を払うループのために最もに使用される標準的な慣習ややハックだといない、それが割り当てx
とy
、上の終了をチェックlen
0に到達し、インクリメントの両方x
とy
。それはあなたが期待するものではありませんが、それは有効なコードです。
str
ます。_-.
、そうでない場合は、ルックアップを実行するURLENCODEとほぼ同じ割り当てを行いますが、y++
ではなくを使用して、異なる方法でインクリメントしますto[1]
。これは、文字列はさまざまな方法で構築されていますが、いずれにしても最終的に同じ目標に到達します。\0
バイトを割り当てます。違い:
\0
文字列にバイトを割り当てませんが、RawUrlEncodeは割り当てます(これは問題になる可能性があります)それらは基本的に異なって反復し、ASCII 20のイベントでは+記号を割り当てます。
URLENCODE:
0
であることを除いて、.
または-
、OR未満A
しかしチャーより大きい9
、ORより大きいZ
未満a
ではありません_
。またはより大きいz
(そうです、EBCDICは動作するように少し混乱しています)。それらのいずれかに一致する場合は、ASCIIバージョンにあるのと同様のルックアップを実行します(os_toasciiでのルックアップは必要ありません)。RAWURLENCODE:
z
、~
URLエンコードから除外されます。\0
返される前に、バイトを文字列に追加します。~
、UrlEncodeが管理しないRawUrlEncode を使用することをお勧めします(これは報告されている問題です)。ASCIIとEBCDIC 0x20はどちらもスペースであることは注目に値します。+
に作り、RawUrlEncodeは%20
配列ルックアップを介してスペースを作ります。免責事項:私は何年もCに触れていません。また、EBCDICを本当に長い間見ていません。どこか間違っている場合はお知らせください。
これらすべてに基づいて、rawurlencodeはほとんどの場合に行く方法です。Jonathan Finglandの答えに見られるように、ほとんどの場合それを使います。これは、URIコンポーネントの最新のスキームを扱います。urlencodeは昔ながらの方法で+は「スペース」を意味します。
古い形式と新しい形式の間で変換しようとしている場合は、コードが失敗して、デコードされた+記号であるものを誤ってダブルエンコードすることによってスペースに変換しないようにしてください。スペース/ 20%/ +問題。
新しいフォーマットを好まない古いソフトウェアを備えた古いシステムで作業している場合は、urlencodeを使用してください。ただし、古い標準では%20が機能していたので、%20は実際には下位互換性があると思います優先。あなたが遊んでいるなら、それを試してみてください、それがあなたのためにどのようにうまくいったかを教えてください。
基本的に、EBCDICシステムが本当に嫌いでない限り、生のままにしておくべきです。ほとんどのプログラマーは、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は、+
代わりにスペースをエンコードする点でRFC 1738と異なります%20
どちらかを選択する実用的な理由の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関数を使用する必要があります。
json_encode
とJSON.parse
、その目的のために。
スペースは次のようにエンコードする必要があると思います。
%20
URLパスコンポーネント内で使用する場合+
URLクエリ文字列コンポーネントまたはフォームデータ内で使用した場合(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
q
は、次のlady gaga
ものが含まれます」クエリパラメータがq
渡さ同じ価値があるようです$_GET
かかわらず、使用しての配列rawurlencode
またはurlencode
PHP 5.2+では。ただし、GETリクエストのデフォルトurlencode
のapplication/x-www-form-urlencoded
形式でエンコードするため、私はあなたのアプローチを採用します。+1
+
し、%20
クエリ文字列で使用する場合スペースとしてデコードされています。
違いは戻り値、すなわち:
-_を除くすべての非英数字が含まれる文字列を返します。パーセント(%)記号とそれに続く2つの16進数とプラス(+)記号としてエンコードされたスペースに置き換えられました。WWWフォームからポストされたデータがエンコードされるのと同じ方法でエンコードされます。つまり、application / x-www-form-urlencodedメディアタイプの場合と同じです。これは»RFC 1738エンコーディング(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">
唯一の違いは、スペースの処理方法です。
urlencode-レガシー実装に基づいてスペースを+に変換します
rawurlencode- RFC 1738に基づき、スペースを%20に変換します
違いは、+が予約されており、URLで有効(エンコードされていない)であるためです。
私は本当にどちらかを選択するいくつかの理由を見たいと思っています...私はただ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!
%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 the path-パスは「?」の前の部分です -スペースは%20としてエンコードする必要があります*クエリ文字列をurlencodeします-クエリ文字列は「?」の後の部分です -スペースは「+」としてより適切にエンコードされます= rawurlencodeは一般により互換性があります