php判断数组里面的每个ip是否在给定的另一组ip数组段内
php判断数组里面的每个ip是否在给定的另一组ip数组段内,两个数组里面可能同时含有ipv4和ipv6:
namespace App\Helpers;
class IpValidator
{
public function isIpInRange($ip, $ranges)
{
foreach ($ranges as $range) {
if (strpos($range, '-') !== false) {
// 是起止IP格式
[$start, $end] = explode('-', $range);
if ($this->ipInRange($ip, $start, $end)) {
return true;
}
} else {
// 是CIDR格式
[$prefix, $length] = explode('/', $range);
if ($this->ipInCidr($ip, $prefix, $length)) {
return true;
}
}
}
return false;
}
public function ipInRange($ip, $start, $end)
{
// 实现逻辑
return ip2long($ip) >= ip2long($start) && ip2long($ip) <= ip2long($end);
}
public function ipInCidr($ip, $net, $bits)
{
// 实现逻辑
return (ip2long($ip) & ~0 << (32 - $bits)) == ip2long($net);
}
public function isIpv6InRange($ipv6, $ranges)
{
foreach ($ranges as $range) {
// 提取网络前缀和掩码长度
[$prefix, $length] = explode('/', $range);
// 提取给定IPv6和网络前缀的网络部分
$givenNetPrefix = substr($ipv6, 0, strpos($ipv6, ':'));
$rangeNetPrefix = substr($prefix, 0, strpos($prefix, ':'));
// 比较网络前缀是否匹配
if ($givenNetPrefix === $rangeNetPrefix) {
// 获取给定IPv6地址长度
$givenLength = strlen($ipv6) - strpos($ipv6, ':');
// 判断是否小于等于网络掩码长度
if ($givenLength <= $length) {
return true;
}
}
}
return false;
}
public function separateIpRanges($ipRanges)
{
$ipv4Ranges = [];
$ipv6Ranges = [];
foreach ($ipRanges as $range) {
// 按逗号分隔多个范围
if (strpos($range, '-') !== false) {
$start_ip = explode('-', $range)[0];
}
if (strpos($range, '/') !== false) {
$start_ip = explode('/', $range)[0];
}
$segment = trim($start_ip);
if (filter_var($segment, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
// 是IPv6范围
$ipv6Ranges[] = $range;
} else {
// 是IPv4范围
$ipv4Ranges[] = $range;
}
}
return [
'ipv4' => $ipv4Ranges,
'ipv6' => $ipv6Ranges,
];
}
public function validateIps($ipArray, $ipRanges)
{
$ipv4Ranges = $this->separateIpRanges($ipRanges)['ipv4'];
$ipv6Ranges = $this->separateIpRanges($ipRanges)['ipv6'];
$notInIps = [];
foreach ($ipArray as $ip) {
$ipVersion = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? 6 : 4;
if ($ipVersion == 4) {
$res = $this->isIpInRange($ip, $ipv4Ranges);
} else {
$res = $this->isIpv6InRange($ip, $ipv6Ranges);
}
if (!$res) {
$notInIps[] = $ip;
}
}
return $notInIps;
}
}
使用方式:
$ipArray = [
'101.127.120.255',
'2608:3404:1234:2100:0000:0000:0000:11',
'192.168.1.0',
'192.168.1.1',
'1123:3404:1234:2100:0000:0000:0000:11',
'114.246.18.255',
'1123:3404:1234:2100:0000:0000:0000:11',
'61.241.95.0',
'1123:8642:EFC:1480:0000:0000:0000:1',
'116.169.105.1',
'1123:8766:1:D00:0000:0000:0000:1',
];
$ipRanges = [
'101.127.196.0-101.127.197.255',
'1123:3404:1234:2100:0000:0000:0000:0000/56',
'114.246.18.0-114.246.19.255',
'1123:3404:1234:2000:0000:0000:0000:0000/56',
'61.241.94.0/23',
'1123:8642:EFC:1480::/57',
'61.241.92.0/23',
'1123:8642:EFC:1400::/57',
'116.169.104.0/22',
'1123:8766:1:D00::/56',
'116.169.104.0/22',
'1123:8766:1:D00::/56',
'101.125.212.0/24',
'1123:8706:0000:5400::/56',
'1123:8706:0000:5500::/56',
'101.125.213.0/24',
'101.125.214.0/24',
'101.125.215.0/24',
'116.169.140.0/24',
'116.169.141.0/24',
'1123:8766:1:1200::/56',
'101.148.4.0/22',
'1123:8740:C4FC:200::/56',
'119.255.137.0/25',
'2407:4f00:1:2000::/63',
'119.255.137.128/25',
'2407:4f00:1:2002::/63',
'117.107.160.0/25',
'240e:604:208:1950::/63',
'117.107.160.128/25',
'240e:604:208:1952::/63',
'183.247.147.192/26',
];
$validator = new IpValidator;
$notInIps = $validator->validateIps($ipArray, $ipRanges);
print_r($notInIps);