我发现这种方法使用INET_ATON将MySQL数据库中的IP地址存储为整数:https://stackoverflow.com/a/5133610/4491952
由于IPv4地址长度为4个字节,因此您可以使用恰好有4个字节的INT
(UNSIGNED
):
`ipv4` INT UNSIGNED
INSERT INTO `table` (`ipv4`) VALUES (INET_ATON("127.0.0.1"));
SELECT INET_NTOA(`ipv4`) FROM `table`;
对于IPv6地址,您可以使用BINARY
代替:
`ipv6` BINARY(16)
使用PHP’s inet_pton
和inet_ntop
进行转换:
'INSERT INTO `table` (`ipv6`) VALUES ("'.mysqli_real_escape_string(inet_pton('2001:4860:a005::68')).'")'
'SELECT `ipv6` FROM `table`'
$ipv6 = inet_pton($row['ipv6']);
但是如何使用INET_ATON和PHP的ip2long函数进行通配符搜索,例如192.168。%?
答案 0 :(得分:3)
通配符搜索对字符串进行操作,因为它通常不能从索引中受益,所以它往往非常慢。
如果您将IP地址存储在针对计算机的规范化表示中(与人类可读的点符号相比),您可以将它们视为数字,使用许多标准运算符并充分利用索引。一个例子:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="header">
<span class="navButton"></span>
<ul class="nav">
<li><a href="index.html">Home</a></li>
<li><a href="journey.html">The Journey</a></li>
<li><a href="getintouch.html">Get In Touch</a></li>
</ul>
</div>
...可以改写为:
SELECT *
FROM foo
WHERE dot_notation LIKE '192.168.%';
即使这些SELECT *
FROM foo
WHERE as_integer BETWEEN INET_ATON('192.168.0.0') AND INET_ATON('192.168.255.255');
实例仅仅是为了可读性,您也可以输入结果整数。如果你使用PHP它是微不足道的,因为你可以将它外包给PHP:
INET_ATON()
我现在无法测试它,但我知道这也适用于IPv6。
答案 1 :(得分:3)
MySQL提供的一个巧妙的技巧就是移位。您可以使用它来查看ip是否包含在用cidr表示法编写的地址块中。您可以使用此方法将地址视为X.X.X.X / 16 cidr块。
set @cidr_block:='10.20.30.40/16';
select inet_ntoa(inet_aton(substring_index(@cidr_block,'/',1))>>(32-substring_index(@cidr_block,'/',-1))<<(32-substring_index(@cidr_block,'/',-1))) as first_ip,
inet_aton(substring_index(@cidr_block,'/',1))>>(32-substring_index(@cidr_block,'/',-1))<<(32-substring_index(@cidr_block,'/',-1)) as first_ip_num,
inet_ntoa((((inet_aton(substring_index(@cidr_block,'/',1))>>(32-substring_index(@cidr_block,'/',-1)))+1)<<(32-substring_index(@cidr_block,'/',-1)))-1) as last_ip,
(((inet_aton(substring_index(@cidr_block,'/',1))>>(32-substring_index(@cidr_block,'/',-1)))+1)<<(32-substring_index(@cidr_block,'/',-1)))-1 as last_ip_num
;
+-----------+--------------+---------------+-------------+
| first_ip | first_ip_num | last_ip | last_ip_num |
+-----------+--------------+---------------+-------------+
| 10.20.0.0 | 169082880 | 10.20.255.255 | 169148415 |
+-----------+--------------+---------------+-------------+
1 row in set (0.00 sec)
查看ip是否在地址块中的快捷方式 - 只需筛选cidr地址和ip以查看它们是否相同。当然,如果应用于存储值,这将是一个表扫描。
select inet_aton('127.0.0.1')>>16 = inet_aton('127.0.10.20')>>16 as `1 = true`;
+----------+
| 1 = true |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
select inet_aton('127.0.0.1')>>16 = inet_aton('127.10.10.20')>>16 as `0 = false`;
+-----------+
| 0 = false |
+-----------+
| 0 |
+-----------+
1 row in set (0.00 sec)