为啥 PHP 的 uniqid 函数只返回 13 位而不是 14?

Posted

技术标签:

【中文标题】为啥 PHP 的 uniqid 函数只返回 13 位而不是 14?【英文标题】:Why does PHPs uniqid function return only 13 digits and not 14?为什么 PHP 的 uniqid 函数只返回 13 位而不是 14? 【发布时间】:2011-01-29 04:42:27 【问题描述】:

uniqid() 函数返回一个 13 位长的十六进制数。根据spec in php.net site,函数使用microtime生成唯一值。

microtime 以字符串格式返回数字,如下所示:

"0.70352700 12689396875"

基本上是微秒和自 1970 年以来经过的秒数。 这是一个 9+11 位的十进制数。

将 20 位十进制数转换为十六进制会导致 16 位十六进制而不是 13 位。

我也想过去掉“0”。似乎永远不会改变的部分,以及似乎始终保持“00”的微秒部分的最后两位数字。这样做,十进制数只有 9+11-3 位长,但仍然将 17 位十进制数转换为十六进制会导致 14 位十六进制数不是 13。

我对以其他方式获得唯一 ID 或更长/更短的唯一 ID 不感兴趣!我只是问是否有人知道为什么 uniqid 只返回 13 位数字。

似乎很废话:如果uniqid返回的结果比microtime少一位,这意味着microtime给出的结果比uniqid返回的结果更独特

【问题讨论】:

你应该使用 more_entropy 选项,它会给你一个更独特的结果。 不需要更多唯一性,我需要知道为什么结果只有 13 个字符长。无论如何感谢您的建议。 微时间中最重要的部分根本不经常出现。因此,当您尝试在几毫秒内生成两个唯一的字符串时,它们毫无用处。下周的所有时间戳都将从 126 开始。而且,如果您设法在同一微秒内调用 uniqid() 两次(无论是在两个不同的线程中还是在两个不同的服务器中),您会发现它的结果不会很独一无二。 如果你真的想知道为什么它是 13 个字符,下载并阅读源代码 @Powerlord:我必须全部写成大写粗体,因为每个人都在回答我的问题,向我解释获得唯一 ID 的其他方法。我只是想让它更清楚。 【参考方案1】:

在http://www.php.net/manual/en/function.uniqid.php#95001找到这个

对我来说很有意义。如果您需要解释,请发表评论

作为记录,基础 uniqid() 的函数似乎是 大致如下:

$m=微时间(真); sprintf("%8x%05x\n",floor($m),($m-floor($m))*1000000);

换句话说,前 8 个十六进制字符 = Unixtime,最后 5 个十六进制字符 = 微秒。这就是为什么它有 微秒精度。还有,它 提供了一种手段 对时间进行逆向工程 uniqid 已生成:

date("r",hexdec(substr(uniqid(),0,8)));

随着你往下走越来越多 字符串,数字变为“更多 独特的”随着时间的推移,除了 数字 9,其中数字流行 是 0..3>4>5..f,因为 10^6 和 16^5 之间的差异(这个 其余的可能是正确的 数字也是如此,但要少得多 明显)。

【讨论】:

【参考方案2】:

我认为uniqid 生成的数字基于当前时间(以微秒为单位)——但不是那个时间:计算可能比你想象的要难一些。

不过,如果您需要超过 13 位数字,您可以将 true 作为第二个参数传递给 uniqid,以获得更多的熵 - 它会为您提供一个 23 个字符长的字符串。

例如,使用这部分代码:

var_dump(uniqid());
var_dump(uniqid('', true));

我刚刚得到:

string '4ba284384e4ca' (length=13)
string '4ba284384e4df9.73439132' (length=23)

【讨论】:

这不能回答我的问题,关键仍然是为什么 uniqid 函数返回一个只有 13 个字符长的值。由于缺少一个数字,它不能像 microtime() 函数那样独特。无论如何感谢您的建议。 直到 2106 年 2 月上旬,Unix 时间戳的秒数可以“适合”在 8 个十六进制字符内((十六进制)FFFFFFFF 是(十进制)4294967295)。一微秒是百万分之一秒,所以最大的微秒值是999999(任何更大的,它将是下一个整秒)或十六进制的F423F。所以:13 个十六进制字符来表示 Unix 时间到微秒。【参考方案3】:

对于 32 个字符的唯一 ID,请尝试以下操作:

$unique = uniqid(rand(), true);

要缩短它,只需使用 substr():

$unique = substr(uniqid(rand(), true), 16, 16); // 16 characters long

【讨论】:

这不会严重影响重复的机会吗? 机会仍然非常小,几乎不可能发生。但是,如果目标是确保最大的唯一性,则应使用整个 MD5。 您正在添加字符,但会减少熵和唯一性。 md5 不是抗碰撞的,不应该用于此【参考方案4】:

根据 PHP 手册,默认值为 13,将 $more_entropy 设置为 true,它将为 23,但您始终会得到一个 Unix 时间戳。

我经常用$uid = md5( uniqid() );

更新: 现在这将为您提供 32 个字符,并且在此生中碰撞的可能性最小。

md5(uniqid(mt_rand(), true)); 

【讨论】:

md5() 根本没有引入任何熵。如果有的话,它会删除一点,因为哈希冲突的可能性很小。 md5 不是抗碰撞的,不应该用于此 对不起,我完全忘了添加完整的例子 md5(uniqid(mt_rand(), true)); uniqid 是熵更多的那个。

以上是关于为啥 PHP 的 uniqid 函数只返回 13 位而不是 14?的主要内容,如果未能解决你的问题,请参考以下文章

探索 PHP 生成全局唯一的 id

使用PHP内置函数 uniqid 和Md5可以生成一个唯一的ID

PHP生成唯一ID的三种方法

PHP uniqid 高并发生成不重复唯一ID

PHP uniqid 高并发生成不重复唯一ID

javascript / jquery中的uniqid()?