前段时间我写了一个随机字符串生成器,它使用字符串中的mt_rand()字符构建一个字符串,直到达到所需的长度。
public function getPassword ()
{
if ($this -> password == '')
{
$pw = '';
$charListEnd = strlen (static::CHARLIST) - 1;
for ($loops = mt_rand ($this -> min, $this -> max); $loops > 0; $loops--)
{
$pw .= substr (static::CHARLIST, mt_rand (0, $charListEnd), 1);
}
$this -> password = $pw;
}
return $this -> password;
}
(CHARLIST是一个类常量,包含密码的字符池。$ min和$ max是长度约束)
今天,在完全研究其他内容时,我偶然发现了以下代码:
function generateRandomString ($length = 10) {
return substr(str_shuffle ("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, $length);
}
这实现了与我在一行中基于循环mt_rand()的代码完全相同的效果。我非常喜欢它,原因很简单,更少的代码行总是好事。 :)
但是当我在PHP的手册中查找str_shuffle时,它的文档很轻松。我真正热衷于学习的一件事是它用于随机性的算法是什么?手册没有提到为获得混洗字符串做了什么样的随机化。如果它使用rand()而不是mt_rand()那么坚持我当前的解决方案可能会更好。
所以基本上我想知道str_shuffle如何随机化字符串。它是使用rand()还是mt_rand()?我正在使用我的随机字符串函数来生成密码,因此随机性的质量很重要。
UPDATE :正如已经指出的那样,str_shuffle方法不等同于我已经使用的代码,并且由于字符串的字符与输入保持相同而不会随机,因为他们的订单改变了。但是我仍然对str_shuffle函数如何随机化其输入字符串感到好奇。
答案 0 :(得分:33)
更好的解决方案是mt_rand
使用Mersenne Twister更好。
正如已经指出的那样,str_shuffle方法不等同于我已经使用的代码,并且由于字符串的字符与输入保持相同而且随着它们的顺序改变而变得不那么随机。但是我仍然很好奇str_shuffle函数如何使其输入字符串随机化。
要使输出相等,只需使用0,1
并查看每个函数的可视化表示
简单测试代码
header("Content-type: image/png");
$im = imagecreatetruecolor(512, 512) or die("Cannot Initialize new GD image stream");
$white = imagecolorallocate($im, 255, 255, 255);
for($y = 0; $y < 512; $y ++) {
for($x = 0; $x < 512; $x ++) {
if (testMTRand()) { //change each function here
imagesetpixel($im, $x, $y, $white);
}
}
}
imagepng($im);
imagedestroy($im);
function testMTRand() {
return mt_rand(0, 1);
}
function testRand() {
return rand(0, 1);
}
function testShuffle() {
return substr(str_shuffle("01"), 0, 1);
}
输出testRand()
输出testShuffle()
输出testMTRand()
所以基本上我想知道str_shuffle如何随机化字符串。它是使用rand()还是mt_rand()?我正在使用我的随机字符串函数来生成密码,因此随机性的质量非常重要。
您可以清楚地看到str_shuffle
产生的输出几乎与rand
...
答案 1 :(得分:3)
请注意,如果您的应用程序真正专注于安全性,则不应使用此方法。 Mersenne Twister不具有加密安全性。 PRNG可以产生统计上看似随机但仍易于破裂的值。
答案 2 :(得分:0)
仍然没有加密安全性,但这是一种在允许字符重复的同时使用str_shuffle()
的方法,从而提高了复杂性......
generate_password($length = 8, $strength = 3) {
if ($length < 6) $length = 6;
if ($length > 32) $length = 32;
// Excludes [0,O,o,1,I,i,L,l,1] on purpose for readability
$chars = 'abcdefghjkmnpqrstuvwxyz';
if ($strength >= 2) $chars .= '23456789';
if ($strength >= 3) $chars .= strtoupper($lower);
if ($strength >= 4) $chars .= '!@#$%&?';
return substr(str_shuffle(str_repeat($chars, $length)), 0, $length);
}
$chars
在字符串被洗牌之前重复$length
次,以使其比仅仅一次性改组更好一些。
我们只在不存储敏感信息的系统中使用它;)