WordPressプラグインを改造していてMySQLの文字コードにはまる

2015年7月12日WordPress,パソコン・インターネット

日本語化されていない、WordPressプラグインを、日本語化して使おうとしています。今回、MySQLのデータベースのテーブルの列の文字コードの設定が、utf8ではなくlatin1になっていて、かなりはまりました。

VCCW環境を使って作業できるので、とても楽です。

国際化にきちんと対応されたプラグインだと、potファイルを元にpo/moファイルを作るだけなので、簡単です。ところがこのプラグインは、
potファイルも無いし、国際化のための文字列の切り出しも中途半端です。かなり修正しました。potファイルを作るのは、次の方法でできます。

VCCW環境内では、xgettextがあらかじめインストールされているので簡単です。

[vagrant@vccw ~]$ cd /var/www/wordpress/wp-content/plugins/pluginname/
[vagrant@vccw ~]$ xgettext --language=php --keyword=__ --keyword=_e --keyword=_n:1,2 --keyword=_x -o languages/pluginname.pot *.php */*.php

こうやって作成した、日本語化のためのローカライズファイル(po/mo)を読み込むための定番は、次の通りです。最初この記述をどこに入れれば良いかで、かなり悩みました。試行錯誤の上、プラグインの先頭に入れるだけでした。当たり前ですね。

	$path = dirname(plugin_basename( __FILE__ )) . '/languages';
	load_plugin_textdomain( 'pluginname', false, $path);

このやり方は、私も持っている次の本に載っています。

[amazonjs asin="B00M939Y0I" locale="JP"]

この設定の末、日本語化の道筋が見えました。

このプラグインで、Webから取得したデータをキャッシュしておく機能があります。キャッシュされてい無い状態では表示が文字化けしないのですが、キャッシュされた2回目以降のアクセスでは、文字化けします。

プラグイン内部で、var_dump()して、どこで文字化けするかを探しました。その結果、取得したデータを、MySQLに保存するところが怪しいことがわかりました。

必死に検索して、次の記事がヒントになりました。

VCCWのWordPressデータベースは、次の設定になっています。

% vagrant ssh
Last login: Sat Jul 11 08:16:16 2015 from 10.0.2.2
                   ___           ___           ___
      ___         /  /\         /  /\         /__/\
     /__/\       /  /:/        /  /:/        _\_ \:\
     \  \:\     /  /:/        /  /:/        /__/\ \:\
      \  \:\   /  /:/  ___   /  /:/  ___   _\_ \:\ \:\
  ___  \__\:\ /__/:/  /  /\ /__/:/  /  /\ /__/\ \:\ \:\
 /__/\ |  |:| \  \:\ /  /:/ \  \:\ /  /:/ \  \:\ \:\/:/
 \  \:\|  |:|  \  \:\  /:/   \  \:\  /:/   \  \:\ \::/
  \  \:\__|:|   \  \:\/:/     \  \:\/:/     \  \:\/:/
   \__\::::/     \  \::/       \  \::/       \  \::/
       ~~~~       \__\/         \__\/         \__\/

http://vccw.cc/

Initial code by Takayuki Miyauchi.
https://github.com/miya0001
[vagrant@vccw ~]$ egrep 'DB_' /var/www/wordpress/wp-config.php 
define('DB_NAME', 'wordpress');
define('DB_USER', 'wordpress');
define('DB_PASSWORD', 'wordpress');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

直接、MySQLにつないで、データベースを確認します。

[vagrant@vccw wordpress]$ mysql -u wordpress -p 
Enter password: wordpress
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 604
Server version: 5.5.43-log MySQL Community Server (GPL) by Remi

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test               |
| wordpress          |
+--------------------+
3 rows in set (0.00 sec)

mysql> use wordpress
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

ちゃんと"wordpress"データベースがありました。直接、テーブルにデータを挿入します。まずは、ASCIIだけのデータを挿入します。

mysql> insert into wp_pluginname (URL, body, updated) values ("AAA", "AAA", NOW());
Query OK, 1 row affected (0.01 sec)

mysql> select * from wp_pluginname;
+----------+----------------------------------------+---------------------+--------+
| Cache_id | URL                                    | updated             | body   |
+----------+----------------------------------------+---------------------+--------+
|       10 | AAA                                    | 2015-07-11 08:23:34 | AAA    |
+----------+----------------------------------------+---------------------+--------+
1 rows in set (0.00 sec)

問題なく、挿入できました。次は、日本語を含んだデータを挿入します。

mysql> insert into wp_pluginname (URL, body, updated) values ("BBB", "BBBいいい", NOW());
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from wp_pluginname;
+----------+----------------------------------------+---------------------+--------+
| Cache_id | URL                                    | updated             | body   |
+----------+----------------------------------------+---------------------+--------+
|       10 | AAA                                    | 2015-07-11 08:23:34 | AAA    |
|       11 | BBB                                    | 2015-07-11 08:24:09 | BBB??? |
+----------+----------------------------------------+---------------------+--------+
2 rows in set (0.00 sec)

げげっ! 化けてる。WordPressの問題ではなく、MySQLのデータベースが何かおかしいです。設定されている文字コードを表示させてみます。

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)

mysql> show create table wp_pluginname;
+----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table          | Create Table                                                                                                                                                                                                                                                                                                                    |
+----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| wp_pluginname | CREATE TABLE `wp_pluginname` (
  `Cache_id` int(10) NOT NULL AUTO_INCREMENT,
  `URL` text NOT NULL,
  `updated` datetime DEFAULT NULL,
  `body` longtext CHARACTER SET latin1,
  PRIMARY KEY (`Cache_id`),
  UNIQUE KEY `URL` (`URL`(255)),
  KEY `Updated` (`updated`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 |
+----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

データベースそのものはutf8になっているけど、wp_pluginnameと言うテーブルの文字コードが"latin1″になっている! これが原因だ〜!! プラグインのコード内で、文字コードを設定する部分も発見できました。やはり、latin1に設定しています。

      $alterSQL = "ALTER TABLE `{$table}` CHANGE `body` `body` LONGTEXT CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL;";

文字コードを、utf8に変更します。

mysql> ALTER TABLE wp_pluginname CHANGE `body` `body` LONGTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table wp_pluginname;
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table          | Create Table                                                                                                                                                                                                                                                                                               |
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| wp_pluginname | CREATE TABLE `wp_pluginname` (
  `Cache_id` int(10) NOT NULL AUTO_INCREMENT,
  `URL` text NOT NULL,
  `updated` datetime DEFAULT NULL,
  `body` longtext,
  PRIMARY KEY (`Cache_id`),
  UNIQUE KEY `URL` (`URL`(255)),
  KEY `Updated` (`updated`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 |
+----------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

utf8になったっぽいです。データを挿入してみます。

mysql> insert into wp_pluginname (URL, body, updated) values ("CCC", "CCCううう", NOW());
Query OK, 1 row affected (0.00 sec)

mysql> select * from wp_pluginname;
+----------+----------------------------------------+---------------------+--------------+
| Cache_id | URL                                    | updated             | body         |
+----------+----------------------------------------+---------------------+--------------+
|       10 | AAA                                    | 2015-07-11 08:23:34 | AAA          |
|       11 | BBB                                    | 2015-07-11 08:24:09 | BBB???       |
|       12 | CCC                                    | 2015-07-11 08:33:49 | CCCううう    |
+----------+----------------------------------------+---------------------+--------------+
3 rows in set (0.00 sec)

やりました! ちゃんと、日本語が保存されています。この後、実際のプラグイン操作で、文字化けし無いことを確認しました。MySQLのデータベースに文字コードの設定があったのは知っていましたが、まさかテーブルの文字コードを個別に変更できるとは!! 正確には、テーブルよりもっと細かい、列のレベルで文字コードの設定ができます。

この問題を解決するまで、かなりの時間がかかりました。

Posted by お市のかた