【发布时间】:2015-05-05 07:59:59
【问题描述】:
我想检查一个 IP 是否被列入白名单,但 IPv6-Adresses 可以有不同的表示:
例如2001:0DB8:0:0:1::1 是2001:0db8:0000:0000:0001:0000:0000:0001 的缩写。
因此,字符串比较不起作用。我怎么知道两个地址相等?
【问题讨论】:
我想检查一个 IP 是否被列入白名单,但 IPv6-Adresses 可以有不同的表示:
例如2001:0DB8:0:0:1::1 是2001:0db8:0000:0000:0001:0000:0000:0001 的缩写。
因此,字符串比较不起作用。我怎么知道两个地址相等?
【问题讨论】:
使用inet_pton。
function is_ip_equal($ip1, $ip2) {
return inet_pton($ip1) == inet_pton($ip2);
}
(但是,这仅在 PHP 未使用 --disable-ipv6 option 编译时才有效。您可以使用 if (!defined('AF_INET6')) echo "IPv6 support was disabled"; 进行检查)。
【讨论】:
inet_pton 不会去掉带括号的 IPv6 地址中的括号,这仅对非常特定的用例很重要:inet_pton("[::1]") 返回 FALSE。这是因为括号内的地址在技术上不是有效的 IPv6 地址(相反,括号内的地址包含一个 IPv6 地址),即使当 IPv6 在 URL 中时括号是必需的。
这里是仅限 IPv6 的功能:
$bothBracketsArray = array('[', ']');
function are_ipv6_equal($a, $b) {
global $bothBracketsArray;
return inet_pton(str_replace($bothBracketsArray, '', $a)) === inet_pton(str_replace($bothBracketsArray, '', $b));
}
$bothBracketsArray 是全局的,因此 PHP 不必每次都分配新数组或对其模板进行浅层克隆(或 PHP 现在正在做的任何事情)。
我自己的目的还需要比较端口号并处理 IPv4,因为我正在监视 netstat 的输出,以查看套接字另一侧的进程 PID。
$bothBracketsArray = array('[', ']');
function doIpsAndPortsEqual($a, $b) {
global $bothBracketsArray;
$lastPosA = strrpos($a, ":"); // port #
$lastPosB = strrpos($b, ":"); // port #
if (substr($a, $lastPosA+1) !== substr($b, $lastPosB+1)) return false;
$ipA = substr($a, 0, $lastPosA);
$ipB = substr($a, 0, $lastPosB);
if (strpos($ipA, ':') !== false) { // Ipv6
return inet_pton(str_replace($bothBracketsArray, '', $ipA)) === inet_pton(str_replace($bothBracketsArray, '', $ipB));
} else { // Ipv4
return $ipA === $ipB;
}
}
【讨论】: