[jQuery]選択されたcheckboxをハイライトするスクリプト WebDAV+Basic認証で認証されない
2月 25

今回も結構レアなケースだろうから、あんまり役には立たないかもしれないけど、小規模・低予算のサイトの場合、案外ありそうな気もするのと、備忘録として。

前書き

ウェブサイトを構築する場合、最近はほとんどUTFを使う場合が多い。jQueryその他マッシュアップAPI、OSSなどを用いる場合、UTFのほうが便利。(むしろUTF前提で作られてるものが多い)

新規に構築する場合で、MySQL4.1~であれば、何も考えずにHTML,PHP側もUTFにしておけば混乱は少ない。

しかし、MySQL3.xの頃から稼働しているサイトの場合、DBやHTML,PHPがEUCであることも多く、コレをすべてUTFに移行するのは、恐ろしく手間が掛かる。(ハイリスク・ローリターン)

しかし、MySQL3.0,4.0系から、4.1~へアップグレードすると、ほぼ間違いなく文字化けするようになり、この文字化けが回避できず、せっかくMySQLが複数エンコーディングをサポートしているにも関わらず、サーバ側・クライアント側をEUCガチガチに固定して運用してしまうケースも多々あると思う。(恥ずかしながら僕がそうです)

だがそれでは前述のAjaxや最新のOSS(WordPressとか)などUTF8を前提としている機能が使えないというデメリットがある。

1つのホスト内でのVirtualHostで、あるサイトはEUCを、あるサイトはUTF8を使うようにMySQLで設定できないか、というのが今回のテーマである。

テスト環境

下記のようなVirtualHostがあるとする。

host A) eucdb.example.com – 127.0.0.1
host B) utfdb.example.com – 127.0.0.1

eucdb.example.comは、既に稼働しているサイトであり、MySQL4.0系を使っている。
utfdb.example.comは新しく設置したサイトで、今後、UTF8にて運用する予定。

つまり、1つのMySQL[mysqld]にて、EUC,UTF8のデータ利用したい、という訳である。

今回テストしたOSは、OS X10.4だけれど、基本的にLinuxでもWindowsでも関係なく、MySQLとPHP側の設定で解決できます。

my.cnfファイルの記述

[mysqld]
default-characterset=utf8
character-set-server=utf8

my.cnfには、とりあえず”utf8″を指定しておく。
skip-character-set-client-handshakeや、init-connectは使わない。[mysql]や[client]に対しての明示的なエンコーディングの指定は行わない。

データベースの作成

■eucdb.example.comで使うデータベースの生成

CREATE DATABASE データベース名 DEFAULT CHARACTER SET eucjpms ;

※MySQL 5以降の場合、ujisではなく、eucjpmsを使うのが良いらしい。MySQL 4.1~の場合は、素直にujisを指定しよう。

■utfdb.example.comで使うデータベースの生成

CREATE DATABASE データベース名 DEFAULT CHARACTER SET utf8;
[/codecode]

<h3>インポート</h3>
[text]
% mysql -uXXXXX -pXXXXX テーブル名 --default-character-set=eucjpms < インポートするファイル

MySQL[mysqld]自体は、utf8にしておいて、単純に、CREATE DATABASEするときと、そこにインポートする時に、ちゃんとdefault-character-setで、eucjpms(ujis)を指定すること。

ただし、これだけでは、PHPからDBにアクセスしてデータを取得しても、utf8で返ってきてしまう。なぜなら、mysqlのクライアントに対して、変換の指示をしていないからutf8になる。CREATE DATABASEで指定したエンコーディングを自動的に返せばいいのにね。

※my.cnfの設定により、eucjpms(ujic)固定で値を返すことも可能。ただし、my.cnfで設定してしまうと、今度はutf8を扱えなくなってしまう。

PHP側の処理

CREATE DATABASEでeucjpmsを指定し、合わせてちゃんとimportしてるにも関わらず、PHPからアクセスすると、utfでデータが返ってくる。なぜそうなるのか100%理解してるわけではないが、my.cnfにクライアント側のエンコーディングを指定してないため、デフォルトでもあるutfに勝手に変換されてるのだと思う。

最初からサーバ側とクライアント側が同一エンコーディングであればこの問題は発生しないが、何度も書いているように、euc,utf8のデータベースを使いたいから、その設定は使えない。

そこで、PHP側からはMySQLに対し、明示的にエンコーディングを指示してやることで、指定したエンコーディングでデータを取得できる。
そのもっとも簡単な方法が、’set names XXXX’である。XXXの部分はeucjpmsやujisを入れる。
しかし、set namesにはさまざまな問題があり、PHP 5.2.3~かつ、MySQL 5.0.7 移行であれば、mysql_set_charsetを使うのが推奨されている。

PHP 4.xを使ってる場合は、この際5系に切り替えた方がいいでしょう。

ちなみに、僕はDB_DataObjectをよく使っていて(PEARだし、フレームワークに依存しないし、遅いけど便利と思うんだけどな)、テスト用のサーバはPHPが4.xのため、set namesを使わざるを得ない。その場合、DB_DataObjectの初期化の直後に、

$dbinit = new DB_DataObject;
$dbinit->query('set names eucjpms');
:

という感じで、factoryせずにDB_DataObjectクラスから1度だけqueryで実行してやればOKです。

いずれ、PHP用のActiveRecordとか、Propelに移行しないとダメとは思うけど、既に手に馴染んでるからなぁ…

まとめ

perlだと、

use DBI;
my $dbh = DBI->connect(
    'DBI:mysql:database=sandbox;host=localhost;mysql_read_default_file=/etc/mysql/my.cnf',
    qw/id password/,
);

という感じで、コネクト時にcnfファイルを指定できるらしい。これは便利。

phpでも、mysqli関数を使えばできるらしいが、これはこれでまた面倒の種が増える…。

正直、MySQL4.1からのエンコーディング周りの処理には、いい印象がなく、文字化けにウンザリしていたのだが、腰を据えてやってみると、案外簡単であった。

サーバを移行しようにも、MySQL3.x → MySQL 4.1~5での文字化けが怖くてできない…けど、EUC固定もできないし!という方はこのエントリが参考になれば幸いです。

参考リンク

SET NAMESは禁止
PHPからSET NAMESを使わない方が良い理由と対策まとめ | twk @ ふらっと

MySQL5開拓団 - 日本語処理の鉄則 / KLab株式会社 ← 重要!
mysql_set_charset関数を使ってみる – PHPプロ!TIPS+
へぼへぼCTO日記 – libmysqlclientを使うプログラムはset namesをutf8であっても使ってはいけない

Popularity: 15% [?]

written by ANN

add to hatena hatena.comment (2) add to del.icio.us (0) add to livedoor.clip (0) add to Yahoo!Bookmark (1) Total: 3

Leave a Reply