- 2005-03-07 (月)
- Movable Type
自宅サーバに MySQL version 4.1.10 を導入 〜 Movable Type 3.151 のデータストアに使おうとして出くわした不具合。Google検索してみたところ、誰も触れてないようだったので書いてみました。
1) 症状
日本語文字(とその他マルチバイトコードの文字)が「??????」といった文字列に置き換わってしまいます。BLOG管理画面のエントリ一覧等、直接データストアから情報を抽出してくる画面を見ればすぐに症状が発見できます。
2) 発生条件
MySQLの最新バージョン(2005/03/07現在)である 4.1.x 系を Movable Type のデータストアとして使用する場合に発生します。詳しい発生条件を図にしてみました:
Webをさらさらっと調べてみた感じ、同不具合の報告は見られませんでした... みんな MySQLの最新版 (v4.1) は敬遠気味?普通バイナリパッケージからインストールしないの?(不安気味
3) 原因
日本語文字列が「???????」といった半角ハテナに置き換わる「文字化け」現象はさまざまな原因で発生するものですが、今回の原因は MySQL 4.1 からの新仕様:
サーバとクライアントそれぞれに対して異なるキャラクタセットを設定可能
に起因します。「〜を設定可能」というのは、言い換えれば「サーバとクライアントそれぞれに対してきちんと使用するキャラクタセットを指定する事が必須」って事です。今までのバージョンのMySQLでは「サーバ側のキャラクタセット設定=クライアント側も強制的に同キャラクタセットが使われる」仕様だったようなので、この仕様変更には注意が必要になります。※この辺の仕様やキャラクタセットの正しい設定方法は別エントリ「MySQL 4.1 日本語環境設定方法 (キャラクタセット設定方法)」を参照してください。
4.1) 解決方法
DBI::mysql にてMySQLサーバに接続する際、クライアント側(Perl)で使用するキャラクタセットを明示的に指定する事でさくっと解決できます。現在 Movable Type に実装されている MySQL用ドライバ( MT::ObjectDriver::DBI::mysql)にはクライアント側(MT側)のキャラクタセットを設定する記述がありませんので、以下の箇所に1行記述を足してあげます:
.../mt/lib/MT/ObjectDriver/DBI/mysql.pm 52-53行目
$driver->{dbh} = DBI->connect($dsn, $cfg->DBUser, $cfg->DBPassword,
{ RaiseError => 0, PrintError => 0 })
or return $driver->error(MT->translate("Connection error: [_1]",
$DBI::errstr));
$driver;
を以下のように変更(1行追記) :
$driver->{dbh} = DBI->connect($dsn, $cfg->DBUser, $cfg->DBPassword,
{ RaiseError => 0, PrintError => 0 })
or return $driver->error(MT->translate("Connection error: [_1]",
$DBI::errstr)); $driver->{dbh}->do("SET NAMES ujis"); # ujis|sjis|utf8
$driver;
このように、"SET NAMES x" コマンドによりMovable Typeで使用しているキャラクタセットを指定してやればOKです(MySQL では EUC-JP のキャラクタセット名が ujis になっている点に注意)。
4.2) Movable Type 3.2 以降の場合
MT3.2からは mt-config.cgi の
SQLSetNames 1
設定を施す事で、上記 CGI 修正と同様の効果になります。
4.3) おまけ
上記解決法ではやっつけ的に、ソースコードに直接 "SET NAMES ujis" なんてベタガキしましたが、Movable Typeのコンフィグ設定と連動した、より汎用的な解決策はこんな感じになるかと...多分。
どっかの定数定義ブロックで 通常のキャラクタセット名 <> MySQL側でのキャラクタセット名の対応表を定義しておく:
$charset_mysql => { "EUC-JP" => "ujis", "Shift_JIS" => "sjis", "UTF-8" => "utf8", # ... その他キャラクタセットを定義。うわ面倒くさっ };
で、「4.1) 解決方法」での修正箇所に対して以下の様に追記:
$driver->{dbh} = DBI->connect($dsn, $cfg->DBUser, $cfg->DBPassword,
{ RaiseError => 0, PrintError => 0 })
or return $driver->error(MT->translate("Connection error: [_1]",
$DBI::errstr)); $driver->{dbh}->do("SET NAMES ".
$charset_mysql->{$cfg->{PublishCharset}});
$driver;
Comments:1
- 青樹洋文 2012-02-28 (火) 11:46
-
有り難うございます。半日悪戦苦闘していましたが、こちらの情報のお陰で無事解決しました。