PHPからMySQL4.1とか5.0とか5.1とかに接続すると文字化けする

Posted on 7月 24, 2006
Filed Under MySQL | 1 Comment

GoogleさんやYahooさんで「PHP MySQL 文字化け」とかで検索しても
なかなか自分の環境にあった文字化け回避方法がなく超悩んで試行錯誤してみました。

なんか、いろいろなサイトを見ても、MySQLのバージョンが明確にされていないんです。
それじゃぁなんだかしっくりきません。
ある環境では文字化けが解消されたとしても、違う環境だと文字化けてしまうかもしれません。

ということで、まず、MySQLの文字コードに関する重要な設定項目を調べてみましょ。

・・・の前にMySQLのマニュアルにあるCJK(Chinese, Japanese, Korean)のFAQページに目を通してみましょう。
MySQL 5.0 Reference Manual :: 10.10 FAQ: MySQL Chinese, Japanese, and Korean Character Sets

自分は結構MySQLのマニュアルページを参考にするんですが、まず、日本語のマニュアルは古い情報しか載っていないのであんまオススメできません。
英語のマニュアルページだと結構知りたかった情報がてんこ盛りだったりします(でもウチ英語は不得意なのよね・・・!)。
でもGoogleでmysql関連の検索をしても、mysqlの公式サイトってなかなか上位に出てこない。。。なので、ウチが検索する時はGoogleで「(検索文字列) site:dev.mysql.com」な感じで検索してます。

で、ざーっと見た限り”SET CHARACTER SET utf8″するとか、”SET NAMES ‘utf8′”するとかskip-character-set-client-handshakeするくらいしか見当たりません。

とりあえずMySQL設定ファイルの文字コードに関連するオプションとしては以下のものが重要っぽいです。
 ・「SET NAMES xxx」文
 ・「SET CHARACTER SET xxx」文
 ・「default-character-set」オプション
 ・「skip-character-set-client-handshake」オプション
 ・「init_connect」オプション

 ※一応参照:MyNA Web Site - 4.1以上の壁 (日本語の扱いの違い、文字化け等/含む5.0以上)

MySQLのバージョン別に、どうやればPHPからMySQLに接続した時文字化けが発生しないかを考察した結果を記述します。

■1.MySQL v4.1.15以降、MySQL v5.0.13以降 の場合
MySQLの設定ファイル(my.ini, my.cnf)に以下の記述をすることで解決します。多分。

[mysqld]
default-character-set=ujis
skip-character-set-client-handshake

4.1.15以降と5.0.13以降のバージョンであれば「skip-character-set-client-handshake」というオプションが使えます。
で、このオプションを指定してやればPHPから接続したときでも自動的にクライアント側の文字コードが「default-character-set」で指定されたものに自動設定されます。
これは本当に素晴らしいオプションです。
今までバージョンでの苦労がアホみたいです。

一応設定ファイルには次のオプションも書いておきましょう。

[mysql]
default-character-set=ujis
[mysqldump]
default-character-set=ujis

もしかしたら「skip-character-set-client-handshake」の設定がしてあればこの設定をしなくても大丈夫かもしれません(検証してないです)。
mysqldumpセクションの設定はダンプするのなら必要かもしれませんね。

■2.MySQL v4.1.2~4.1.14、MySQL v5.0.0~5.0.12 の場合
これらのバージョンだと、悲しい事に「skip-character-set-client-handshake」が使用できません。
なので、代わりに「SET NAMES」を使うことにします。
「SET NAMES」の指定方法にも2通り考えられます。

 (1)プログラムからDBに接続後、直接「SET NAMES」文をぶち込む。
 (2)「init_connect」オプションを使う。

(1)の方法はweb上にもたくさん情報があるので説明不要かもしれません。
まず先にMySQL設定ファイルに文字コードを指定します。

[mysqld]
default-character-set=ujis
[mysql]
default-character-set=ujis
[mysqldump]
default-character-set=ujis

この状態でPHPのプログラム上から以下のようにSET NAMES文のクエリを発行してやります。

mysql_query('SET NAMES ujis', $connect);

もしくはPEAR::DBを使っていればこんな感じ。

$db->query('SET NAMES ujis');

余談ですが、WindowsのDOSプロンプトから接続している時はSET NAMES cp932が良いです。
sjisだとNEC拡張文字、IBM拡張文字が文字化けちゃったりします。

(2)の方法を使用する場合は一つだけ制約があります。
それは、MySQLのSUPER権限を持つユーザー以外で接続することです。
つまり、rootユーザーではなく、GRANT文等で作成されたユーザーで接続しなければなりません。
rootユーザーで接続した場合はinit_connectを設定しても、そのクエリは実行されません。

 ※参照(4.1):MySQL 3.23, 4.0, 4.1 Reference Manual :: 5.2.2 Server System Variables
 ※参照(5.0):MySQL 5.0 Reference Manual :: 5.2.2 Server System Variables

なので、まず、MySQLに接続するためのユーザーを作成します。

mysql> GRANT ALL ON *.* TO user@localhost IDENTIFIED BY 'pass';
mysql> REVOKE SUPER ON *.* FROM user;
mysql> FLUSH PRIVILEGES;

みたいな感じでしょうか。
ダメだったら必要な権限だけつけてGRANTしてやりましょう。

次にMySQLの設定ファイルに文字コードオプションを指定します。

[mysqld]
default-character-set=ujis
init_connect="SET NAMES ujis"
[mysql]
default-character-set=ujis
[mysqldump]
default-character-set=ujis

これで、作成したユーザーで接続すればおそらく文字化けは解消されるような気がします。

で、また余談なんですが、「init_connect」に関して非常に意味不明なことがあります。
それはGoogleの検索結果なんですが、検索件数が以下のようになってました(2006-07-24現在)
 Googleで「”init_connect”」を検索(Web全体から) ⇒ 14,800 件
 Googleで「”init_connect”」を検索(日本語のみ) ⇒ 42 件
 Googleで「”init-connect”」を検索(Web全体から) ⇒ 805 件
 Googleで「”init-connect”」を検索(日本語のみ) ⇒ 225 件
なんで日本語のページは「init」と「connect」の区切りがハイフンになってるほうが圧倒的に多いんでしょうね?MySQLのマニュアルではアンダーバーなのに・・・。ハイフンでも普通に動作するんですかね。

と、ちょっと話がそれましたが、
上記2通りの方法でもダメな場合はバージョンアップを検討しちゃいましょう。

■3.MySQL v4.1.0~4.1.1 の場合
このバージョンだとinit_connectオプションがサポートされていません。
なので、以下の設定をした上でプログラムから「SET NAMES」文をぶち込む方法しかないと思われます。

[mysqld]
default-character-set=ujis
[mysql]
default-character-set=ujis
[mysqldump]
default-character-set=ujis

っていうか、こんな古いバージョンのは使わないようにしちゃいましょう!

■3.MySQL v4.0系の場合
4.0系の場合は以下を設定しておけばそうそう文字化けないはずです。

[mysqld]
default-character-set=ujis
[mysql]
default-character-set=ujis
[mysqldump]
default-character-set=ujis

以上、試行錯誤終わり。

なお、今回はすべて文字コードにujisを設定していますが、MySQL v5.0.3以降を使える環境であればeucjpmsを使ったほうがいいかもしれませんね。
ujisだと先日も文字化けで苦戦したIBM拡張文字がサポートされてないかもしれません。
検証してないのでワカランですがそのうち試してみたいと思います。

もしくは、UTF-8を選択するのも良いかもしれません。

Recently


Categories


Archives