uniqid有多独特?


76

这个问题实际上并不是寻找解决方案的问题,而仅仅是出于好奇。PHP uniqid函数具有一个更熵的标志,以使输出“更唯一”。这让我想知道,当more_entropy为true时(而不是true时),此函数多次产生相同结果的可能性有多大。换句话说,启用more_entropy时与禁用时相比,uniqid的唯一性如何?始终启用more_entropy是否有任何弊端?


3
如果您想要始终唯一的东西,则需要实现GUID。由于函数中只有太多的熵,因此几乎所有其他东西最终都会发生冲突。例如,uniqidmore_entropy集给出熵的约92位(23个hexbits)。要了解为什么这样做不利于独特性,请参见《生日问题...》
ircmaxell,2010年

@ircmaxell感谢您指出生日问题,这很有趣。在答案中应该明确提及。
彼得·佩勒

2
uniqid()不是哈希函数,因此生日问题不适用于它。它确实有其漏洞。
乔尔·梅隆

@ircmaxell这个数字从哪里来?more_entropy大约是30位的熵(九位十进制数字),微秒部分大约是20位(六位十进制数字),其余部分从何而来?您需要从100,000年的范围内选择第二个,以获得42位的熵。
Tgr 2016年

Answers:


36

2014年3月更新:

首先,必须注意这uniqid是一个误称,因为它不能保证唯一的ID。

根据PHP文档

警告!

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

此函数不会生成加密安全的令牌,实际上,如果未传递任何其他参数,则返回值与microtime()几乎没有什么不同。如果您需要生成加密安全的令牌,请使用openssl_random_pseudo_bytes()


根据文档,将更多熵设置为true会生成一个更唯一的值,但是执行时间更长(尽管程度很小):

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

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

您可以“无限地”争取唯一性,并使用任意数量的加密例程,添加等来增强它-这取决于目的。

我建议您查看有关主要PHP主题的评论,尤其是:

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

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

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

我建议您弄清楚为什么需要唯一性,这是出于安全性考虑(例如,添加到加密/加扰例程中)?另外,它需要有多独特?最后,看一下速度注意事项。适应性将随着基本注意事项而变化。


1
这些函数注释中最重要的一课是,uuid本身是一个非常危险的标识符,以cookie /客户端可读的ID形式传递,但是作为本地/受保护的唯一ID,它具有一些良好的用途,即速度。2.5美分
DrPerdix

3
我不知道这是否很明显,但不要将uniqid(或它的派生)用于与安全相关的任何事情。PHP提供了很多加密安全的随机生成器,例如:openssl_random_pseudo_bytes。请使用正确的工具进行作业。
Halcyon

1
假设在同一微秒中没有保存2个文件,则每个文件的unix微秒时间戳将是唯一的。
CMCDragonkai 2014年

从统计上讲,您不会发生碰撞,但并非不可能。把你的uniqid代内do{} while(collision)。例如,当生成上载文件的路径时,我会使用这种方法。
afilina

2
不知道为什么这个答案被接受。唯一!=随机/不可预测
gadelat '16

16

只有当您检查事物还不存在时,它们才是唯一的。用来生成“随机”字符串或ID的函数无关紧要-如果您不仔细检查它是否不是重复项,那么总会有这种机会。

尽管uniqid是基于当前时间的,但上面的注意事项仍然适用-它仅取决于您将在哪里使用这些“唯一ID”。这一切的线索是它说“更加独特”。独特就是独特。您如何拥有或多或少独特的东西,这让我有些困惑!

如上进行检查,并将所有这些东西组合在一起,将使您最终获得接近唯一性的东西,但其全部与使用键的位置和上下文有关。希望有帮助!


10
在“发生碰撞的机会是万分之一”和“发生碰撞的变化小于同时被闪电击中的程序的每个用户”之间存在巨大差异。考虑到获得可证明的(和不可预测的)独特性的高昂成本,由具有良好种子的优质RNG生成的128位值非常接近“真正”独特。
Michael Borgwardt 2010年

