在 PHP 中生成随机字母数字字符串

作者: siediyer 分类: PHP 发布时间: 2022-09-18 17:04

在 PHP 中生成随机数有三种不同的函数。它们都将接受随机数的最小和最大可能值,并为您输出一个随机数。它们是 rand($min, $max)、 mt_rand($min, $max)和 random_int($min, $max)

使用 rand(),您可以生成的整数的最小值和最大值介于 0 和 返回的值 之间getrandmax()。在 PHP 7.1.0 之前,这个函数比 mt_rand(). 但是,从 PHP 7.1.0 开始,它已成为 mt_rand(). 但是,与 不同 mt_rand()的是,您可以将 的值设置 $max 为低于而 $min 不会导致错误。

使用 mt_rand(),您可以生成的整数的最小值和最大值介于 0 和 返回的值 之间mt_getrandmax()。它依赖于 Mersenne Twister 的实现来生成随机数。但请注意——在 PHP 7.1.0 之前,该函数实现了错误版本的算法来生成数字。但是,它已在较新的版本中得到修复。

在 PHP 7.2.0 中,通过消除模偏差错误,该功能变得更好。这意味着对于某些特定的种子,与旧版本相比,您的随机数序列现在会稍微好一些。不过,一些专门的代码实际上可能依赖于这种偏见。如果是这样,您可以通过调用 mt_srand() 函数来为随机数生成器播种并 MT_RAND_PHP 作为第二个参数的值传递来使用较旧的种子算法。

该 mt_rand() 函数的周期为 2 19937 -1,这基本上意味着在最佳情况下,您会在序列开始重复之前获得多达 2 个19937 -1 的随机数。您应该注意,序列的重复与特定数字的重复不同。换句话说,您可能会两次获得相同的随机数,但这并不意味着序列本身已经开始重复。以下序列是一个示例:

187 3276 1267 15 1267 34598 3467 125 17

在上面的序列中,我们在输出中有两次 1267,但这并不意味着整个序列在那之后开始重复。不太可能如此快地以随机顺序重复相同的数字,但这是可能的!

密码安全的随机整数

如果你想要加密安全的伪随机数,  random_int() PHP 中的函数是你最好的选择。它将在提供的 $min 和 $max 值之间生成随机数,默认为 PHP_INT_MIN 和 PHP_INT_MAX。不幸的是,此功能仅从 PHP 7.0 开始可用。对于之前的版本,你可以在 GitHub 上使用这个 polyfill。

随机浮点数

您可能还想生成浮点数,而不是生成随机整数。这可以通过简单地将随机数除以返回的值来轻松完成 mt_getrandmax()。以下示例将说明如何生成介于 0 和 1 之间或任何其他最小和最大限制之间的随机浮点数。

<?php

// Output: 0.69458310943776
echo mt_rand(0, mt_getrandmax())/mt_getrandmax();

function mt_random_float($min, $max) {
    $float_part = mt_rand(0, mt_getrandmax())/mt_getrandmax();
    $integer_part = mt_rand($min, $max - 1);
    return $integer_part + $float_part;
}

// Output: 10.199064863938
echo mt_random_float(10, 11);

// Output: 35.540808309121
echo mt_random_float(15, 50);

?>

在给定限制之间生成随机浮点数时,我们确保随机整数不超过 $max - 1. 这样,我们可以确定添加浮点部分不会使数字超过最大限制。

播种随机数生成器

一个需要一点解释的概念是种子。简而言之,这些只是可用于  在生成任何随机数之前初始化rand() and 函数的数字。mt_rand()调用种子 的函数,rand() 调用 种子 的 srand($seed)函数 。mt_rand()mt_srand($seed, $mode)

重要的是要记住,在调用之前每次都提供一个初始种子值 rand() , mt_rand() 不一定会产生更好的随机数。事实上,每次使用相同的种子也会得到相同的随机数!

<?php

