random_int
Generates a cryptographically secure, uniformly distributed integer between a minimum and maximum.
random_int(int $min, int $max): int- Added in PHP 7.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$min | int | The lowest value that may be returned. Can be as low as PHP_INT_MIN. |
$max | int | The highest value that may be returned. Must be greater than or equal to min, and can be as high as PHP_INT_MAX. |
Return value
intA cryptographically secure, uniformly selected integer from the closed interval [min, max]. Both min and max are possible return values.
Errors
Throws Random\RandomException if no suitable source of randomness is available, and ValueError if max is less than min.
Changelog
- PHP 8.2.0A CSPRNG failure now throws Random\RandomException. Previously a plain Exception was thrown, so old catch (Exception $e) blocks still work because Random\RandomException extends Exception.
random_int() draws from the operating system's cryptographically secure random source — getrandom() or /dev/urandom on Linux, the CNG API on Windows, CCRandomGenerateBytes() on macOS. The result is uniform across the closed interval, with no modulo bias, and it cannot be predicted from previous outputs.
When to reach for it
Use it for anything an attacker would benefit from guessing: one-time passwords, invite codes, password reset PINs, coupon codes, shuffling that decides money. Also reach for it when you simply want a correct random integer in a range and do not care about speed — it is fast enough for anything that is not a tight simulation loop.
Keep mt_rand() for bulk simulation, Monte Carlo work, or seeded procedural generation, where you need millions of draws or reproducibility. Everything else should default to random_int().
What trips people up
It signals failure by throwing, never by returning false. In practice the CSPRNG is available, so most code can let Random\RandomException bubble up — but a bare-metal container with no /dev/urandom will turn that into a fatal error, not a quiet fallback.
The range is inclusive on both ends. When picking an array index, the upper bound is count($items) - 1.
Example
When to use it
- Generate a six-digit one-time password for two-factor login
- Create a human-readable coupon or invite code from a restricted alphabet
- Pick a random winner from a list of contest entries where fairness matters
- Add a random jitter of a few seconds to a retry delay so clients do not stampede
Frequently asked questions
What is the difference between random_int and mt_rand?
random_int() pulls from the operating system's cryptographic random source and is unpredictable, while mt_rand() uses a Mersenne Twister whose full internal state can be recovered from a few hundred observed outputs. Use random_int() for anything security-related and mt_rand() only for simulation or seeded, reproducible output.
Is random_int inclusive of the max value?
Yes, both bounds are inclusive: random_int(1, 6) can return 1 and 6. When picking an array index, pass count($array) - 1 as the maximum.
Do I need to wrap random_int in a try/catch?
Usually no — Random\RandomException is only thrown when the system has no usable randomness source, which does not happen on a normal server. Catch it only if you have a meaningful fallback; ValueError, by contrast, means your min and max are the wrong way round and should be fixed in code.
More examples
Six-digit one-time password
Drawing once from 0 to 999999 and left-padding keeps every code equally likely, including ones that start with zeros. The output always shows a length of 6 — building the code digit by digit would be fine too, but padding a single draw is shorter and just as uniform.
<?php
$otp = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
echo "OTP: $otp\n";
echo 'length: ', strlen($otp), "\n";
echo 'digits only: ', var_export(ctype_digit($otp), true), "\n";Fair pick from a list, and the full integer range
The index bound is count() - 1 because the interval is inclusive at both ends. The second half shows what mt_rand() cannot do: random_int() spans the whole 64-bit integer range, so the drawn value is usually far larger in magnitude than getrandmax().
<?php
$entries = ['ana', 'ben', 'cleo', 'dev', 'eli'];
$winner = $entries[random_int(0, count($entries) - 1)];
echo "winner: $winner\n";
$big = random_int(PHP_INT_MIN, PHP_INT_MAX);
echo 'full-range draw: ', $big, "\n";
echo 'beyond rand() max: ', var_export(abs($big) > getrandmax(), true), "\n";
Discussion