mt_rand

Generates a pseudo-random integer, optionally within an inclusive minimum and maximum.

Signature
mt_rand(): int
mt_rand(int $min, int $max): int
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$minoptionalintThe lowest value that can be returned. Must be supplied together with max; with no arguments the range starts at 0.
$maxoptionalintThe 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

Try it yourself
Loading editor…
Press Run to execute the code.

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.

Example · php
<?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.

Example · php
<?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.

Example · php
<?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

  • Be the first to comment on this lesson.