mt_srand(10);
// Output: 1656398468
echo mt_rand();

mt_srand(10);
// Output: 1656398468
echo mt_rand();

mt_srand(10);
// Output: 1656398468
echo mt_rand();

?>

在您想要生成随机但可重现的序列的情况下,播种随机数很有用。以下代码片段在运行两次时会生成相同的随机数序列。

<?php

mt_srand(10);

$count = 0;

while($count < 10) {
    echo mt_rand(0, 100)." ";
    $count++;
}

// Output on First Run:
// 68 58 68 13 3 48 30 37 96 82

// Output on Second Run:
// 68 58 68 13 3 48 30 37 96 82

以这种方式生成可重现的随机序列可以帮助调试正在使用随机数据进行测试的程序——如果您跟踪种子,您可以重现相同的输入以找出问题所在。

在 PHP 中生成随机字母数字字符串

有很多方法可以生成随机字母数字字符串,您使用什么将取决于您的需要。

生成唯一 ID

如果您只是想生成一个唯一的字符串并且它不必是加密安全的,那么请考虑使用该 uniqid() 函数。它根据当前时间戳返回一个唯一标识符。

该函数还接受两个参数来添加前缀或增加生成字符串的熵。以下是它的一些例子:

<?php

// Output: 5fa7f46962f25
echo uniqid();

// Output: user_5fa7f46962f3a
echo uniqid('user_');

// Output: user_5fa7f46962f3d4.76070232
echo uniqid('user_', true);

?>

生成混洗字符串

如果要从一组固定字符生成随机字母数字字符串,可以使用该 str_shuffle($string) 函数。此函数将为您提供一个随机打乱的字符串。从 PHP 7.1 开始,确定输出字符串中字符随机顺序的算法已更改为 Mersenne Twister。

请记住,以这种方式生成的随机字符串在密码学上是不安全的。但是,对于生成随机文件名或 URL 等常见用途,该字符串仍然非常不可预测。这里有一些例子:

<?php

$permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyz';
// Output: 54esmdr0qf
echo substr(str_shuffle($permitted_chars), 0, 10);

$permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Output: video-g6swmAP8X5VG4jCi.mp4
echo 'video-'.substr(str_shuffle($permitted_chars), 0, 16).'.mp4';

?>

在这两种情况下,您的输出很可能会有所不同。在第一种情况下,我们只是打乱了允许的字符串,然后取出它的前 10 个字符。在第二种情况下,我们在生成的字符串的开头添加了“video”,在末尾添加了“.mp4”。

这种生成随机字母数字字符串的方法非常简单,但它有几个问题。例如,您永远不会在随机字符串中两次获得相同的字符。此外,随机输出字符串的长度只能与输入字符串一样长。

生成随机字符串

如果我上面列出的问题是一个交易破坏者,你可能想看看其他一些实现。下面的代码将解决这两个问题。

<?php

$permitted_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

function generate_string($input, $strength = 16) {
    $input_length = strlen($input);
    $random_string = '';
    for($i = 0; $i < $strength; $i++) {
        $random_character = $input[mt_rand(0, $input_length - 1)];
        $random_string .= $random_character;
    }

    return $random_string;
}

// Output: iNCHNGzByPjhApvn7XBD
echo generate_string($permitted_chars, 20);

// Output: 70Fmr9mOlGID7OhtTbyj
echo generate_string($permitted_chars, 20);

// Output: Jp8iVNhZXhUdSlPi1sMNF7hOfmEWYl2UIMO9YqA4faJmS52iXdtlA3YyCfSlAbLYzjr0mzCWWQ7M8AgqDn2aumHoamsUtjZNhBfU
echo generate_string($permitted_chars, 100);

?>

您可以修改它以向生成的随机字符串添加特定的后缀和前缀。使用 PHP 7 的人可以通过使用加密安全函数 random_int() 而不是 mt_rand().

生成随机十六进制字符串

