Генерируйте уникальные случайные алфавитно-цифровые символы, которые являются 7 символами долго

Это не должны быть значимые слова - больше как случайное поколение пароля, но выгода - они должны быть уникальными. Я буду использовать это для некоторого пакета / код продукта. Который является лучшим доступным методом?:)

6
задан Prasanth 9 May 2010 в 22:57
поделиться

12 ответов

Как правило, невозможно сгенерировать последовательности с уникальными и случайными элементами: очевидно, чтобы быть уникальным, алгоритм должен учитывать ранее сгенерированные элементы в последовательности, поэтому следующие не будут действительно случайными.

Поэтому лучше всего обнаружить коллизии и просто повторить попытку (что в вашем конкретном случае может оказаться очень дорогостоящим).

Если вы ограничены 7 символами, вы не можете многое сделать выше:

$allowed_chars = 'abcdefghijklmnopqrstuvwxz';
$allowed_count = strlen($allowed_chars);
$password = null;
$password_length = 7;

while($password === null || already_exists($password)) {
    $password = '';
    for($i = 0; $i < $password_length; ++$i) {
        $password .= $allowed_chars{mt_rand(0, $allowed_count - 1)};
    }
}

В конечном итоге это должно дать вам новый пароль.

Однако в подобных случаях, с которыми я сталкивался, я обычно выбираю больший размер пароля, который также является размером шестнадцатеричного представления популярной хеш-функции (например, md5 ). Тогда вы можете упростить себе задачу и уменьшить вероятность ошибок:

$password = time(); // even better if you have some other "random" input to use here

do {
    $password = md5(time().$password);
}
while (already_exists($password));

Это также имеет дополнительное преимущество, заключающееся в том, что пространство последовательности больше, следовательно, будет меньше коллизий. Вы можете выбрать размер хэш-функции в соответствии с ожидаемым количеством паролей, которые вы создадите в будущем, чтобы «гарантировать» низкую вероятность коллизии и, следовательно, меньше вызовов возможно дорогой функции already_exists .

6
ответ дан 17 December 2019 в 00:05
поделиться
$random = substr(hash('md5',openssl_random_pseudo_bytes(32)),0,7);
0
ответ дан 17 December 2019 в 00:05
поделиться

Вот что-то, что выглядит случайным, должно быть уникальным и содержать 7 символов на будущее:

echo base_convert(intval(microtime(true) * 10000), 10, 36);

Или немного больше случайность и менее уникальность (между 1000 и 10000 в секунду):

echo base_convert(mt_rand(1, 9) . intval(microtime(true) * 1000), 10, 36);

Или (уникальность между 100 и ] 10000 в секунду) - это, вероятно, лучший вариант:

echo base_convert(mt_rand(10, 99) . intval(microtime(true) * 100), 10, 36);

Или (уникальность между 10 и 10000 в секунду):

echo base_convert(mt_rand(100, 999) . intval(microtime(true) * 10), 10, 36);

Понятно.

1
ответ дан 17 December 2019 в 00:05
поделиться

+1 к комментарию @Michael Haren. Если пароли на вашем сайте не должны иметь ограничения на уникальность.

Если я пытаюсь использовать данный пароль и получаю ошибку, что я не могу его использовать, потому что он уже используется, то я знаю, что у какого-то пользователя в системе есть такой пароль. Если есть 1000 пользователей, мне нужно попробовать максимум 1000 других учетных записей, прежде чем я найду того, у кого есть этот пароль.

Не совсем ответ на ваш вопрос, но больше, чем комментарий. Поэтому я помечаю это CW.

0
ответ дан 17 December 2019 в 00:05
поделиться

Случайное буквенно-цифровое значение (основание 36 = 0..9 + ..z ) значение с 7 символами должно иметь представление по основанию 10 между 2176782336 и 78364164095 , следующий фрагмент доказывает это:

