小心,以 0 开头的地址返回 false。
示例
<?php
inet_pton('172.27.1.04'); // 返回 false
inet_pton('172.27.1.4') ;// 返回正确的结果
?>
(PHP 5 >= 5.1.0, PHP 7, PHP 8)
inet_pton — 将可读的 IP 地址转换为其打包的 in_addr 表示形式
此函数将可读的 IPv4 或 IPv6 地址(如果 PHP 构建时启用了 IPv6 支持)转换为适合 32 位或 128 位二进制结构的地址族。
ip
可读的 IPv4 或 IPv6 地址。
返回给定 ip
的 in_addr
表示形式,如果给出语法无效的 ip
(例如,没有点的 IPv4 地址或没有冒号的 IPv6 地址),则返回 false
。
示例 #1 inet_pton() 示例
<?php
$in_addr = inet_pton('127.0.0.1');
$in6_addr = inet_pton('::1');
?>
小心,以 0 开头的地址返回 false。
示例
<?php
inet_pton('172.27.1.04'); // 返回 false
inet_pton('172.27.1.4') ;// 返回正确的结果
?>
关于 ::127.0.0.1 表示法
这是一个非常特殊的情况,不需要处理。这种表示法是为 ipv4 兼容的 ipv6 地址保留的。
例如,表示法 ::ffff:192.0.2.128 可以轻松地解释为“映射到 ipv4 地址 192.0.2.128 的 ipv6 地址”
但是,正如 RFC 所说
https://tools.ietf.org/html/rfc5156#page-2
2.2. IPv4 映射地址
::FFFF:0:0/96 是 IPv4 映射地址 [RFC4291]。地址
此块中的地址不应出现在公共互联网上。
2.3. IPv4 兼容地址
::<ipv4-address>/96 是 IPv4 兼容地址 [RFC4291]。
这些地址已弃用,不应出现在公共
互联网。
这意味着,如果您需要与私有 IP 兼容,则只需要处理这种表示法。
如果您想使用上述函数,您应该在 '.' 之前测试 ':' 字符。这意味着,在检查 ipv4 之前,您应该检查它是否为 ipv6 地址。
为什么?IPv6 允许这种表示法
::127.0.0.1
如果您检查 '.' 字符,您会认为这是一个 ipv4 地址,它将失败。
可以使用 AF_INET6 常量来验证 PHP 是否是用 --disable-ipv6 选项编译的。
<?php
if (defined('AF_INET6')) {
echo "PHP 使用 --disable-ipv6 选项编译";
} else {
echo "PHP 未使用 --disable-ipv6 选项编译";
}
?>
如果输入字符串不是可读的 IP 地址,inet_pton() 将生成 E_WARNING 并返回 FALSE。inet_ntop() 也是如此。
此外,inet_pton() 不会在输入字符串中识别网络掩码表示法(例如:“1.2.3.4/24” 或 “1:2::3:4/64”)。这与某些数据库系统(如 postgreSQL)支持 IP 地址类型的方式不同,因此,如果您在处理 PHP 中的 IP 地址时需要这种功能,则需要自己编写。
一个粗略的示例
<?php
// 示例 IP 地址
$ipaddr = '1.2.3.4/24'; // IPv4 带 /24 子网掩码
$ipaddr = '1:2::3:4/64'; // IPv6 带 /64 子网掩码
// 如果存在,则剥离子网掩码。
$cx = strpos($ipaddr, '/');
if ($cx)
{
$subnet = (int)(substr($ipaddr, $cx+1));
$ipaddr = substr($ipaddr, 0, $cx);
}
else $subnet = null; // 不存在子网掩码
// 将地址转换为打包格式
$addr = inet_pton($ipaddr);
// 以十六进制格式显示它
foreach(str_split($addr) as $char) echo str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
echo "<br />\n";
// 转换子网掩码
if (is_integer($subnet))
{
// 最大子网掩码长度 = 与打包地址相同
$len = 8*strlen($addr);
if ($subnet > $len) $subnet = $len;
// 创建子网掩码的十六进制表达式
$mask = str_repeat('f', $subnet>>2);
switch($subnet & 3)
{
case 3: $mask .= 'e'; break;
case 2: $mask .= 'c'; break;
case 1: $mask .= '8'; break;
}
$mask = str_pad($mask, $len>>2, '0');
// 子网掩码的打包表示
$mask = pack('H*', $mask);
}
// 以十六进制格式显示子网掩码
foreach(str_split($mask) as $char) echo str_pad(dechex(ord($char)), 2, '0', STR_PAD_LEFT);
?>
如果您收到有关 IPv6 地址的“无法识别的地址”错误,则您的 PHP 版本可能未编译为支持 IPv6。
要检查,请加载 phpinfo(); 并查看“IPv6 支持”是否设置为“已禁用”。
在下面的函数中并不容易... 它没有处理 '::' 的情况,这种情况可能发生在 IPv6 中,它代表任何数量的 0,地址可以像 ff05::1 那样简单