A better way to deal with disallowed characters than hardcoded replacements would be to have a list of valid characters (similar to your "vowels" list) that would simply not include any of the contents of $confusing. The way it stands, probability of anything in $replacements is doubled.
I've got good news, and I've got bad news: The universe is merely a figment of my imagination. Now are you ready for the bad news?
Note how, though they're not great, you could actually pronounce most of 'em if you tried. "Nine zeck eck thirty-three" (9xekek33) or "Sack eh dicky" (sakediky) is easier to remember than fzwzklgn. Also note how you don't have any Il10O problems.
I've got good news, and I've got bad news:
The universe is merely a figment of my imagination.
Now are you ready for the bad news?
<?php
/**
* Generates slightly more human-understandable random passwords
*
* @param int $len
* @return string
*/
function makePassword($len = 8)
{
$vowels = array('a', 'e', 'i', 'o', 'u', 'y');
$confusing = array('I', 'l', '1', 'O', '0');
$replacements = array('A', 'k', '3', 'U', '9');
$choices = array(0 => rand(0, 1), 1 => rand(0, 1), 2 => rand(0, 2));
$parts = array(0 => '', 1 => '', 2 => '');
if ($choices[0]) $parts[0] = rand(1, rand(9,99));
if ($choices[1]) $parts[2] = rand(1, rand(9,99));
$len -= (strlen($parts[0]) + strlen($parts[2]));
for ($i = 0; $i < $len; $i++)
{
if ($i % 2 == 0)
{
do $con = chr(rand(97, 122));
while (in_array($con, $vowels));
$parts[1] .= $con;
}
else
{
$parts[1] .= $vowels[array_rand($vowels)];
}
}
if ($choices[2]) $parts[1] = ucfirst($parts[1]);
if ($choices[2] == 2) $parts[1] = strrev($parts[1]);
$r = $parts[0] . $parts[1] . $parts[2];
$r = str_replace($confusing, $replacements, $r);
return $r;
}
?>
1. 9xekek33
2. Makoryxu
3. 37mahyz5
4. 9jitoz35
5. gugipe38
6. Xemyvare
7. 33iciQ39
8. Boxycusa
9. 39yqymyX
10. 36huwup3
11. ikiwyR28
12. apaqyV33
13. 9votuf35
14. qehuvo35
15. Cojafe23
16. sakediky
17. 39sirody
18. Potewube
19. cejitira
20. Hukugop3