【问题标题】:PHP Random string generation miraculously generated the same stringPHP随机字符串生成奇迹般地生成了相同的字符串
【发布时间】:2019-12-25 00:50:10
【问题描述】:

所以我在 PHP 中有一个相当简单的函数,它可以呈现 10 个字符长的订单 ID:

function createReference($length = 10)
    {
        $characters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789';
        $string = '';
        for ($i = 0; $i < $length; $i++) {
            $string .= $characters[rand(0, strlen($characters) - 1)];
        }
        return $string;
    }

但是,今天在第 154020 条表记录上,它生成了与之前的订单 ID(即表中的第 144258 条记录)相同的 10 个字符的 ID,并尝试插入它。由于我对该列有UNIQUE 限制,因此我收到了一个错误并收到了来自该列的通知。

根据我的计算,上面的脚本创建了34^10 = 2.064.377.754.059.776不同的可能性。

我读过一些关于 rand()mt_rand() 做不同事情的东西,但这不应该是 PHP 7.1+ 的问题。该脚本在PHP 7.3 上运行。

那么我现在应该买彩票吗,或者这里使用的伪随机性有什么可预测的吗?如果是这样,有什么解决方案可以更好地分配?

【问题讨论】:

  • 不太可能的事情偶尔会发生。
  • @Barmar 这不是使用rand()(非加密安全)和random_int()(加密安全)之间的区别吗?我一直在阅读一些关于加密安全 RNG 的内容,也许 rand() 函数更有可能重新生成相同的数字集。
  • 这当然是可能的。

标签: php random


【解决方案1】:

假设rand()是一个真正的RNG,那么在达到比所有可能性的平方根多一点后,产生重复的预期机会达到50%(有关更精确的陈述和公式,请参阅“Birthday problem”) . 34^10 的平方根是 45435424,因此远高于 144258,但当然,rand() 远非完美或“真正的”RNG。

无论如何,使用randmt_rand(而不是像random_int 这样的加密RNG)生成唯一的随机标识符无论如何都是一个坏主意。根据 ID 是否必须难以猜测,或者仅 ID 是否足以授予对资源的访问权限,使用自动递增的记录号而不是随机数可能是更好的主意,也可能不是更好的主意。请参阅我的“Unique Random Identifiers”部分了解更多注意事项。

另见this question

【讨论】:

  • 谢谢,我已经预感到random_int。我现在已将函数更改为使用random_int。我生成的唯一字符串仅用作用户可读的订单 ID,而没有透露有关先前订单数量的任何详细信息。我会看看你的资源,非常有趣的东西 PHP 的 array_rand() 如何使用可能导致类似问题的非 CSPRNG。
猜你喜欢
  • 1970-01-01
  • 2011-05-20
  • 1970-01-01
  • 2017-08-01
  • 2011-06-30
  • 2010-11-10
相关资源
最近更新 更多