Reputation: 587
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
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
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
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
Reputation: 1299
Why don't you hash a random number then take a random substring from the hash?
Upvotes: 1