サービスを運用する上で、ユーザー調査やログイン履歴のためにIPアドレスをログに出力したり、データベースに保管したいと思うことが多々あります。
MySQLにIPアドレスの履歴を保存するときは、特に何も考えなければ、出力されるIPアドレスをそのまま文字列としてvarchar型でデータベースに保存してしまえば問題ありません。しかし文字列で保存すると、IPアドレスでない形のデータも保存できる状態になってしまいます。
今回は、IPアドレスをMySQLに保存したいときに知っておくと良いかもしれないことを紹介します。なお、利用しているMySQLのバージョンは8.
文字列としてIPアドレスを保存する
文字列として保存する場合はvarchar型として保存することが多いでしょう。
mysql> CREATE TABLE ip_varchar (ip varchar(255));
Query OK, 0 rows affected (0.08 sec)
mysql> INSERT INTO ip_varchar VALUES('127.0.0.1'),('0.0.0.0'),('255.255.255.255');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM ip_varchar;
+-----------------+
| ip |
+-----------------+
| 127.0.0.1 |
| 0.0.0.0 |
| 255.255.255.255 |
+-----------------+
3 rows in set (0.00 sec)
このような形式で作成したデータは実際は文字列であり、たとえ文字数を15文字以内に制限をかけたとしても、IPアドレス形式以外のデータを挿入することができます。
mysql> INSERT INTO ip_varchar VALUES ('256.256.256.256'),('fukamachi');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM ip_varchar;
+-----------------+
| ip |
+-----------------+
| 127.0.0.1 |
| 0.0.0.0 |
| 255.255.255.255 |
| 256.256.256.256 |
| fukamachi |
+-----------------+
5 rows in set (0.00 sec)
IPアドレスのみを登録できるように制限をかけるにはどうすればよいでしょうか?
実はMySQLにはバージョン5.
mysql> SELECT ip, is_ipv4(ip) FROM ip_varchar; +-----------------+-------------+ | ip | is_ipv4(ip) | +-----------------+-------------+ | 127.0.0.1 | 1 | | 0.0.0.0 | 1 | | 255.255.255.255 | 1 | | 256.256.256.256 | 0 | | fukamachi | 0 | +-----------------+-------------+ 5 rows in set (0.01 sec)
これを利用することで、対象のデータがIPアドレスかどうかを確認することができます。さらに、MySQL 8.
mysql> CREATE TABLE ip_varchar (ip varchar(255) CHECK(is_ipv4(ip)));
Query OK, 0 rows affected (0.02 sec)
mysql> INSERT INTO ip_varchar VALUES('127.0.0.1'),('0.0.0.0'),('255.255.255.255');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> INSERT INTO ip_varchar VALUES ('256.256.256.256'),('fukamachi');
ERROR 3819 (HY000): Check constraint 'ip_varchar_chk_1' is violated.
不正な文字列は制限したい場合には有用な手段となります。
INET_ATONを利用して数字としてIPアドレスを保存する
MySQLにはINET_
mysql> SELECT inet_aton('127.0.0.1'), inet_aton('0.0.0.0'), inet_aton('255.255.255.255'), inet_aton('255.255.255.256');
+------------------------+----------------------+------------------------------+------------------------------+
| inet_aton('127.0.0.1') | inet_aton('0.0.0.0') | inet_aton('255.255.255.255') | inet_aton('255.255.255.256') |
+------------------------+----------------------+------------------------------+------------------------------+
| 2130706433 | 0 | 4294967295 | NULL |
+------------------------+----------------------+------------------------------+------------------------------+
1 row in set, 1 warning (0.01 sec)
この関数を利用することで、IPアドレスを数値型として保存することができます。
ただし、これを利用する場合はinet_
mysql> SELECT inet_aton('127.0.0.1'), inet_aton('127.1'), inet_aton('127.'), inet_aton('127');
+------------------------+--------------------+-------------------+------------------+
| inet_aton('127.0.0.1') | inet_aton('127.1') | inet_aton('127.') | inet_aton('127') |
+------------------------+--------------------+-------------------+------------------+
| 2130706433 | 2130706433 | NULL | 127 |
+------------------------+--------------------+-------------------+------------------+
1 row in set, 1 warning (0.00 sec)
数値で保存したIPアドレスをINET_NTOAを使って参照する
INET_
mysql> SELECT inet_ntoa(2130706433), inet_ntoa(0), inet_ntoa(4294967295), inet_ntoa(NULL),inet_ntoa('2130706433'), inet_ntoa('a');
+-----------------------+--------------+-----------------------+-----------------+-------------------------+----------------+
| inet_ntoa(2130706433) | inet_ntoa(0) | inet_ntoa(4294967295) | inet_ntoa(NULL) | inet_ntoa('2130706433') | inet_ntoa('a') |
+-----------------------+--------------+-----------------------+-----------------+-------------------------+----------------+
| 127.0.0.1 | 0.0.0.0 | 255.255.255.255 | NULL | 127.0.0.1 | 0.0.0.0 |
+-----------------------+--------------+-----------------------+-----------------+-------------------------+----------------+
1 row in set, 1 warning (0.00 sec)
INET_
文字列で保存するか、数値型で保存するか
IPアドレスを数値型で保存するメリットとしては、データ量が少ないことにあります。通常文字列で保存した場合は最大16バイトですが、数値型の場合4バイトで保存することが可能です。データ量が多くならないような場合では文字列でも良いですが、履歴を溜め込むようなテーブルであれば、数値型で保存することも考慮に入れて良いと思います。
IPv6に対応する関数
IPv6版のIS_
ただし、INET6_
また、INET6_
userテーブルのHostはどう保存されているか
ここまで読む中で、アカウント管理をしているmysqlスキーマのuserテーブルのHostカラムはどの形式なのか、気になった方もいるかもしれません。実はHostはchar(255)の形式で保存するように定義されています。実際に保存するデータとしては、IPv4形式のIPアドレス以外にホスト名やワイルドカード文字も入るので、たしかに数値型では保存できないのです。
まとめ
今回はIPアドレスをMySQLに保存したいときに知っておくと良いかもしれないこととして、MySQLで利用できるIPアドレス周りの関数を紹介しました。アプリケーションのサービスの定義によっては不要なものかもしれませんが、データ量が多くなるときや、データの形式を保証したい場合などに利用できるので、このような関数があることを認識しておくとよいでしょう。