Это не должно быть значимых слов – больше похоже на случайное генерирование пароля, но улов – они должны быть уникальными. Я буду использовать это для какого-то кода пакета / продукта. Какой из лучших методов доступен? 🙂
Как правило, невозможно генерировать последовательности как с уникальными, так и с произвольными элементами: очевидно, чтобы быть уникальным, алгоритм должен учитывать ранее сгенерированные элементы в последовательности, поэтому следующие не будут случайными.
Поэтому лучше всего будет выявлять столкновения и просто повторять (что может быть очень дорого в вашем конкретном случае).
Если вы ограничены только 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);
Это оказалось более сложным, чем я изначально не пострадал, поскольку существует множество ограничений:
Если мы можем игнорировать любой из вышеперечисленных, было бы намного проще, и я уверен, что это может быть еще более оптимизировано, но, как я сказал, это скучно мне. Может быть, кто-то хотел бы забрать это, где я ушел. =) Я голоден! = S
Учитывая, что вы упоминаете здесь пароли, я предполагаю, что вам нужен безопасный метод (т. Е. Кто-то не должен угадывать чужой пароль, основываясь на знании любого другого пароля). Вы можете использовать следующее:
Если безопасность не является проблемой, шаги 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. Эта часть должна быть простой.