var_dump(base_convert('1000000', 36, 10));                   //  2176782336
var_dump(base_convert('zzzzzzz', 36, 10));                   // 78364164095

Для этого чтобы быть уникальными, мы должны полагаться на неповторяющийся фактор, очевидным выбором будет time () :

var_dump(time());                                            //  1273508728
var_dump(microtime(true));                                   //  1273508728.2883

Если бы мы только хотели гарантировать минимальный коэффициент уникальности 1 уникальный код в секунду, мы могли бы сделать :

var_dump(base_convert(time() * 2, 10, 36));                  // 164ff8w
var_dump(base_convert(time() * 2 + 1, 10, 36));              // 164ff8x
var_dump(base_convert(time() * 2 + 2, 10, 36));              // 164ff8y
var_dump(base_convert(time() * 2 + 3, 10, 36));              // 164ff8z

Вы заметите, что эти коды не случайны, вы также заметите, что time () ( 1273508728 ) меньше, чем 2176782336 (минимальное десятичное представление 7-символьного кода), поэтому я делаю time () * 2 .

Теперь давайте проведем математику даты, чтобы добавить случайности и увеличить коэффициент уникальности, соблюдая целочисленные ограничения старых версий PHP ( <5.0 ?):

var_dump(1 * 60 * 60);                                       //       3600
var_dump(1 * 60 * 60 * 24);                                  //      86400
var_dump(1 * 60 * 60 * 24 * 366);                            //   31622400
var_dump(1 * 60 * 60 * 24 * 366 * 10);                       //  316224000
var_dump(1 * 60 * 60 * 24 * 366 * 20);                       //  632448000
var_dump(1 * 60 * 60 * 24 * 366 * 30);                       //  948672000
var_dump(1 * 60 * 60 * 24 * 366 * 31);                       //  980294400
var_dump(PHP_INT_MAX);                                       // 2147483647

Что касается PHP_INT_MAX Я не уверен, что именно изменилось в последних версиях PHP, потому что следующее явно работает в PHP 5.3.1, возможно, кто-то сможет пролить свет на это :

var_dump(base_convert(PHP_INT_MAX, 10, 36));                 // zik0zj
var_dump(base_convert(PHP_INT_MAX + 1, 10, 36));             // zik0zk
var_dump(base_convert(PHP_INT_MAX + 2, 10, 36));             // zik0zl
var_dump(base_convert(PHP_INT_MAX * 2, 10, 36));             // 1z141z2
var_dump(base_convert(PHP_INT_MAX * 2 + 1, 10, 36));         // 1z141z3
var_dump(base_convert(PHP_INT_MAX * 2 + 2, 10, 36));         // 1z141z4

Я как бы заблудился с здесь мое объяснение, и мне скучно, поэтому я просто закончу очень быстро. Мы можем использовать почти всю кодировку base 36 и безопасно генерировать последовательных кодов с минимальным гарантированным коэффициентом уникальности 1 уникальный код в секунду для 3.16887646 лет , используя это:

base_convert(mt_rand(22, 782) . substr(time(), 2), 10, 36);

Я только что понял, что приведенное выше может иногда возвращать повторяющиеся значения из-за первого аргумента mt_rand () , чтобы получить уникальные результаты, нам нужно ограничить наш немного кодировки base 36:

base_convert(mt_rand(122, 782) . substr(time(), 2), 10, 36);

Помните, что приведенные выше значения по-прежнему являются последовательными, чтобы они выглядели случайными, мы можем использовать microtime () , но мы можем гарантировать только коэффициент уникальности 10 кодов в секунду в течение 3,8 месяцев :

base_convert(mt_rand(122, 782) . substr(number_format(microtime(true), 1, '', ''), 3), 10, 36);

Это оказалось сложнее, чем я первоначально предполагал, так как есть много ограничений:

  • использовать всю кодировку base 36
  • генерировать случайный вид коды
  • компромисс между коэффициентом уникальности в секунду и долговечностью уникальности
  • Целочисленные ограничения PHP

