プログラミング言語や環境設定を中心としたパソコン関連の技術メモです。
主にシステム開発中に調べたことをメモしています。TIPS的な位置付けで、気が向いたときにちまちま更新していきます。
FuelPHP1.7、文字コードがSJISのDB(MySQL)を扱う時の注意点
※留意事項
 「文字エンコーディング」と記載するのが本来正しいのでしょうが、
 めんどっちーので「文字コード」の表現で書いていきます。
 こだわり派な人は適当に読み替えてください。

結論から書けば

1.MySQLのクライアント側文字コードを「sjis」にする。
 ※configのdb.phpに「'charset' => 'sjis',」を追加する

2.取得したデータはSJISで返ってくるので、必要に応じてUTF-8にコンバートする

3.データをinsert/updateする際は、値を自前でSJIS-winに変換してから投入する

が必要です。
要は自前で文字コードを管理しろってことですね。

一見するとですね。
特に気にしなくても大丈夫なように見えるのです。
設定をいじらないでSJISのテーブルからデータを引っ張ってきてもUTF-8になっているし、
特に変換しないでデータを突っ込んでも文字化けしないでSJISで保存されます。

ところがどっこい、これが罠です(--)b

なんで一見問題が無いように見えるかと言うと、最初から
MySQLのクライアント側文字コードがutf8で設定されているからです。

具体的には

fuel\app\config\db.php
fuel\app\config\development\db.php
fuel\app\config\production\db.php
fuel\app\config\staging\db.php
fuel\core\config\db.php

のどこかで指定している「'charset' => 'utf-8',」がMySQLのクライアント側文字コードです。
「ん?特に指定していないけど?」という場合は

fuel\core\config\db.php

の中の値が使われていますよ。

この「db.php」内で指定された「charset」が使われるのですが……えっとですね。
まず

fuel\core\classes\database\connection.php

の「instance()」メソッド内の69行目辺り

if ($config === null)
{
    // Load the configuration for this database
    $config = \Config::get("db.{$name}");
}

で設定ファイルからメモリ上に設定内容が展開されます。
77行目近辺の

// Set the driver class name
$driver = '\\Database_' . ucfirst($config['type']) . '_Connection';

// Create the database connection instance
new $driver($name, $config);



\\Database_MySQL_Connection
\\Database_MySQLi_Connection
\\Database_PDO_Connection

のどれかのインスタンスをnewしています。
ちなみに、それぞれのクラスは

fuel\core\classes\database\mysql\connection.php
fuel\core\classes\database\mysqli\connection.php
fuel\core\classes\database\pdo\connection.php

に格納されていますよ。

その後でDBに接続しているわけですが

\\Database_PDO_Connection(fuel\core\classes\database\pdo\connection.php)

を例に挙げると、この中の「connect()」メソッド106行目近辺で

if ( ! empty($this->_config['charset']))
{
    // Set Charset for SQL Server connection
    if (strtolower($this->driver_name()) == 'sqlsrv')
    {
        $this->_connection->setAttribute(\PDO::SQLSRV_ATTR_ENCODING, \PDO::SQLSRV_ENCODING_SYSTEM);
    }
    else
    {
        // Set the character set
        $this->set_charset($this->_config['charset']);
    }
}

と「set_charset()」メソッドを呼び出しています。
「set_charset()」の中身は

public function set_charset($charset)
{
    // Make sure the database is connected
    $this->_connection or $this->connect();

    // Execute a raw SET NAMES query
    $this->_connection->exec('SET NAMES '.$this->quote($charset));
}

です。中で「SET NAMES」していますね。
「\\Database_MySQL_Connection」「\\Database_MySQLi_Connection」も基本的には同じ流れです。

このような流れでMySQLのクライアント側文字コードがUTF-8になっているのですが、
慣れている方はもう分かりましたよね?

髙(はしご高)や﨑(立つ崎)等の特殊文字が化けます。

きちんと調べたわけではないので推測ですが、
クライアント側文字コード(UTF-8)←→DBの文字コード(SJIS)の変換は
サーバ側のMySQLさんが勝手に頑張ってやってくれているのでしょう。
だって、PHP側から送り出してるのはUTF-8ですからね。
UTF-8←→SJISの変換はMySQLさんの方でやってくれているはずです。

この変換が特殊文字に対して上手くいってないんだろーなーと。
残念ながら力及ばずって感じですね。特殊文字は「?」になっちゃいます。

と言う訳で、FuelPHPでSJISのDBを扱う際はPHP側で自前でUTF-8←→SJISの変換を行ってください
MySQLさん任せにすると後から痛い目に遭いかねません。

別にFuelPHPに限った話ではないのですが、DBからPHPまでの文字コードはすべて合わせておいて、
変換が必要だったらPHPのコード内で行うのが無難でしょうね。
あと状況が許すのであれば、そもそもSJISを使わない(UTF-8にしておく)のが最善だと思います。

なんか長々と書いちゃったけど、取り合えず完了\(--)/
スポンサーリンク
 
このエントリーをはてなブックマークに追加 

category:FuelPHP  thema:システム開発 - genre:コンピュータ  Posted by ササキマコト