はじめに
こんにちはー!
今日は、URLエンコードの勉強をしたいと思います。なぜ今なのかというと、最近IoT関係でデータを渡したりやりとりするさいにGETをよく使うのですが、このような場合にURLエンコードを使いたいからです。
というわけで、仕様とか含めて調査していきます。まずPHPから調査してみます。
PHPのURLエンコードについて
文字コードについて
はじめに
PHPには、URLエンコードをする関数が用意されています。これを使えばURLエンコードができると思うのですが、変換する前の文字コードってどうなるんだという素朴な疑問点がうかびました。というわけで先に文字コードについて調査してみます。
以下のURLエンコード用の関数を確認します。
実験環境は以下の通り
- PHP : Server: Apache/2.4.37 (Win32) OpenSSL/1.1.1a PHP/7.3.0, IE 11.472.17134.0
実験1 – デフォルトの文字コードを調査
ソースコードの文字コードは、UTF-8(BOM無し)で保存。
<?php $text = "abc あいうえお"; echo $text . "<br />"; echo urlencode($text) . "<br />"; echo rawurlencode($text) . "<br />"; ?>
これをWebサイトで表示させました。
abc あいうえお abc+%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A
HTMLのウェブサイトの文字コードはUTF-8になっており、文字のURLエンコードも「あ」が「%E3%81%82
」つまり「0xE3 0x81 0x82
」なので、UTF-8の文字コードを変換していることがわかります。
実験2 – phpのソースコードの文字コードを変えてみる
default_charset がUTF-8になっていたため、実験1のような動作になった可能性があります。というわけで、次は以下のようなコードを、Shift_JIS(Windows-31J)で保存。
<?php header("Content-type: text/html; charset=Windows-31J"); $text = "abc あいうえお"; echo $text . "<br />"; echo urlencode($text) . "<br />"; echo rawurlencode($text) . "<br />"; ?>
php.iniも一応以下のように変更。
mbstring.language=Japanese mbstring.detect_order=SJIS mbstring.internal_encoding=SJIS mbstring.http_output=SJIS mbstring.encoding_translation=On
これをWebサイトで表示させました。
abc あいうえお abc+%82%A0%82%A2%82%A4%82%A6%82%A8 abc%20%82%A0%82%A2%82%A4%82%A6%82%A8
HTMLのウェブサイトの文字コードは、Shift_JIS(Windows-31J)となり、文字のURLエンコードも「あ」が「%82%a0
」つまり「0x82a0
」から、Shift_JISでエンコードされたことが分かります。
結果
phpのURLエンコードは、phpの文字コードによって変化することが分かりました。
デフォルトはUTF-8なので、通常はUTF-8を使っていればいいですが、もしShift_JISのphpに対してデータを送りたい場合は、Shift_JISで変換する必要があるようです。現在はそのようなサイトは数少ないと思うため問題ないとは思いますが、確認できるなら確認したほうがよいと思われます。
URLエンコードについて
はじめに
いよいよURLエンコードがどのように変換されるか調べてみましょう。
関数の解説サイトには次のような説明がありました。rawurlencodeの関数の説明には、URLエンコードは、RFC 3986にそっている。PHP 5.3.0 より前のバージョンは、RFC 1738にそっている。urlencodeとの違いは、urlencode
はRFCに対して厳密ではなく、スペースが%20
ではなく+
記号に置き換わるとのことです。
実際に動作させて変換後の結果をみてみましょう。
ソースコード
<?php $text = ""; $text .= "<table>"; $text .= "<caption>URLエンコード結果一覧</caption>"; $text .= "<tr>"; $text .= "<th>10進数</th>"; $text .= "<th>16進数</th>"; $text .= "<th>文字</th>"; $text .= "<th>urlencode</th>"; $text .= "<th>rawurlencode</th>"; $text .= "</tr>"; for($charcode = 0; $charcode < 128 ; $charcode++ ) { $text .= "<tr>"; $text .= sprintf("<td>%d</td><td>0x%02X</td><td>%c</td><td>%s</td><td>%s</td>", $charcode, $charcode, $charcode, urlencode(chr($charcode)), rawurlencode(chr($charcode)), ); $text .= "</tr>"; } $text .= "</table>"; echo $text; ?>
実行結果
URLエンコード結果一覧
10進数 | 16進数 | 文字 | urlencode | rawurlencode |
0 | 0x00 | ? | %00 | %00 |
1 | 0x01 | ? | %01 | %01 |
2 | 0x02 | ? | %02 | %02 |
3 | 0x03 | ? | %03 | %03 |
4 | 0x04 | ? | %04 | %04 |
5 | 0x05 | ? | %05 | %05 |
6 | 0x06 | ? | %06 | %06 |
7 | 0x07 | ? | %07 | %07 |
8 | 0x08 | ? | %08 | %08 |
9 | 0x09 | ? | %09 | %09 |
10 | 0x0A | ? | %0A | %0A |
11 | 0x0B | ? | %0B | %0B |
12 | 0x0C | ? | %0C | %0C |
13 | 0x0D | ? | %0D | %0D |
14 | 0x0E | ? | %0E | %0E |
15 | 0x0F | ? | %0F | %0F |
16 | 0x10 | ? | %10 | %10 |
17 | 0x11 | ? | %11 | %11 |
18 | 0x12 | ? | %12 | %12 |
19 | 0x13 | ? | %13 | %13 |
20 | 0x14 | ? | %14 | %14 |
21 | 0x15 | ? | %15 | %15 |
22 | 0x16 | ? | %16 | %16 |
23 | 0x17 | ? | %17 | %17 |
24 | 0x18 | ? | %18 | %18 |
25 | 0x19 | ? | %19 | %19 |
26 | 0x1A | ? | %1A | %1A |
27 | 0x1B | ? | %1B | %1B |
28 | 0x1C | ? | %1C | %1C |
29 | 0x1D | ? | %1D | %1D |
30 | 0x1E | ? | %1E | %1E |
31 | 0x1F | ? | %1F | %1F |
32 | 0x20 | + | %20 | |
33 | 0x21 | ! | %21 | %21 |
34 | 0x22 | “ | %22 | %22 |
35 | 0x23 | # | %23 | %23 |
36 | 0x24 | $ | %24 | %24 |
37 | 0x25 | % | %25 | %25 |
38 | 0x26 | & | %26 | %26 |
39 | 0x27 | ‘ | %27 | %27 |
40 | 0x28 | ( | %28 | %28 |
41 | 0x29 | ) | %29 | %29 |
42 | 0x2A | * | %2A | %2A |
43 | 0x2B | + | %2B | %2B |
44 | 0x2C | , | %2C | %2C |
45 | 0x2D | – | – | – |
46 | 0x2E | . | . | . |
47 | 0x2F | / | %2F | %2F |
48 | 0x30 | 0 | 0 | 0 |
49 | 0x31 | 1 | 1 | 1 |
50 | 0x32 | 2 | 2 | 2 |
51 | 0x33 | 3 | 3 | 3 |
52 | 0x34 | 4 | 4 | 4 |
53 | 0x35 | 5 | 5 | 5 |
54 | 0x36 | 6 | 6 | 6 |
55 | 0x37 | 7 | 7 | 7 |
56 | 0x38 | 8 | 8 | 8 |
57 | 0x39 | 9 | 9 | 9 |
58 | 0x3A | : | %3A | %3A |
59 | 0x3B | ; | %3B | %3B |
60 | 0x3C | < | %3C | %3C |
61 | 0x3D | = | %3D | %3D |
62 | 0x3E | > | %3E | %3E |
63 | 0x3F | ? | %3F | %3F |
64 | 0x40 | @ | %40 | %40 |
65 | 0x41 | A | A | A |
66 | 0x42 | B | B | B |
67 | 0x43 | C | C | C |
68 | 0x44 | D | D | D |
69 | 0x45 | E | E | E |
70 | 0x46 | F | F | F |
71 | 0x47 | G | G | G |
72 | 0x48 | H | H | H |
73 | 0x49 | I | I | I |
74 | 0x4A | J | J | J |
75 | 0x4B | K | K | K |
76 | 0x4C | L | L | L |
77 | 0x4D | M | M | M |
78 | 0x4E | N | N | N |
79 | 0x4F | O | O | O |
80 | 0x50 | P | P | P |
81 | 0x51 | Q | Q | Q |
82 | 0x52 | R | R | R |
83 | 0x53 | S | S | S |
84 | 0x54 | T | T | T |
85 | 0x55 | U | U | U |
86 | 0x56 | V | V | V |
87 | 0x57 | W | W | W |
88 | 0x58 | X | X | X |
89 | 0x59 | Y | Y | Y |
90 | 0x5A | Z | Z | Z |
91 | 0x5B | [ | %5B | %5B |
92 | 0x5C | \ | %5C | %5C |
93 | 0x5D | ] | %5D | %5D |
94 | 0x5E | ^ | %5E | %5E |
95 | 0x5F | _ | _ | _ |
96 | 0x60 | ` | %60 | %60 |
97 | 0x61 | a | a | a |
98 | 0x62 | b | b | b |
99 | 0x63 | c | c | c |
100 | 0x64 | d | d | d |
101 | 0x65 | e | e | e |
102 | 0x66 | f | f | f |
103 | 0x67 | g | g | g |
104 | 0x68 | h | h | h |
105 | 0x69 | i | i | i |
106 | 0x6A | j | j | j |
107 | 0x6B | k | k | k |
108 | 0x6C | l | l | l |
109 | 0x6D | m | m | m |
110 | 0x6E | n | n | n |
111 | 0x6F | o | o | o |
112 | 0x70 | p | p | p |
113 | 0x71 | q | q | q |
114 | 0x72 | r | r | r |
115 | 0x73 | s | s | s |
116 | 0x74 | t | t | t |
117 | 0x75 | u | u | u |
118 | 0x76 | v | v | v |
119 | 0x77 | w | w | w |
120 | 0x78 | x | x | x |
121 | 0x79 | y | y | y |
122 | 0x7A | z | z | z |
123 | 0x7B | { | %7B | %7B |
124 | 0x7C | | | %7C | %7C |
125 | 0x7D | } | %7D | %7D |
126 | 0x7E | ~ | %7E | ~ |
127 | 0x7F | ? | %7F | %7F |
結果
URLエンコードをすることで、制御文字はほぼ変換されました。
変換されていない記号は以下の通り。
+
(※rawurlencode
では変換される)-
(ハイフン).
(ドット)_
(アンダーバー)~
(※rawurlencode
では変換されない)
URLデコードについて
urlencode
とrawurlencode
の互換性を調べたいと思います。
デコードを組み合わせて以下のコードで確認しました。
<?php echo "\"" . urldecode("%20") . "\"<br>"; echo "\"" . rawurldecode("+") . "\"<br>"; echo "\"" . urldecode("~") . "\"<br>"; echo "\"" . rawurldecode("%7E") . "\"<br>"; ?>
結果は、
" " "+" "~" "~"
このようになりました。
+
に関しては、rawurldecode
で元に戻せません。つまり、urlencode
で変換した文字は、rawurldecode
で元に戻せないことなります。逆なら大丈夫なので、urldecode
であれば問題ありません。
urlencode
かrawurlencode
か、どちらを使えばいいのでしょうか。これについては、最後に記載したいと思います。ちなみに、JavaScriptにあるencodeURIComponentによると
application/x-www-form-urlencoded によれば、スペースは ‘+’ に置換されます。そのため、
encodeURIComponent
による置換に加えて “%20” を “+” に変換したいと考えるユーザーもおられるでしょう。
と記載があります。これはどういう意味かといいますと、Webページでデータを投稿する際のURLエンコードは、スペースは ‘+’ にするという決まりがあるのです。そのため、urlencode
によるエンコード方法は非推奨とかではなく、普通に利用されている関数なのです。
JavaScriptのURLエンコードについて
文字コードについて
はじめに
データを渡す際などに利用するJavaScriptの動作を調べてみましょう。
JavaScript用のURLエンコード用関数を確認します。
- escape(非推奨)
- encodeURI
- encodeURIComponent
- URLSearchParams(IE使用不可)
実験1 – デフォルトの文字コードを調査
htmlの文字コードは、UTF-8(BOM無し)で保存。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script type="text/javascript"> const text = "abc あいうえお"; console.log(escape(text)); console.log(encodeURI(text)); console.log(encodeURIComponent(text)); const params = new URLSearchParams(); params.set("", "abc あいうえお") console.log(params.toString()); </script> </body> </html>
Chrome 71.0.3578.98 での結果は、
sample.html:9 abc%20%u3042%u3044%u3046%u3048%u304A sample.html:10 abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A sample.html:11 abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A sample.html:14 =abc+%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A
Microsoft EdgeHTML 17.17134 での結果は、
abc%20%u3042%u3044%u3046%u3048%u304A abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A =abc+あいうえお
escape
では、「あ」を0x3042
に変換しています。これはどうやらUTF-16になっているようです。
サロゲートペアのツチヨシ「𠮷」を試してみましょう。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script type="text/javascript"> const text = "𠮷"; console.log(escape(text)); console.log(encodeURI(text)); console.log(encodeURIComponent(text)); const params = new URLSearchParams(); params.set("", text) console.log(params.toString()); </script> </body> </html>
Chrome及びEdgeでの結果は、
sample.html:9 %uD842%uDFB7 sample.html:10 %F0%A0%AE%B7 sample.html:11 %F0%A0%AE%B7 sample.html:14 =%F0%A0%AE%B7
escape
ではやはり、UTF-16を使用しているようです。encodeURI
、encodeURIComponent
、URLSearchParams
は、UTF-8を使用しています。
実験2 – HTMLの文字コードを変えた場合
phpと同じように、ファイルの文字コードの依存する可能性があるため確認します。
以下のようなコードを、Shift_JIS(Windows-31J)で保存。
<!DOCTYPE html> <html> <head> <meta charset="Shift_JIS"> </head> <body> <script type="text/javascript"> const text = "abc あいうえお"; console.log(escape(text)); console.log(encodeURI(text)); console.log(encodeURIComponent(text)); const params = new URLSearchParams(); params.set("", text); console.log(params.toString()); </script> </body> </html>
Chrome 71.0.3578.98 での結果は、
sample.html:9 abc%20%uFFFD%uFFFD%uFFFD%uFFFD%uFFFD%uFFFD%uFFFD%uFFFD%uFFFD%uFFFD sample.html:10 abc%20%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD sample.html:11 abc%20%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD sample.html:14 =abc+%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD%EF%BF%BD
Microsoft EdgeHTML 17.17134 での結果は、
abc%20%u3042%u3044%u3046%u3048%u304A abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A =abc+あいうえお
Chromeですが文字エンコードに失敗しているようです。原因について分かりませんでした。Edgeに関しては、UTF-8で変換しているようです。
Chromeでうまく動かなかったので、UTF-16 Little Endianで試しました。
<!DOCTYPE html> <html> <head> <meta charset="utf-16le"> </head> <body> <script type="text/javascript"> const text = "abc あいうえお"; console.log(escape(text)); console.log(encodeURI(text)); console.log(encodeURIComponent(text)); const params = new URLSearchParams(); params.set("", text); console.log(params.toString()); </script> </body> </html>
Chrome 71.0.3578.98 での結果は、
sample.html:9 abc%20%u3042%u3044%u3046%u3048%u304A sample.html:10 abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A sample.html:11 abc%20%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A sample.html:14 =abc+%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A
上記の結果から、HTMLの文字コードは関係なく、UTF-8に変換されることが分かりました。
結果
escape
については非推奨なので、動作は分からないです。ただ、encodeURI
、encodeURIComponent
、URLSearchParams
に関していえば、UTF-8に変換してくれます。ただChromeの動作を考えると、HTMLを記載する際は、Unicodeを使ったほうがよさそうです。
URLエンコードについて
はじめに
escape
、encodeURI
、encodeURIComponent
、URLSearchParams
がどのように変換するか確認します。
ソースコード
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script type="text/javascript"> let text = ""; text += "<table>"; text += "<caption>URLエンコード結果一覧</caption>"; text += "<tr>"; text += "<th>10進数</th>"; text += "<th>16進数</th>"; text += "<th>文字</th>"; text += "<th>escape</th>"; text += "<th>encodeURI</th>"; text += "<th>encodeURIComponent</th>"; text += "<th>URLSearchParams</th>"; text += "</tr>"; for(let charcode = 0; charcode < 128 ; charcode++ ) { const chardata = String.fromCharCode(charcode); text += "<tr>"; text += "<td>" + charcode + "</td>"; text += "<td>0x" + charcode.toString(16).toUpperCase() + "</td>"; text += "<td>" + chardata + "</td>"; text += "<td>" + escape(chardata) + "</td>"; text += "<td>" + encodeURI(chardata) + "</td>"; text += "<td>" + encodeURIComponent(chardata) + "</td>"; text += "<td>" + (new URLSearchParams({"":chardata})).toString().substr(1) + "</td>"; text += "</tr>"; } text += "</table>"; document.body.insertAdjacentHTML("beforeend", text); </script> </body> </html>
実行結果
URLエンコード結果一覧
10進数 | 16進数 | 文字 | escape | encodeURI | encodeURI Component |
URL Search Params |
0 | 0x0 | ? | %00 | %00 | %00 | %00 |
1 | 0x1 | ? | %01 | %01 | %01 | %01 |
2 | 0x2 | ? | %02 | %02 | %02 | %02 |
3 | 0x3 | ? | %03 | %03 | %03 | %03 |
4 | 0x4 | ? | %04 | %04 | %04 | %04 |
5 | 0x5 | ? | %05 | %05 | %05 | %05 |
6 | 0x6 | ? | %06 | %06 | %06 | %06 |
7 | 0x7 | ? | %07 | %07 | %07 | %07 |
8 | 0x8 | ? | %08 | %08 | %08 | %08 |
9 | 0x9 | ? | %09 | %09 | %09 | %09 |
10 | 0xA | ? | %0A | %0A | %0A | %0A |
11 | 0xB | ? | %0B | %0B | %0B | %0B |
12 | 0xC | ? | %0C | %0C | %0C | %0C |
13 | 0xD | ? | %0D | %0D | %0D | %0D |
14 | 0xE | ? | %0E | %0E | %0E | %0E |
15 | 0xF | ? | %0F | %0F | %0F | %0F |
16 | 0x10 | ? | %10 | %10 | %10 | %10 |
17 | 0x11 | ? | %11 | %11 | %11 | %11 |
18 | 0x12 | ? | %12 | %12 | %12 | %12 |
19 | 0x13 | ? | %13 | %13 | %13 | %13 |
20 | 0x14 | ? | %14 | %14 | %14 | %14 |
21 | 0x15 | ? | %15 | %15 | %15 | %15 |
22 | 0x16 | ? | %16 | %16 | %16 | %16 |
23 | 0x17 | ? | %17 | %17 | %17 | %17 |
24 | 0x18 | ? | %18 | %18 | %18 | %18 |
25 | 0x19 | ? | %19 | %19 | %19 | %19 |
26 | 0x1A | ? | %1A | %1A | %1A | %1A |
27 | 0x1B | ? | %1B | %1B | %1B | %1B |
28 | 0x1C | ? | %1C | %1C | %1C | %1C |
29 | 0x1D | ? | %1D | %1D | %1D | %1D |
30 | 0x1E | ? | %1E | %1E | %1E | %1E |
31 | 0x1F | ? | %1F | %1F | %1F | %1F |
32 | 0x20 | %20 | %20 | %20 | + | |
33 | 0x21 | ! | %21 | ! | ! | %21 |
34 | 0x22 | “ | %22 | %22 | %22 | %22 |
35 | 0x23 | # | %23 | # | %23 | %23 |
36 | 0x24 | $ | %24 | $ | %24 | %24 |
37 | 0x25 | % | %25 | %25 | %25 | %25 |
38 | 0x26 | & | %26 | & | %26 | %26 |
39 | 0x27 | ‘ | %27 | ‘ | ‘ | %27 |
40 | 0x28 | ( | %28 | ( | ( | %28 |
41 | 0x29 | ) | %29 | ) | ) | %29 |
42 | 0x2A | * | * | * | * | * |
43 | 0x2B | + | + | + | %2B | %2B |
44 | 0x2C | , | %2C | , | %2C | %2C |
45 | 0x2D | – | – | – | – | – |
46 | 0x2E | . | . | . | . | . |
47 | 0x2F | / | / | / | %2F | %2F |
48 | 0x30 | 0 | 0 | 0 | 0 | 0 |
49 | 0x31 | 1 | 1 | 1 | 1 | 1 |
50 | 0x32 | 2 | 2 | 2 | 2 | 2 |
51 | 0x33 | 3 | 3 | 3 | 3 | 3 |
52 | 0x34 | 4 | 4 | 4 | 4 | 4 |
53 | 0x35 | 5 | 5 | 5 | 5 | 5 |
54 | 0x36 | 6 | 6 | 6 | 6 | 6 |
55 | 0x37 | 7 | 7 | 7 | 7 | 7 |
56 | 0x38 | 8 | 8 | 8 | 8 | 8 |
57 | 0x39 | 9 | 9 | 9 | 9 | 9 |
58 | 0x3A | : | %3A | : | %3A | %3A |
59 | 0x3B | ; | %3B | ; | %3B | %3B |
60 | 0x3C | < | %3C | %3C | %3C | %3C |
61 | 0x3D | = | %3D | = | %3D | %3D |
62 | 0x3E | > | %3E | %3E | %3E | %3E |
63 | 0x3F | ? | %3F | ? | %3F | %3F |
64 | 0x40 | @ | @ | @ | %40 | %40 |
65 | 0x41 | A | A | A | A | A |
66 | 0x42 | B | B | B | B | B |
67 | 0x43 | C | C | C | C | C |
68 | 0x44 | D | D | D | D | D |
69 | 0x45 | E | E | E | E | E |
70 | 0x46 | F | F | F | F | F |
71 | 0x47 | G | G | G | G | G |
72 | 0x48 | H | H | H | H | H |
73 | 0x49 | I | I | I | I | I |
74 | 0x4A | J | J | J | J | J |
75 | 0x4B | K | K | K | K | K |
76 | 0x4C | L | L | L | L | L |
77 | 0x4D | M | M | M | M | M |
78 | 0x4E | N | N | N | N | N |
79 | 0x4F | O | O | O | O | O |
80 | 0x50 | P | P | P | P | P |
81 | 0x51 | Q | Q | Q | Q | Q |
82 | 0x52 | R | R | R | R | R |
83 | 0x53 | S | S | S | S | S |
84 | 0x54 | T | T | T | T | T |
85 | 0x55 | U | U | U | U | U |
86 | 0x56 | V | V | V | V | V |
87 | 0x57 | W | W | W | W | W |
88 | 0x58 | X | X | X | X | X |
89 | 0x59 | Y | Y | Y | Y | Y |
90 | 0x5A | Z | Z | Z | Z | Z |
91 | 0x5B | [ | %5B | %5B | %5B | %5B |
92 | 0x5C | \ | %5C | %5C | %5C | %5C |
93 | 0x5D | ] | %5D | %5D | %5D | %5D |
94 | 0x5E | ^ | %5E | %5E | %5E | %5E |
95 | 0x5F | _ | _ | _ | _ | _ |
96 | 0x60 | ` | %60 | %60 | %60 | %60 |
97 | 0x61 | a | a | a | a | a |
98 | 0x62 | b | b | b | b | b |
99 | 0x63 | c | c | c | c | c |
100 | 0x64 | d | d | d | d | d |
101 | 0x65 | e | e | e | e | e |
102 | 0x66 | f | f | f | f | f |
103 | 0x67 | g | g | g | g | g |
104 | 0x68 | h | h | h | h | h |
105 | 0x69 | i | i | i | i | i |
106 | 0x6A | j | j | j | j | j |
107 | 0x6B | k | k | k | k | k |
108 | 0x6C | l | l | l | l | l |
109 | 0x6D | m | m | m | m | m |
110 | 0x6E | n | n | n | n | n |
111 | 0x6F | o | o | o | o | o |
112 | 0x70 | p | p | p | p | p |
113 | 0x71 | q | q | q | q | q |
114 | 0x72 | r | r | r | r | r |
115 | 0x73 | s | s | s | s | s |
116 | 0x74 | t | t | t | t | t |
117 | 0x75 | u | u | u | u | u |
118 | 0x76 | v | v | v | v | v |
119 | 0x77 | w | w | w | w | w |
120 | 0x78 | x | x | x | x | x |
121 | 0x79 | y | y | y | y | y |
122 | 0x7A | z | z | z | z | z |
123 | 0x7B | { | %7B | %7B | %7B | %7B |
124 | 0x7C | | | %7C | %7C | %7C | %7C |
125 | 0x7D | } | %7D | %7D | %7D | %7D |
126 | 0x7E | ~ | %7E | ~ | ~ | %7E |
127 | 0x7F | ? | %7F | %7F | %7F | %7F |
結果
encodeURI
は、記号のいくつかが変換されていません。例えば、&
とかです。これは、URL上で特別な意味を持つため、変換するとURLとしての特別な意味をなくしてしまいます。これはどういった場面を想定しているのでしょうか。URL全体のデータに対して、エンコードした後に、エンコード後のURLに対してアクセスまで行うといったことを想定しているのかもしれません。
encodeURIComponent
は、&
などURL上で特殊な意味をもつ記号も変換されています。つまり、GETなどでデータを入れるように文字列を変換したいという場合を想定しています。
URLSearchParams
は、多くの記号をURLエンコードしてくれますが、半角スペースの
を+
に変換していたり、チルダを%7E
に変換するなど一部動作が異なる処理をしています。これはPHPのurlencode
と同一の動作となっております。
URLデコードについて
本当は比較のためにURLSearchParams
を使って、URLデコードをしたかったのですが、よくわからなかったので以下のような感じで調査します。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <script type="text/javascript"> let text = "_%20_+_%7E_~_"; let html = ""; html += unescape(text) + "<br>"; html += decodeURI(text) + "<br>"; html += decodeURIComponent(text) + "<br>"; html += decodeURIComponent(text.replace(/\+/g, "%20")) + "<br>"; document.body.insertAdjacentHTML("beforeend", html); </script> </body> </html>
結果は以下の通り
_ _+_~_~_ _ _+_~_~_ _ _+_~_~_ _ _ _~_~_
+
を
に変換したい場合は、通常の関数だけでは変換できなので、予めreplace(/\+/g, "%20")
のように、+をスペースに置換後に関数にかけるという手がよいかもしれません。
リンデンスクリプト言語
はじめに
おまけですが、セカンドライフ上で動作するリンデンスクリプト(Linden Scripting Language)でも確認してみました。
URLエンコードについて
スクリプト
以下を実行します。ASCIIコードから文字への変換関数がなかったので、作りました。
string toUrlCode(integer x) { string HEX_MAP = "0123456789ABCDEF"; if(x < 0x10) { return "%0" + llGetSubString(HEX_MAP, x, x); } else { return "%" + llGetSubString(HEX_MAP, x >> 4, x >> 4) + llGetSubString(HEX_MAP, x & 0xF, x & 0xF); } } string fromCharCode(integer x) { return llUnescapeURL(toUrlCode(x)); } default { state_entry() { string text = ""; integer charcode = 0; for(charcode = 0;charcode < 128;charcode++) { text += llEscapeURL(fromCharCode(charcode)) + "\n"; } llOwnerSay(text); } }
実行結果
URLエンコード結果一覧
10進数 | 16進数 | 文字 | llEscapeURL |
0 | 0x0 | ? | ? |
1 | 0x1 | ? | %01 |
2 | 0x2 | ? | %02 |
3 | 0x3 | ? | %03 |
4 | 0x4 | ? | %04 |
5 | 0x5 | ? | %05 |
6 | 0x6 | ? | %06 |
7 | 0x7 | ? | %07 |
8 | 0x8 | ? | %08 |
9 | 0x9 | ? | %09 |
10 | 0xA | ? | %0A |
11 | 0xB | ? | %0B |
12 | 0xC | ? | %0C |
13 | 0xD | ? | %0D |
14 | 0xE | ? | %0E |
15 | 0xF | ? | %0F |
16 | 0x10 | ? | %10 |
17 | 0x11 | ? | %11 |
18 | 0x12 | ? | %12 |
19 | 0x13 | ? | %13 |
20 | 0x14 | ? | %14 |
21 | 0x15 | ? | %15 |
22 | 0x16 | ? | %16 |
23 | 0x17 | ? | %17 |
24 | 0x18 | ? | %18 |
25 | 0x19 | ? | %19 |
26 | 0x1A | ? | %1A |
27 | 0x1B | ? | %1B |
28 | 0x1C | ? | %1C |
29 | 0x1D | ? | %1D |
30 | 0x1E | ? | %1E |
31 | 0x1F | ? | %1F |
32 | 0x20 | %20 | |
33 | 0x21 | ! | %21 |
34 | 0x22 | “ | %22 |
35 | 0x23 | # | %23 |
36 | 0x24 | $ | %24 |
37 | 0x25 | % | %25 |
38 | 0x26 | & | %26 |
39 | 0x27 | ‘ | %27 |
40 | 0x28 | ( | %28 |
41 | 0x29 | ) | %29 |
42 | 0x2A | * | %2A |
43 | 0x2B | + | %2B |
44 | 0x2C | , | %2C |
45 | 0x2D | – | %2D |
46 | 0x2E | . | %2E |
47 | 0x2F | / | %2F |
48 | 0x30 | 0 | 0 |
49 | 0x31 | 1 | 1 |
50 | 0x32 | 2 | 2 |
51 | 0x33 | 3 | 3 |
52 | 0x34 | 4 | 4 |
53 | 0x35 | 5 | 5 |
54 | 0x36 | 6 | 6 |
55 | 0x37 | 7 | 7 |
56 | 0x38 | 8 | 8 |
57 | 0x39 | 9 | 9 |
58 | 0x3A | : | %3A |
59 | 0x3B | ; | %3B |
60 | 0x3C | < | %3C |
61 | 0x3D | = | %3D |
62 | 0x3E | > | %3E |
63 | 0x3F | ? | %3F |
64 | 0x40 | @ | %40 |
65 | 0x41 | A | A |
66 | 0x42 | B | B |
67 | 0x43 | C | C |
68 | 0x44 | D | D |
69 | 0x45 | E | E |
70 | 0x46 | F | F |
71 | 0x47 | G | G |
72 | 0x48 | H | H |
73 | 0x49 | I | I |
74 | 0x4A | J | J |
75 | 0x4B | K | K |
76 | 0x4C | L | L |
77 | 0x4D | M | M |
78 | 0x4E | N | N |
79 | 0x4F | O | O |
80 | 0x50 | P | P |
81 | 0x51 | Q | Q |
82 | 0x52 | R | R |
83 | 0x53 | S | S |
84 | 0x54 | T | T |
85 | 0x55 | U | U |
86 | 0x56 | V | V |
87 | 0x57 | W | W |
88 | 0x58 | X | X |
89 | 0x59 | Y | Y |
90 | 0x5A | Z | Z |
91 | 0x5B | [ | %5B |
92 | 0x5C | \ | %5C |
93 | 0x5D | ] | %5D |
94 | 0x5E | ^ | %5E |
95 | 0x5F | _ | %5F |
96 | 0x60 | ` | %60 |
97 | 0x61 | a | a |
98 | 0x62 | b | b |
99 | 0x63 | c | c |
100 | 0x64 | d | d |
101 | 0x65 | e | e |
102 | 0x66 | f | f |
103 | 0x67 | g | g |
104 | 0x68 | h | h |
105 | 0x69 | i | i |
106 | 0x6A | j | j |
107 | 0x6B | k | k |
108 | 0x6C | l | l |
109 | 0x6D | m | m |
110 | 0x6E | n | n |
111 | 0x6F | o | o |
112 | 0x70 | p | p |
113 | 0x71 | q | q |
114 | 0x72 | r | r |
115 | 0x73 | s | s |
116 | 0x74 | t | t |
117 | 0x75 | u | u |
118 | 0x76 | v | v |
119 | 0x77 | w | w |
120 | 0x78 | x | x |
121 | 0x79 | y | y |
122 | 0x7A | z | z |
123 | 0x7B | { | %7B |
124 | 0x7C | | | %7C |
125 | 0x7D | } | %7D |
126 | 0x7E | ~ | %7E |
127 | 0x7F | ? | %7F |
※NUL文字はLSL上では利用できないため変換を確かめることができませんでした。
結果
は+
に変換せず、そのまま%20
にURLエンコードしています。URLエンコードしておけば、元のスペースに戻るので特に気にする必要はありません。
URLデコードについて
デコードの方も少し確認してみました。
default { state_entry() { llOwnerSay(llUnescapeURL("_%20_+_")); } }
実行結果は以下の通り
_ _+_
llEscapeURL
の仕様から+
は+
のままですね。他の言語で
を+
に変換してしまうと元に戻せなくなるので注意が必要です。
おわりに
今回、PHPとJavaScriptとLSLのURLエンコードについて実際の動作を確認してみました。
以下、結論となります。
文字コードについて
URLエンコードにおいては、JavaScriptの仕様からUTF-8が基本となるようです。
PHPは、ソースコードの文字コードによって内部動作が変わるため、必ずUTF-8を使用したほうがよいです。また、Chromeに至ってもURLエンコードが正しく動作しない可能性があるため、HTMLの文字コードはUTF-8を使用しましょう。
URLエンコードの方法
送信先の仕様が分かっているのであれば、方式を合わせるのが最も良いです。
Webページのフォームなどで利用される可能性があるなら、Webページのサブミットで利用される変換方法(application/x-www-form-urlencoded)、つまり半角スペースの
を+
に変換、チルダを%7E
に変換する方法をとりましょう。
- php ー
urlencode
及び、urldecode
- JavaScirpt ー
URLSearchParams
(※IE11は使用不可)
※URLSearchParams
は動かない環境もあるため、replace(/%20/g, "+")
のようなものを挟み込んでおけばよいと思われます。
データをURL上でやりとりしたいという理由であれば、以下の関数を使いましょう。
- php ー
rawurlencode
及び、rawurldecode
- JavaScirpt ー
encodeURIComponent
及び、decodeURIComponent
一部SQLなどに直接食わせたりすると危険な文字列とかあるので、デコード後は必要に応じて加工が必要かと思います。
コメント