PHP fast random string function
Asked Answered
G

6

8

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?

Goose answered 21/1, 2011 at 9:53 Comment(4)
Always use MCRYPT_DEV_URANDOM. It has decent performance is secure.Lamee
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?Lamee
mcrypt_create_iv($numBytes, MCRYPT_DEV_URANDOM) is actually faster than trying to build it using mt_rand(). :)Lustig
mcrypt_create_iv() is deprecated in PHP 7.1. An alternative is php.net/manual/en/function.random-bytes.phpCoherent
P
3
  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.

Pintle answered 21/1, 2011 at 10:53 Comment(3)
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.Goose
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.Pintle
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).Goose
E
6

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).

Euonymus answered 31/3, 2018 at 3:24 Comment(1)
This function is fast and really random but random_bytes() function is works in php 7. We can change this function with this for older php versions: hash('sha512', rand(), 1)Madigan
R
5

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
Retinue answered 9/12, 2014 at 3:38 Comment(2)
The disadvantage of this method is the limited number of letters that the hexadecimal representation offers (a-f).Euonymus
@Euonymus that's true, this code does not produce g-z lettersRetinue
H
4

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 https://mcmap.net/q/1324267/-how-to-create-a-random-string-using-php
    $alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    return substr(str_shuffle(str_repeat($alphabet, $length)), 0, $length);
}

function rstr2($length)
{
    // @see https://mcmap.net/q/1324267/-how-to-create-a-random-string-using-php
    $alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $str = '';
    $count = strlen($alphabet);
    while ($length--) {
        $str .= $alphabet[mt_rand(0, $count-1)];
    }
    return $str;
}

function rstr3($length) {
    // @see https://mcmap.net/q/1269358/-php-fast-random-string-function/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;
}
Houdon answered 9/9, 2013 at 8:1 Comment(3)
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.Goose
rstr4 has the disadvantage of not offering a full range of lettersEuonymus
@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)Houdon
P
3
  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.

Pintle answered 21/1, 2011 at 10:53 Comment(3)
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.Goose
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.Pintle
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).Goose
S
0

I usually work with this one. Also I can choose if I don't want certain characters

function rstr5($length = 1) {
    return substr(str_shuffle(str_repeat("0123456789abcdefghijklmnopqrstuvwxyz", $length)), 0, $length);
}
Scutate answered 5/10, 2022 at 11:12 Comment(0)
M
-1

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);
Micahmicawber answered 21/1, 2011 at 13:3 Comment(2)
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.Goose
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.Goose

© 2022 - 2024 — McMap. All rights reserved.