PHPとJavaScriptとLSLのURLエンコードについて動作をまとめてみた

プログラミング
スポンサーリンク

はじめに

こんにちはー!

今日は、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デコードについて

urlencoderawurlencodeの互換性を調べたいと思います。

デコードを組み合わせて以下のコードで確認しました。

<?php
echo "\"" . urldecode("%20") . "\"<br>";
echo "\"" . rawurldecode("+") . "\"<br>";
echo "\"" . urldecode("~") . "\"<br>";
echo "\"" . rawurldecode("%7E") . "\"<br>";
?>

結果は、

" "
"+"
"~"
"~"

このようになりました。

+に関しては、rawurldecodeで元に戻せません。つまり、urlencodeで変換した文字は、rawurldecodeで元に戻せないことなります。逆なら大丈夫なので、urldecodeであれば問題ありません。

urlencoderawurlencodeか、どちらを使えばいいのでしょうか。これについては、最後に記載したいと思います。ちなみに、JavaScriptにあるencodeURIComponentによると

application/x-www-form-urlencoded によれば、スペースは ‘+’ に置換されます。そのため、encodeURIComponentによる置換に加えて “%20” を “+” に変換したいと考えるユーザーもおられるでしょう。

encodeURIComponent() – MDN – Mozillaen より抜粋

と記載があります。これはどういう意味かといいますと、Webページでデータを投稿する際のURLエンコードは、スペースは ‘+’ にするという決まりがあるのです。そのため、urlencodeによるエンコード方法は非推奨とかではなく、普通に利用されている関数なのです。

JavaScriptのURLエンコードについて

文字コードについて

はじめに

データを渡す際などに利用するJavaScriptの動作を調べてみましょう。

JavaScript用のURLエンコード用関数を確認します。

実験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を使用しているようです。encodeURIencodeURIComponentURLSearchParamsは、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については非推奨なので、動作は分からないです。ただ、encodeURIencodeURIComponentURLSearchParamsに関していえば、UTF-8に変換してくれます。ただChromeの動作を考えると、HTMLを記載する際は、Unicodeを使ったほうがよさそうです。

URLエンコードについて

はじめに

escapeencodeURIencodeURIComponentURLSearchParamsがどのように変換するか確認します。

ソースコード

<!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などに直接食わせたりすると危険な文字列とかあるので、デコード後は必要に応じて加工が必要かと思います。

コメント

タイトルとURLをコピーしました