如何使用PHP创build一个随机string?

我知道PHP中的rand函数会生成随机整数,但生成随机string的最佳方法是什么?

原始string,9个字符

$string = 'abcdefghi'; 

示例随机string限制为6个字符

 $string = 'ibfeca'; 

更新:我已经发现吨这些types的function,基本上我试图了解每一步背后的逻辑。

更新:函数应该根据需要生成任何数量的字符。

如果您回复,请评论部分。

那么,你没有澄清我在我的评论中问的所有问题,但我会假设你想要一个可以接受一串“可能”字符和一串string返回的函数。 为了清楚起见,按照要求彻底评论,使用比我通常更多的variables:

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

请注意,此函数不检查传递给它的有效字符的唯一性。 例如,如果您使用有效的string'AAAB'调用该string,则将每个字母的Aselect为B的可能性会高出三倍。根据您的需要,这可能被视为错误或function。

如果你想允许重复出现的字符,你可以使用这个function:

 function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { $str = ''; $count = strlen($charset); while ($length--) { $str .= $charset[mt_rand(0, $count-1)]; } return $str; } 

基本algorithm是生成< length >乘以0到< number of characters > -1之间的随机数,我们用它作为索引从我们的集合中挑选一个字符并连接这些字符。 0和< 字符数 > –1个边界代表$charsetstring的边界,因为第一个字符用$charset[0]寻址,而最后一个用$charset[count($charset) - 1]寻址。

我的最爱:

  echo substr(md5(rand()), 0, 7); 

所以,让我开始说“ USE A LIBRARY” 。 许多存在:

  • RandomCompat
  • RandomLib
  • SecurityMultiTool

问题的核心几乎每个答案在这个页面都容易受到攻击。 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()除外)都返回“原始string”,这意味着它们可以包含任何从0 - 255 ASCII字符。 如果你想要一个可打印的string,我build议通过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在下面的评论中的重要build议更新了代码。

@ taskamiski优秀的答案更好的和更新的版本:

更好的版本,使用mt_rand()而不是rand()

 echo md5(mt_rand()); // 32 char string = 128bit 

更好的是,对于更长的string,使用hash()函数可以select散列algorithm:

 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 

在最后join字符应该更有效,重复string连接。

编辑#1:添加选项以避免字符重复。

编辑#2:抛出exception,以避免进入无限循环,如果$ norepeat被选中,并且$ len大于从中select的字符集。

编辑#3:select$ norepeat时,使用数组键来存储选取的随机字符,因为关联数组键的查找比线性search数组要快。

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

这将产生随机string

 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; } 

谢谢

这方面的大部分内容已经被讨论过了,但是我build议稍微更新一下:如果你正在使用这个零售版,我会避免使用ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

而是使用:ABCDEFGHJKMNPQRSTUVWXY3456789

当然,最终的字符会less得多,但是它可以节省很多麻烦,因为客户不会把O误认为0,或者把Z误认为1或2,而且可以对input做一个UPPER,然后客户就可以input大写或小写字母 – 这有时也会令人困惑,因为它们看起来相似。

你需要一个随机的string?

这是用来远程类似于密码的东西吗?

如果你的随机string需要任何安全属性,你应该使用PHP 7的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; } 

这只适用于使用mcrypt编译PHP的UNIX环境。

你想通过原始字母的随机排列来创build你的密码吗? 它应该只包含独特的人物?

使用rand来按索引select随机字母。

你可以创build一个字符数组,然后使用rand()从数组中select一个字母并将其添加到string中。

 $letters = array( [0] => 'a' [1] => 'b' [2] => 'c' [3] => 'd' ... [25] = 'z'); $lengthOfString = 10; $str = ''; while( $lengthOfString-- ) { $str .= $letters[rand(0,25)]; } echo $str; 

*请注意,这确实允许重复的字符

这build立在Gumbo的解决scheme上,通过添加function来列出要在基本字符集中跳过的一组字符。 随机string从$base_charset中select不会出现在$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 

好吧,我正在寻找一个解决scheme,我kindda使用@Chad Birch的解决scheme与@ 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; } 

我认为评论是非常不必要的,因为我用来build立这个的答案已经彻底评论。 干杯!

如果你不关心时间,内存或CPU的效率,如果你的系统可以处理它,为什么不试一试呢?

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

也许这会更好,如果它使用recursion,但我不知道如果PHP使用尾recursion或不…