views:

1305

answers:

6

I know that the rand function in PHP generates random integers, but what is the best way to generate a random string such as:

Original string, 9 chars

$string = 'abcdefghi';

Example random string limiting to 6 chars

$string = 'ibfeca';

UPDATE: I have found tons of these types of functions, basically I'm trying to understand the logic behind each step.

UPDATE: The function should generate any amount of chars as required.

Please comment the parts if you reply.

thanks, Keith

A: 
function generate_random_string($name_length = 8) {
 $alpha_numeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 return substr(str_shuffle($alpha_numeric), 0, $name_length);
}

discuss

"UPDATE: The function should generate any amount of chars as required." -- this function will max out at length 62.
Chad Birch
Additionally, it's not random - there can only be one of each character in the resulting string with this approach. A truly random algorithm would have the *possibility* of resulting in 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', however unlikely.
ceejayoz
thats scope creep, im calling shenanigans!
+2  A: 

Do you want to create your password by a random permutation of the original letters? Should it just contain unique characters?

Use rand to choose random letters by index.

Dario
Succinct and functional.
Beska
Succinct, true. However he directly asked for people to NOT be succinct, because he's trying to understand the logic behind it.
Chad Birch
+4  A: 

If you want to allow repetitive occurences of characters, you can use this function:

function randString($length, $charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
{
    $str = '';
    $count = strlen($charset);
    while ($length--) {
        $str .= $charset[mt_rand(0, $count-1)];
    }
    return $str;
}

The basic algorithm is to generate <length> times a random number between 0 and <number of characters> − 1 we use as index to pick a character from our set and concatenate those characters. The 0 and <number of characters> − 1 bounds represent the bounds of the $charset string as the first character is addressed with $charset[0] and the last with $charset[count($charset) - 1].

Gumbo
+3  A: 

Joining characters at the end should be more efficient that repeated string concatenation.

Edit #1: Added option to avoid character repetition.

Edit #2: Throws exception to avoid getting into infinite loop if $norepeat is selected and $len is greater than the charset to pick from.

Edit #3: Uses array keys to store picked random characters when $norepeat is selected, as associative array key lookup is faster than linearly searching the array.

function rand_str($len, $norepeat = true)
{
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $max = strlen($chars) - 1;

    if ($norepeat && len > $max + 1) {
        throw new Exception("Non repetitive random string can't be longer than charset");
    }

    $rand_chars = array();

    while ($len) {
        $picked = $chars[mt_rand(0, $max)];

        if ($norepeat) {
            if (!array_key_exists($picked, $rand_chars)) {
                $rand_chars[$picked] = true;
                $len--;
            }
        }
        else {
            $rand_chars[] = $picked;
            $len--;
        }
    }

    return implode('', $norepeat ? array_keys($rand_chars) : $rand_chars);   
}
Imran
For the no-repeating case, if you're concerned with efficiency, it'd probably be better to use array_splice() to take each picked char out of the $chars array as it's picked, instead of adding an array search on every iteration.
Chad Birch
Another way to improve efficiency could be storing the picked random chars as array index, and then use array_key_exists to check for repeated character. Array key lookup should be more efficient than in_array(), which probably does linear search.
Imran
+8  A: 

Well, you didn't clarify all the questions I asked in my comment, but I'll assume that you want a function that can take a string of "possible" characters and a length of string to return. Commented thoroughly as requested, using more variables than I would normally, for clarity:

function get_random_string($valid_chars, $length)
{
    // start with an empty random string
    $random_string = "";

    // count the number of chars in the valid chars string so we know how many choices we have
    $num_valid_chars = strlen($valid_chars);

    // repeat the steps until we've created a string of the right length
    for ($i = 0; $i < $length; $i++)
    {
        // pick a random number from 1 up to the number of valid chars
        $random_pick = mt_rand(1, $num_valid_chars);

        // take the random character out of the string of valid chars
        // subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
        $random_char = $valid_chars[$random_pick-1];

        // add the randomly-chosen char onto the end of our string so far
        $random_string .= $random_char;
    }

    // return our finished random string
    return $random_string;
}

To call this function with your example data, you'd call it something like:

$original_string = 'abcdefghi';
$random_string = get_random_string($original_string, 6);

Note that this function doesn't check for uniqueness in the valid chars passed to it. For example, if you called it with a valid chars string of 'AAAB', it would be three times more likely to choose an A for each letter as a B. That could be considered a bug or a feature, depending on your needs.

Chad Birch
excellent answer, thanks!
Keith Donegan
A: 

you could make an array of characters then use rand() to pick a letter from the array and added it to a string.

$letters = array( [0] => 'a' [1] => 'b' [2] => 'c' [3] => 'd' ... [25] = 'z');

$lengthOfString = 10;
$str = '';

while( $lengthOfString-- )
{
   $str .= $letters[rand(0,25)];
}
echo $str;

*note that this does allow repeat characters

Josh Curren
Considering that rand() with no arguments returns a value between 0 and getrandmax(), this code is going to print out an empty string about 99.9% of the time, quite possibly more, depending on your platform. And never mind the way you used 27 lines of code to set up a 26-element array.
Chad Birch
opps.. I fixed the missing parameters for rand()...
Josh Curren
That isn't a valid way to declare an array, and you still have a 1/27 chance of picking a non-existent array element every time.
Chad Birch