2012年7月13日金曜日

ownCloud 4.0.4+MySQLで日本語ファイル名を扱うとクライアントアプリが落ちる現象を解決

現象のあらまし
タイトル通りなのだが、MySQLを使うようセットアップしたownCloudに対して、Windows版のクライアントアプリを利用して日本語(マルチバイト文字)を含むファイルを保存しようとすると、クライアントアプリがクラッシュしてしまう。
Figure.1 ownCloudアプリがクラッシュ

公式のバグレポートを見ていたところ、
ownCloud ~ [OPEN] oc-811 - ownCloud Desktop Client crashes when filename has non ASCII characters
を発見した。ここに
I worked around the problem by disabling the file share app in web settings.
という記述があるので、試しに"Share Files"を無効化してみたところ、確かにクライアントアプリはクラッシュしなくなった。
Figure.2 "Share Files"を無効化するとクライアントアプリは落ちなくなる
しかし、これでは複数アカウントでファイルを共有できず、不便極まりないので、原因を追求することにした。
原因はテーブルの文字コード
まず、Apacheのエラーログを確認。
[Tue Jul 10 10:35:03 2012] [error] [client **.**.***.***]PHP Fat
al error:  Uncaught exception 'PDOException' with message 'SQLST
ATE[HY000]: General error: 1267 Illegal mixof collations (latin1
_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operat
ion '='' in /var/www/owncloud/lib/db.php:598\nStack trace:\n#0 /
var/www/owncloud/lib/db.php(598): PDOStatement->execute(Array)\n
#1 /var/www/owncloud/apps/files_sharing/lib_share.php(229): PDOS
tatementWrapper->execute(Array)\n#2 /var/www/owncloud/apps/files
_sharing/lib_share.php(470): OC_Share::getMySharedItem('/dsp7411
8/files...')\n#3 [internal function]: OC_Share::updateItem(Array
)\n#4 /var/www/owncloud/lib/hook.php(62): call_user_func(Array, 
Array)\n#5 /var/www/owncloud/lib/filecache.php(685): OC_Hook::em
it('OC_Filesystem', 'post_write', Array)\n#6 /var/www/owncloud/l
ib/filecache.php(260): OC_FileCache::updateFolder('/TestProject'
, '')\n#7 /var/www/owncloud/lib/files.php(39): OC_FileCache::get
FolderContent('/TestProject', '', '')\n#8 /var/www/owncloud/apps
/files/index.php(46): OC_Files::getDirectoryContent('/TestProjec
t')\n#9 /var/www/ownc in /var/www/owncloud/lib/db.php on line 59
8, referer: http://servername/?app=files

文字コードのアンマッチ風のメッセージであり、DBの文字コードが怪しい。
なお、DBのデフォルト文字コードはUTF-8に設定してある。
(snip)
[mysqld]
default-character-set = utf8
(snip)
※私の環境はMySQL 5.0である。5.5以降はcharacter-set-serverである。

エラーログにあるlib_share.phpの229行目付近を見てみる。
        $query = OCP\DB::prepare("SELECT uid_shared_with, permissions FROM *PREFIX*sharing WHERE source = ? AND uid_owner = ?");
        $result = $query->execute(array($source, OCP\USER::getUser()))->fetchAll();

*PREFIX*はoc_にしているので、oc_sharingテーブルを調べてみる。
$ mysql -u owncloud -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 330
Server version: 5.0.77 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> use owncloud
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
mysql> show create table oc_sharing;
+------------+--------------------------------------+
| Table      | Create Table                         |
+------------+--------------------------------------+
| oc_sharing | CREATE TABLE `oc_sharing`
 `uid_owner` varchar(64) NOT NULL default '',
  `uid_shared_with` varchar(64) NOT NULL default '',
  `source` varchar(128) NOT NULL default '',
  `target` varchar(128) NOT NULL default '',
  `permissions` tinyint(4) NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1              |
+------------+--------------------------------------+
なんと文字コードがlatin1になっている。
これが原因に違いない。早速UTF-8に直す。
mysql> alter table oc_sharing convert to character set utf8;
Query OK, 1 row affected (0.09 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> show create table oc_sharing;
+------------+--------------------------------------+
| Table      | Create Table                         |
+------------+--------------------------------------+
| oc_sharing | CREATE TABLE `oc_sharing`
 `uid_owner` varchar(64) NOT NULL default '',
  `uid_shared_with` varchar(64) NOT NULL default '',
  `source` varchar(128) NOT NULL default '',
  `target` varchar(128) NOT NULL default '',
  `permissions` tinyint(4) NOT NULL default '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+------------+--------------------------------------+
この状況で"Share Files"を有効に戻したところ、クライアントアプリはクラッシュしなくなった。めでたしめでたし!

他のテーブルはどうか。
他のテーブルも気になったので、調べてみた。
4.0.4のデフォルトインストール状態で作成されたテーブルは、下記の通り。
mysql> show tables;
+----------------------------+
| Tables_in_owncloud         |
+----------------------------+
| oc_appconfig               |
| oc_calendar_calendars      |
| oc_calendar_objects        |
| oc_calendar_share_calendar |
| oc_calendar_share_event    |
| oc_contacts_addressbooks   |
| oc_contacts_cards          |
| oc_fscache                 |
| oc_gallery_sharing         |
| oc_group_user              |
| oc_groups                  |
| oc_locks                   |
| oc_log                     |
| oc_media_albums            |
| oc_media_artists           |
| oc_media_sessions          |
| oc_media_songs             |
| oc_media_users             |
| oc_pictures_images_cache   |
| oc_preferences             |
| oc_properties              |
| oc_sharing                 |
| oc_users                   |
+----------------------------+
23 rows in set (0.00 sec)

このうち、文字コードがlatin1になっていたテーブルは以下のとおり。
oc_gallery_sharing oc_media_albums
oc_media_artists oc_media_sessions
oc_media_songs oc_media_users
oc_pictures_images_cache oc_sharing
これらのテーブルも、utf8に変えておく必要がある。

0 コメント:

コメントを投稿