tags:

views:

89

answers:

2

This is an issue which keeps coming up for me when using random strings.

This is basically the process.

  1. Generate random string
  2. Check if it already exists in the database
  3. If it doesn't use it, else generate another one

So how would I do this using PHP?

+5  A: 

Why not just use a GUID and let the database maintain this. You could then just call a stored proc.

Irwin M. Fletcher
A: 

I would use this function, very simple:

/**
 * Generates a string with random characters taken from the given string
 * of the desided length
 *
 * @param int $length the resulting string length
 * @param string $chars the chars; defaults to all alphanumerics
 * @return string the random string
 * @author Andrea Baron
 */
function rand_string($length,
        $chars = 'qwertyuiopasdfghjklzxcvbnm0123456789') {
    $r = '';
    $cm = strlen($chars)-1;
    for($i=1; $i<=$length; ++$i) {
        $r .= $chars[mt_rand(0, $cm)];
    }

    return $r;
}

then you can do something like this

$used = $db->prepare('SELECT EXISTS(SELECT string FROM table WHERE string = ?)');
do {
    $string = rand_string(32);
    $used->execute(array($string));
    $exists = $used->fetch(PDO::FETCH_NUM);
    $used->closeCursor();
} while($exists && $exists[0]);

$ins = PP::$db->prepare('INSERT INTO table SET string=?');
$ins->execute(array($string));

if you use PDO and MySQL; I would set the string field as Primary Key, or a HASH index if on a secondary field; or more concise and, maybe, not as strong:

do {
    $string = rand_string(32);
    $exists = PP::$db->exec('INSERT INTO a SET string='.PP::$db->quote($string));
} while(!$exists);

this because exec() returns the number of affected rows on no error, or false if there's an error, in this case a duplicate key value.

Or, as an alternative, you can add a timestamp and forget about checking at all. Like:

$string = rand_string(8).time();

The probability of having a duplicate identifier resets each second, and, with 8 characters, as you see is 1 in 37^8, or 3.5E12.

iBobo