【问题标题】:How unique is uniqid?uniqid 有多独特?
【发布时间】:2010-11-01 15:08:12
【问题描述】:

这个问题实际上并不是一个寻找解决方案的问题,它只是一个简单的好奇心问题。 PHP uniqid 函数有一个更熵标志,以使输出“更独特”。这让我想知道,当 more_entropy 为真时,这个函数产生相同结果的可能性有多大,而当它不是时。换句话说,启用 more_entropy 时 uniqid 与禁用时相比有多独特?一直启用 more_entropy 有什么缺点吗?

【问题讨论】:

  • 如果您想要始终独特的东西,您需要实现GUID。几乎所有其他东西最终都会发生碰撞,因为函数中只有这么多的熵。例如,uniqidmore_entropy提供大约 92 位熵(23 十六进制位)。要了解为什么这不利于唯一性,请参阅 The Birthday Problem...
  • @ircmaxell 感谢您指出生日问题,这很有趣。答案中应该明确提及。
  • uniqid() 不是哈希函数,因此生日问题不适用于它。但它确实有它的弱点。
  • @ircmaxell 这个数字是从哪里来的? more_entropy 大约是 30 位熵(九位十进制数字),微秒部分大约是 20(六位十进制数字),其余的从何而来?您需要从 100,000 年的范围中选择第二个才能获得 42 位熵。

标签: php


【解决方案1】:

2014 年 3 月更新:

首先,重要的是要注意uniqid 有点用词不当,因为它不能保证唯一的 ID。

根据PHP documentation

警告!

此函数不会创建随机或不可预测的字符串。这 功能不得用于安全目的。以加密方式使用 安全随机函数/生成器和加密安全哈希 创建不可预知的安全 ID 的函数。

此函数不会生成加密安全令牌,在 事实上没有被传递任何额外的参数返回值 与microtime() 略有不同。如果需要生成 加密安全令牌使用openssl_random_pseudo_bytes()


根据文档,将 more-entropy 设置为 true 会生成更独特的值,但执行时间会更长(尽管程度很小):

如果设置为 TRUE,uniqid() 将添加额外的熵(使用 组合线性同余生成器)在返回结束时 值,这增加了结果唯一的可能性。

请注意increases the likelihood that the result will be unique 这行,这不会保证唯一性。

您可以在一定程度上“无休止地”争取唯一性,并使用任意数量的加密例程进行增强,添加 salts 等 - 这取决于目的。

我建议查看有关 PHP 主要主题的 cmets,特别是:

http://www.php.net/manual/en/function.uniqid.php#96898

http://www.php.net/manual/en/function.uniqid.php#96549

http://www.php.net/manual/en/function.uniqid.php#95001

我建议弄清楚为什么你需要唯一性,是为了安全(即添加到加密/加扰例程中)?另外,它需要如何独一无二?最后,看看速度方面的考虑。适合性会随着基本考虑因素而改变。

【讨论】:

  • 这些函数 cmets 最重要的教训是,uuid 本身是一个非常危险的标识符,作为 cookie/客户端可读 ID 传递,但作为本地/受保护的唯一 ID,它有一些很好的用途,即速度。 2.5 美分。
  • 我不知道这是否很明显,但不要将uniqid(或其衍生物)用于与安全相关的任何事情。 PHP 提供了一整套加密安全的随机生成器,例如:openssl_random_pseudo_bytes。请为工作使用正确的工具。
  • 假设在同一微秒内没有保存 2 个文件,则每个文件的 unix 微秒时间戳都是唯一的。
  • 发生碰撞的可能性在统计上是不可能的,但并非不可能。将您的 uniqid 代放在 do{} while(collision) 中。例如,我在为上传的文件生成路径时使用这种方法。
  • 不知道为什么这个答案被接受了。唯一!= 随机/不可预测
【解决方案2】:

只有当您检查它们不存在时,它们才是唯一的。使用什么函数来生成“随机”字符串或 ID 并不重要——如果你不仔细检查它是否是重复的,那么总会有这样的机会.. ;)

虽然 uniqid 基于当前时间,但上述注意事项仍然适用 - 它仅取决于您将在何处使用这些“唯一 ID”。所有这一切的线索就是它说“更独特”的地方。独一无二的就是独一无二的。你怎么能拥有或多或少独特的东西,这让我有点困惑!

如上检查,并结合所有这些东西会让你最终得到一些接近唯一性的东西,但这一切都与键的使用位置和上下文有关。希望对您有所帮助!

