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

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

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

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

Если вы ограничены только 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 дорогостоящую функцию already_exists .

Здесь вы можете сделать это без хэшей или петель:

 $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) ); 

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

Вот что выглядит случайным и должно быть уникальным и иметь 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); 

Вы поняли эту идею.

Случайное буквенно-цифровое (базовое значение 36 = 0..9 + a..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 (минимальное базовое 10-символьное представление 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 

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

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

Я просто понял, что вышеприведенное может иногда возвращать повторяющиеся значения из-за первого аргумента mt_rand() , для того чтобы произвести уникальные результаты, нам нужно немного ограничить нашу базовую кодировку 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); 

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

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

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

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

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

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

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

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

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

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

 $random = substr(hash('md5',openssl_random_pseudo_bytes(32)),0,7); 

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

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

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

 md5( microtime() ); 

это мой любимый способ сделать это.

 $pretrimmedrandom = md5(uniqid(mt_rand(),true)); $trimmed = substr($pretrimmedrandom ,0,7); 

uniqid использует текущее время для создания уникальной случайной строки. результаты выглядят как «3f456yg».

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

 $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; $passwordlength = 7; for ($x = 1; $x <= $passwordlength; $x++) { $charlist .= $chars; } $temp_pw = substr( str_shuffle( $charlist ), 0, $passwordlength ); 
 substr(str_shuffle(md5(microtime())),rand(0,21),7); 

попробуй это

 echo $unique_key = substr(md5(rand(0, 1000000)), 0, 5); 

он даст строку длиной 5.

Используйте текст Коханы,

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

Например,

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

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

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

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

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