8

I'm generating a 6 digit code from the following characters. These will be used to stamp on stickers.
They will be generated in batches of 10k or less (before printing) and I don't envisage there will ever be more than 1-2 million total (probably much less).
After I generate the batches of codes, I'll check the MySQL database of existing codes to ensure there are no duplicates.

// exclude problem chars: B8G6I1l0OQDS5Z2

$characters = 'ACEFHJKMNPRTUVWXY4937';

$string = '';

for ($i = 0; $i < 6; $i++) {
    $string .= $characters[rand(0, strlen($characters) - 1)];
}   

return $string;
  1. Is this a solid approach to generating the code?
  2. How many possible permutations would there be? (6 Digit code from pool of 21 characters). Sorry math isn't my strong point
4

6 回答 6

14

21^6 = 85766121 种可能性。

使用数据库并存储使用过的值是不好的。如果你想伪造随机性,你可以使用以下方法:

减少到 19 个可能的数字,并利用 p^k 阶组(其中 p 是奇素数)总是循环的事实。

以 7 ^ 19 阶的组为例,使用生成器与 7 ^ 19 互质(我会选择 13 ^ 11,你可以选择任何不能被 7 整除的东西)。

然后以下工作:

$previous = 0;

function generator($previous)
{

  $generator = pow(13,11);
  $modulus = pow(7,19); //int might be too small
  $possibleChars = "ACEFHJKMNPRTUVWXY49";

  $previous = ($previous + $generator) % $modulus;
  $output='';
  $temp = $previous;

  for($i = 0; $i < 6; $i++) {
    $output += $possibleChars[$temp % 19];
    $temp = $temp / 19;
  }

  return $output;
}

它将循环遍历所有可能的值,并且看起来有点随机,除非他们去挖掘。一个更安全的选择是乘法组,但我已经忘记了我的数学:(

于 2013-05-09T23:36:41.857 回答
7
  • 有很多可能的组合有或没有重复,所以你的逻辑就足够了
  • 碰撞会很频繁,因为您使用的是randstr_shuffle和 randomness
  • 更改randmt_rand
  • memcached检查时是否使用redisMySQL 之类的快速存储

完全的可能性

21 ^ 6 = 85,766,121

85,766,121应该没问题,要将数据库添加到这一代尝试:

例子

$prifix = "stamp.";

$cache = new Memcache();
$cache->addserver("127.0.0.1");

$stamp = myRand(6);
while($cache->get($prifix . $stamp)) {
    $stamp = myRand(6);
}
echo $stamp;

使用的功能

function myRand($no, $str = "", $chr = 'ACEFHJKMNPRTUVWXY4937') {
    $length = strlen($chr);
    while($no --) {
        $str .= $chr{mt_rand(0, $length- 1)};
    }
    return $str;
}
于 2013-05-09T23:39:28.583 回答
3

您将有 21 ^ 6 个代码 = 85 766 121 ~ 8580万个代码!

要全部生成它们(这将需要一些时间),请查看此问题的选定答案:将采用数字或单词并找到所有可能组合的算法

于 2013-05-09T23:36:05.973 回答
3

正如巴巴所说,即时生成字符串将导致大量碰撞。您越接近已经生成的 8000 万个字符串,就越难获得可用的字符串

另一种解决方案可能是一次生成所有可能的组合,并将它们中的每一个都存储在数据库中,并带有一些布尔列字段来标记是否已经使用了行/令牌

然后得到其中之一

SELECT * FROM tokens WHERE tokenIsUsed = 0 ORDER BY RAND() LIMIT 0,1

然后将其标记为已使用

UPDATE tokens SET tokenIsUsed = 1 WHERE token = ...
于 2013-05-10T00:10:07.143 回答
0

我遇到了同样的问题,我发现了非常令人印象深刻的开源解决方案:

http://www.hashids.org/php/

您可以使用它,也值得查看它的源代码以了解幕后发生的事情。

于 2013-06-15T22:54:51.880 回答
-2

或者...您可以在 md5 中编码用户名+日期时间并保存到数据库,这肯定会生成一个唯一的代码;)

于 2015-06-01T07:44:58.480 回答