16

不久前,我编写了一个随机字符串生成器,它使用字符串中的第 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()?我正在使用我的随机字符串函数来生成密码,所以随机性的质量很重要。

更新:正如已经指出的那样, str_shuffle 方法并不等同于我已经在使用的代码,并且由于字符串的字符与输入保持相同,只是它们的顺序发生了变化,因此随机性会降低。但是,我仍然对 str_shuffle 函数如何随机化其输入字符串感到好奇。

4

3 回答 3

35

更好的解决方案是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...

于 2012-12-29T08:27:29.440 回答
3

请注意,如果您的应用程序真正关注安全性,则不应使用此方法。Mersenne Twister 不是加密安全的。PRNG 可以产生在统计上看起来是随机的但仍然很容易破坏的值。

于 2013-11-04T16:20:16.027 回答
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在字符串被洗牌之前重复多次,这比只洗牌一次出现要好一点。

我们只在不存储敏感信息的系统中使用它;)

于 2017-09-30T17:41:10.343 回答