【问题标题】:How to create a random string using PHP?如何使用 PHP 创建随机字符串?
【发布时间】:2010-10-25 15:00:54
【问题描述】:

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

原始字符串,9 个字符

$string = 'abcdefghi';

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

$string = 'ibfeca';

更新:我发现了大量此类函数,基本上我试图了解每个步骤背后的逻辑。

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

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

【问题讨论】:

  • 我不确定你到底想要什么。随机字符串必须包含原始字符串中的字母?每个字符只能使用一次吗?如果您尝试创建比原始字符串更长的随机字符串怎么办?
  • 这是一个“写我的代码”的问题吗?关于使用我们可以帮助您学习的随机数,您有什么不明白的地方?看来您的算法比生成任何长度为 x 的随机字符串更具体。
  • @DForck42 - 因为它毕竟不是那么随机。比较:使用符号 [0-9a-f] 生成长度为 32 的随机字符串,并制作例如 md5(time())。在第二种情况下,我可以在几秒钟内猜出“随机”字符串(如果我可以轻松检查这个随机字符串是否是使用过的字符串),而真正的随机字符串需要很长时间。
  • 好问题!几乎所有“随机字符串”函数都只输出数字,而不是字符串。直到今天我还没有看到任何单行字符串随机函数

标签: php string random


【解决方案1】:
function generate_random_string($name_length = 8) {
    $alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alpha_numeric, $name_length)), 0, $name_length);
}

根据mzhang在下面的cmets中的好建议更新了代码。

【讨论】:

  • "更新:该函数应根据需要生成任意数量的字符。" -- 这个函数最大长度为 62。
  • 此外,它不是随机的 - 使用这种方法在结果字符串中只能有一个字符。一个真正随机的算法有可能导致'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',但不太可能。
  • 那是范围蠕变,我叫恶作剧!
  • 这可能是我见过的用于生成随机字符串的最好的近乎单行代码了。
  • 我真的很喜欢这个解决方案,但我可以解决@ChadBirch 和@ceejayoz 的问题——而不是str_shuffle($alpha_numeric),只需使用str_shuffle(str_repeat($alpha_numeric, $name_length))str_repeat 生成一个重复 n 次的字符串 - 这允许 n 未打乱字符串中每个字母的实例,允许将“AAAA ...”作为最终输出。
【解决方案2】:

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

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

【讨论】:

  • 简洁,真实。但是他直接要求人们不要简洁,因为他试图理解其背后的逻辑。
【解决方案3】:

如果要允许字符重复出现,可以使用这个函数:

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] 寻址。

【讨论】:

  • 喜欢这种方式,它比公认的解决方案要好,尽可能简单,但是您应该通过从循环中删除 $count-1 并将其放在上面来最小化它: $count = strlen($charset) - 1;
  • 也喜欢这种方式!非常好的解决方案,我优先使用它而不是接受的解决方案。 charset 选项也使它更有用。
  • @s3m3n 再次阅读接受的答案。代码是一样的,只是有更多的 cmets 并使用了更多的临时变量 :)
  • 警告:此代码不安全,因为它依赖于mt_rand(),即vulnerable to multiple attacks
【解决方案4】:

在末尾加入字符应该比重复的字符串连接更有效。

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

【讨论】:

  • 对于不重复的情况,如果您关心效率,最好使用 array_splice() 将每个选择的字符从 $chars 数组中取出,而不是在每次迭代中添加数组搜索。
  • 另一种提高效率的方法是将选取的随机字符存储为数组索引,然后使用 array_key_exists 来检查重复字符。数组键查找应该比 in_array() 更有效,in_array() 可能会进行线性搜索。
  • 看起来串联实际上快了 20%-30%。以下是一些您可以测试的代码:pastebin.com/5mUxdWVH
  • 对于没有重复的逻辑,这会更简单:$c = str_split($chars); shuffle($c); return substr(implode('', $c), 0, $len);.
【解决方案5】:

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

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

【讨论】:

  • 警告:此代码不安全,因为它依赖于mt_rand(),即vulnerable to multiple attacks
  • @KeithDonegan 你能不接受这个答案吗?正如 ircmaxell 指出的那样,它非常不安全。 This answer 是正确的。
