Как бы я начал генерировать это … Я хочу сохранить свой первичный ключ последовательным и иметь 12-значный уникальный контакт, сгенерированный для каждого нового объекта, добавленного в базу данных.
Причина, по которой это может быть просто автоинкремент, – я не хочу, чтобы последовательные числа были легко угаданы.
Он должен быть целым числом, потому что у меня будут коды подтверждения, которые необходимо набирать на клавиатуре телефона.
Используйте конкатенацию уникального инкрементированного числа и произвольно сгенерированного числа.
Уникальное инкрементное число гарантирует, что результат уникален, а случайно созданное число делает его едва ли допустимым.
Это просто и гарантирует отсутствие столкновения (1). Результат является инкрементным , частично случайным и непредсказуемым (при условии, что часть случайного числа генерируется с хорошим PRNG).
(1): вам нужно либо набирать id
либо random
с нулями, либо отделять их каким-либо несимметричным символом.
С MySQL db это означает:
CREATE TABLE foo ( id int not null auto_increment, random int not null, ... primary key (id) );
Возможно, вы можете использовать UUID_SHORT()
. Не более 12 цифр, но все же может быть жизнеспособным вариантом:
mysql> select uuid_short(); +-------------------+ | uuid_short() | +-------------------+ | 22048742962102272 | +-------------------+
Так:
INSERT INTO `table` (`id`, `text`) VALUES (UUID_SHORT(), 'hello world!');
Примечание. Если вы действительно хотите иметь ровно 12 цифр, тогда даже не пытайтесь подстроить результат, если бы не гарантировали уникальность идентификатора и могли вызвать конфликты.
<?php $allowed_characters = array(1,2,3,4,5,6,7,8,9,0); for($i = 1;$i <= 12; $i++){ $pass .= $allowed_characters[rand(0, count($allowed_characters) - 1)]; } echo $pass; ?>
Один из методов заключается в том, чтобы взять ваше первичное значение ключа, солить его несколькими другими случайными битами данных (имя пользователя, текущее время, идентификатор процесса, фиксированную строку и т. Д.) И хешировать его с помощью md5 или sha1. Затем вы берете хэш-строку и преобразуете ее в цифры посредством основных операций с строкой. Это даст вам относительно уникальный цифровой код.
конечно, всего 12 цифр, у вас гораздо больше шансов столкнуться с столкновением, чем с использованием хеш-строки raw, но поскольку вам требуется, чтобы это набиралось на клавиатуре, это приемлемый компромисс.
Если штыри недействительны / удалены после использования, вероятность столкновения будет значительно уменьшена.
Вы хотите две вещи
Если вы хотите, чтобы и то и другое происходило из одной последовательности, вам не удастся (буквально). Уникальность гарантируется наличием большого пространства выборки + случайным + check-unique. Это означает, что фактическое число может находиться где угодно между выборкой.
Но если вы хотите уникальное свойство + incremental, вы делите пространство выборки на 2. В 64 попытках вы уменьшили бы пространство с пробелами в 64 бит до 1 бит пространства выборки.
Удачи !
Вообще, я предпочту сделать что-то немного более низкотехнологичное. Я скрываю значения в PHP и оставляю их как автоинкремент в JS.
$seeds = array( /*series 100 of very large >= 10-digit numbers*/ ); $seedID = rand( count( $seeds ) ); // randomly choose one of those. // a string combination which represents the ID + some hash. $id = bcadd( $seeds[ $seedID ], /* id retrieved from database */ ); // make sure we've not accidentally passed the 10^12 point $id = bcmod( $id, 1000000000000 ); // make sure to pad $id = str_pad('' . $id, 3, "0", STR_PAD_LEFT); $outID = substr( $id, 0, 5 ) . $seedID . substr( $id, 6 );
Затем, при получении идентификатора от пользователя:
$seedID = substr( $outID, 6, 2 ); $tmpID = substr( $outID, 0, 5 ) . substr( $outID, 8 ); $id = bcsub( $tmpID, $seeds[ $seedID ] ); // we passed the modulus se we need to add this back in. if( $id < 0 ) $id = bcmod( bcadd( $id, 1000000000000 ), 1000000000000 );
Это в основном означает, что вы просто затушевываете любое количество, которое вы хотите – вы можете использовать auto_increment с безнаказанностью!
Все решения до сих пор не имеют ничего общего с вашим приложением: безопасность !
Вы сказали, что будете использовать эти цифры в качестве (товарного) кода проверки – так что вы действительно хотите, чтобы это было непредсказуемо, иначе оно будет эксплуатироваться.
Ни встроенная функция RANDOM
MySQL, ни какая-либо из случайных функций, предоставляемых PHP, сегодня являются безопасными случайными функциями. Они ведут себя псевдослучайно, хорошо, но все они предсказуемы!
Ваш единственный шанс – взломать что-то свое, используя /dev/urandom
на машине * nix или используя Crypto API в Windows. OpenSSL действительно обеспечивает безопасные случайные числа на основе этих механизмов – вы можете повторно использовать это либо в расширении C для PHP, либо путем чтения вывода из сценария командной строки, называемого PHP. См. Также этот ответ .
О вашем требовании о том, чтобы цифры были последовательными – это действительно так важно? Это усложняет ситуацию. В противном случае вам было бы неплохо пойти с простым безопасным 6-байтовым случайным числом, закодированным в строку с использованием шестнадцатеричной кодировки (с 12-символьной строкой). Хотя я бы рекомендовал сделать это 10 байт и 20 символов, чтобы быть более безопасным.
Но если вы хотите быть последовательным, который я интерпретирую как монотонно увеличивающийся (поскольку простой +1 будет тривиально предсказуемым), это делает вещи намного сложнее. И вы ничего не получаете от этой сложности, единственное, что может случиться, это то, что вы нарушаете безопасность, изобретая неясную схему, которую легко использовать.
Мое предложение: добавьте еще один столбец, который действует как простой старый автоматически увеличиваемый идентификатор и добавит код как случайное число, сконструированное, как указано выше, как отдельный столбец. Насколько я вижу, нет необходимости требовать, чтобы код активации продукта был идентификатором одновременно.