PHP IP地址函数 ip2long()返回值为负数对策

PHP 的 ip2long 是将 IP 位址转换为数值的 function.

ip2long() 转出来的数值应该都是正整数, 但是在某些机器转出负数, 刚开始以为是 PHP 版本问题, 后来做些测试, 确定是系统版本 32bits 和 64bits 的问题.

  • 32 bits ip2long(): -2147483648 ~ 214748364764
  • 64 bits ip2long(): 0 ~ 42949672945

测试

<?php
// 自己做转换, 这方法计算出来的数值是正确的.(32bits / 64bits 皆正确)
function iptolong($ip)
{
list($a, $b, $c, $d) = split('\.', $ip);
$ip_long = (($a * 256 + $b) * 256 + $c) * 256 + $d;

return $ip_long;
}
?>

另外做测试, 于 return 值加上 intval(), 如下述:

<?php
// 这样子的数值就会产生负数.
function iptolong($ip)
{
list($a, $b, $c, $d) = split('\.', $ip);
$ip_long = (($a * 256 + $b) * 256 + $c) * 256 + $d;

return intval($ip_long);
}
?>

intval 在 32 bits / 64 bits 最大值是不同的, 于 intval() 里面有写到下述:

The maximum value depends on the system.
32 bit systems have a maximum signed integer range of -2147483648 to 2147483647.
So for example on such a system, intval(‘1000000000000’) will return 2147483647.
The maximum signed integer value for 64 bit systems is 9223372036854775807.

另外做其它测试:

ip2long() 于 32bits 的系统测试
  • ip2long(‘127.255.255.255’); // 2147483647 = 十进制的最大值
  • ip2long(‘255.255.255.255’); // -1
  • ip2long(‘255.255.255.254’); // -2
  • ip2long(‘192.168.1.2’); // -1062731518
ip2long() 于 64bits 的系统测试
  • ip2long(‘127.255.255.255’); // 2147483647 = 十进制的最大值
  • ip2long(‘255.255.255.255’); // 4294967295
  • ip2long(‘255.255.255.254’); // 4294967294
  • ip2long(‘192.168.1.2’); // 3232235778

知道问题是 32bits 系统造成的, 就很好解决囉~

解法1 – 自己转换

<?php
function iptolong($ip)
{
list($a, $b, $c, $d) = split('\.', $ip);
return (($a * 256 + $b) * 256 + $c) * 256 + $d;
}
?>

解法2 – 转成二进制, 再转回十进制

<?php
// bindec 只吃 string, 回传 double
// decbin 会回传 string
echo bindec(decbin(ip2long('192.168.1.2'))); // 3232235778
// 此方法我也有点不太懂, 忘记从哪边看到的解法.
?>

解法3 – 官方建议的解法 (推荐用此方法)

<?php
// 直接印值, 使用 printf("%u")
printf("%u", ip2long('192.168.1.2')); // 3232235778

// 回传值(于 function 或 echo 等), 使用 sprintf(“%u”)
echo sprintf(“%u”, ip2long(‘192.168.1.2’)); // 3232235778
?>

另外 于此篇 (PHP 的 ip2long 有 Bug) 看到的案例如下:

<?php
echo ip2long('058.99.11.1'); // null
echo ip2long('58.099.11.1'); // null
?>

若是会有这种情况, 用 解法1 即可解决.

from http://www.hksilicon.com/kb/cn/articles/4155/PHP-ip2long

发表评论?

2 条评论。

  1. 真是瞎说,IPv4本身就是32位的,跟机器有什么关系?在32位平台上PHP默认的整数类型是32有符号整型。例如:A.B.C.D。当A大于127就为负数了,至于为什么,建议看看《tcp/ip协议详解》这本书,别在这里YY了。http://my.oschina.net/goal/blog/198049

    • 跟机器有关的,操作系统是64位或32不同的,至少在centos6 x64 官方yum源里的php版本,var_dump(ip2long(‘222.73.1.1’)) 输出计算结果是 int(3729326337)
      猜测:windows 64位下,如果安装x86版本的php,输出仍然是负数;x64 的php,输出应该也是正数。win下个人没有亲测。
      btw,本文是当时在32位下做开发时,发现ip2long结果为负值结果,查资料学习后转来的。

发表评论