使用 php 检查 ip 是否与 ip 列表中包含的任何 ip 匹配

check if an ip matches any ip contained in an ip list using php

在数组 $white 中我有一个这样的 ip 列表(大约 10000-12000 ips)

74.125.244.0/22
207.126.144.0/20
77.238.189. 
212.211.149.128/26
194.25.134.8 
194.25.134.9 
194.25.134.12       
174.2.114.12-174.2.115.255
153.2.242.243
153.2.244.12 
153.2.244.50 
153.2.244.63 
153.2.246.30 
153.2.246.31 
153.2.246.35 
153.2.247.30 
153.2.247.31 
153.2.247.32      

因此,$white数组中的ip列表可以包含这三种格式的ip

153.2.247.32 (simple ip address)
207.126.144.0/20 ( CIDR notation )
174.2.114.12-174.2.115.255 ( Hyphenated ranges )

我的目标是检查另一个数组 $ips(大约 1000-2000 ips)中列出的 ips 是否存在于 $白名单。

$ips列表中的格式只是简单的ip地址,如

207.126.144.0
207.126.141.2
201.126.144.5

我正在做这个

foreach ($ips as $check) {
if (in_array($check,$white)){
echo "Ip $check exists";
}
}

然而,只检查简单的 ip 地址是好的,但我无法检查 $ips 中列出的 ips 是否包含在 $white 的连字符范围和 CIDR 范围中。

我找到了使用 ip_in_range.php 的解决方案 https://github.com/irazasyed/php-ip-range/blob/master/ip_in_range.php

foreach ($ips as $check) {
    if (in_array($check,$white))
    {
    echo "Ip $check exists";
    }
    else
    {
    foreach( $white as $checkrange )
    {       
if (substr_count($checkrange, '/')>=1 or substr_count($checkrange, '-')>=1 )
{ 
    if (ip_in_range($check, $checkrange)) 
{ 
    echo "Ip $check exists"; 
    break;
}
}

}
}
}

但是它非常慢,因为 $white 和 $ips 是巨大的列表。 是否存在更快更有效的解决方案?

你可以试试 preg_grep:

foreach ($ips as $check){

    if(preg_grep("/$check/i",$white))
    {
        echo $input." whitelisted";
    }else{
        echo $input." blacklisted";
    }
{

将所有白名单范围预扩展为一个巨大的单一 IP 地址列表。例如,给定:

1.2.3.4
2.3.4.5
3.4.5.6-3.4.5.10

您将处理列表一次以生成此列表:

1.2.3.4
2.3.4.5
3.4.5.6
3.4.5.7
3.4.5.8
3.4.5.9
3.4.5.10

然后,将该列表存储在 key/value 缓存中。可以像内存中的本机 PHP 关联数组一样简单,也可以像 Redis 数据库一样更健壮。然后你有一个简单的等效检查包含。正确实施(例如,通过 array_key_exists() 而不是 in_array()),无论白名单的大小如何,您都将获得 IP 查找的 O(1) 性能。它不能变得更快。

您不必在每次 IP 检查时一遍又一遍地执行所有范围处理,而是在白名单更改时只执行一次。您基本上是在放弃内存以获得 CPU.