今日は会社に行ってきた。

で、“MySQLの文字コードの取り扱い”で躓いた。

■phpMyAdminの設定
MySQL の文字セット: UTF-8 Unicode (utf8)

■php.iniの設定
mbstring.internal_encoding = utf-8
mbstring.http_output = utf-8

■phpファイル(というかhtml)の文字コード
当然、
<?xml version="1.0" encoding="utf-8"?>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

として、utf-8(BOMナシ)で記述。

で、phpのコードは以下の通り。

$conn = mysql_connect($db['host'],$db['user'],$db['pass']);
mysql_select_db ($db['dbname']);
$tblname = $db['tblname'];
$sql= "SELECT * FROM {$db['dbname']}.{$tblname} WHERE `id`='{$id}'";
$res = mysql_query($sql,$conn);
$row = mysql_fetch_assoc($res);
print $row['name'];

これで出力された値は、

????????

なんでじゃあ~~~!!!!

全部同じ文字コードに統一していたら、大丈夫だと思っていた。

実際、2年前までのEUC-JPでの運用時には問題なかった。

全っ然分からん、、、

で、素直なボクは(ボクよりphpやらMySQLに精通している)会社の人に聞いて解決した。

結論としては、mysql_connectの直後に
mysql_set_charset('utf8');
と、明示的に言語指定しなければならない。

この指定をしていないと、どうやらMySQLからphpにデータが渡される際に、自動的に“latin1”でエンコーディングされてるらしい(と、先輩に教わった)。

実は、実際に教えてもらったのは、
mysql_query("SET NAMES 'utf8'");
だったのだが、家に帰ってからググってみたところあまり良くないということがわかった。

PHP manual
http://www.php.net/manual/ja/function.mysql-set-charset.php

注意:

文字セットを変更するにはこの方法を使うことを推奨します。 mysql_query() で SET NAMES .. を実行する方法はお勧めできません。

SET NAMESは禁止
http://blog.ohgaki.net/set_namesa_mcb_asc

MySQLには文字エンコーディングを変更する「SET NAMES」SQL文が用意されています。(PostgreSQLも同様のSQL文、SET CLIENT_ENCODINGがあります)この機能はSQLコンソールからは使ってよい機能ですが、アプリケーションからは使ってはならない機能です。SQLインジェクションに脆弱になる場合があります。

よくよく読んでみたら、特にSJISの場合が危ないらしく、EUC-JPやutf-8はあまり問題ないらしい。しかしまあ、“君子、危うきに近寄らず”ですな。

んもう、日本語ってめんどくさっ。(英語圏以外ではみんな同じような苦労に悩まされているんだろうけど。)

もうひとつ、大事なこと。

MySQL関係では“utf-8”は通じない。“utf8”でないとダメ。

んもう、めんどくさっ。

最後に、何故以前はmysql_set_charsetをしなくても問題なかったのかが気になったので、ついでに調べてみた。

PHP5+MySQL5でのEUC-JP運用
http://ex-potion.com/cgi/kakurediary/?p=367

どうやらMySQL4.1以降からデータベースへの入力において言語変換を行うようになったことが理由なようです。

それ以前はDB自体の文字コードを設定していれば問題なかったのですが、今のバージョンではクライアント、DB自体、テーブルなどとそれぞれ文字コートが変わってきたりします。

DB自体はEUC-JPだったりutf-8だったりと好きな文字コードで作成できるのですが、実際にDB自体に格納される時点では、EUC-JP→latin1に変換されているということらしいのです。

つまり入力やら出力やらは自分が決めた文字コードでやりとりできるのに、DBの内部で更に変換が行われていると言うこと。

ここの自動変換機能が悪さをしているようです。

どうやらその内部的なデフォルトの文字コードがlatin-1ということみたいです。

くぅー、つまり“EUC-JPだから問題なかった”のではなく、単に“2年前に使用していたMySQLのバージョンが古かったから問題なかった”のかー、、、

スッキリしたので、寝ます。