如果要在 PHP 中生成随机的十六进制字符串,也可以使用 md5($string, $raw_output) 或 sha1($string, $raw_output) 函数。它们都将生成给定输入字符串的哈希值。

只要输入是唯一的,您就会不断获得唯一的哈希值。这可以通过使用类似函数的输出 time() 作为输入来实现。默认情况下, md5() 将返回一个 32 个字符的十六进制字符串, sha1() 并将返回一个 40 个字符的十六进制字符串。substr() 可以使用该功能将它们修剪为特定长度 。

以下是这些函数返回的输出示例:

<?php

// Output: 36e5e490f14b031e
echo substr(md5(time()), 0, 16);

// Output: aa88ef597c77a5b3
echo substr(sha1(time()), 0, 16);

// Output: 447c13ce896b820f353bec47248675b3
echo md5(time());

// Output: 6c2cef9fe21832a232da7386e4775654b77c7797
echo sha1(time());

?>

如您所见,在 PHP 中生成最长 40 个字符的随机且唯一的十六进制字符串非常容易。

生成加密安全的随机字符串

到目前为止,我们讨论的生成随机字母数字字符串的三个函数在密码学上并不安全。幸运的是,PHP 还有一个函数调用 random_bytes($length) 来生成加密安全的伪随机字节。该 $length 参数确定输出字符串的长度。

一旦获得了随机字节的输出,就可以使用该 bin2hex() 函数将它们转换为十六进制值。这将使字符串的长度加倍。

<?php

// Output: b7b33efa07915b60ad55
echo bin2hex(random_bytes(10));

// Output: a2e6cb1f25616324c8a11a2cceb0b47c590949ea
echo bin2hex(random_bytes(20));

// Output: 25af3b86e11884ef5e8ef70a0ad06cba81b89ed6af3781a0
echo bin2hex(random_bytes(24));

?>

另一个可用于生成加密安全随机字节的函数是 openssl_random_pseudo_bytes($length, &$crypto_strong). 第二个参数的值可用于确定是否将使用加密安全算法生成输出字符串。

在上面的示例中,使用该 bin2hex() 函数将最终值作为十六进制字符串提供给我们。如果出于某种原因,您想要一个使用从 a 到 z 的所有字符的加密安全随机字母数字字符串,您应该考虑使用以下函数。

<?php

function secure_random_string($length) {
    $random_string = '';
    for($i = 0; $i < $length; $i++) {
        $number = random_int(0, 36);
        $character = base_convert($number, 10, 36);
        $random_string .= $character;
    }

    return $random_string;
}

// Output: 07y1s10prb8
echo secure_random_string(10);

// Output: d9bcwoo7pc
echo secure_random_string(10);

// Output: 6llfxe4pvm
echo secure_random_string(10);

?>

我们上面编写的 secure_random_string() 函数接受一个参数,该参数确定我们希望它返回的字符串的长度。我们运行一个 for 循环,生成一个 0 到 36 范围内的随机整数。之后,我们使用函数将我们的数字从以 10 为底转换为以 36 为底 base_convert() 。生成的字符可以是从数字 0 到 9 以及字符 a 到 z 的任何字符。我们将它附加在随机字符串的末尾。最后,我们返回完整的字符串。

最后的想法

在本教程中,我们研究了 PHP 中随机数和字母数字字符串的生成。生成随机数在各种情况下都很有用,例如在游戏中你必须生成敌方玩家或随机给用户一些关于字母的线索,以便他们可以组成一个完整的单词。

就像随机数一样,随机字母数字字符串的生成在许多情况下也很有帮助。在 的帮助下 str_shuffle(),您可以选择随机字符串中出现的字符集。使用 sha1() 和 md5(),您可以轻松生成随机十六进制序列,并且 random_bytes() 可以生成加密安全字符串。这将允许您生成有意义但随机的文件名和难以猜测的用户名。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

Title - Artist
0:00