URLエンコードについて
JavaScriptでは文字列をエンコードする命令が3つ用意されています。
1つは古いブラウザでも利用できるescape()メソッド、次がencodeURI()、そして最後がencodeURIComponent()です。
| # | 関数 | 説明 |
|---|---|---|
| 1 | escape | Safariではうまく日本語が処理できないことがあります。 |
| 2 | encodeURI | Internet Explorerでは5.5以降でのみ利用できます。 |
| 3 | encodeURIComponent | Internet Explorerでは5.5以降でのみ利用できます。 |
encodeURI()とencodeURIComponent()の違い
「#$&+,/:;=?@」をエンコードするかどうかの違いがあります。
encodeURI()はこれらの文字をエンコードしませんが、encodeURIComponent()では下表のようにエンコードします。
| 関数 | # | $ | & | + | , | / | : | ; | = | ? | @ |
|---|---|---|---|---|---|---|---|---|---|---|---|
| encodeURI() | # | $ | & | + | , | / | : | ; | = | ? | @ |
| encodeURIComponent() | %23 | %24 | %26 | %2B | %2C | %2F | %3A | %3B | %3D | %3F | %40 |
比較表
すべての関数でエンコードされない文字は、*-.@_ 0から9 AからZ aからz
escape()でエンコードされない記号は、*+-./@_の7文字(水色の背景色)
encodeURI()でエンコードされずにencodeURIComponent()でエンコードされる記号は、黄色の背景色の箇所。その反対のパターンは存在しない。
| 半角スペース | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| escape | %20 | %21 | %22 | %23 | %24 | %25 | %26 | %27 | %28 | %29 | * | + | %2C | - | . | / |
| encodeURI | %20 | ! | %22 | # | $ | %25 | & | ' | ( | ) | * | + | , | - | . | / |
| encodeURI Componet |
%20 | ! | %22 | %23 | %24 | %25 | %26 | ' | ( | ) | * | %2B | %2C | - | . | %2F |
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | |
| escape | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %3A | %3B | %3C | %3D | %3E | %3F |
| encodeURI | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | %3C | = | %3E | ? |
| encodeURI Componet |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | %3A | %3B | %3C | %3D | %3E | %3F |
| @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | |
| escape | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
| encodeURI | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
| encodeURI Componet |
%40 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
| P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | |
| escape | P | Q | R | S | T | U | V | W | X | Y | Z | %5B | %5C | %5D | %5E | _ |
| encodeURI | P | Q | R | S | T | U | V | W | X | Y | Z | %5B | %5C | %5D | %5E | _ |
| encodeURI Componet |
P | Q | R | S | T | U | V | W | X | Y | Z | %5B | %5C | %5D | %5E | _ |
| ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | |
| escape | %60 | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
| encodeURI | %60 | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
| encodeURI Componet |
%60 | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
| p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | DL | |
| escape | p | q | r | s | t | u | v | w | x | y | z | %7B | %7C | %7D | %7E | |
| encodeURI | p | q | r | s | t | u | v | w | x | y | z | %7B | %7C | %7D | %7E | |
| encodeURI Componet |
p | q | r | s | t | u | v | w | x | y | z | %7B | %7C | %7D | %7E |
エンコード
デコード
escape関数の問題点
歴史的な経緯もあり、escape、unescapeメソッドがURI文字列をハンドリングするために使われてきましたが、その動作はブラウザごとに異なるため現在は推奨されていません。
IEでは文字列をUCS2の16進表示にした上で「%u」をプレフィクスとして付けた文字列が生成され、これはunescape()ではデコードできますが、decodeURI(decodeURIComponent)ではデコードできません。
そもそもCookieに格納する文字列は、UTF-8に変換された上でURIエンコーディングされることになっています。これをエンコード、デコードするJavaScriptのメソッドはencodeURI(またはencodeURIComponent)、decodeURI(またはdecodeURIComponent)です。
逆にencodeURI(encodeURIComponent)を使って正しくURIエンコーディングされた文字列は、unescapeではデコードできません。
要するにescape、unescapeメソッドは使うべきではありません。
encodeURI(encodeURIComponent)の注意点
JavaScriptのencodeURI(encodeURIComponent)はHTMLソースの文字コードに依らずUTF-8でエンコードします。decodeURI(decodeURIComponet)でデコードする際にもUTF-8でエンコードされていることを前提としています。
デコードした文字列を表示する場合、HTMLソースの文字コードに自動的に変更してくれるので文字化けは発生しません。要するにHTML内で閉じている場合は特に問題は発生しません。
ところが、エンコードした文字列をサーバーに渡してデコードする場合や、反対にサーバーで生成した文字列をエンコードしてJavaScriptに渡してデコードする場合には注意が必要です。
サーバー(PHP)のURLエンコードは文字コードにより異なります。すなわち、JavaScriptのようにUTF-8を前提としているわけではないのです。
従って、クライアントから送信された文字列の文字コードは何かということを意識してデコードしないと文字化けを起こしてしまいます。
PHPでは、mb_convert_encoding()関数で文字コードを変更することができます。encodeURI()でエンコードする前に文字列を明示的にUTF-8に変更してからエンコードすることでJavaScriptと同じ方式でエンコードされることが保証されます。
GETメソッドについて
encodeURI(encodeURIComponet)によりエンコードする際の文字コードはUTF-8でしたが、フォームをGETメソッドで送信する際に自動でエンコードされる時には、HTMLソースの文字コードが適用されるようです。(これはIE8の場合です。ブラウザによって実装が異なるかもしれません。)
下記は、フォームのvalueという名前のテキストボックスに「日本語」と入力して送信したときにどのようにエンコードされるかを示したものです。ページの文字コードによって送信クエリーが異なることが分かります。
| ページの文字コード | 送信クエリー |
|---|---|
| UTF-8 | value=%E6%97%A5%E6%9C%AC%E8%AA%9E |
| EUC-JP | value=%C6%FC%CB%DC%B8%EC |
| SHIFT_JIS | value=%93%FA%96%7B%8C%EA |
サーバー側では送信クエリーの文字コードを知っている必要があります。多くの場合は自動判定でも認識できるようですが、本来は明示的に文字コードを指定してデコードすべきです。
送信クエリーにはエンコードの文字コードを示すものは送信されません。これは歴史的な経緯によるものだと思いますが、明らかに仕様の不備だと思います。例えば、Googleの検索クエリーでは「IE」や「OE」というパラメータによって文字コードを明示的に示しています。これに習って文字コードを一緒にパラメータで渡すようにするのは良い習慣だと思います。