6
为了进一步说明您的观点,@ Michael:对于128位,您需要美国每个人(3亿)在一天左右的时间内每秒产生100万个数字,才能有50%的碰撞机会...对于512比特,您需要地球上的每个人(70亿人口)在未来10^47几年中每秒产生1万亿个数字,才有50%的机会发生碰撞...所以是的,具有足够大的上限在随机数和足够好的RNG上,您可以只用随机性来模拟唯一性...
ircmaxell,2010年

1
我完全同意您上述理想的例子。机会很小。但是,在原始问题中提到的实现中,随机性并不完美,我认为使用此唯一数字的领域很重要。如果您有1000台服务器基于微时间执行“唯一” ID,并假设它们是唯一的“仅因为”,那么到某个时候,您很可能会被淘汰。忽略代码中的任何怪癖,错误或任何其他问题。这里的区别是现实与理论之间的区别,这就是我们检查的原因;)
dmp 2010年

5
“通过简单地将Bambleweeny 57子介子脑的逻辑电路连接到悬挂在强大的Brownian Motion生产器中的原子矢量绘图仪(例如,一杯热茶),产生少量有限不可能的原理当然是众所周知的。”
dmp 2010年

1
@ircmaxell:问题是这些数字需要真正的随机性,因此也需要真正的RNG。您甚至无法使用内部状态> 128位的PRNG对其进行仿真,除非您还可以通过> 128位的唯一/随机值为它播种。但这就是您必须解决的问题!除此之外,几乎可以保证碰撞。如果这三亿人使用他们的编译器笨拙的股票rand(),那么他们在第一次迭代中就有90%以上的机会发生碰撞。另外,如果您需要独特性,甚至.001%的碰撞几率也太大。
cHao 2013年

10

从PHP手册站点上有关该函数的讨论:

如下所述,没有前缀,也没有“加熵”,此函数仅返回UNIX时间戳,并以十六进制数字形式添加微秒计数器。它或多或少是microtime(),为十六进制格式。

[...]

另外值得一提的是,由于microtime()仅适用于具有gettimeofday()> present的系统,而Windows本机不支持,因此uniqid()在Windows环境中可能仅产生一秒分辨率的UNIX时间戳。

换句话说,如果没有“ more_entropy”,该函数绝对是可怕的,绝对不能使用。根据文档,该标志将使用“组合线性同余生成器”来“添加熵”。好吧,这是一个相当弱的RNG。因此,我将完全跳过此功能,对与安全无关的事物使用基于mt_rand的种子,并为其提供良好的种子,而对与安全无关的事物使用SHA-256。


7

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

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


21
信不信由你,它实际上调用usleep(1)来确保永远不会发生!
伊莱

2
@Eli不知道是否拖钓,但是显然不是这样,因为我正在运行此命令重复:for($ i = 0; $ i <10; $ i ++)echo uniqid()。“ \ n”;
djule5 2014年

3
@ djule5不,不是拖钓:github.com/php/php-src/blob / ...您是否正在运行旧版本的PHP或是否不存在用于usleep的平台?
伊莱2014年

@Eli有趣的哈哈谢谢你的出处!我正在运行PHP 5.5.11,但是我在Windows上的这台开发机上...所以大概可以解释一下!因此,它在Windows上肯定不那么独特...
djule5

1
@ user5542121他们决定不调用usleep和轮询时间,因为usleep“可能导致内核安排另一个进程,导致大约10ms的暂停” 〜github.com/php/php-src/blob/PHP-7.2.12/ ext / standard /…
x3ns

5

源代码中的相关位是

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增加了9个有点随机的十进制数字(php_combined_lcg()返回的值(0,1))-熵的29.9位,最高(实际上可能更少,因为LCG并不是安全加密的伪随机数生成器)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.