文字コードの問題に正しく対応する前提として,アプリケーションが稼働する基盤ソフトウエアがマルチバイト文字列処理に対応している必要がある。特に問題となるのが,言語処理系とデータベース管理システム(DBMS)である。利用者の使い方が正しくない場合も,ぜい弱性が混入することがある。このため,今回は主要言語とデータベース(MySQLとMS SQL Server)のマルチバイト文字対応状況について説明する。

文字列の処理単位は文字単位かバイト単位か

 Webアプリケーション開発で人気のあるスクリプト言語の多くは,かつては文字列をバイト単位で扱っているものが多かった。以下のPerlスクリプトは“漢字”という文字列の長さを表示するものだが,ソースの文字エンコーディングによって結果が変わる。具体的には,Shift_JISやEUC-JPの場合は4,UTF-8の場合は6と表示される。原因は,このスクリプトが文字列の内部表現上のバイト数を表示してしまうためである。

[画像のクリックで拡大表示]

 開発者にとって,これでは不便である。スクリプト言語は簡便にアプリケーションを開発できることが魅力なので,日本語も文字単位に扱いたい。このため各スクリプト言語は,文字列処理のマルチバイト対応により,日本語なども文字単位に扱えるようになりつつある。先の例を「文字単位」に扱うようするには,以下のように「use utf8;」という1行を追加して,ソースをUTF-8で保存する。

[画像のクリックで拡大表示]

 このスクリプトを実行すると,今度は2と表示される。use utf8;宣言した場合,Perlは文字単位の文字列処理を行っていることがわかる。次にPerlを含む主要なWebアプリケーション開発ツールの対応状況を説明しよう。

◆PHP
 現行バージョンのPHP5.2.9は,言語処理系本体ではマルチバイト文字に対応しておらず,マルチバイト文字列処理はmbstring拡張モジュールが実行する。言語処理系本体が日本語対応していないため,PHPソースコードをShift_JISで記述すると5C問題が発生する。例えば以下のようなコードはコンパイル・エラーになる。

[画像のクリックで拡大表示]

 5C問題のメカニズムを説明しよう。「"表"」の文字コードは図1のようになる。「表」のShift_JISとしてのコードは「0x95 0x5C」だが,PHPではこの2バイトが独立した2文字であると解釈する。

図1●「"表"」の文字コード
図1●「"表"」の文字コード

 0x5C(バックスラッシュ)はPHPの文字列リテラル中では特別な意味があり,後続する「"」と結びついて,リテラル中の「"」自体を示すものと解釈される。このため,文字列リテラルを終端するダブルクオートが「バックスラッシュに食われ」,リテラルが閉じられていない状態となり,PHPの文法エラーになる。

 このPHPの5C問題への対策としては以下の二つの方法がある。

  • PHPをソースからコンパイルし直し,その際に--enable-zend-multibyteオプションを指定する
  • PHPソースを記述する際の文字エンコーディングとしてShift_JISを避け,EUC-JPかUTF-8を使用する

 正当なアプローチとしては「--enable-zend-multibyte」オプションを付けてPHP自体をコンパイルし直すべきだが,このオプションは実績としてはあまり広く使われていないようだ。それよりは,対症療法的ではあるが,後者のShift_JISを避ける方法が広く使われている。

 現状のPHPの文字列は単なるバイト列として実装されており,文字単位の処理ではない。一方,次のメジャーバージョンであるPHP6は,内部文字エンコーディングがUTF-16になると発表されている。近い将来のPHP6対応に備えて,今後PHPで開発するアプリケーションについてはUnicodeを使うことをお勧めする。入力,出力,ソースコードの記述に使用する文字エンコーディングをUTF-8とすればよい。

 また,PHP本体がマルチバイト文字列に対応していないことから,利用予定の拡張モジュールについてもマルチバイト文字列対応していることを個別に確認する必要がある。第7回で例に挙げたmysql_escape_string関数が,まさにそれだ。mysql_escape_string関数はマルチバイト文字列に対応していないため,mysql_real_escape_string関数を使用するべきである。