Если мы сможем игнорировать любое из вышеперечисленных, это будет намного проще, и я уверен, что это можно оптимизировать, но как я уже сказал: это мне скучно. Может, кто-то захочет забрать это там, где я оставил. знак равно Я голоден! = S

1
ответ дан 17 December 2019 в 00:05
поделиться

Вот как я мог бы решить эту проблему:

Учтите, что 7 символов могут быть одной из 26 букв (abc..z) или 10 цифр (01 ... 9). Это делает 36 возможных символов.

Каждый раз, когда ваше приложение генерирует новый код, заставляйте его увеличивать глобальную переменную. Вы можете превратить этот уникальный номер в уникальную строку, используя "шестнадцатеричный" преобразователь и добавив символы-заполнители, чтобы составить оставшуюся часть строки.

Взгляните на эту ссылку. Думаю, у этого парня была та же проблема, что и у вас: http://www.codemaxima.com/2010/04/the-hexatridecimal-numbering-system/

0
ответ дан 17 December 2019 в 00:05
поделиться

Вот способ, как это можно сделать без хэшей или циклов:

$password = sprintf(
    "%04s%03s",
    base_convert(mt_rand(0, pow(36, 4) - 1), 10, 36),
    base_convert(mt_rand(0, pow(36, 3) - 1), 10, 36)
);

Как уже говорили другие, обеспечение уникальности сложнее, и в нем нет необходимости. Самый простой способ - добавлять дополнительные символы в конце, увеличивая их количество с каждым сгенерированным паролем.

1
ответ дан 17 December 2019 в 00:05
поделиться

Учитывая, что вы упоминаете здесь пароли, я предполагаю, что вам нужен безопасный метод (т.е. может угадать чужой пароль на основе знания любого другого пароля). Вы можете использовать следующее:

  1. Выберите мастер-пароль, например «MasterPassword»
  2. Для каждого сгенерированного пароля добавьте к нему случайный или последовательный одноразовый номер , например «MasterPassword1», «МастерПароль2».
  3. Выполните криптографический хеш для этого (SHA, MD5 и т. Д.) И преобразуйте хэш в шестнадцатеричное представление, например, «ce7f181a44a4a5b7e43fe2b9a0b1f0c1».
  4. Сократите это число до необходимого количества символов - возможно, семи, как вы указали: «ce7f181».
  5. Проверьте, было ли это назначено ранее. Если нет, верните это как свой пароль. В противном случае повторите, начиная с 2.

Если безопасность не является проблемой, шагов 1 и 2 будет достаточно. Если безопасность является проблемой, важно, чтобы никто, кроме вас самих, не знал ценности MasterPassword.

0
ответ дан 17 December 2019 в 00:05
поделиться

Вот очень простой способ

$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$temp_pw = substr( str_shuffle( $chars ), 0, 7 );
if ( check_unique( $temp_pw ) ) {
    $pw = $temp_pw;
}

Вам придется реализовать свою собственную функцию check_unique. Эта часть должна быть легкой.

-1
ответ дан 17 December 2019 в 00:05
поделиться

Используйте текст Kohana,

http://docs.kohanaphp.com/helpers/text

Например,

   $prod_id = text::random('alpha', 7);

Если вы не хотите использовать фреймворк, вы можете просто скопировать код. Там вы найдете много полезного.

-1
ответ дан 17 December 2019 в 00:05
поделиться

Ответ Галена допускает только одно использование каждого символа в пароле. В этой строке не так много информации. Однако простое изменение:

$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$passwordlength = 7;
for ($x = 1; $x <= $passwordlength; $x++) {
  $charlist .= $chars;
}
$temp_pw = substr( str_shuffle( $charlist ), 0, $passwordlength );
0
ответ дан 17 December 2019 в 00:05
поделиться
md5( microtime() );
0
ответ дан 17 December 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: