【问题标题】:How to make sure my hashes are unique?如何确保我的哈希是唯一的?
【发布时间】:2017-05-11 08:33:36
【问题描述】:

我正在创建简短的 5 个字符散列来为我的学生打造独特的教室......典型的散列看起来像 AJ678

我正在生成这样的哈希:

public function generateToken($length = 5)
{
    return strtoupper(substr(md5(rand()), 0, $length));
}

我预计在应用程序的整个生命周期中会生成数千个教室...所以最终会发生冲突...我想知道如何确保每个哈希都是唯一的。

我已将 token 字段设为唯一字段。

我认为最好的方法是生成哈希,然后检查哈希是否已存在于我的数据库中,如果存在则生成新的哈希,否则使用哈希。

这是正确的做法吗?

编辑:我对实现一个调用自身的函数有点不安全......这看起来对吗?

public function generateToken($length = 5)
{
    $token = strtoupper(substr(md5(rand()), 0, $length));
    if ($this->tokenExistsAlready($token)) {
        $this->generateToken();
    } else {
        return $token;
    }
}

public function tokenExistsAlready()
{
    $this->db->where('token', $token);
    $query = $this->db->get('classes');
    if ($query->num_rows() > 0) {
        return true;
    } else {
        return false;
    }
}

【问题讨论】:

  • 如你所说,当它生成一个令牌时,检查它是否已经存在于数据库中,否则生成一个新的。
  • 我建议使用时间戳和 id(或您可能拥有的其他主键),您可能不会得到重复的令牌或检查 uniqid()
  • @Ian,我已经用一些代码更新了我的问题,不确定你是否熟悉 PHP……看起来对吗?
  • 看起来不错,但有一种稍微不同的方法可以节省您的查询:使您的令牌列唯一。用它执行你的 UPDATE/INSERT 指令,如果你收到一个违反约束的错误,再做一次。这样您就不必先检查。
  • 错误:您应该在递归调用中将$length 传回。否则,当要求 len 6 时,有些人会返回 len 5。

标签: php mysql hash token unique


【解决方案1】:

首先,定义“独特”。用我们的术语来说,唯一的是一个任意长度的字符串,它在您的数据库中尚不存在。

这几乎可以回答您的问题。您永远无法确定您的字符串是唯一的,除非您根据数据库对其进行检查。绳子越长,机会就越小。所以在你的情况下,我会创建一个while 循环检查数据库。从您保存在数据库中的第二个字符串开始,您可能(并且可能稍后会沿着时间线)连续命中两个随机生成的字符串。因此,在循环中检查唯一性直到找到“唯一”的唯一性是一个好主意。像这样抽象的东西:

$token = generateToken();

while(tokenExists($token))
{
    $token = generateToken();
}

请记住,nothing 可以保证字符串的真正唯一性。您可以使用 MySQL UUID()UUID_SHORT()、PHP uniqid() 或其他任何生成随机字符串的工具。但它仍然不能保证所述唯一性,除非您对照现有数据库进行检查。

【讨论】:

  • 没想到使用while循环...感谢您的回答。
  • 从您保存在数据库中的第二个字符串开始,您可能(并且可能稍后会沿着时间线)连续命中两个随机生成的字符串。所以在循环中检查唯一性是个好主意。
【解决方案2】:

使用 uniqid() 函数

public function generateToken($length = 5)
{
    return strtoupper(substr(uniqid(md5(rand()), 0, $length)));
}

【讨论】:

  • 嗨,阿米特,这似乎是一个很棒、简单的解决方案,我完全赞成。需要了解 uniqueid 的工作原理...我的意思是它如何知道我的数据库中已有的内容?
  • 这不会保证数据库中不存在 5 个字符的字符串,这就是问题所在。
  • @Thomas G,这种事情会让我在凌晨 3 点惊醒,一身冷汗。我正在截断 md5 哈希,这意味着发生冲突的可能性更高......所以如果 uniqueid 生成两个唯一字符串 abc123ksdrfhj 和 abc123lskkivm` 并且我截断到前 5 个字符,它们都将是 abc12,这对我来说会导致冲突。
  • 扩展我的评论:uniquid 基于微时间生成一个字符串,如果将其结果截断为 5 个字符,则无法保证足够的唯一性和熵。
  • 不要把事情复杂化。我和 Ian 一起讨论这个问题:生成,检查数据库中是否存在该值,如果存在则重复。这是使用 5char 字符串的最佳方法。
【解决方案3】:

令牌可以只是一个唯一的整数吗?使用具有单个 AUTO_INCREMENT 列的表很容易生成。

【讨论】:

    猜你喜欢
    • 2011-02-15
    • 2015-07-27
    • 2019-02-03
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 2016-12-10
    相关资源
    最近更新 更多