Создание уникального 6-значного кода

Я генерирую 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; 
  1. Является ли это надежным подходом к генерации кода?
  2. Сколько возможных перестановок было бы? (6 цифр кода из пула из 21 символа). Извините, математика не моя сильная сторона

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 миллиона кодов!

Чтобы сгенерировать их все (что займет некоторое время), посмотрите на выбранный ответ на этот вопрос: алгоритм, который будет принимать числа или слова и находить все возможные комбинации .

У меня была та же проблема, и я нашел очень впечатляющее решение с открытым исходным кодом:

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

Вы можете взять и использовать его, также стоит посмотреть в его исходный код, чтобы понять, что происходит под капотом.

Или … вы можете закодировать имя пользователя + datetime в md5 и сохранить в базе данных, это наверняка сгенерирует уникальный код;)