Rand Alternatives: Should You Stop Using It?
The calculator for this page is switched off while it is checked. The formula is below, and the worked example in the article shows how to use it by hand.
Yes, you should stop using PHP’s rand() function for security-sensitive purposes, and use random_int() or random_bytes() instead. For non-security uses like simulations or games, mt_rand() is a better choice than rand() because it is faster and has better statistical properties.
Formula
The calculator above helps you understand the practical difference between rand() and mt_rand() in PHP. The key formula is the number of values in the range: range size = max – min + 1. The entropy in bits is logâ‚‚(range size). The expected number of calls before a repeat (the birthday bound) is approximately sqrt(Ï€/2 × state_size / range_size), but the calculator shows a simplified cycle length estimate: state_size / range_size, where state_size is 2³¹ for rand() and 2¹â�¹â�¹Â³â�· for mt_rand().
Worked Example
Using the default values: min = 1, max = 100, so range size = 100 – 1 + 1 = 100. Entropy = logâ‚‚(100) ≈ 6.64 bits. For rand(), the estimated cycles before repeat = 2³¹ / 100 ≈ 21,474,836. For mt_rand(), it’s 2¹â�¹â�¹Â³â�· / 100, which is astronomically larger. This shows that mt_rand() can generate far more unique sequences before repeating.
Background: Why rand() Is Problematic
PHP’s rand() uses the C library’s random number generator, which varies by operating system. On many systems, it uses a linear congruential generator (LCG) with a period of 2³¹. This means it can produce at most about 2.1 billion numbers before repeating. More importantly, the lower bits of LCG outputs are not very random, and the distribution can be biased when you use modulo to map to a range. For example, rand() % 100 will not produce a perfectly uniform distribution because 2³¹ is not evenly divisible by 100.
How the Generators Compare
- rand(): Simple, but slow and statistically weak. Period 2³¹. Not suitable for cryptography.
- mt_rand(): Uses the Mersenne Twister algorithm. Period 2¹��³�, much faster, and passes many statistical tests. Still not cryptographically secure.
- random_int(): Generates cryptographically secure random integers using the operating system’s entropy source. This is the only safe choice for security tokens, passwords, or any unpredictable data.
- random_bytes(): Returns raw random bytes, also cryptographically secure. Use it when you need binary data or want to generate a random string yourself.
When to Use Which
If you are generating a session ID, CSRF token, password reset link, or any value that an attacker could exploit, you must use random_int() or random_bytes(). rand() and mt_rand() are predictable: if an attacker knows the seed or can observe enough outputs, they can predict future values. For non-security uses like shuffling a deck of cards in a game, picking a random background color, or Monte Carlo simulations, mt_rand() is fine and faster. rand() is essentially obsolete; use mt_rand() instead if you cannot use random_int() for some reason.
Common Mistakes and Misconceptions
A frequent mistake is using rand() or mt_rand() for anything security-related because they are “random enough” in casual tests. Another is using modulo to restrict the range, which introduces bias. For example, rand() % 100 will favor smaller numbers slightly. Always use random_int($min, $max) for a uniform range when security matters. Also, seeding mt_srand() manually is rarely needed and can reduce entropy if done poorly. In PHP 7.1+, mt_rand() is automatically seeded, so you don’t need to call mt_srand() yourself.
How to Migrate Your Code
- Find all calls to
rand()andmt_rand()in your codebase. - For each call, decide if the output is used in a security context (e.g., tokens, IDs, passwords). If yes, replace with
random_int($min, $max). - If not security-related, replace
rand()withmt_rand()for better performance and quality. - If you need a random string (e.g., for a filename), use
bin2hex(random_bytes($length))orrandom_int()with a character set. - Test thoroughly, especially if you rely on the same sequence of random numbers for reproducibility (in that case, consider using a seeded PRNG like
mt_srand()deliberately).
Performance and Portability
random_int() is slower than mt_rand() because it reads from the OS entropy pool, which can block if insufficient entropy is available. However, for most applications, the number of calls is small, so the performance difference is negligible. On Linux, random_int() uses getrandom() which is fast and non-blocking after boot. On Windows, it uses CryptGenRandom. Both are portable across PHP 7 and later. rand() is implemented differently on different platforms, which can lead to inconsistent behavior across servers.
Frequently Asked Questions
Is mt_rand() cryptographically secure?
No. mt_rand() is a Mersenne Twister, which is a pseudo-random number generator that is not designed for cryptography. Its state can be reconstructed from a few hundred outputs, making it predictable. Use random_int() for any security-sensitive data.
Can I use random_int() for non-security purposes?
Yes, you can, but it may be slower than mt_rand() if you need millions of random numbers. For most applications, the difference is negligible. If performance is critical and security is not a concern, mt_rand() is a better fit.
What is the difference between random_int() and random_bytes()?
random_int($min, $max) returns a random integer within a specified range. random_bytes($length) returns a string of raw random bytes. Use random_bytes() when you need binary data or want to generate a random string by encoding the bytes (e.g., base64 or hex).
Why does rand() produce biased results with modulo?
Because the range of rand() (0 to RAND_MAX) is not evenly divisible by your modulo value. For example, if RAND_MAX is 32767 and you do rand() % 100, numbers 0-67 appear one extra time each. This bias is small but can be significant in simulations or games.
Does PHP 7.1 automatically seed mt_rand()?
Yes, since PHP 7.1, mt_rand() is automatically seeded with a cryptographically secure random value, so you don’t need to call mt_srand() manually. However, you can still call mt_srand() to reproduce a specific sequence for testing.
What should I use for generating a random password?
Use random_bytes() and then encode it, or use random_int() to pick characters from a defined set. For example, to generate a 16-character alphanumeric password, you can loop 16 times and pick a random character from a string of allowed characters using random_int(0, strlen($charset)-1).
Related
Formula used
in t | Number of values | - | 10 | 1 in min | Minimum value | - | 1 | 0 in max | Maximum value | - | 100 | 0 out range | Range size | - | max - min + 1 | 0 out entropy | Entropy (bits) | bits | log2(max - min + 1) | 2 out rand_cycles | rand() cycles before repeat | - | 2^31 / (max - min + 1) | 0 out mt_cycles | mt_rand() cycles before repeat | - | 2^19937 / (max - min + 1) | 0
Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.