【讨论】:

  • “发生碰撞的几率是万分之一”和“发生碰撞的变化小于程序的每个用户同时被闪电击中”。考虑到获得可证明(且不可预测)独特的东西的高昂成本,由具有良好种子的良好 RNG 生成的 128 位值非常接近“真正”独特,这并不重要。
  • 只是为了进一步说明您的观点@Michael:对于 128 位,您需要美国的每个人(3 亿)在大约一天的时间内每秒生成 100 万个数字,以获得 50% 的机会碰撞...对于 512 位,您需要地球上的每个物体(70 亿人)在接下来的10^47 年中每秒产生 1 万亿个数字,才能有 50% 的碰撞几率。 . 所以是的,只要随机数有足够大的上限和足够好的 RNG,你就可以只用随机性来模拟唯一性......
  • 我完全同意上述理想世界的例子。机会微乎其微。但是,在原始问题中提到的实现中,随机性并不完美,我认为,使用这个唯一数字的域很重要。如果你有 1000 台服务器,每台服务器都基于微时间做“唯一”ID,并假设它们是唯一的“只是因为”,那么在某些时候,你很可能会被烧毁。忽略代码中的任何怪癖..错误或其他任何东西。这里的区别在于现实和理论之间,这就是我们检查的原因;)
  • “通过简单地将 Bambleweeny 57 亚介子大脑的逻辑电路连接到悬挂在强大的布朗运动发生器中的原子矢量绘图仪(比如一个漂亮的热杯)来生成少量有限不可能性的原理茶)当然很好理解。”
  • @ircmaxell:问题是这些数字需要真正的随机性,因此是真正的RNG。您甚至无法使用具有 >128 位内部状态的 PRNG 来模拟它,除非您也有办法使用唯一/随机 >128 位值对其进行播种。但这正是您必须解决的问题!除此之外,几乎可以保证碰撞。那些同样的 3 亿人,如果他们使用他们编译器的糟糕库存rand(),那么在第一次迭代 时发生冲突的可能性将超过 90%。另外,如果您需要唯一性,即使是 0.001% 的碰撞几率也太大了。
【解决方案3】:

来自 PHP 手册网站上关于函数的讨论:

正如下面的其他人所说,没有前缀 并且没有“增加的熵”,这 函数只返回 UNIX 添加微秒的时间戳 计数器为十六进制数;更多或 不只是 microtime(),十六进制形式。

[...]

另外值得注意的是,由于 microtime() 仅适用于存在 gettimeofday() > 的系统,而 Windows 本身不支持,因此 uniqid() 在 Windows 环境中可能只产生单秒分辨率的 UNIX 时间戳。

换句话说,没有“more_entropy”,这个函数绝对是可怕的,永远不应该使用,句号。根据文档,该标志将使用“组合线性同余生成器”来“添加熵”。嗯,这是一个相当弱的RNG。所以我会完全跳过这个函数,并使用基于mt_rand 的东西,对于与安全无关的东西有一个很好的种子,而对于那些与安全相关的东西,则使用 SHA-256。

【讨论】:

    【解决方案4】:

    如果没有 more_unique 标志,它会返回带有微秒计数器的 unix 时间戳,因此如果两个调用在同一微秒内进行,那么它们将返回相同的“唯一”ID。

    从那里开始,这是一个可能性的问题。答案是,不是非常,但不是折扣程度。如果您需要一个唯一的 id 并且您经常生成它们(或使用其他地方生成的数据),不要指望它是绝对唯一的。

    【讨论】:

    • 信不信由你,它实际上调用了 usleep(1) 以确保永远不会发生!
    • @Eli 不确定是否是拖钓,但显然情况并非如此,因为我正在运行此操作:for($i=0; $i
    • @djule5 不,不是拖钓:github.com/php/php-src/blob/… 您可能正在运行一个非常旧的 PHP 版本,或者正在使用的平台不存在?
    • @Eli 有趣哈哈感谢来源!我正在运行 PHP 5.5.11,但我在这台开发机器上的 Windows 上......所以这可能解释了它!所以它在 Windows 上绝对不是独一无二的......
    • @user5542121 他们决定不调用 usleep 和轮询时间,因为 usleep “可能会导致内核调度另一个进程,导致大约 10 毫秒的暂停”~github.com/php/php-src/blob/PHP-7.2.12/ext/standard/…
    【解决方案5】:

    来自the source code的相关位是

    if (more_entropy) {
        uniqid = strpprintf(0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg() * 10);
    } else {
        uniqid = strpprintf(0, "%s%08x%05x", prefix, sec, usec);
    }
    

    所以more_entropy 添加了九个有点随机的十进制数字(php_combined_lcg()(0,1) 中返回一个值) - 这是 29.9 位的熵,最高(实际上可能更少,因为 LCG 不是加密安全的伪随机数生成器)。

    【讨论】:

      猜你喜欢
      • 2011-05-21
      • 2014-01-24
      • 1970-01-01
      • 1970-01-01
      • 2011-07-26
      • 1970-01-01
      • 2021-08-15
      • 2011-04-27
      相关资源
      最近更新 更多