我需要在其中存储带有通配符的IP地址,例如10.0。%。1。然后,我希望从我的查询中找到任何IP地址在允许范围内(10.0.0-255.1)的人。
你能帮帮我吗?我已经尝试存储10.0。%。1但是找不到LIKE查询(我甚至不知道这是不是这样做 - 可能不是)。提前致谢。
答案 0 :(得分:3)
将IP地址转换为32位整数,并为地址和掩码创建一列。您可以使用INET_NTOA()
和INET_ATON()
功能。 10.0。%。1范围可以表示为网络10.0.0.1,掩码为255.255.0.255。要查看给定IP地址是否与此网络匹配,请将掩码应用于IP地址,并将其与网络地址进行比较。如果匹配,则地址在网络中。例如,如果要测试10.0.4.1,则使用按位AND将掩码应用于它:
10.0.4.1 & 255.255.0.255 = 10.0.0.1
这与您的网络地址匹配,因此该IP位于网络中。
您可以将此网络存储在您的表中(ip和mask是整数):
CREATE TABLE networks (id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, ip INT, mask INT);
INSERT INTO networks (ip, mask)
VALUES (INET_ATON('10.0.0.1'), INET_ATON('255.255.0.255'));
您可以找到给定的IP(10.0.23.1)是否匹配如下:
SELECT * FROM networks
WHERE ip & mask = INET_ATON('10.0.23.1') & mask
这会将IP选为整数,如果你想让它们具有人类可读性:
SELECT id, INET_NTOA(ip) AS ipstring, INET_NTOA(mask) AS maskstring
FROM networks
WHERE ip & mask = INET_ATON('10.0.23.1') & mask
这允许您测试单个给定的IP地址是否与网络匹配。如果要测试一系列IP,则必须将掩码应用于范围中的每个IP,并按上面的方式测试每个IP。您可以在一个查询中执行此操作,只需列出您正在测试的每个IP地址。
答案 1 :(得分:2)
如何将ip地址保存为数据库中的4个整数,如下所示:
IPpart1 IPpart2 IPpart3 IPpart4
-------------------------------
127 0 0 1
让它们成为可空的。 (NULL将成为我们的通配符)
然后您可以像这样对数据库进行查询:
SELECT * FROM iptable WHERE (IPpart1 IS NULL OR IPpart1 = '$firstpart') AND (IPpart2 IS NULL OR IPpart2 = '$secondpart') AND (IPpart3 IS NULL OR IPpart3 = '$thirdpart') AND (IPpart4 IS NULL OR IPpart4 = '$fourthpart')
它完成工作有点冗长。
甚至可以从普通的IP字段构造一个具有该结构的临时表,但是如果你有很多请求,这将是很多开销。
答案 2 :(得分:0)
我仔细查看了MySQL文档页面,并在那里找到了符合您需求的帖子:
SELECT '10.0.0.1' AS IP0,
( SUBSTRING_INDEX( '10.0.0.1', '.', 1 ) * 16777216 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.0.1', '.', 2 ),'.',-1) * 65536 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.0.1', '.', -2 ),'.',1) * 256 +
SUBSTRING_INDEX( '10.0.0.1', '.', -1 )
),
'10.0.255.1' AS IP1,
( SUBSTRING_INDEX( '10.0.255.1', '.', 1 ) * 16777216 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.255.1', '.', 2 ),'.',-1) * 65536 +
SUBSTRING_INDEX(SUBSTRING_INDEX( '10.0.255.1', '.', -2 ),'.',1) * 256 +
SUBSTRING_INDEX( '10.0.255.1', '.', -1 )
) AS IP2Num1
返回每个IP的数值:
Ip: | 10.0.0.1 | 10.0.255.1 |
--------------------------------
Num: | 167772161 | 167837441 |
换句话说:
SELECT foo
FROM bar.foobar
WHERE ( SUBSTRING_INDEX( ipField, '.', 1 ) * 16777216 +
SUBSTRING_INDEX(SUBSTRING_INDEX( ipField, '.', 2 ),'.',-1) * 65536 +
SUBSTRING_INDEX(SUBSTRING_INDEX( ipField, '.', -2 ),'.',1) * 256 +
SUBSTRING_INDEX( ipField, '.', -1 )
) BETWEEN 167772161 AND 167837441;
嗯,你可以这样做:
WHERE ipField LIKE '10.0.%.1'
AND (CAST
(REPLACE(SUBSTRING_INDEX(ipField,'.',3),
CONCAT(SUBSTRING_INDEX(ipField ,'.',2),'.')
,'')
AS UNSIGNED) BETWEEN 0 AND 255)
我使用以下查询进行了测试:
SELECT IF ('10.0.12.1' LIKE '10.0.%.1'
AND (CAST
(REPLACE( SUBSTRING_INDEX('10.0.12.1','.',3),
CONCAT(SUBSTRING_INDEX('10.0.12.1','.',2),'.')
,'')
AS UNSIGNED) BETWEEN 0 AND 255),
TRUE,
FALSE);
然后它返回1
,但老实说,这有点不对劲,不是吗?为什么不简单:
WHERE ipField REGEXP '10\\.0\\.[0-9]{1,3}\\.1'
你可以调整一下这个表达式,但基本上,在我看来,这是查询这些IP地址的最简单方法。
有关MySQL字符串函数的更多信息(这几乎总是很痛苦)写),见the docs here