[PHP-users 33214] Re: PHP5+MSSQLSERVER2005での中国語の取得について

kanonbell kanonbell.sky @ gmail.com
2008年 1月 31日 (木) 23:16:44 JST


こんばんは。

私にとっても懸念事項だったので、調べてみました。
PHP+MSSQLの環境は文字については正直厳しいですね。。
扱うのが日本語(+ANSI)のみだったら問題ないんですが。

結果からいうと、「ニーハオ」って中国語と「あいうえお」という日本語をNVARCHARな
カラムに記述しているレコードを正常に表示できました。
表示その他は基本的にUTF-8です。
DBの照合順序を変えたりもしてみましたが、表示には影響しませんでした。

使うのはADO。
データベース仮想化レイヤのADOdbではなく、WindowsのCOM APIの、
データベースアクセスに良く使うやつです。
PHPにはCOM関数があるのでそれ使ってもいいんですが、今回はADOdb経由で
使ってみました。楽だし。

http://jp.php.net/manual/ja/class.com.php
オプション扱いの引数にcodepageがあるので、65001(UTF-8)を指定します。

include('adodb.inc.php');
$conn = &ADONewConnection('ado_mssql');
$conn->charpage = 65001
  :
って感じになります。

取得したレコードセットは普通にUTF-8で入っているので、特に文字コード変換などを
行わなくてもそのまま表示できました。

> Windows Server 2003
> HTTPD2.2系の最新
> PHP5.2系の最新
> MS SQLSERVER 2005

試した環境自体は全く同じです。
MSSQLはローカル。
NVARCHARなカラムに、Management Studio上から直接日本語と中国語を
打ち込んでいます。
当然ながらManagement Studio上からは正常に表示できます。
UTF-8で表示しているASP上でも、正常に表示できます。

以下は蛇足。

> いろいろと調べてみたところ、
> 抽出された文字列がSJISであるため
> UTF-8への変換が必要であることがわかりました。

まあそうなんですが、ちょっと補足。
MSSQL2005は内部的にUCS-2(UCS-2LE?)で文字列を保持しています。
このデータをデータベースクライアントに渡す際に文字コードの変換が発生して
いるみたいなんですね。
BOL読む限り、「ユニコードに対応していない場合データベースクライアントが
相手だったら、相手のコードページにあわせて変換する」ってなことが書いてある
ようですし。

> 試しに、データベースへの接続を思い当たる3つの方法
> ・mssql関数
> ・PDO_ODBC
> ・ADBdb
> にて行ってみましたが、どれも同じ結果になりました。

ADOdbは仮想化レイヤであってドライバ選べるので。。

mssql関数が使用するデータベースクライアントはDB-Libraryで、ものすごく古く、
MSSQL2005ではまだ使えるもののサポートの打ち切りが明言されています。
PHP+MSSQLで使う分には多分一番高機能なのが泣かせますが。。
このDBクライアントはユニコードに対応していないので、強制的にこのクライアントが
存在するWindowsのコードページ(つまりWebサーバのコードページ)である
SJISに変換されます。他言語版Windowsだったら多分他のになるでしょう。
この辺はカラムの照合順序を変えるとSJIS以外の文字コードに変換されることも
あるので、実装が謎だったりしますが。
インド系の照合順序にしてみたら、DB-Libraryはユニコード対応してないから
無理だよ的エラーが出たりもしました。

ODBCはバージョンによるもののユニコードに対応しているんですが、PHP側の
ODBCドライバがOSのコードページをそのまま申請しちゃうのかな?
DB-Libraryと同じようにSJIS変換がかけられてしまい、どうにもダメでした。
ODBCの設定で文字コード変換を無効にしてもだめですね。

SQL Server 2005 Driver for PHP CTPは結局試さなかったんですが、すでに
お試しになってるようですね。
PHP+MSSQLでのまともなデータベースクライアントが風前の灯って感じだったので、
これには少々期待してるんですが、更新されるのかなあ。。
DATETIME型まだ使えないらしいですが。

MSSQL関数の説明ページには、文字コードの強制変換の問題を回避するやり方
として、バイナリを利用するやり方がコメントの形で解説されています。
ADOdbのADOドライバ(ラッパー)は軽く見た感じ最小限度の機能が用意されている
程度で不安を感じないでもなかったので、そちらのやり方も参考にしておくと良いかも
しれません。


PHP-users メーリングリストの案内