关于ip地址存储的方法, ip地址很多人都用char方式存储, 但我建议还是觉得用整数来存储读取更快.
ip地址转整数的方式比较多, 我逐一说明一下, 部分代码参考网友:Tsung的文章.
1. 用ip2long ip地址转整数
ip2long() 转出来的数值在32位机器转出负数, 系统版本 32bits 和 64bits 转换的结果不一样.
32 bits ip2long(): -2147483648 ~ 214748364764
64 bits ip2long(): 0 ~ 4294967295
32bits 系统测试ip2long()
ip2long('127.255.255.255'); // 2147483647 = 十进位的最大值
ip2long('255.255.255.255'); // -1
ip2long('255.255.255.254'); // -2
ip2long('192.168.1.2'); // -1062731518
64bits 系统测试ip2long()
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. ip2long 转成二进位, 再转回十进位避免负值
echo bindec(decbin(ip2long('192.168.1.2'))); // 3232235778
?>
老修备注一下, 这个方法ipv4和ipv6通吃, 数据存储格式要用Unsigned 无标签int类型.
方法2. 可避免ipv4转换后产生负数的另一种算法:
// 自己做转换, 这方法计算出来的数值是正确的.(32bits / 64bits 皆正确)
function iptolong($ip)
{
list($a, $b, $c, $d) = split('.', $ip);
$ip_long = (($a * 256 + $b) * 256 + $c) * 256 + $d;
return $ip_long;//如果加上intval($ip_long);会产生负数
}
?>
此方法同样有的ip地址会产生bigint值.
注: intval 在 32 bits / 64 bits 最大值是不同的:
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.
方法3. 使用 printf("%u")
$ipbigint = sprintf("%u", ip2long('192.168.1.2'));
?>
这里要注意的是printf 和sprintf的区别, printf是直接输出给浏览器了, 相当于echo (sprintf());
方法4. 使用mysql的 inet_aton 转换函数.
我不建议在mysql 的查询中做数据运算, 这会给脆弱的数据库造成额外的压力, 能php解决的尽量不要放到数据库里操作.
不过方法还是分享一下:
select * from iplist where inet_aton(ip)=inet_aton('{$ip}')