Zend Framework+MySQLの文字化け対策
PHP5 + Zend Framework 1.9.2 + MySQL5 で、DBからデータを取得したときに文字化けするのを防ぐ方法について。
以下のように「set names utf8」を先に発行しておけば文字化けは防げるが、汎用的な Zend_Db を使っている以上、やはり MySQL 特有のコマンドは使いたくないしSQLインジェクションを引き起こす可能性があります。(参考 SET NAMESは禁止:http://blog.ohgaki.net/set_namesa_mcb_asc)
$db = Zend_Db::factory('Pdo_Mysql', array( 'host' => 'xxx.xxx.xxx.xxx', 'username' => 'xxx', 'password' => 'xxx', 'dbname' => 'xxx' )); $db->query("set names utf8");
そこで調べてみると、factory() のパラメータに charset を指定できることが判明。以下のようにすると、文字化けを防ぐことができました。
$db = Zend_Db::factory('Pdo_Mysql', array( 'host' => 'xxx.xxx.xxx.xxx', 'username' => 'xxx', 'password' => 'xxx', 'dbname' => 'xxx', 'charset' => 'utf8' ));
これでよしよし・・・と思ったのですが、念のため Zend Framework のソースコード(Zend/Db/Adapter/Pdo/Mysql.php)を見てみると、「set names xxx」を使っているじゃないですか! PDO の driver_options パラメータに「set names xxx」を渡していました。SQLインジェクションは大丈夫なのでしょうか・・・?
以下がソースコードの一部引用です。
protected function _connect() { if ($this->_connection) { return; } if (!empty($this->_config['charset'])) { $initCommand = "SET NAMES '" . $this->_config['charset'] . "'"; $this->_config['driver_options'][1002] = $initCommand; // 1002 = PDO::MYSQL_ATTR_INIT_COMMAND } parent::_connect(); }
ちょっと不安なので、Pdo_Mysql ではなく Mysqli を使うことに。これで文字化けせずにうまく動きました。
$db = Zend_Db::factory('Mysqli', array( 'host' => 'xxx.xxx.xxx.xxx', 'username' => 'xxx', 'password' => 'xxx', 'dbname' => 'xxx', 'charset' => 'utf8' ));
Mysqli の ソースコード(Zend/Db/Adapter/Mysqli.php)を見ると、mysqli_set_charset() で文字コードをセットしていました。これを使えば、SQLインジェクションは大丈夫なようです。