0

我试图阻止某些 IP 地址和 IP 范围执行某些操作。现在,SELECT * FROM blocked WHERE ip=$_SERVER['REMOTE_ADDR']如果 ->num_rows 返回 > 0,我将重定向用户。

这适用于完整的 IP 地址,但如果我将199.90.*.*例如放入数据库中,我该如何匹配呢?另外,将IP存储在数据库中的最佳方法是什么?

4

3 回答 3

4

您的问题的答案是使用like

SELECT *
FROM blocked
WHERE $_SERVER['REMOTE_ADDR'] like replace(ip, '*', '%')

中的通配符like'%'而不是'*',所以这用百分号替换了星号。我猜您实际上会将字符串存储为'199.199.%.%',但上面是为了清楚起见。

虽然这在技术上解决了您的问题,但它还有其他问题,因为 MySQL 可能不使用索引进行这些比较(请参阅此处)。影响取决于阻塞表的大小。如果它有 100 行,这可能不是问题。如果它有 100,000,那么它可能是。

对阻塞表使用通配符的另一种方法是将FromIPToIP作为列。然后像“199.199.. 这样的东西将简单地存储为“199.199.000.000”和“199.199.999.999”。查询将是:

where $_SERVER['REMOTE_ADDR'] between FromIP and ToIP

你会有一个关于blocked(FromIP, ToIP).

于 2013-06-20T18:12:25.377 回答
0

您最好的解决方案是使用INET_ATON函数。

给定 IPv4 网络地址作为字符串的点分四元组表示,返回一个整数,该整数表示网络字节顺序(大端)地址的数值。

因此,如果您想查找某个范围内的 IP,您可以使用如下查询:

SELECT * FROM blocked WHERE INET_ATON($_SERVER['REMOTE_ADDR']) between INET_ATON(this_ip) and INET_ATON(this_other_ip).

我认为,在 MySQL 数据库中存储 IPv4 地址的最佳方法是使用该函数,将它们转换为一个int值并像这样存储它。如果您想从它的int表示中获取 IP,请使用INET_NTOA

将 IP 存储为int,查询结束如下:

SELECT * FROM blocked WHERE INET_ATON($_SERVER['REMOTE_ADDR']) between this_ip and this_other_ip.

而不是使用 199.90.*.* 使用 (199.90.0.0)。

于 2013-06-20T18:32:31.523 回答
0

我将首先检查完整的 IP 地址,然后用 * 屏蔽最后一个字节,然后检查它,然后检查最后 2 个字节,依此类推。这样一来,您就可以从特定到不太特定,如果一旦命中,IP就会被阻止。这可能不是最有效的方法,但我想您只需在登录时执行一次。

为简单起见,我会将 IP 地址存储为字符串。

另一种解决方案可能是将 IP 地址存储为字节数组,但我猜这不会让任何事情变得更容易,并且使用例如命令行工具 SQL 工具的可维护性会大大降低。

于 2013-06-20T18:05:18.763 回答