Contact Form DB のテーブルについて
Contact Form 7 というアンケートフォームのプラグインは、メールを送信するだけなので、DBへデータを格納するようにするプラグインが Contact Form DB です。
両プラグインをWordPressに入れることで、手軽に入力フォームの内容をDBに格納できます。
しかし、この Contact Form DB で作られるテーブルが曲者でした。
WordPressの管理画面から Contact Form DB の管理画面を表示すると、入力フォームから入力されたデータの一覧を表示でき、それを見るとあたかも一つのフォームからの投稿が一つのレコードとして格納されているように見えます。 しかし、実際のテーブルには、入力フォームの input 一つ一つがそれぞれ1レコードとして登録されます。
入力項目が3つのフォームだと、1回の投稿で3つレコードが登録されるわけで、それぞれのレコードには、それぞれの入力項目の内容のみが、投稿時間と入力フォーム名と入力項目名をキーに記録されるのです。
ちなみにテーブル構造は下記の通り。
mysql> DESC wp_cf7dbplugin_submits;
+-------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+-------+
| submit_time | decimal(16,4) | NO | MUL | NULL | |
| form_name | varchar(127) | YES | MUL | NULL | |
| field_name | varchar(127) | YES | MUL | NULL | |
| field_value | longtext | YES | | NULL | |
| field_order | int(11) | YES | | NULL | |
| file | longblob | YES | | NULL | |
+-------------+---------------+------+-----+---------+-------+
6 rows in set (0.03 sec)
インデックス一覧は下記の通り。
mysql> SHOW INDEX FROM wp_cf7dbplugin_submits;
+------------------------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| wp_cf7dbplugin_submits | 1 | submit_time_idx | 1 | submit_time | A | 2 | NULL | NULL | | BTREE | | |
| wp_cf7dbplugin_submits | 1 | form_name_idx | 1 | form_name | A | 1 | NULL | NULL | YES | BTREE | | |
| wp_cf7dbplugin_submits | 1 | field_name_idx | 1 | field_name | A | 26 | NULL | NULL | YES | BTREE | | |
+------------------------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
ちなみに、時間が同じで投稿内容が違うレコードを insert してみたところ、登録できてしまい、その状態で管理画面からデータを参照すると、時間が同じ2つの投稿がごちゃごちゃに一つのレコードとして表示されてしまいます。 (まぁ、当然ですが)
同じ時間になるのはミリ秒単位で同一の場合なので、そんなに気にしないWebサイトなら問題無いかもしれないですが、特に個人情報を扱うようなWebサイトでは気にするべきでしょう。
で、対応策としては、テーブル構造を変えてしまいます。
まずインデックス削除。
ALTER TABLE wp_cf7dbplugin_submits DROP INDEX submit_time_idx;
ALTER TABLE wp_cf7dbplugin_submits DROP INDEX form_name_idx;
ALTER TABLE wp_cf7dbplugin_submits DROP INDEX field_name_idx;
続いて、複合キーで設定し直します。
alter table wp_cf7dbplugin_submits add constraint primary key(submit_time, form_name, field_name);
結果はこんな感じ。
mysql> SHOW INDEX FROM wp_cf7dbplugin_submits;
+------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name |Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| wp_cf7dbplugin_submits | 0 | PRIMARY | 1 | submit_time |A | 173 | NULL | NULL | | BTREE | | |
| wp_cf7dbplugin_submits | 0 | PRIMARY | 2 | form_name |A | 173 | NULL | NULL | | BTREE | | |
| wp_cf7dbplugin_submits | 0 | PRIMARY | 3 | field_name |A | 1038 | NULL | NULL | | BTREE | | |
+------------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
ちなみに、MySQLのバージョンによっては複合キーは設定できないようですが、最近のものはできます。
これで、仮に完全同一タイミングで投稿があっても、どちらか片方は登録されませんので、データの整合性は保てます。