为啥 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?的主要内容,如果未能解决你的问题,请参考以下文章