使用 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.
在数组 $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.