Jason
Jason

Reputation: 587

PHP Random String Generator... not so random

I always thought my code generated pretty random strings but I've been pressing F5 for about 10 minutes and I display 10 strings at once and I have had THREE DUPLICATES, UNIBON, ZANOPE and ZOTAXS.

Can anyone explain why this is when I though there code be 26^6 possibilities?

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

Any advice would be much appreciated.

Thanks


Using mt_rand the first duplicate takes on average between 10 and 60 seconds, that seems okay doesn't it?

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;
    }
}

Upvotes: 1

Views: 843

Answers (4)

dwilkins
dwilkins

Reputation: 2131

I think that's just the nature of the beast. Increase the length to 7 and add some more characters and the probability of duplicates goes down. This is what I used to test:

<?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;
}
?>

Using mt_rand() vs rand() didn't change the output much

Upvotes: 0

Songo
Songo

Reputation: 5726

You should use mt_rand.

mt_rand is way better than rand. From the PHP manual

Many random number generators of older libcs have dubious or unknown characteristics and are slow. By default, PHP uses the libc random number generator with the rand() function. The mt_rand() function is a drop-in replacement for this. It uses a random number generator with known characteristics using the » Mersenne Twister, which will produce random numbers four times faster than what the average libc rand() provides.

That aside you can use this function instead to generate random strings with the length you wish ;)

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;
}

This function can be used easily to generate CAPTCHAs too ;)

Upvotes: 0

Userbn
Userbn

Reputation: 342

You should try this :

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

Upvotes: 0

Pete
Pete

Reputation: 1299

Why don't you hash a random number then take a random substring from the hash?

Upvotes: 1

Related Questions