mt_rand
Generates a pseudo-random integer, optionally within an inclusive minimum and maximum.
mt_rand(): int
mt_rand(int $min, int $max): int- Added in PHP 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$minoptional | int | The lowest value that can be returned. Must be supplied together with max; with no arguments the range starts at 0. |
$maxoptional | int | The highest value that can be returned, inclusive. Must be supplied together with min; with no arguments it defaults to mt_getrandmax(). |
Return value
intA random integer between min and max inclusive, or between 0 and mt_getrandmax() when called with no arguments.
Errors
Throws a ValueError as of PHP 8.0.0 if max is less than min.
Changelog
- PHP 8.0.0A ValueError is thrown if max is less than min. Previously an E_WARNING was raised and the function returned false.
- PHP 7.2.0A modulo bias bug was fixed, so sequences generated from a specific seed may differ from PHP 7.1 on 64-bit machines.
- PHP 7.1.0Switched to the fixed, correct Mersenne Twister implementation, and rand() became an alias of mt_rand().
mt_rand() draws from a Mersenne Twister generator. It is fast and has a very long period, which makes it the right default for simulations, sampling, shuffling test data and picking a random element.
It is not secure
Mersenne Twister is fully deterministic. Given a modest number of consecutive outputs, an attacker can reconstruct the internal state and predict every future value. Never use mt_rand() for password reset tokens, session identifiers, API keys, CSRF tokens, coupon codes or anything else where guessing has a cost. Use random_int() for those — it has the same signature and pulls from the operating system's cryptographic source.
Both bounds or neither
You must pass $min and $max together. Both are inclusive, so mt_rand(1, 6) can return 6. Since PHP 8.0, passing a $max lower than $min throws a ValueError instead of returning false, so validate ranges that come from user input.
Range width matters
The generator produces 32-bit values internally. A requested range wider than mt_getrandmax() is scaled up, which makes the distribution coarser — you get gaps, not every integer. For 64-bit ranges use random_int() or the Random\Randomizer class.
Example
When to use it
- Pick a random element from an array by index for a demo or a test fixture
- Roll dice or shuffle cards in a game simulation
- Generate reproducible sample data by seeding with mt_srand() first
- Add jitter to a retry delay so clients do not all reconnect at once
Frequently asked questions
What is the difference between mt_rand and random_int?
random_int() is cryptographically secure and unpredictable; mt_rand() is fast but fully deterministic and can be predicted from a handful of outputs. Use random_int() for tokens, passwords and anything security-related, and mt_rand() for simulations and test data.
Is mt_rand inclusive of min and max?
Yes, both bounds are inclusive. mt_rand(1, 6) can return 1 or 6, so when indexing an array you need mt_rand(0, count($array) - 1).
How do I make mt_rand return the same sequence every time?
Call mt_srand() with a fixed integer seed before the first mt_rand() call. Re-seeding with the same value restarts the identical sequence, which is useful for reproducible tests.
More examples
Reproducible output by seeding
Re-seeding with the same value restarts the generator from the same state, so the two arrays are identical. This is what makes mt_rand() useful for repeatable test fixtures - and exactly why it is unsafe for tokens.
<?php
mt_srand(1234);
$first = [mt_rand(1, 100), mt_rand(1, 100), mt_rand(1, 100)];
mt_srand(1234);
$second = [mt_rand(1, 100), mt_rand(1, 100), mt_rand(1, 100)];
print_r($first);
var_dump($first === $second); // bool(true)Off-by-one when indexing an array
mt_rand(0, count($a)) would sometimes return an index one past the end. The counts array shows roughly 250 hits per element, confirming the distribution across the correct 0-3 range is even.
<?php
$fruit = ['apple', 'banana', 'cherry', 'date'];
// Correct: both bounds inclusive, so subtract 1
$i = mt_rand(0, count($fruit) - 1);
echo $fruit[$i], "\n";
// array_rand() avoids the arithmetic entirely
echo $fruit[array_rand($fruit)], "\n";
$counts = array_fill_keys($fruit, 0);
for ($n = 0; $n < 1000; $n++) {
$counts[$fruit[mt_rand(0, 3)]]++;
}
print_r($counts);Checking the range is valid first
Since PHP 8.0 an inverted range throws a ValueError rather than quietly returning false. Catching it, or validating the bounds beforehand, is necessary whenever the range comes from user input or configuration.
<?php
function pick(int $min, int $max): int|string {
try {
return mt_rand($min, $max);
} catch (ValueError $e) {
return 'error: ' . $e->getMessage();
}
}
var_dump(pick(1, 10) >= 1); // bool(true)
echo pick(10, 1), "\n"; // error: ...
Discussion