PHP rand() vs. random_int()

Revisiting the question and seeing there's been an answer given, I find it's only fair that I submit my comments to an answer, seeing they were submitted before.

The manual on PHP 7's random_int() function states:

"Returns a cryptographically secure random integer in the range min to max, inclusive."

  • http://php.net/manual/en/function.random-int.php

and for rand()

*This function does not generate cryptographically secure values" *

  • http://php.net/manual/en/function.rand.php

OP's comment:

"@Fred-ii- thank you. But what does "cryptographically secure pseudo-random" mean? – NDFA"

That can be found in the following links as per my findings:

  • https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator

Which states:

A cryptographically secure pseudo-random number generator (CSPRNG) or cryptographic pseudo-random number generator (CPRNG)[1] is a pseudo-random number generator (PRNG) with properties that make it suitable for use in cryptography.


  • How does a cryptographically secure random number generator work?

In regards to performance, you will need to run a benchmark yourself.


rand()

rand() is now an alias for mt_rand(). Looking at the source code of mt_rand(), it can be seen the random number is not random at all. It's a simple mathematical computation not much more complex than

return $min + suffle_bits($internal_counter++) % ($max - $min);

where suffle_bits() is some predictable binary arithmetic to make it looks like $internal_counter is not just incrementing itself.

That's why rand() is said to returns pseudo-random numbers. The returned numbers seem to be drawn at random but knowing the value of the $internal_counter lets you predict what will follow.

random_int()

random_int() doesn't suffer from this predictability issue provided the computer's entropy generator is properly primed.

Guessing the next value is not possible even if an attacker collects a huge number of values.

Which one is best

If an attacker can guess the value of the $internal_counter from the output of your code and use that knowledge to interfere with the intended purpose of your code, then use random_int().

If the random number is used to display, let's say, a random greeting, then rand() is perfectly safe.

Now, if a long list of GUID or barcodes must be generated and the end user must not be able to guess another valid value from a subset, then random_int() is better not only for security but also because it doesn't repeat itself. rand() may repeat itself as quickly as 32768 output depending on the platform.

Which one is faster

Without any doubt, rand() is simpler and, therefore, faster.

Here is a crude one-line easy to copy/paste command to count how many numbers can be drawn from rand() in 10 seconds:

php -r '$s=microtime(true);$c=0;while(microtime(true)-$s<10){rand(0,9);$c++;};echo "$c\n";'

And the same for random_int():

php -r '$s=microtime(true);$c=0;while(microtime(true)-$s<10){random_int(0,9);$c++;};echo "$c\n";'

The counters for php 7.3 are:

rand():       36665142
random_int(): 10511327

rand() is less than 4 times faster. Unless speed is an issue, random_int() is the way to go but for the most basic non critical missions.


Starting with PHP 7.1, rand() is an alias for mt_rand(). The newer random_int() is the slowest, but only secure method of the three.

<?php

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += rand(0, 32767);
}
printf('[rand] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += mt_rand(0, 32767);
}
printf('[mt_rand] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += random_int(0, 32767);
}
printf('[random_int] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

Results on PHP 7.4:

[rand] Time: 0.320 s      
[mt_rand] Time: 0.326 s   
[random_int] Time: 9.255 s

Tags:

Php

Php 7