PHP rand vs mt_rand and openssl_random_pseudo_bytes

July 17, 2013 — Leave a comment

I’ve been doing some work with random strings lately and, in an effort to improve the speed of my code, did some testing. I discovered an interesting alternative to php rand…

Overview of the php rand function

rand($minimum, $maximum) is a function, built-in to PHP, that returns a random* number between $minimum and $maximum. The number is generated using an automatic seed **.

php rand() and mt_rand()

You might see recommendations to use mt_rand(), even from the documentation at php.net. The reasons given are usually 1: Security, and 2: Speed. As it happens, both of these arguments are no longer valid and a third option might be better.

Security, libc, Mersenne

Many hosting environments now run the Suhosin PHP extension. Suhosin replaces rand()’s use of libc with the much more secure Mersenne Twister. So sites on servers running Suhosin are using the same algorithm as mt_rand(). Of course, if you’re not in control of hosting, or your project is open source, you might want togo straight for mt_rand() so that you can be sure.

Speed of mt_rand() vs rand()

First: any recommendations to use mt_rand due to alleged speed will only apply if the platform is not running Suhosin. But also it seems that the differences in performnace between these might have become much less of afactor in the last few years. In the tests I ran mt_rand performed around the same or slightly better: around 2-4% faster on average.

php rand for passwords

It’s common to use rand() and mt_rand() for password generation (in fact a recent tutorial post for beginners documents this method). But a better idea might be to use another function, openssl_random_pseudo_bytes(). In my test, documented below, this function has been significantly faster. It’s faster even with an additional functional call to normalise the results (base64_encode) to make them password-friendly.

Windows gotcha
Note that Windows has long been noted for poor OpenSSL performance. So on windows use mt_rand() – openssl_random_pseudo_bytes runs best on Linux & Mac OS.

Try the code below… you need the GLPTimer class to do the performance profiling.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
include 'GLPTimer.php';
 
function generateRandom($length) {
   $validCharacters = 'abcdefghijklmnopqrstuvwxyz0123456789';
   $myKeeper = '';
   for ($n = 1; $n < $length; $n++) {
      $whichCharacter = rand(0, strlen($validCharacters)-1);
      $myKeeper .= $validCharacters{$whichCharacter};
   }
   return $myKeeper;
}
 
function generateRandomdMT($length) {
   $validCharacters = 'abcdefghijklmnopqrstuvwxyz0123456789';
   $myKeeper = '';
   for ($n = 1; $n < $length; $n++) {
      $whichCharacter = mt_rand(0, strlen($validCharacters)-1);
      $myKeeper .= $validCharacters{$whichCharacter};
   }
   return $myKeeper;
}
 
GLPTimer::getInstance()->snap();
echo '<h2 style="font-family: sans-serif; font-size: 16px; margin-top: 20px">rand():</h2>';
echo htmlentities(generateRandom(100000));
GLPTimer::getInstance()->snap();
 
echo '<h2 style="font-family: sans-serif; font-size: 16px; margin-top: 20px">mt_rand():</h2>';
echo htmlentities(generateRandomdMT(100000));
GLPTimer::getInstance()->snap();
 
echo '<h2 style="font-family: sans-serif; font-size: 16px; margin-top: 20px">openssl_random_pseudo_bytes():</h2>';
echo htmlentities(substr(base64_encode(openssl_random_pseudo_bytes(100000)), 0, 100000));
GLPTimer::getInstance()->snap();

Typical results on my machine:
GLPTimer: php rand and mt_rand vs openssl
…note that mt_rand is sometimes slower than rand. openssl_random_pseudo_bytes is always faster than both of them.

* Not truly random. The number is pseudo random: in some cases the results may be repeatable.

** Prior to PHP 4.2.0 it was important to seed the random number generator with srand() but this is now done automatically.

No Comments

Be the first to start the conversation.

Leave a Reply

*

Text formatting is available via select HTML.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>