The switch could be shortened
switch ($number%3) {
case 0: $str .= chr(mt_rand(50,57)); break; //2-9
case 1: $str .= chr(mt_rand(65,90)); break; //A-Z
case 2: $str .= chr(mt_rand(97,122)); break; //a-z
}
or replaced by
$lo_ranges = array(50, 65, 97);
$hi_ranges = array(57, 90, 122);
$lo_range = $lo_ranges[$number%3];
$hi_range = $hi_ranges[$number%3];
$str .= chr(mt_rand($lo_range, $hi_range));
or
$digits='23456789'; $max_digit=7;
$uppercase='ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $max_uppercase=25;
$lowercase='abcdefghijklmnopqrstuvwxyz'; $max_lowercase=25;
switch ($number%3) {
case 0: $str .= $digits{mt_rand(0,$max_digit)}; break; //2-9
case 1: $str .= $uppercase{mt_rand(0,$max_uppercase)}; break; //A-Z
case 2: $str .= $lowercase{mt_rand(0,$max_lowercase)}; break; //a-z
}
I don't see what the point of $rn and $rn2 are in generating $number is; what's wrong with $number=mt_rand(0,9)? Or even mt_rand(0,2) (except that (0,2) doesn't have a bias in favour of selecting digits over upper- or lowercase letters).
I also don't see the point of randomly generating a lot more characters than necessary and then making a random selection from those - a uniformly distributed selection from a uniform distribution is still just a uniform distribution.
//0 and 1 are not retrieved to avoid confusion between the letter O and number 0,
//and letter I or letter l and number 1
$character_sets = array(
'23456789',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'
);
$character_set_max_offsets = array(7,25,25);
for($count_passwd=0; $count_passwd<$num_output; ++$count_passwd)
{
$str = '';
for($char=0; $char<$length; ++$char)
{
$n = mt_rand(0,9)%3;
$character_set = $character_sets[$n];
$character_set_max_offset = $character_set_max_offsets[$n];
$str .= $character_set{mt_rand(0,$character_set_max_offset)};
}
$rand[] = $str;
}