总结一下到目前为止我在答案和 cmets 中的内容:
- IPv6 地址具有规范格式,这是 inet_ntop() 返回的内容。
- 不推荐使用 ::/96 地址范围,但不推荐使用 ::ffff/80。
- 尽管 inet_ntop() 将 all ::/96 地址呈现为 ::/IPv4 地址是有意义的,但似乎 inet_ntop() 呈现 ::/112 地址和“ ::/96 中的“更高”为 ::/IPv4-dotted-quad(例如 ::254.239.24.134),并将 ::/96 地址“低于” ::/112 呈现为“普通”IPv6 地址。
- 如果您希望 inet_ntop() 以相同的方式呈现所有 IPv6 地址(即使用通常的零压缩规则的 8 个十六进制字),那么您需要编写自己的方法来实现这一点。
我自己的解决方法是扩展 inet_ntop(),将任何 IPv4 点四边形重写为十六进制字(我将逻辑分解为多种方法,以便我更容易跟踪我在做什么):
function _inet_ntop($addr) {
return fix_ipv4_compatible_ipv6(inet_ntop($addr));
}
/**
* If $str looks like ::/IPv4-dotted-quad then rewrite it as
* a "pure" IPv6 address, otherwise return it unchanged.
*/
function fix_ipv4_compatible_ipv6($str) {
if (
($str[0] == ':') &&
($str[1] == ':') &&
preg_match('/^::(\S+\.\S+)$/', $str, $match)
) {
$chunks = explode('.', $match[1]);
return self::ipv4_zones_to_ipv6(
$chunks[0],
$chunks[1],
$chunks[2],
$chunks[3]
);
} else {
return $str;
}
}
/**
* Return a "pure" IPv6 address printable string representation
* of the ::/96 address indicated by the 4 8-bit "zones" of an
* IPv4 address (e.g. (254, 239, 24, 134) -> ::feef:1886).
*/
function ipv4_zones_to_ipv6($q1, $q2, $q3, $q4) {
if ($q1 == 0) {
if ($q2 == 0) {
if ($q3 == 0) {
if ($q4 == 0) {
return '::0';
} else {
return '::' . self::inflate_hexbit_pair($q4);
}
} else {
return '::' . self::inflate_hex_word($q3, $q4);
}
} else {
return '::' . self::inflate_hexbit_pair($q2) . ':' . self::inflate_hex_word($q3, $q4);
}
} else {
return '::' . self::inflate_hex_word($q1, $q2) . ':' . self::inflate_hex_word($q3, $q4);
}
}
/**
* Convert two 8-bit IPv4 "zones" into a single 16-bit hexword,
* stripping leading 0s as needed, e.g.:
* (254, 239) -> feef
* (0,1) -> 1
*/
function inflate_hex_word($hb1, $hb2) {
$w = self::inflate_hexbit_pair($hb1) . self::inflate_hexbit_pair($hb2);
return ltrim($w, '0');
}
/**
* Convert one 8-bit IPv4 "zone" into two hexadecimal digits,
* (hexits) padding with a leading zero if necessary, e.g.:
* 254 -> fe
* 2 -> 02
*/
function inflate_hexbit_pair($hb) {
return str_pad(dechex($hb), 2, '0', STR_PAD_LEFT);
}
虽然可以说远不如 JC Sama 提出的 _inet_ntop() 函数优雅,但它的运行速度比我的(基本上是随机的)测试用例快 25%。