Как создать случайную строку с помощью PHP?
Я знаю, что функция rand в PHP генерирует случайные целые числа, но каков наилучший способ генерации случайной строки, такой как:
исходная строка, 9 символов
$string = 'abcdefghi';
пример случайной строки, ограничивающейся 6 символами
$string = 'ibfeca';
обновление: я нашел тонны этих типов функции, в основном я пытаюсь понять логику каждого шага.
обновление: функция должна генерировать любое количество символы по мере необходимости.
пожалуйста, прокомментируйте детали, если вы ответите.
17 ответов:
Ну, вы не уточнили все вопросы, которые я задал в своем комментарии, но я предполагаю, что вы хотите, чтобы функция, которая может принимать строку "возможных" символов и длину строки для возврата. Прокомментировал тщательно, как просили, используя больше переменных, чем я обычно, для ясности:
function get_random_string($valid_chars, $length) { // start with an empty random string $random_string = ""; // count the number of chars in the valid chars string so we know how many choices we have $num_valid_chars = strlen($valid_chars); // repeat the steps until we've created a string of the right length for ($i = 0; $i < $length; $i++) { // pick a random number from 1 up to the number of valid chars $random_pick = mt_rand(1, $num_valid_chars); // take the random character out of the string of valid chars // subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1 $random_char = $valid_chars[$random_pick-1]; // add the randomly-chosen char onto the end of our string so far $random_string .= $random_char; } // return our finished random string return $random_string; }
чтобы вызвать эту функцию с вашими данными примера, вы бы назвали это что-то вроде:
$original_string = 'abcdefghi'; $random_string = get_random_string($original_string, 6);
обратите внимание, что эта функция не проверяет уникальность в допустимых символах передаваемый ему. Например, если вы вызвали его с допустимой строкой символов
'AAAB'
, это было бы в три раза более вероятно, чтобы выбрать A для каждой буквы в качестве B. Что может рассматриваться как ошибка или функция, в зависимости от ваших потребностей.
если вы хотите разрешить повторные вхождения символов, вы можете использовать эту функцию:
function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { $str = ''; $count = strlen($charset); while ($length--) { $str .= $charset[mt_rand(0, $count-1)]; } return $str; }
основной алгоритм заключается в создании длина> раз случайное число между 0 и количество символов> - 1 мы используем в качестве индекса, чтобы выбрать символ из нашего набора и объединить эти символы. 0 и количество символов> - 1 границы представляют границы
$charset
строка в качестве первого символа адресуется с$charset[0]
и последнее с$charset[count($charset) - 1]
.
Итак, позвольте мне начать с того, что ИСПОЛЬЗУЙТЕ БИБЛИОТЕКУ. Многие существуют:
суть проблемы заключается в том, что почти каждый ответ на этой странице подвержен атаке.
mt_rand()
,rand()
,lcg_value()
иuniqid()
все уязвим для атак.хорошая система будет использовать
/dev/urandom
из файловой системы, илиmcrypt_create_iv()
(СMCRYPT_DEV_URANDOM
) илиopenssl_pseudo_random_bytes()
. Что все вышеперечисленное и делает. PHP 7 будет поставляться с двумя новыми функциямиrandom_bytes($len)
иrandom_int($min, $max)
это тоже безопасно.имейте в виду, что большинство из этих функций (кроме
random_int()
) возврат "необработанных строк" означает, что они могут содержать любой символ ASCII из0 - 255
. Если вам нужна строка для печати, я бы предложил запустить результат черезbase64_encode()
.
function generate_random_string($name_length = 8) { $alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; return substr(str_shuffle(str_repeat($alpha_numeric, $name_length)), 0, $name_length); }
обновлен код согласно mzhang ' s большое предложение в комментариях ниже.
лучшая и обновленная версия отличного ответа @taskamiski:
лучшая версия, используя
mt_rand()
вместоrand()
:echo md5(mt_rand()); // 32 char string = 128bit
еще лучше, для более длинных строк, используя
hash()
функция, позволяющая выбрать алгоритм хэширования:echo hash('sha256', mt_rand()); // 64 char string echo hash('sha512', mt_rand()); // 128 char string
если вы хотите сократить результат, скажем, до 50 символов, сделайте это так:
echo substr(hash('sha256', mt_rand()), 0, 50); // 50 char string
объединение символов в конце должно быть более эффективным, чем повторная конкатенация строк.
правка #1: добавлена опция, чтобы избежать повторения символов.
Edit #2: бросает исключение, чтобы избежать попадания в бесконечный цикл, если выбран $norepeat и $len больше, чем набор символов для выбора.
Edit #3: использует ключи массива для хранения выбранных случайных символов при выборе $norepeat, так как поиск ключа ассоциативного массива выполняется быстрее, чем линейный поиск матрица.
function rand_str($len, $norepeat = true) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; $max = strlen($chars) - 1; if ($norepeat && len > $max + 1) { throw new Exception("Non repetitive random string can't be longer than charset"); } $rand_chars = array(); while ($len) { $picked = $chars[mt_rand(0, $max)]; if ($norepeat) { if (!array_key_exists($picked, $rand_chars)) { $rand_chars[$picked] = true; $len--; } } else { $rand_chars[] = $picked; $len--; } } return implode('', $norepeat ? array_keys($rand_chars) : $rand_chars); }
это создаст случайную строку
function generateRandomString($length=10) { $original_string = array_merge(range(0,9), range('a','z'), range('A', 'Z')); $original_string = implode("", $original_string); return substr(str_shuffle($original_string), 0, $length); } echo generateRandomString(6);
Я думаю, что я добавлю свой вклад здесь.
function random_string($length) { $bytes_1 = openssl_random_pseudo_bytes($length); $hex_1 = bin2hex($bytes_1); $random_numbers = substr(sha1(rand()), 0, $length); $bytes_2 = openssl_random_pseudo_bytes($length); $hex_2 = bin2hex($bytes_2); $combined_chars = $hex_1 . $random_numbers . $hex_2; $chars_crypted = hash('sha512', $combined_chars); return $chars_crypted; }
спасибо
большинство аспектов этого уже обсуждались, но я бы порекомендовал небольшое обновление: Если вы используете это для розничного использования, я бы избегал домена ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
и вместо использования: ABCDEFGHJKMNPQRSTUVWXY3456789
конечно, вы получаете гораздо меньше символов, но это экономит много хлопот, так как клиенты не могут ошибиться 0 для O, или 1 для l или 2 для Z. Кроме того, вы можете сделать верхний на входе и затем клиенты могут вводить буквы верхнего или нижнего регистра - это также иногда сбивает с толку, поскольку они могут выглядеть одинаково.
для чего вам нужна случайная строка?
это будет использоваться для чего-либо отдаленно похожее на пароль?
если ваша случайная строка требует любой свойства безопасности вообще, вы должны использовать PHP 7's
random_int()
функция вместо всех небезопасныхmt_rand()
ответов в этой теме./** * Generate a random string * * @link https://paragonie.com/b/JvICXzh_jhLyt4y3 * * @param int $length - How long should our random string be? * @param string $charset - A string of all possible characters to choose from * @return string */ function random_str($length = 32, $charset = 'abcdefghijklmnopqrstuvwxyz') { // Type checks: if (!is_numeric($length)) { throw new InvalidArgumentException( 'random_str - Argument 1 - expected an integer' ); } if (!is_string($charset)) { throw new InvalidArgumentException( 'random_str - Argument 2 - expected a string' ); } if ($length < 1) { // Just return an empty string. Any value < 1 is meaningless. return ''; } // This is the maximum index for all of the characters in the string $charset $charset_max = strlen($charset) - 1; if ($charset_max < 1) { // Avoid letting users do: random_str($int, 'a'); -> 'aaaaa...' throw new LogicException( 'random_str - Argument 2 - expected a string at least 2 characters long' ); } // Now that we have good data, this is the meat of our function: $random_str = ''; for ($i = 0; $i < $length; ++$i) { $r = random_int(0, $charset_max); $random_str .= $charset[$r]; } return $random_str; }
если вы еще не на PHP 7 (что, вероятно, так, поскольку он не был выпущен на момент написания этой статьи), то вы захотите paragonie / random_compat, который является пользовательской реализацией
random_bytes()
иrandom_int()
для PHP 5 проектов.для контекстов безопасности, всегда использовать
random_int()
, а неrand()
,mt_rand()
и т. д. посмотреть ircmaxell это как хорошо.
// @author http://codeascraft.etsy.com/2012/07/19/better-random-numbers-in-php-using-devurandom/ function devurandom_rand($min = 0, $max = 0x7FFFFFFF) { $diff = $max - $min; if ($diff < 0 || $diff > 0x7FFFFFFF) { throw new RuntimeException('Bad range'); } $bytes = mcrypt_create_iv(4, MCRYPT_DEV_URANDOM); if ($bytes === false || strlen($bytes) != 4) { throw new RuntimeException('Unable to get 4 bytes'); } $ary = unpack('Nint', $bytes); $val = $ary['int'] & 0x7FFFFFFF; // 32-bit safe $fp = (float) $val / 2147483647.0; // convert to [0,1] return round($fp * $diff) + $min; } function build_token($length = 60, $characters_map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { $map_length = mb_strlen($characters_map)-1; $token = ''; while ($length--) { $token .= mb_substr($characters_map, devurandom_rand(0,$map_length),1); } return $token; }
это будет работать только в среде UNIX, где PHP компилируется с
mcrypt
.
вы хотите создать свой пароль путем случайной перестановки исходных букв? Должен ли он просто содержать уникальные символы?
использовать
rand
для выбора случайных букв по индексу.
вы можете создать массив символов, а затем использовать rand (), чтобы выбрать букву из массива и добавить ее в строку.
$letters = array( [0] => 'a' [1] => 'b' [2] => 'c' [3] => 'd' ... [25] = 'z'); $lengthOfString = 10; $str = ''; while( $lengthOfString-- ) { $str .= $letters[rand(0,25)]; } echo $str;
* обратите внимание, что это позволяет повторять символы
это строится на решение Гамбо добавляя функциональность для перечисления набора символов, которые будут пропущены в базовом наборе символов. Случайная строка выбирает символы из
$base_charset
которые также не отображаются в$skip_charset
./* Make a random string of length using characters from $charset, excluding $skip_chars. * @param length (integer) length of return value * @param skip_chars (string) characters to be excluded from $charset * @param charset (string) characters of posibilities for characters in return val * @return (string) random string of length $length */ function rand_string( $length, $skip_charset = '', $base_charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'){ $skip_len = strlen($skip_charset); for ($i = 0; $i<$skip_len; $i++){ $base_charset = str_replace($skip_charset[$i], '', $base_charset); } cvar_dump($base_charset, '$base_charset after replace'); $str = ''; $count = strlen($base_charset); while ($length--) { $str .= $base_charset[mt_rand(0, $count - 1)]; } return $str; }
вот некоторые примеры использования. В первых двух примерах используется значение по умолчанию для
$base_charset
. Последний пример явно определяет$base_charset
.echo rand_string(15, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'); // 470620078953298 echo rand_string(8, 'abcdefghijklmnopqrstuvwxyz0123456789'); // UKLIHOTFSUZMFPU echo rand_string(15, 'def', 'abcdef'); // cbcbbccbabccaba
ну, я искал решение, и я kindda использовал решение @Chad Birch, объединенное с решением @Gumbo. Вот что я придумал:
function get_random_string($length, $valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456790!·$%&/()=?¿¡',.-;:+*`+´ç") { $random_string = ""; $num_valid_chars = strlen($valid_chars); for ($i = 0; $i < $length; $i++, $random_string .= $valid_chars[mt_rand(1, $num_valid_chars)-1]); return $random_string; }
Я думаю, что комментарии в значительной степени излишни, так как ответы, которые я использовал для создания этого, уже полностью прокомментированы. Ура!
Если вас не волнует время, память или эффективность процессора, и если ваша система может справиться с этим, почему бы не попробовать этот алгоритм?!
function randStr($len, $charset = 'abcdABCD0123') { $out = ''; $str = array(); for ($i = 0; $i < PHP_INT_MAX; $i++) { $str[$i] = $charset; shuffle($str); $charset .= implode($charset, $str); $charset = str_shuffle($charset); } $str = array_flip($str); $str = array_keys($str); for ($i = 0; $i < PHP_INT_MAX; $i++) { shuffle($str); } $str = implode('', $str); for ($i = 0; $i < strlen($str); $i++) { $index = mt_rand(1, strlen($str)); $out .= $str[$index - 1]; } for ($i = 0; $i < PHP_INT_MAX; $i++) { $out = str_shuffle($out); } return substr($out, 0, $len); }
возможно, это будет лучше читать, если он использует рекурсию, но я не уверен, что PHP использует хвостовую рекурсию или нет...