php 生成唯一的 6 位代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16472862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generating unique 6 digit code
提问by Quad6
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.
我正在从以下字符生成一个 6 位代码。这些将用于在贴纸上盖章。
它们将以 10k 或更少的批次生成(打印前),我不认为总数会超过 1-200 万(可能更少)。
批量生成代码后,我会检查现有代码的MySQL数据库,以确保没有重复。
// exclude problem chars: B8G6I1l0OQDS5Z2
$characters = 'ACEFHJKMNPRTUVWXY4937';
$string = '';
for ($i = 0; $i < 6; $i++) {
$string .= $characters[rand(0, strlen($characters) - 1)];
}
return $string;
- Is this a solid approach to generating the code?
- How many possible permutations would there be? (6 Digit code from pool of 21 characters). Sorry math isn't my strong point
- 这是生成代码的可靠方法吗?
- 有多少种可能的排列?(来自 21 个字符池的 6 位代码)。抱歉数学不是我的强项
回答by Jean-Bernard Pellerin
21^6 = 85766121 possibilities.
21^6 = 85766121 种可能性。
Using a DB and storing used values is bad. If you want to fake randomness you can use the following:
使用数据库并存储使用过的值是不好的。如果你想伪造随机性,你可以使用以下方法:
Reduce to 19 possible numbers and make use of the fact that groups of order p^k where p is an odd prime are always cyclic.
减少到 19 个可能的数字,并利用 p^k 阶组(其中 p 是奇素数)始终是循环的这一事实。
Take the group of order 7^19, using a generator co-prime to 7^19 (I'll pick 13^11, you can choose anything not divisible by 7).
取 7^19 阶的组,使用生成器与 7^19 互质(我会选择 13^11,你可以选择任何不能被 7 整除的东西)。
Then the following works:
然后以下工作:
$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;
}
It will cycle through all possible values and look a little random unless they go digging. An even safer alternative would be multiplicative groups but I forget my math already :(
它会循环遍历所有可能的值并且看起来有点随机,除非他们去挖掘。一个更安全的选择是乘法组,但我已经忘记了我的数学:(
回答by Baba
- There is a lot of possible combination with or without repetition so your logic would be sufficient
- Collision would be frequent because you are using
rand
see str_shuffle and randomness. - Change
rand
tomt_rand
- Use fast storage like
memcached
orredis
not MySQL when checking
- 有很多可能的组合有或没有重复,所以你的逻辑就足够了
- 冲突会很频繁,因为您正在使用
rand
see str_shuffle 和 randomness。 - 更改
rand
为mt_rand
- 使用快速存储像
memcached
或redis
检查时没有的MySQL
Total Possibility
完全的可能性
21 ^ 6 = 85,766,121
85,766,121
should be ok , To add database to this generation try:
85,766,121
应该没问题,要将数据库添加到这一代尝试:
Example
例子
$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 Used
使用的功能
function myRand($no, $str = "", $chr = 'ACEFHJKMNPRTUVWXY4937') {
$length = strlen($chr);
while($no --) {
$str .= $chr{mt_rand(0, $length- 1)};
}
return $str;
}
回答by Baba
as Baba said generating a string on the fly will result in tons of collisions. the closer you will go to 80 millions already generated ones the harder it will became to get an available string
正如 Baba 所说,动态生成一个字符串会导致大量的碰撞。越接近已经生成的 8000 万个字符串,获得可用字符串的难度就越大
another solution could be to generate all possible combinations once, and store each of them in the database already, with some boolean column field that marks if a row/token is already used or not
另一种解决方案可能是一次生成所有可能的组合,并将它们中的每一个都存储在数据库中,并使用一些布尔列字段来标记行/令牌是否已被使用
then to get one of them
然后得到其中之一
SELECT * FROM tokens WHERE tokenIsUsed = 0 ORDER BY RAND() LIMIT 0,1
and then mark it as already used
然后将其标记为已使用
UPDATE tokens SET tokenIsUsed = 1 WHERE token = ...
回答by silkfire
You would have 21 ^ 6 codes = 85 766 121 ~ 85.8million codes!
您将有 21 ^ 6 个代码 = 85 766 121 ~ 8580万个代码!
To generate them all (which would take some time), look at the selected answer to this question: algorithm that will take numbers or words and find all possible combinations.
要全部生成它们(这需要一些时间),请查看此问题的选定答案:将采用数字或单词并找到所有可能组合的算法。
回答by Tamás Pap
I had the same problem, and I found very impressive open source solution:
我遇到了同样的问题,我发现了非常令人印象深刻的开源解决方案:
You can take and use it, also it's worth it to look in it's source code to understand what's happening under the hood.
您可以获取并使用它,也值得查看它的源代码以了解幕后发生的事情。
回答by Ionut Ionete
Or... you can encode username+datetime in md5 and save to database, this for sure will generate an unique code ;)
或者...您可以在 md5 中对用户名+日期时间进行编码并保存到数据库中,这肯定会生成一个唯一的代码;)