2009年7月28日火曜日

PHPの URLエンコード (urlencode, rawurlencode, http_build_query)

(2013/5/19 変更:rawurlencode()はRFC3986なのにRFC1738と書いてたので訂正。)


まずはurlencode()rawurlencode()を比較。

  • urlencode()
    • 半角チルダ(~)を%7Eに変換する
    • 半角スペースをプラス(+)に変換する
  • rawurlencode()
    • 半角チルダ(~)の変換についてはPHPのバージョンによって違う
      • PHP 5.2.xまでは、%7Eに変換する
      • PHP 5.3.0からは、%7Eに変換しない(チルダのまま)
    • 半角スペースを%20に変換する

rawurlencode()はRFC1738 RFC3986に沿った変換とされているので、基本的にはurlencode()よりrawurlencode()の方が無難。
ただし、RFC1738 3986ではチルダを%7Eに変換しない。


ちなみに、RFC1738はその後、RFC3986によって更新されているが、RFC3986はパッと見た感じではURLエンコードについては(JavaScriptのencodeURIComponent()で使われるRFC2396の方ではなく、)RFC1738を踏襲しているようだ。(2013/5/19 追記:一部変更されてる。)

Amazonの新しいAPIでも、RFC3986によるURLエンコードを使っている。(参考:Amazon Product Advertising API への対応(PHP版) - もやし日記



次に、http_build_query()の話。
http_build_query()は便利だが、URLエンコードの内容はurlencode()と同じなのが残念。
RFC1738/3986に沿った形にするには、もう1つ変換を咬ませなければならない。
//例
function encodeAlongRFC1738($str) {
return strtr($str, array('%7E' => '~', '+' => '%20'));
}

echo encodeAlongRFC1738(http_build_query($arr));
上記の変換は、PHP5.2までのrawurlencode()にも使える。



あとは実験結果。上記のencodeAlongRFC1738()も交えて。
元の文字
 "~_ _+"

urlencode()の場合
変換結果
 "%7E_+_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると(正しくデコードできない)
 "~_+_+"

rawurlencode()の場合(PHP 5.2)
変換結果
 "%7E_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"

rawurlencode()の場合(PHP 5.3)
変換結果
 "~_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"


urlencode() + encodeAlongRFC1738()の場合
変換結果
 "~_%20_%2B"
urldecode()すると
 "~_ _+"
rawurldecode()すると
 "~_ _+"


元の配列
 array("test[0]" => "~_ _+")

http_build_query()の場合
変換結果
 "test%5B0%5D=%7E_+_%2B"
urldecode()すると
 "test[0]=~_ _+"
rawurldecode()すると(正しくデコードできない)
 "test[0]=~_+_+"

http_build_query() + encodeAlongRFC1738()の場合
変換結果

 "test%5B0%5D=~_%20_%2B"
urldecode()すると
 "test[0]=~_ _+"
rawurldecode()すると
 "test[0]=~_ _+"

urldecode()はurlencode()に対してもrawurlencode()に対しても使える。



参考:URIに使ってよい文字の話 - RFC2396 と RFC3986 - Text::Easyhacking

0 件のコメント:

ブログ アーカイブ

tags