I need fast way for generating random strings a-Z0-9 in PHP. I've been doing some thinking and testing, this is what I've got so far:

function randStr($length) {
    $result = null;
    $replace = array('/', '+', '=');
        while(!isset($result[$length-1])) {
        $result.= str_replace($replace, NULL, base64_encode(mcrypt_create_iv($length, MCRYPT_RAND)));
        }
    return substr($result, 0, $length);
}

Function seems to be working fast compared to functions which iterate and choose random ASCII value for each char, but I'm concerned with 'quality' of my implementation. I do not know much about cryptography, so I'd like to ask whether this kind of function creates 'good' random values or not.

  1. mcrypt_create_iv seems to return some kind of random binary values, actually used for encrypting/decrypting data with mcrypt library. What is base64_encode effect on this kind of binary data, do I actually decrease entropy, when I base64_encode it?

  2. How does second parameter for mcrypt_create_iv affect my results? php.net manual states that MCRYPT_RAND is 'system random number generator'. Is it OS specific and if so, how good values are created?

  • Always use MCRYPT_DEV_URANDOM. It has decent performance is secure. – CodesInChaos Feb 25 '14 at 10:06
  • Post your alternative as an answer, not in the question. (It's also a very bad solution). You should also clarify the question. Does the function need to be secure, or not? – CodesInChaos Feb 25 '14 at 10:08
  • 1
    mcrypt_create_iv($numBytes, MCRYPT_DEV_URANDOM) is actually faster than trying to build it using mt_rand(). :) – Scott Arciszewski Dec 3 '15 at 21:28
  • mcrypt_create_iv() is deprecated in PHP 7.1. An alternative is php.net/manual/en/function.random-bytes.php – jchook Feb 23 '17 at 2:29
up vote 3 down vote accepted
  1. base64_encoding won't decrease entropy, it is just a different representation of the same data.

  2. It is OS specific, but I think the random values created are good enough with this function. Under PHP 5.3 you have to seed the generator beforehand, it can be a problem if you use this code on different servers.

  • Thank you for your answer. My real concern about base64 is that should I base my results length on binary data length or base64 length? For example - if I generate random string with user 'Core Xii' suggested way and with my function, both having string length 100, are those strings equivalent? What i really mean is that when I base64_decode my result it becomes shorter, although it seems to be binary. – Mikk Jan 21 '11 at 16:16
  • 1
    If I get it... If you want a 20 chars long string, you should cut down the base64 to 20 chars. This method seems absolutely right to me. – kapa Jan 21 '11 at 16:22
  • Thank you for helping me undestand. I think I'll implement this function since there is no downside I can think of (except compatibility between PHP versions). – Mikk Jan 21 '11 at 16:41

This supposed to be secure on most of the systems and fast:

bin2hex(openssl_random_pseudo_bytes($length / 2));

benchmarks (1000000 records, string length 100 chars)

rstr1: 198.93383002281
rstr2: 35.5827729702
rstr3: 6.8811790943146
rstr4: 5.4545040130615
this:: 3.9310231208801
  • The disadvantage of this method is the limited number of letters that the hexadecimal representation offers (a-f). – Joseph Mar 31 at 3:08
  • @Joseph that's true, this code does not produce g-z letters – Afanasii Kurakin Mar 31 at 9:55

From my tests, your function is already very fast, but i managed to get to a faster one, even if it decreases the entropy

fcn     time  
rstr1:  1.074s (slowest)
rstr2:  0.917s
rstr3:  0.028s (yours)
rstr4:  0.022s (mine)

In my scenario, i needed 1k strings, as fast as possible.

function rstr1($length)
{
    // @see http://stackoverflow.com/a/853846/11301
    $alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alphabet, $length)), 0, $length);
}

function rstr2($length)
{
    // @see http://stackoverflow.com/a/853870/11301
    $alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $str = '';
    $count = strlen($alphabet);
    while ($length--) {
        $str .= $alphabet[mt_rand(0, $count-1)];
    }
    return $str;
}

function rstr3($length) {
    // @see http://stackoverflow.com/q/4757392/11301
    $result = null;
    $replace = array('/', '+', '=');
    while(!isset($result[$length-1])) {
        $result.= str_replace($replace, NULL, base64_encode(mcrypt_create_iv($length, MCRYPT_RAND)));
    }
    return substr($result, 0, $length);
}

function rstr4($length)
{
    // uses md5 & mt_rand. Not as "random" as it could be, but it works, and its fastest from my tests
    return str_shuffle(substr(str_repeat(md5(mt_rand()), 2+$length/32), 0, $length));
}


// test the functions
for($i=0; $i<1000; $i++){
    #$x = rstr1(1024); # 
    #$x = rstr2(1024);  # 0.917s
    #$x = rstr3(1024);  # 0.028s
    #$x = rstr4(1024);  # 0.022s

    #dlog($x); return;
}
  • Nice to see another interesting solution and some benchmarking. As you said, md5(mt_rand()) cryptographically is actually not that "random" since md5 produces 128-bit hash value and mt_rand() depending on your configuration gives you only 32/64-bit integers. It all comes down to whether you need cryptographically "good" values or you need some raw speed. – Mikk Sep 9 '13 at 10:02
  • rstr4 has the disadvantage of not offering a full range of letters – Joseph Mar 31 at 3:21
  • @Joseph: True, but it wasn't a requirement, the poster only needed a random string, this gets the job done, and its fast (or at least it was at that time, PHP 7 changed a few things I assume) – Quamis Apr 2 at 7:36

For anyone looking for an updated version of the "best" algorithm:

function randomString($length) {
   $result = null;
   $replace = array('/', '+', '=');
   while(!isset($result[$length-1])) {
      $result.= str_replace($replace, NULL, base64_encode(random_bytes($length)));
   }
   return substr($result, 0, $length);
}

I use the term "best" because it is faster than the random string manipulations of rstr1 and rstr2 and in comparison to the other solutions offers a full spectrum of letters (lower- and uppercased).

This is how I'm doing it, though it's not exactly cryptographic; The Mersenne Twister is fast and reliable, but not the most secure.

function str_rand($chars, $len)
  {
  $str = '';
  for ($max = strlen($chars) - 1, $i = 0; $i < $len; ++$i)
       {
       $str .= $chars[mt_rand(0, $max)];
       }
  return $str;
  }

$strRand = str_rand('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 40);
  • 1
    Thank you for your reply, your function seems to be working fine, but in my case, it's too slow calling mt_rand for each single char. – Mikk Jan 21 '11 at 16:21
  • Did you benchmark or is that an assumption? – Core Xii Jan 21 '11 at 21:57
  • 4
    Well now that you asked, I measured it. When generating 1000000 random strings with length 100, your function took on my small laptop ~92 seconds, function using mcrypt random iv, made same job with ~13.8 seconds. – Mikk Jan 22 '11 at 19:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.