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