2012-03-28 216 views
2

我一直认为我的代码生成的是非常随机的字符串,但我一直按F5约10分钟,我一次显示10个字符串,我有三个DUPLICATES,UNIBON,ZANOPE和ZOTAXS。PHP随机字符串生成器...并非如此随机

任何人都可以解释为什么这是当我虽然有代码26^6的可能性吗?

$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
$pass = ''; 
for ($i = 0; $i < $len; $i++){ 
    $pass .= $chars[(rand() % strlen($chars))]; 
} 
return $pass; 

任何意见将不胜感激。

感谢


使用mt_rand第一个重复发生在10至60秒之间的平均水平,这似乎还好,不是吗?

echo 'start: '.date('H:i:s'); 
for ($i = 1; ; $i++) { 
    $testarr[] = passGen(6); 
    $new  = passGen(6); 
    if (in_array($new,$testarr)){ 
     echo '<br>end: '.date('H:i:s'); 
     echo '<br>string: '.$new; 
     echo '<br>count: '.count($testarr); 
     break; 
    } 
} 
+1

可重复获得相同的三个副本?大声笑... – 2012-03-28 14:26:32

+4

http://xkcd.com/221/ – 2012-03-28 14:27:13

+2

也许尝试'rand(0,strlen($ chars))' – phimuemue 2012-03-28 14:28:23

回答

1

为什么不散列一个随机数,然后从散列中取一个随机子串?

+0

不是一个坏主意,我会看看PHP需要多长时间才能创建一个与mt_rand相同的副本,如果它太快,那么我会尝试你的方法,谢谢 – TSUK 2012-03-28 14:42:54

0

你应该试试这个:

$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
     $pass = ''; 
     $length = strlen($chars)-1; 
     for ($i = 0; $i < 10; $i++){ 
      $randomNumber = rand(0,$length); 
      $pass .= substr($chars,$randomNumber,1); 
     } 
     return $pass; 
0

您应该使用mt_rand

mt_randrand更好。来自PHP手册

许多老式libcs​​的随机数发生器具有可疑或未知的特性,并且速度很慢。默认情况下,PHP使用libc随机数生成器和rand()函数。 mt_rand()函数是对此的替代替代。它使用具有已知特征的随机数生成器,使用»Mersenne Twister,它将产生比平均libc rand()提供的速度快4倍的随机数。

这且不说,你可以使用此功能,而不是生成你想要的长度的随机字符串)

function random($length = 10) 
{  
    $chars = 'BCDFGHJKLMNPQRSTVWXYZAEIUO'; 

    for ($i = 0; $i < $length; $i++) 
    { 
     $pass .= ($i%2) ? $chars[mt_rand(19, 25)] : $chars[mt_rand(0, 18)]; 
    } 

    return $pass; 
} 

此功能可方便地用于生成的验证码太;)

+0

分组字母的想法是什么('$ chars '),为什么你不使用整个字母表(0-25)?它会减少可能的组合。 – martinstoeckli 2012-03-28 15:06:25

+0

@martinstoeckli对不起,我错了(^^,)我忘了重新安排字母表来为例子工作。我通常按​​特定的顺序排列字母,以创造易于发音的单词(即常量,元音,常量,元音,等等) – Songo 2012-03-28 16:02:05

+0

@Songo如果你不介意古语,那么一个有26个字母的句子:“Cwm fjord银行字形vext测验“。 – beltorak 2013-02-07 17:55:07

0

我想这只是野兽的本质。将长度增加到7并添加更多字符,并且重复的概率降低。这是我用来测试:

<?php 
$len = 6; 
# Remove characters that can be mistaken for others, I,0,L,1 and 0 
$chars = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; 
for ($j=0;$j<100000;$j++) { 
    $pass = ''; 
    for ($i = 0; $i < $len; $i++){ 
    $pass .= $chars[(rand() % strlen($chars))]; 
    } 
    if(isset($saved[$pass])) { 
    echo "Password \"$pass\" on iteration $j has duplicate(s) from iteration(s) " . implode(',',$saved[$pass]) . "\n"; 
    } 
    $saved[$pass][] = $j; 
} 
?> 

使用mt_rand()与兰特()并没有改变输出多