很多小伙伴在对字符串进行取模或者做指纹存储的时候用到CRC32这个函数.
今天就来分享下CRC32隐藏的坑.
假如我根据一个连接地址,对这个连接地址进行分表.
http://www.xxx.com/www/index/ad/1/count/123/do/click/**** 等一串连接
小伙伴们肯定会想到用
$sign = crc32(md5($link));
然后在根据sign 进行取模.
这句代码有个坑,看完接下来的解释在回过头来说。
首先PHP手册上针对CRC32已经给出警告
Warning
由于 PHP 的整数是带符号的,所以在 32 位系统上许多 crc32 校验码将返回负整数。 尽管在 64 位上所有 crc32() 的结果将都是正整数。
接下来分析下这句话的隐藏含义:
crc32函数会按照php中的两个常量参考计算 PHP_INT_SIZE,PHP_INT_MAX
这两个常量的定义:
整型数的字长和平台有关,尽管通常最大值是大约二十亿(32 位有符号)。PHP 不支持无符号整数。Integer值的字长可以用常量PHP_INT_SIZE来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量PHP_INT_MAX来表示。
输出下32位中PHP_INT_SIZE:4,PHP_INT_MAX:2147483647
输出下64位中PHP_INT_SIZE:8,PHP_INT_MAX:9223372036854775807
则32位无符号整形
2^32-1 = 4294967295
由于前面说了php 不支持无符号整形,所以md5后 再 crc32的值一旦超出有符号整形的最大范围则就溢出。
所以在回过头来看顶部的例子,就看出端倪来了。
如何调整
public function getModSign($str){
$unsign = sprintf('%u', crc32($string));
if ($unsign > 2147483647)
{
$unsign -= 4294967296;
}
return abs($unsign);
}
如此以来,在32位系统占用运行 杠杠的.