某次在线上排查问题时发现,代码中使用的一个使用str_shuffle随机打乱字符串函数生成的唯一字符出现了重复,导致插入数据库失败。觉得很奇怪,生成随机字符串的方法如下:
function makeString($len)
{
$char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle($char), 0, $len);
}
从php的手机中看到,str_shuffle函数在php7.1.0中有所变化,其内置的随机算法从 libc rand 函数改成了梅森旋转演伪随机数发生算法。
但不知道和我这有没有关系,我使用的php版本也正是7.1.0。但在线上环境中确实是出现了生成的字符重复的问题,而我在自己的环境和服务器的环境中使用脚本检测重复的情况却也没有再复现。示例脚本如下:
#检测重复率
$data =array();
for($i=0;$i<=50000;$i++){
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$data[] = substr(str_shuffle(str_repeat($pool,32)), 0, 32);
}
$new = array_count_values($data);
echo '<pre>';
print_r(array_filter($new, function($var){
return($var>1);
}));
有说str_shuffle函数的PHP内部实现也是使用随机数(PHP内部如何实现打乱字符串顺序函数str_shuffle-腾讯云开发者社区-腾讯云),它使用随机数抽取字符串与一个特定的字符串(最后一个)进行替换。这样就不用去考虑随机数重复的问题。不会因为重复到账一些字符串被覆盖。
可以自定义函数对生成的随机字符串进行存在性判断,但这样不能保证经过n次后结束,因为需要跳过随机数重复的情况。但str_shuffle函数在php内部的实现,都是n次循环后结束。在性能上肯定比需要去重的随机数方法要好。str_shuffle函数内部实现如下(强调下这张图不是我原创的):
目前尚未找到出现此问题的底层原因,我使用了unquid方法进行了替代目前解决了问题,代码如下:
#使用uniqid生成唯一ID,使用随机数区分多台服务器
function makeString($len)
{
return md5(uniqid(mt_rand(0,10000)));
}
此外php中除了str_shuffle函数可对字符串进行打乱外,还有一个shuffle函数可以用来快速打乱数组,不过其使用的是伪随机数产生器,并不适合密码学的场合。
str_shuffle函数和shuffle的返回值稍微有点区别,str_shuffle函数返回一个新的长度符合的字符串,而shuffle只返回true或false这个处理结果,修改的是原数组本身。
标签:随机数,shuffle,函数,重复,str,字符串,PHP From: https://blog.csdn.net/weixin_47792780/article/details/137153894