Я генерирую 6-значный код из следующих символов. Они будут использоваться для штамповки наклейки.
Они будут генерироваться партиями по 10 тыс. Или менее (до печати), и я не предполагаю, что их будет больше 1-2 миллионов (вероятно, гораздо меньше).
После того, как я создам пакеты кодов, я проверю базу данных MySQL на существующие коды, чтобы убедиться, что дубликатов нет.
// exclude problem chars: B8G6I1l0OQDS5Z2 $characters = 'ACEFHJKMNPRTUVWXY4937'; $string = ''; for ($i = 0; $i < 6; $i++) { $string .= $characters[rand(0, strlen($characters) - 1)]; } return $string;
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; }
Он будет проходить через все возможные значения и выглядеть немного случайным, если они не будут копать. Еще более безопасная альтернатива была бы мультипликативной группой, но я забыл свою математику уже 🙁
rand
видите str_shuffle и randomness . rand
на mt_rand
memcached
или redis
не MySQL при проверке Общая возможность
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; }
как сказал Баба, генерация струны «на лету» приведет к тонне коллизий. тем ближе вы отправитесь к 80 миллионам уже сгенерированных, тем сложнее будет получить доступную строку
другим решением может быть создание всех возможных комбинаций один раз и сохранение каждого из них в базе данных уже, с некоторым полем булевского столбца, которое отмечает, если строка / токен уже используется или нет
затем получить один из них
SELECT * FROM tokens WHERE tokenIsUsed = 0 ORDER BY RAND() LIMIT 0,1
и затем пометить его как уже использованный
UPDATE tokens SET tokenIsUsed = 1 WHERE token = ...
У вас было бы 21 ^ 6 кодов = 85 766 121 ~ 85,8 миллиона кодов!
Чтобы сгенерировать их все (что займет некоторое время), посмотрите на выбранный ответ на этот вопрос: алгоритм, который будет принимать числа или слова и находить все возможные комбинации .
У меня была та же проблема, и я нашел очень впечатляющее решение с открытым исходным кодом:
Вы можете взять и использовать его, также стоит посмотреть в его исходный код, чтобы понять, что происходит под капотом.
Или … вы можете закодировать имя пользователя + datetime в md5 и сохранить в базе данных, это наверняка сгенерирует уникальный код;)