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);