2012-03-28 153 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()與蘭特()並沒有改變輸出多