如何使用PHP创建随机字符串?

时间:2009-05-12 17:06:36

标签: php string random

我知道PHP中的rand函数会生成随机整数,但生成随机字符串的最佳方法是:

原始字符串,9个字符

$string = 'abcdefghi';

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

$string = 'ibfeca';

更新:我发现了大量这些类型的功能,基本上我正试图理解每一步背后的逻辑。

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

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

21 个答案:

答案 0 :(得分:98)

如果您想允许重复出现的字符,可以使用此功能:

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

基本算法是生成< length >乘以0到< 字符数之间的随机数> - 1我们用作索引从我们的集合中选择一个字符并连接这些字符。 0和< 字符数> - 1个边界表示$charset字符串的边界,因为第一个字符使用$charset[0]处理,最后一个字符使用$charset[count($charset) - 1]处理。

答案 1 :(得分:91)

好吧,你没有澄清我在评论中提出的所有问题,但我会假设你想要一个可以接受一串“可能”字符和一串字符串返回的函数。为清晰起见,根据要求进行了彻底的评论,使用了比我通常更多的变量:

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的可能性会高出三倍。这可能被视为错误或功能,具体取决于您的需要。

答案 2 :(得分:52)

我的最爱:

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

答案 3 :(得分:24)

所以,让我先说使用图书馆。许多存在:

问题的核心几乎是本页中的每个答案都容易受到攻击。 mt_rand()rand()lcg_value()uniqid()都是vulnerable to attack

一个好的系统会使用文件系统中的/dev/urandom,或mcrypt_create_iv()MCRYPT_DEV_URANDOM}或openssl_pseudo_random_bytes()。以上所有都做了。 PHP 7 will come with two new functions random_bytes($len)random_int($min, $max)也是安全的。

请注意,大多数这些功能(random_int()除外)都返回&#34;原始字符串&#34;意味着它们可以包含来自0 - 255的任何ASCII字符。如果您想要一个可打印的字符串,我建议您通过base64_encode()运行结果。

答案 4 :(得分:17)

function generate_random_string($name_length = 8) {
    $alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alpha_numeric, $name_length)), 0, $name_length);
}

根据mzhang在以下评论中提出的重要建议更新了代码。

答案 5 :(得分:9)

@ 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

答案 6 :(得分:6)

最后加入字符应该比重复字符串连接更有效。

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

编辑#2:抛出异常以避免在选择$ norepeat并且$ len大于要挑选的字符集时进入无限循环。

编辑#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);   
}

答案 7 :(得分:4)

这将生成随机字符串

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

答案 8 :(得分:3)

我想我也会在这里添加我的贡献。

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

由于

答案 9 :(得分:2)

这方面的大多数方面已经讨论过,但我建议稍作更新: 如果您将其用于零售用途,我会避开该域名 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

而是使用: ABCDEFGHJKMNPQRSTUVWXY3456789

当然,你最终会得到更少的字符,但它可以节省很多麻烦,因为客户不能将0误认为是O,或者将1作为1或2作为Z.此外,你可以在输入上做一个UPPER然后,客户可以输入大写或小写字母 - 这有时也会让人感到困惑,因为它们看起来很相似。

答案 10 :(得分:2)

你需要一个随机字符串?

这是否会用于任何类似于密码的远程操作?

如果随机字符串完全需要任何安全属性,则应使用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,这是{的用户区实现PHP 1项目的{1}}和random_bytes()

对于安全上下文,总是使用random_int(),而不是random_int()rand()等。请参阅ircmaxell's answer同样。

答案 11 :(得分:1)

// @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环境。

答案 12 :(得分:0)

您想通过原始字母的随机排列来创建密码吗?它应该只包含独特的字符吗?

使用rand按索引选择随机字母。

答案 13 :(得分:0)

echo substr(bin2hex(random_bytes(14)), 0, $length);

答案 14 :(得分:0)

尝试一下

足够简单!

function RandomFromCharset($charset,$length) 
{

$characters = $charset; // your existing charset / defined string
    $charactersLength = strlen($characters);
    $random_from_charset = '';
    for ($i = 0; $i < $length; $i++) 
    {
        $random_from_charset.= $characters[rand(0, $charactersLength - 1)];
    }

return random_from_charset;
}

按如下所示调用函数

RandomFromCharset($charset,$length);

其中 $ length 是您想要生成的随机字符串的长度(也可以在函数RandomFromCharset(charset,$length=10)中预定义),然后 $ charset 是您要限制字符的现有字符串。

答案 15 :(得分:0)

这是一个古老的问题,但是我想尝试发布我的解决方案...我总是使用此函数来生成自定义的随机字母数字字符串...

<?php
  function random_alphanumeric($length) {
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345689';
    $my_string = '';
    for ($i = 0; $i < $length; $i++) {
      $pos = mt_rand(0, strlen($chars) -1);
      $my_string .= substr($chars, $pos, 1);
    }
    return $my_string;
  }
  $test = random_alphanumeric(50); // 50 characters
  echo $test;
?>

测试:UFOruSSTCPIqxTRIIMTRkqjOGidcVlhYaS9gtwttxglheVugFM

如果您需要两个或多个唯一的字符串,可以使用此技巧...

$string_1 = random_alphanumeric(50);
$string_2 = random_alphanumeric(50);
while ($string_1 == $string_2) {
  $string_1 = random_alphanumeric(50);
  $string_2 = random_alphanumeric(50);
  if ($string_1 != $string_2) {
     break;
  }
}
echo $string_1;
echo "<br>\n";
echo $string_2;

$ string_1:tMYicqLCHEvENwYbMUUVGTfkROxKIekEB2YXx5FHyVByp3mlJO

$ string_2:XdMNJYpMlFRKFDlF6GhVn6jsBVNQ1BCCevj8yK2niFOgpDI2MU

我希望有帮助。

答案 16 :(得分:0)

建立在https://stackoverflow.com/a/853898/533426

之上

但使用php 7加密安全随机函数以及小写和大写字母

function random($length = 8){
            $valid_chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

            // 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 = random_int(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;
    }

//example output XjdXHakZ, yBG8hpZG, L6jg4FpK

答案 17 :(得分:-1)

如果您不关心时间,内存或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);
}

如果它使用递归,也许这会更好读,但我不确定PHP是否使用尾递归...

答案 18 :(得分:-1)

好吧,我正在寻找一个解决方案,并且我使用@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;
}

我认为评论几乎是不必要的,因为我用来构建这个评论的答案已经被彻底评论过了。干杯!

答案 19 :(得分:-1)

这建立在Gumbo's solution的基础上,通过添加功能来列出要在基本字符集中跳过的一组字符。随机字符串会选择$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

答案 20 :(得分:-1)

你可以创建一个字符数组然后使用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;

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