我想在一个可能永远不会有超过 10,000 条记录的数据库表中使用 PHP 生成的唯一 ID。我不希望创建时间可见或使用纯数值,所以我使用:
sha1(uniqid(mt_rand(), true))
使用哈希作为唯一 ID 是错误的吗?不是所有的散列都会导致冲突,或者在这种情况下不应该考虑它们的可能性很小吗?
还有一点:如果要散列的字符数小于 sha1 散列中的字符数,它不总是唯一的吗?
如果您有 2 个密钥,则理论上的最佳情况是 2 ^ X 的碰撞概率,其中 X 是散列算法中的位数。“最佳情况”,因为输入通常是不使用完整字符集的 ASCII,加上散列函数分布不完美,因此它们在现实生活中的碰撞频率会超过理论上的最大值。
要回答你的最后一个问题:
还有一点:如果要散列的字符数小于 sha1 散列中的字符数,它不总是唯一的吗?
是的,这是真的。但是您会遇到另一个问题,即生成该大小的唯一键。最简单的方法通常是校验和,因此只需选择一个足够大的摘要,以使碰撞空间足够小以使您感到舒适。
正如@wayne 建议的那样,一种流行的方法是连接microtime()
到您的随机盐(并base64_encode
提高熵)。
使用 sha1(time()) 代替,然后您消除重复哈希的随机可能性,只要时间可以表示为比 sha1 哈希更短。(可能比你找到一个工作的 php 解析器要长;))
如果两个结局相同,那该有多可怕?墨菲定律适用——如果可以接受一百万比一甚至十万比一的机会,那么就继续吧!真正的机会要小得多——但如果你的系统一旦发生就会爆炸,那么你的设计缺陷必须首先得到解决。然后充满信心地进行。
计算机随机实际上并不是随机的,你知道吗?假设您在 Unix 环境中,您可以从计算机获得的唯一真正随机是 from /dev/random
,但这是一个阻塞操作,取决于用户交互,例如移动鼠标或在键盘上打字。读取/dev/urandom
不太安全,但它可能比仅使用 ASCII 字符更好,并为您提供即时响应。
sha1($ipAddress.time()) 导致任何人都不可能同时使用相同的 IP 地址