FirefoxのロケーションバーとGETメソッド
下記のようなスクリプトをUTF-8Nで保存し,ウェブブラウザ(Firefox)を通じて実行してみる。
<?php echo '<?xml version="1.0" encoding="utf-8"?>' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>test</title> </head> <body> <form action="test.php" method="get"> <p><input type="text" name="q" /></p> <p><input type="submit" value="送信" /></p> <p><?php echo htmlspecialchars($_GET['q'], ENT_QUOTES) ?></p> </form> </body> </html>
当然のことながら,これは予想通りに動く。画面上に現れるテキストボックスに文字列を入力して送信すると,送信ボタンの下に入力した文字列が表示される。
しかし,Firefox(3以降のバージョン)の場合,このスクリプトは非ASCII文字を含む文字列を扱う際に(一部)予期しない動作をする。例えば,テキストボックスに「ほげ」と入力して送信したとき,Firefoxのアドレスバーには「http://hoge.com/test.php?q=ほげ」と表示されるが*1,このままロケーションバーにキャレットを持って行きEnterキーを押すと,文字化けした文字列が画面上に表示されてしまう。
このとき,Firefoxはロケーションバーに表示されたURIエンコードされていない非ASCII文字を含むURIを独自にURIエンコードしてサーバーに送信している。このURIエンコードがデフォルトではShift-JISで行われるため,UTF-8でのURIエンコードを期待して動作する上記のようなPHPスクリプトでは文字化けが発生してしまうようだ。
したがって,この問題に対応するためには次のようなスクリプトに改良する必要がある。
<?php echo '<?xml version="1.0" encoding="utf-8"?>' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>test</title> </head> <body> <form action="test.php" method="get"> <?php foreach ($_GET as $key => $value) { $_GET[$key] = mb_convert_encoding($value, "UTF-8", "UTF-8, SJIS, EUC-JP"); } ?> <p><input type="text" name="q" /></p> <p><input type="submit" value="送信" /></p> <p><?php echo htmlspecialchars($_GET['q'], ENT_QUOTES) ?></p> </form> </body> </html>
ちなみに,URIエンコードがデフォルトでUTF-8で行われるOperaやChromeではこの問題は発生しない。Firefoxにおいてもabout:configからnetwork.standard-url.encode-utf8の値をtrueにすることでURIエンコードがUTF-8で行われるようになるが,デフォルトではShift-JISになっていることが問題である。
フォームから送信されるパラメータの文字コードがURIエンコード時の文字コードと食い違っていることは原理上仕方ないとしても,URIエンコード時に使用される文字コードが統一されていない現在の状況は開発者にとって不幸であると思う。
ところで,UTF-8でURIエンコードされたURIはデコードされてロケーションバーに表示されるのに,Shift-JISでURIエンコードされたURIがデコードされずにロケーションバーに表示されるのは,URIエンコード時の動作と食い違っていると思うのは私だけ?