【解决方案6】:

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

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

【讨论】:

  • 考虑到没有参数的 rand() 返回一个介于 0 和 getrandmax() 之间的值,此代码将在大约 99.9% 的时间打印出一个空字符串,很可能更多,具体取决于您的平台。别介意你使用 27 行代码来设置一个 26 元素数组的方式。
  • 这不是声明数组的有效方式,而且每次都有 1/27 的机会选择不存在的数组元素。
【解决方案7】:

这建立在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

【讨论】:

  • 投反对票的人,请说明你投反对票的原因
【解决方案8】:

我最喜欢的:

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

【讨论】:

  • 在将整数转换为字符串时,您确定 md5 哈希的前 7 个字符的随机属性吗?如果您需要良好的随机分布,我认为您的代码中涉及的因素太多。
  • 好的,这对于拉斯维加斯赌场的机器来说还不够好,但足以生成注册密钥(例如),它在网站上活跃 30 分钟。
  • +1 表示单行方法,当你只需要一个没有 NSA 安全协议的简单随机字符串时
  • 此解决方案不会生成带有大写字母的字符串。只有小写字母和数字。此外,如果您希望字符串中包含其他非字母数字值,则不会生成它们。
  • 一个不错的单行,但使用它有产生错误印象的危险,即生成的字符串的随机性接近于相同长度的真正随机字符串。请注意,rand() 的最大值可以低至 32767(如果是 Windows 上的 PHP),这意味着此函数将仅生成 32767 个可能的字符串,因此很容易受到暴力攻击。
【解决方案9】:

这将生成随机字符串

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

【讨论】:

    【解决方案10】:
    // @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 环境。

    【讨论】:

      【解决方案11】:

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

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

      【讨论】:

        【解决方案12】:

        这方面的大部分内容已经讨论过了,但我建议稍微更新一下: 如果您将此用于零售用途,我会避免使用该域 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

        改为使用: ABCDEFGHJKMNPQRSTUVWXY3456789

        当然,您最终得到的字符要少得多,但它可以省去很多麻烦,因为客户不会将 0 误认为 O,或将 1 误认为 l 或 2 误认为 Z。此外,您可以在输入上执行 UPPER 并然后客户可以输入大写或小写字母——这有时也会让人感到困惑,因为它们看起来很相似。

        【讨论】:

        • 我会留下大多数小写字母。并且也许拼接一个由“音节”(或至少常见的字母组合)组成的字符串。
        【解决方案13】:

        @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
        

        【讨论】:

        • 简洁优雅!其他不错的选择是bin2hex(openssl_random_pseudo_bytes(16)) // 32 char string
        【解决方案14】:

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

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

        谢谢

        【讨论】:

          【解决方案15】:

          如果您不关心时间、内存或 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 是否使用尾递归......

          【讨论】:

            【解决方案16】:

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

            问题的核心是该页面中的几乎每个答案都容易受到攻击。 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() 除外)返回“原始字符串”,这意味着它们可以包含来自 0 - 255 的任何 ASCII 字符。如果你想要一个可打印的字符串,我建议通过base64_encode() 运行结果。

            【讨论】:

            • 什么是php 7的随机方式?
            【解决方案17】:

            你需要一个随机字符串做什么?

            这将用于远程类似于密码的任何事情吗?

            如果您的随机字符串完全需要任何安全属性,您应该使用 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's answer

            【讨论】:

              【解决方案18】:

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

              <?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

              希望对你有所帮助。

              【讨论】:

                【解决方案19】:
                echo substr(bin2hex(random_bytes(14)), 0, $length);
                

                此代码获取一个随机字节,将其从二进制转换为十六进制,然后获取该十六进制字符串的子字符串,只要您放入 $length 变量

                【讨论】:

                • 请在您的代码中添加一些解释,以便其他人可以从中学习
                【解决方案20】:

                试试这个

                够简单!

                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 将是您的您想要限制字符的现有字符串。

                【讨论】:

                  【解决方案21】:

                  建立在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
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-06-27
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多