【问题标题】:Generating unique codes in PHP/MySQL?在 PHP/MySQL 中生成唯一代码?
【发布时间】:2010-09-18 04:22:10
【问题描述】:

我正在与需要生成数百万个用于杂志刮刮卡、瓶盖奖品等的字母数字代码的客户合作。它们必须足够短才能打印在帽子上,它们要确保不包括像 1 和 I、0 和 O 等模棱两可的字符,并且必须明确存储它们以供将来使用——我们可以当有人试图赎回一个时,它只有一个确定“有效性”的算法。最后,他们希望确保代码随机分布在一个大的“代码空间”内,这样人们就不能只通过字母表来猜测其他代码。

是否有任何关于生成此类代码集的合理有效算法的指针?我在信封背面刮了几下,但这个问题闻起来就像是粗心大意的陷阱。

【问题讨论】:

    标签: php mysql random generator serial-number


    【解决方案1】:

    假设您可以使用一个字符集,例如 40 个明确的大写、小写和数字字符。

    对于 n 个字符的序列,您有 40n 个组合

    • 404 = 2,560,000
    • 405 = 102,400,000
    • 406 = 4,096,000,000
    • 407 = 163,840,000,000
    • 408 = 6,553,600,000,000

    因此 8 个字符提供了一个很好的工作空间 - 如果您生成 1000 万个代码,则必须尝试数十万种组合才能暴力破解代码。

    或者你从另一个方向来 - 给出可能代码的数量,应该你生成多少代码以避免他们称之为Birthday Paradox的陷阱?

    使用 8 个字符的代码,6,553,600,000,000 大约是 242,因此您可以合理地从中生成 221 个代码,或 2,097,152

    【讨论】:

      【解决方案2】:

      如果您需要大约 1000 万个唯一键(例如),最好的方法是选择一个指数级更大的键空间,然后开始随机生成。阅读Birthday Paradox——这是您应该担心的主要问题。如果您想要 2^n 个唯一且安全的密钥,请确保至少有 2^(2 * n) 个可能的值。这是一个粗略的 O(n log n) 算法:

      • 使用至少 2^50 的键空间(也就是说,允许 2^50 个可能的唯一值),您的整个数据集中几乎不会发生任何冲突 - 任何强行使用您的键的人都会如果他们尝试其中的 2^25 次,获得钥匙的几率几乎是偶数。
      • 根据需要生成任意数量的随机数
      • 根据您的键为数据库建立索引(这是 O(n lg n) 步骤:排序)
      • 翻阅数据库并遍历整个数据集以修剪重复项(下面的伪代码)
      • 删除重复的行,大功告成。

      伪代码:

      $last = null;
      while ($current = getnext()) {
          if ($last == $current) {
              push($toDelete, $current);
          }
          $last = $current;
      }
      

      【讨论】:

      • 我的目标是专门避免这种情况,因此您不必在插入时对每一行进行唯一性检查。相反,您可以插入完整的数据列表并在 O(n lg n) 中对其进行一次排序。除非数据库在小于 O(lg n) 的时间内验证您的唯一键,否则您想要一个未索引的数据库。
      【解决方案3】:

      使用一次性密码算法?

      RFC4225 详细介绍了一种基于 HMAC 算法的方法。

      http://www.ietf.org/rfc/rfc4226.txt

      但不是使用 0-9 位 base10 编码,而是使用 base32。

      【讨论】:

        【解决方案4】:

        无论您使用哪种方法,我都建议您添加一个或两个校验位,作为防止人们误输入或试图发明数字的“第一道”防御。

        【讨论】:

          【解决方案5】:

          奇怪的是,使用以下种子我只能生成 32 个唯一字符串。

          ABCDEFGHJKLMNPQRSTUVWXYZ23456789

          使用更长的种子,我能够生成更多——成功生成了 40,000 个唯一字符串。

          ABCDEFGHJKLMNPQRSTUVWXYZ234567892345678923456789ABCDEFGHJKLMNPQRSTUVWXYZ234567892345678923456789ABCDEFGHJKLMNPQRSTUVWXYZ234567892345678923456789

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-19
            • 1970-01-01
            • 2012-03-28
            • 1970-01-01
            • 2023-03-22
            • 2013-05-04
            相关资源
            最近更新 更多