PHPとMySQLと文字コードと

 最近の流れとして、文字コードと言えばUTF8って感じが強い(携帯などではSJISもあるけど)
 しかしながら、CentOSや海外から拾ったコンパイル済みPHPの従来型MySQL関数って、コネクト時のクライアントエンコーディングがlatin1になっている。
 この値は、mbstringとか色々変えても変わらず、自前でビルドしないとダメっぽい。
 他方、MySQLサーバではmy.cnfに

[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci

等と入れてやるとUTF8で回るし、個別にデータベースやテーブルを作るときに指定してやることも出来る(現在のMySQLではdefault-character-setは推奨外) コマンドラインのmysqlもmy.cnfに

[mysql]
default-character-set=utf8

とかすれば、UTF8で繋がる。
 それでも、PHPクライアントでmysql_connectして、mysql_client_encodingで引っ張るとlatin1になるし、SHOW VARIABLESクエリの戻り値もクライアントやリザルトはlatin1になってしまう。
 このため、最近のMySQLとPHP(5.2.3以降)の組み合わせではmysql_set_charsetと言う関数を使ってクライアントのエンコーディングを設定してやることが出来る(古いバージョンでは、SET NAMESクエリを発行して変更できるが、サニタイズ関連の動作が期待と異なる事になったり、タイムアウトしたDB接続を自動再接続したときにエンコーディングが元に戻る様だ)
 しかし、実際の所は、このあたりの設定をせずともPHPから処理する限りは、UTF8の文字列を普通にDBに格納して取得も出来てしまう。 これは、エンコーディング設定が同じなら同じ方法で文字列を化けさせているから、化けた文字列を格納しても、取り出し時に逆処理で戻してしまい、外見上は問題なく動作してしまっているのだ。
これをデータベースマネージャなどでテーブル表示すると化け化けの文字列であるから、管理コマンドや、別のアプリケーションからDBを参照したときに問題が起きるし、検索処理や関数などで予想外の動作をする可能性もあるので、エンコーディング設定はしっかり行っておかなければならない。

 my.cnfの[mysqld]でskip-character-set-client-handshakeを設定してやると、サーバの標準キャラクタセットをクライアント値と同期しないので、mbstring.internal_encodingをutf8にしたPHPとutf8設定のMySQLの組み合わせでutf8で格納されて、データベースマネージャなどでもちゃんと表示できるので、この方法を示しているページもあるが、この状態でもmysql_client_encodingはlatin1で、SHOW VARIABLES結果はutf8設定というおかしな状態になるので、これも予想外の動作をする可能性があるわけで、正しく動作させたければ、毎回mysql_set_charsetを実行するか、ソースからPHPをビルドして、標準エンコーディングをutf8にするなどした方が良いと思う。
 また、skip-character-set-client-handshake設定してしまうと、[mysql]のdefault-character-setと整合を取らなくなるので注意が必要(例えば、mysqlをdefault-character-set=ujisで動かしてると、mysqlコマンドで接続した段階ではクライアントがujisで、サーバはutf8クライアントと認識しているのでキャラクタセットの齟齬で文字化けが生じる)

(465)


カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP   パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です