PHP rand() 与 random_int()

Posted

技术标签:

【中文标题】PHP rand() 与 random_int()【英文标题】:PHP rand() vs. random_int() 【发布时间】:2017-10-28 22:47:50 【问题描述】:

作为php.net indicates: random_int() 函数生成加密安全的伪随机整数

但是,有人能解释一下rand()random_int() 之间的区别吗?当只需要一个随机整数时,我可以使用random_int() 而不是rand() 吗?哪个更快?

【问题讨论】:

php.net/manual/en/function.random-int.php "返回一个加密的安全随机整数,范围从 min 到 max,包括。" 和 php.net/manual/en/function.rand.php "此函数不生成加密安全值” en.wikipedia.org/wiki/… --- ***.com/questions/2449594/… 使用rand(),除非你需要一个安全的随机整数,然后使用random_int()。如果你不知道你是否需要后者,你可能不需要(它会影响“可猜测性”,所以想象一下它在哪里有用)。例如,如果您尝试随机播放幻灯片,rand() 就可以了。 关于速度的事情,除非你知道你需要它,否则不要在此基础上过早优化。专注于函数的应用,然后在必要时调整效率。 mt_rand() 在 PHP 7.1 中取代了 rand()。只是想知道为什么没有提到? 【参考方案1】:

重新审视这个问题并看到给出的答案,我发现我将我的 cmets 提交给一个答案是公平的,因为他们之前已经提交过。

PHP 7 的 random_int() 函数手册指出:

“返回从 min 到 max 范围内的加密安全随机整数。”

http://php.net/manual/en/function.random-int.php

对于rand()

*此函数不生成加密安全值" *

http://php.net/manual/en/function.rand.php

OP 的评论:

“@Fred-ii- 谢谢。但是“加密安全伪随机”是什么意思?- NDFA”

根据我的发现,可以在以下链接中找到:

https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator

其中规定:

加密安全伪随机数生成器 (CSPRNG) 或加密伪随机数生成器 (CPRNG)[1] 是一种伪随机数生成器 (PRNG),其特性使其适用于密码学.


How does a cryptographically secure random number generator work?

关于性能,您需要自己运行基准测试。

【讨论】:

我同意。很高兴将您的答案作为参考留在这里(因为我认为随着 php 开发人员切换到 7 这个问题会引起更多关注)。 确实@NDFA 干杯【参考方案2】:

从 PHP 7.1 开始,rand()mt_rand() 的别名。较新的random_int() 是三种方法中最慢但唯一安全的方法。

<?php

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) 
    $sum += rand(0, 32767);

printf('[rand] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) 
    $sum += mt_rand(0, 32767);

printf('[mt_rand] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) 
    $sum += random_int(0, 32767);

printf('[random_int] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

PHP 7.4 的结果:

[rand] Time: 0.320 s      
[mt_rand] Time: 0.326 s   
[random_int] Time: 9.255 s

【讨论】:

【参考方案3】:

rand()

rand() 现在是mt_rand() 的别名。查看source code of mt_rand(),可以看出随机数根本不是随机的。这是一个简单的数学计算,并不比

复杂多少
return $min + suffle_bits($internal_counter++) % ($max - $min);

其中suffle_bits() 是一些可预测的二进制算术,使$internal_counter 看起来不仅仅是自增。

这就是为什么rand() 被称为返回伪随机数字的原因。返回的数字似乎是随机抽取的,但知道$internal_counter 的值可以让您预测接下来会发生什么。

random_int()

random_int() 不会受到这种可预测性问题的影响,前提是计算机的熵发生器已正确启动。

即使攻击者收集了大量值,也无法猜测下一个值。

哪个最好

如果攻击者可以从您的代码输出中猜出$internal_counter 的值并利用该知识干扰您的代码的预期用途,请使用random_int()

如果使用随机数来显示,比如说,随机问候,那么rand() 是绝对安全的。

现在,如果必须生成一长串 GUID 或条形码,并且最终用户不能从子集中猜测另一个有效值,那么 random_int() 不仅在安全性方面更好,而且因为它不会重复自己。 rand() 可能会以 32768 输出的速度重复自身,具体取决于平台。

哪个更快

毫无疑问,rand() 更简单,因此也更快。

这是一个粗略的单行易于复制/粘贴的命令,用于计算在 10 秒内可以从rand() 中抽取多少个数字:

php -r '$s=microtime(true);$c=0;while(microtime(true)-$s<10)rand(0,9);$c++;;echo "$c\n";'

random_int() 也是如此:

php -r '$s=microtime(true);$c=0;while(microtime(true)-$s<10)random_int(0,9);$c++;;echo "$c\n";'

php 7.3 的计数器是:

rand():       36665142
random_int(): 10511327

rand() 的速度不到 4 倍。除非速度是一个问题,否则random_int() 是可行的方法,但对于最基本的非关键任务。

【讨论】:

【参考方案4】:

与大多数数字生成器一样,使用 rand() 并不安全,因为它不会生成加密安全值,而且 rand() 的输出是可预测的。

PHP 7.0 引入了 random_bytes 和 random_int 作为核心函数,解决了大多数随机数生成器存在的问题。

【讨论】:

那是错误的。首先,这不是问题,它是设计使然,像 rand() 这样的加密不安全函数通常比加密安全函数快,所以如果你不将它用于与安全相关的事情,最好使用非安全函数。您无法真正比​​较加密安全和加密不安全的功能,它们的用法确实不同。【参考方案5】:

我个人在使用 random_int 时没有遇到任何问题,但它应该与 try/catch 一起使用,因为如果无法收集足够的熵,它会引发异常。

【讨论】:

【参考方案6】:

补充Frédéric 响应,在PHP 8.0.3 中,random_int() 似乎比以前快了很多,使用他自己的代码示例。

与:

<?php
    echo "this will take 20 seconds\n\n";
    
    echo "generating random with 'rand' method\n";
    $s1=microtime(true);$c1=0;while(microtime(true)-$s1<10)rand(0,65535);$c1++;;
    $fc1 = number_format($c1 , 0, ',', '.');
    echo "generated: $fc1\n\n";
    
    echo "generating random with 'random_int' method\n";
    $s2=microtime(true);$c2=0;while(microtime(true)-$s2<10 random_int(0,65535);$c2++;;
    $fc2 = number_format($c2 , 0, ',', '.');
    echo "generated: $fc2\n\n"; 
?>

我得到了输出:

this will take 20 seconds

generating random with 'rand' method
generated: 48.423.988

generating random with 'random_int' method
generated: 30.843.067

在他的测试中,random_int()rand() 慢三倍以上。

在这些中,random_int() 仅比 rand() 慢 40%。

PS:我已将最大随机值从 9 增加到 65535 以供个人使用,似乎实际上提高了两种情况的速度。

【讨论】:

以上是关于PHP rand() 与 random_int()的主要内容,如果未能解决你的问题,请参考以下文章

php,rand()函数

PHP rand()和mt_rand()的区别

关于PHP中array_rand函数为啥不能只设置一个随机?

PHP获取随机数的函数rand()和mt_rand()

php的array_rand 函数在多次被执行后为啥会出现一样的结果?

php生成随机数mt_rand和rand