Генерация уникального 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 символов). Извините, математика не моя сильная сторона

6 ответов


21^6 = 85766121 возможностей.

использование БД и хранение используемых значений плохо. Если вы хотите подделать случайность, вы можете использовать следующее:

уменьшить до 19 возможных чисел и использовать тот факт, что группы порядка p^k, где p-нечетное простое число, всегда цикличны.

возьмите группу порядка 7^19, используя генератор Co-prime до 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 и случайности.
  • изменить rand to 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/

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


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