我正在尝试在 PHP 中创建一个随机字符串,但我绝对没有输出:
<?php
function RandomString()
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randstring = '';
for ($i = 0; $i < 10; $i++) {
$randstring = $characters[rand(0, strlen($characters))];
}
return $randstring;
}
RandomString();
echo $randstring;
我究竟做错了什么?
strlen($characters)
=> strlen($characters) - 1
- 字符串长度从 1 开始
要具体回答这个问题,有两个问题:
当您回显它时,$randstring 不在范围内。字符没有在循环中连接在一起。
这是一个带有更正的代码片段:
function generateRandomString($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
使用以下调用输出随机字符串:
// Echo the random string.
// Optionally, you can give it a desired string length.
echo generateRandomString();
请注意,这会生成可预测的随机字符串。如果要创建安全令牌,请参阅此答案。
注意:str_shuffle() 内部使用了 rand(),这不适合加密目的(例如生成随机密码)。您需要一个安全的随机数生成器。它也不允许字符重复。
还有一种方法。
更新(现在这会生成任意长度的字符串):
function generateRandomString($length = 10) {
return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}
echo generateRandomString(); // OR: generateRandomString(24)
而已。 :)
这个问题有很多答案,但没有一个利用 Cryptographically Secure Pseudo-Random Number Generator (CSPRNG)。
简单、安全且正确的答案是使用 RandomLib 而不要重新发明轮子。
对于那些坚持发明自己的解决方案的人,PHP 7.0.0 将为此提供 random_int()
;如果您仍在使用 PHP 5.x,我们编写了一个 PHP 5 polyfill for random_int()
,以便您甚至可以在升级到 PHP 7 之前使用新的 API。
Safely generating random integers in PHP 不是一项简单的任务。在生产中部署本地算法之前,您应该始终检查 your resident StackExchange cryptography experts。
有了安全的整数生成器,使用 CSPRNG 生成随机字符串就像在公园里散步一样。
创建一个安全的随机字符串
/**
* Generate a random string, using a cryptographically secure
* pseudorandom number generator (random_int)
*
* This function uses type hints now (PHP 7+ only), but it was originally
* written for PHP 5 as well.
*
* For PHP 7, random_int is a PHP core function
* For PHP 5.x, depends on https://github.com/paragonie/random_compat
*
* @param int $length How many characters do we want?
* @param string $keyspace A string of all possible characters
* to select from
* @return string
*/
function random_str(
int $length = 64,
string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
): string {
if ($length < 1) {
throw new \RangeException("Length must be a positive integer");
}
$pieces = [];
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$pieces []= $keyspace[random_int(0, $max)];
}
return implode('', $pieces);
}
用法:
$a = random_str(32);
$b = random_str(8, 'abcdefghijklmnopqrstuvwxyz');
$c = random_str();
Demo:https://3v4l.org/IMJGF(忽略 PHP 5 故障;它需要 random_compat)
$keyspace = str_shuffle($keyspace );
以提高安全性
random_int()
而不是 rand()
或 mt_rand()
不会增加开发人员的复杂性。同时,它给了他们更大的安全感。来 StackOverflow 寻找快速解决方案的人可能不知道他们正在构建的东西是否需要安全。如果我们给他们默认的安全答案,他们会创建一个更安全的互联网,即使从他们的角度来看,这完全是偶然的。为什么你会反对这个目标对我来说是个谜。
这将创建一个 20 个字符长的十六进制字符串:
$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars
在 PHP 7 (random_bytes()) 中:
$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+
// or
$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+
// or
$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f
openssl_random_pseudo_bytes()
直到 php 5.6 才使用加密强算法。相关错误:bugs.php.net/bug.php?id=70014
openssl_random_pseudo_bytes()
,您将一无所获。另外,请注意,当使用 bin2hex(openssl_random_pseudo_bytes($length / 2))
时,因为您使用的是整数,它会自动删除模数并使用 2 的下一个最小倍数。因此,$length = 19
将生成长度为 18 的字符串。
fgets($fp, 1024)
打开的文件内容以及每个存在超长行问题的文件编辑器:function string_rand($len, $split="\n") { return substr(chunk_split(bin2hex(openssl_random_pseudo_bytes(ceil($len / 2))), 1023, $split), 0, $len); }
如果应该返回单行,请将 $split
设置为 null
。这样你就可以在这两种情况下使用它。
$string = substr(base64_encode(random_bytes($size)), 0, $size);
@tasmaniski:你的回答对我有用。我有同样的问题,我会建议那些一直在寻找相同答案的人。这是来自@tasmaniski:
<?php
$random = substr(md5(mt_rand()), 0, 7);
echo $random;
?>
这是一个youtube video showing us how to create a random number
md5
将导致 30 个字符的限制,并且始终为小写字符。
md5(rand())
仅提供 2^32 个可能的值。这意味着平均而言,在 2^16 个随机字符串之后,您会期望其中一个重复。
根据您的应用程序(我想生成密码),您可以使用
$string = base64_encode(openssl_random_pseudo_bytes(30));
作为 base64,它们可能包含 =
或 -
以及请求的字符。您可以生成更长的字符串,然后对其进行过滤和修剪以删除它们。
openssl_random_pseudo_bytes
似乎是在 php.ini 中生成正确随机数的推荐方式。为什么 rand
不使用 /dev/random
我不知道。
openssl_random_pseudo_bytes()
是 可移植的。
PHP 7+ 使用 random_bytes 函数生成加密安全的随机字节。
$bytes = random_bytes(16);
echo bin2hex($bytes);
可能的输出
da821217e61e33ed4b2dd96f8439056c
PHP 5.3+ 使用 openssl_random_pseudo_bytes 函数生成伪随机字节。
$bytes = openssl_random_pseudo_bytes(16);
echo bin2hex($bytes);
可能的输出
e2d1254506fbb6cd842cd640333214ad
最好的用例可能是
function getRandomBytes($length = 16)
{
if (function_exists('random_bytes')) {
$bytes = random_bytes($length / 2);
} else {
$bytes = openssl_random_pseudo_bytes($length / 2);
}
return bin2hex($bytes);
}
echo getRandomBytes();
可能的输出
ba8cc342bdf91143
这是一个简单的单行程序,它可以生成真正的随机字符串,而无需任何脚本级别的循环或使用 OpenSSL 库。
echo substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', mt_rand(1,10))), 1, 10);
分解它以便参数清晰
// Character List to Pick from
$chrList = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Minimum/Maximum times to repeat character List to seed from
$chrRepeatMin = 1; // Minimum times to repeat the seed string
$chrRepeatMax = 10; // Maximum times to repeat the seed string
// Length of Random String returned
$chrRandomLength = 10;
// The ONE LINE random command with the above variables.
echo substr(str_shuffle(str_repeat($chrList, mt_rand($chrRepeatMin,$chrRepeatMax))), 1, $chrRandomLength);
此方法通过随机重复字符列表来工作,然后打乱组合字符串,并返回指定的字符数。
您可以进一步随机化,方法是随机化返回字符串的长度,将 $chrRandomLength
替换为 mt_rand(8, 15)
(对于 8 到 15 个字符之间的随机字符串)。
实现此功能的更好方法是:
function RandomString($length) {
$keys = array_merge(range(0,9), range('a', 'z'));
$key = "";
for($i=0; $i < $length; $i++) {
$key .= $keys[mt_rand(0, count($keys) - 1)];
}
return $key;
}
echo RandomString(20);
根据 PHP 7 中的 this 和 this,mt_rand
更加随机。 rand
函数是 mt_rand
的别名。
mt_rand
不会生成加密安全值。为此,您应该使用 PHP7 的 random_int
或 random_bytes
。
function generateRandomString($length = 15)
{
return substr(sha1(rand()), 0, $length);
}
多田!
sha1
将导致 40 个字符的限制,并且始终为小写字符。
rant()
随机无关紧要。如果您从不均匀分布中随机选择,您将得到完全相同的不均匀分布。我要强调的不是“加密级别”随机性,如果是这种情况,您也不应该使用 rand()
。像在接受的答案中那样从均匀分布中提取需要最少的努力,并且它与 rand() 一样随机,这是合理的。
函数作用域中的 $randstring
与调用它的作用域不同。您必须将返回值分配给变量。
$randstring = RandomString();
echo $randstring;
或者直接回显返回值:
echo RandomString();
另外,在你的函数中你有一个小错误。在 for 循环中,您需要使用 .=
以便将每个字符附加到字符串中。通过使用 =
,您将用每个新字符覆盖它,而不是追加。
$randstring .= $characters[rand(0, strlen($characters))];
首先,您定义要使用的字母表:
$alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$special = '~!@#$%^&*(){}[],./?';
$alphabet = $alphanum . $special;
然后,使用 openssl_random_pseudo_bytes()
生成正确的随机数据:
$len = 12; // length of password
$random = openssl_random_pseudo_bytes($len);
最后,您使用此随机数据创建密码。由于 $random
中的每个字符在 chr(255)
之前都可以是 chr(0)
,因此代码使用将其序数值除以 $alphabet_length
后的余数来确保只选择字母表中的字符(请注意,这样做会使随机性产生偏差):
$alphabet_length = strlen($alphabet);
$password = '';
for ($i = 0; $i < $len; ++$i) {
$password .= $alphabet[ord($random[$i]) % $alphabet_length];
}
或者,通常更好的是使用 RandomLib 和 SecurityLib:
use SecurityLib\Strength;
$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new Strength(Strength::MEDIUM));
$password = $generator->generateString(12, $alphabet);
%
将产生有偏差的输出。但是,对于 RandomLib,强 +1。不要重新发明轮子。
我在那里测试了最流行函数的性能,在我的盒子上生成 1'000'000 个 32 个符号的字符串所需的时间是:
2.5 $s = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,32);
1.9 $s = base64_encode(openssl_random_pseudo_bytes(24));
1.68 $s = bin2hex(openssl_random_pseudo_bytes(16));
0.63 $s = base64_encode(random_bytes(24));
0.62 $s = bin2hex(random_bytes(16));
0.37 $s = substr(md5(rand()), 0, 32);
0.37 $s = substr(md5(mt_rand()), 0, 32);
请注意,它实际上有多长并不重要,但哪个更慢,哪个更快,因此您可以根据您的要求进行选择,包括加密准备等。
如果您需要短于 32 个符号的字符串,则添加了 MD5 周围的 substr() 以确保准确性。
为了回答:字符串没有被连接而是被覆盖,并且函数的结果没有被存储。
这是我生成使用友好的随机密码的简单单行解决方案,不包括“1”和“l”、“O”和“0”等看起来相似的字符……这里是 5 个字符,但你可以轻松当然改变它:
$user_password = substr(str_shuffle('abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789'),0,5);
简短的方法..
这是生成随机字符串的一些最短方法
<?php
echo $my_rand_strng = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), -15);
echo substr(md5(rand()), 0, 7);
echo str_shuffle(MD5(microtime()));
?>
一种非常快速的方法是执行以下操作:
substr(md5(rand()),0,10);
这将生成一个长度为 10 个字符的随机字符串。当然,有些人可能会说它在计算方面有点重,但现在处理器已经过优化,可以非常快速地运行 md5 或 sha256 算法。当然,如果 rand()
函数返回相同的值,结果将是相同的,有 1 / 32767 的机会相同。如果安全是问题,那么只需将 rand()
更改为 mt_rand()
Laravel 5 框架的辅助函数
/**
* Generate a "random" alpha-numeric string.
*
* Should not be considered sufficient for cryptography, etc.
*
* @param int $length
* @return string
*/
function str_random($length = 16)
{
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}
function gen_uid($l=5){
return substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 10, $l);
}
echo gen_uid();
默认值[5]:WvPJz
echo gen_uid(30);
值[30]:cAiGgtf1lDpFWoVwjykNKXxv6SC4Q2
从 php7 开始,就有了 random_bytes 函数。 https://www.php.net/manual/ru/function.random-bytes.php 这样您就可以生成一个随机字符串
<?php
$bytes = random_bytes(5);
var_dump(bin2hex($bytes));
?>
function rndStr($len = 64) {
$randomData = file_get_contents('/dev/urandom', false, null, 0, $len) . uniqid(mt_rand(), true);
$str = substr(str_replace(array('/','=','+'),'', base64_encode($randomData)),0,$len);
return $str;
}
这个取自 adminer sources:
/** Get a random string
* @return string 32 hexadecimal characters
*/
function rand_string() {
return md5(uniqid(mt_rand(), true));
}
Adminer,用 PHP 编写的数据库管理工具。
来自 yii2 框架
/**
* Generates a random string of specified length.
* The string generated matches [A-Za-z0-9_-]+ and is transparent to URL-encoding.
*
* @param int $length the length of the key in characters
* @return string the generated random key
*/
function generateRandomString($length = 10) {
$bytes = random_bytes($length);
return substr(strtr(base64_encode($bytes), '+/', '-_'), 0, $length);
}
/**
* @param int $length
* @param string $abc
* @return string
*/
function generateRandomString($length = 10, $abc = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
{
return substr(str_shuffle($abc), 0, $length);
}
来源来自 http://www.xeweb.net/2011/02/11/generate-a-random-string-a-z-0-9-in-php/
另一个单行,它生成包含字母和数字的 10 个字符的随机字符串。它将创建一个带有 range
的数组(调整第二个参数以设置大小),循环该数组并分配一个随机 ASCII 字符(范围 0-9 或 az),然后将数组内爆以获得一个字符串。
$str = implode('', array_map(function () { return chr(rand(0, 1) ? rand(48, 57) : rand(97, 122)); }, range(0, 9)));
注意:这只适用于 PHP 5.3 及更高版本
rand(0, 57-48+122-97)<57-48?...:...
? :)
一个班轮。
对于具有某些独特性的大字符串来说,它的速度很快。
function random_string($length){
return substr(str_repeat(md5(rand()), ceil($length/32)), 0, $length);
}
md5(rand())
是一种非常不安全的随机数生成方式。
function randomString($length = 5) {
return substr(str_shuffle(implode(array_merge(range('A','Z'), range('a','z'), range(0,9)))), 0, $length);
}
该函数的编辑版本工作正常,但我发现只有一个问题:您使用了错误的字符来括住 $characters,因此 ' 字符有时是生成的随机字符串的一部分。
要解决此问题,请更改:
$characters = ’0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;
至:
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
这种方式只使用封闭的字符,并且 ' 字符永远不会成为生成的随机字符串的一部分。
function generateRandomString($length = 10, $hasNumber = true, $hasLowercase = true, $hasUppercase = true): string
{
$string = '';
if ($hasNumber)
$string .= '0123456789';
if ($hasLowercase)
$string .= 'abcdefghijklmnopqrstuvwxyz';
if ($hasUppercase)
$string .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($x = $string, ceil($length / strlen($x)))), 1, $length);
}
并使用:
echo generateRandomString(32);
我喜欢使用 openssl_random_pseudo_bytes 的最后一条评论,但这对我来说不是一个解决方案,因为我仍然必须删除我不想要的字符,而且我无法获得设定长度的字符串。这是我的解决方案...
function rndStr($len = 20) {
$rnd='';
for($i=0;$i<$len;$i++) {
do {
$byte = openssl_random_pseudo_bytes(1);
$asc = chr(base_convert(substr(bin2hex($byte),0,2),16,10));
} while(!ctype_alnum($asc));
$rnd .= $asc;
}
return $rnd;
}
这是我如何获得真正唯一的随机密钥:
$Length = 10;
$RandomString = substr(str_shuffle(md5(time())), 0, $Length);
echo $RandomString;
您可以使用 time() 因为它是一个 Unix 时间戳,并且与上面提到的其他随机相比始终是唯一的。然后,您可以生成它的 md5sum 并从生成的 MD5 字符串中获取所需的长度。在这种情况下,我使用 10 个字符,如果我想让它更独特,我可以使用更长的字符串。
我希望这有帮助。
time()
远非唯一:它会一次又一次地返回相同的值,直到当前秒结束。这里真正提供了一些随机性的是 str_shuffle()
——其余的代码只减少了从中挑选字符的样本。
time()
返回的值(它只是一个时间戳),它是一个弱随机源。
substr(str_shuffle(MD5(microtime())), 0, 10);
之类的东西?rand()
更改为mt_rand()
。我使用了您的方法并经历了 ton 与名称的冲突。