How to Create Your Own Random Number Generator in PHP

Computers cannot generate random numbers. A machine which works in ones and zeros is unable to magically invent its own stream of random data. However, computers can implement mathematical algorithms which produce pseudo-random numbers. They look like random numbers. They feel like random distributions. But they’re fake; the same sequence of digits is generated if you run the algorithm twice.

Planting Random Seeds

To increase the apparent randomness, most algorithms can be passed a seed — an initialization number for the random sequence. Passing the same seed twice will still generate the same set of random numbers but you can set the seed based on external input factors. The easiest option is the current time but it can be anything; the last keypress, a mouse movement, the temperature, the number of hours wasted on YouTube, or any other factor.

Random PHP Functions

PHP offers a number of random number functions. The main ones are:

  1. rand() and the more efficient mt_rand() function. Both return a random number between zero and getrandmax()/mt_getrandmax(). Alternatively, you can pass minimum and maximum parameters:

    
    // random number between 0 and 10 (inclusive)
    echo mt_rand(0, 10);
    
  2. srand($seed) and mt_srand($seed) to set a random number seed. This has been done automatically since PHP 4.2.0.

PHP is Too Random!

There are instances when creating a repeatable list of pseudo-random numbers is useful. It’s often used for security or verification purposes, e.g. encrypting a password before it’s transmitted or generating a hash code for a set of data. Unfortunately, PHP can be a little too random. A generated sequence will depend on your hosting platform and version of PHP. In other words, you can’t guarantee the same ‘random’ sequence will be generated twice on two different machines even if the same seed is used.

Rolling Your Own Random Class

Fortunately, we can write our own random number generator. You’ll find many algorithms on the web, but this is one of the shortest and fastest. First, we initialize our class and a random seed variable:


class Random {

	// random seed
	private static $RSeed = 0;

Next we have a seed() function for setting a new seed value. For the algorithm to work correctly, the seed should always be a positive number greater than zero but not large enough to cause mathematical overflows. The seed function takes any value but converts it to a number between 1 and 9,999,999:


	// set seed
	public static function seed($s = 0) {
		self::$RSeed = abs(intval($s)) % 9999999 + 1;
		self::num();
	}

Finally, we have our num() function for generating a random number between $min and $max. If no seed has been set it’s initialized with PHP’s own random number generator:


	// generate random number
	public static function num($min = 0, $max = 9999999) {
		if (self::$RSeed == 0) self::seed(mt_rand());
		self::$RSeed = (self::$RSeed * 125) % 2796203;
		return self::$RSeed % ($max - $min + 1) + $min;
	}

}

We can now set a seed and output a sequence of numbers:


// set seed
Random::seed(42);

// echo 10 numbers between 1 and 100
for ($i = 0; $i < 10; $i++) {
	echo Random::num(1, 100) . '<br />';
}

If you’ve copied this code exactly, you should see the following values no matter what OS or version of PHP you’re running:

76
86
14
79
73
2
87
43
62
7

Admittedly, repeatable “random” numbers isn’t something you’ll need every day — you’re more likely to require something closer to real randomness and PHP’s functions will serve you better. But there may be occasions when you find this useful.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • IanFromBarrie

    Thanks Craig:
    Being able to repeat a pseudo-random sequence saved one of my clients from a legal challenge.

    This client audits a sample of their membership every year. A disgruntled member once took them to court claiming their sampling process was biased. They had to defend the sampling method used.

    Their IT consultant at the time provided clear proof. He’d used industry standard pseudo-random-number generation algorithms. He built the system in COBOL, and included the ability to repeat a run as your system does. That made my client’s audit process defensible.

    We’ve sinced moved to access, where to repeat a pseudorandom sequence,
    1 you use vba to call rnd(-1),
    2. use vba to call randomize( ####) ( #### seeds the random number generator)
    3. select * from yourtable order by rnd( SomeIntegerValueInTheTable)

    We’re moving to a PHP/MySQL solution, and this sort of thing is just what the doctor ordered.
    Thanks again

    • http://blog.ircmaxell.com ircmaxell

      IanFromBarrie,

      Please do not use an algorithm like this any time there’s legal or security requirements. Use only a vetted FIPS (Federal Information Processing Standards) certified random number generator. Linux has one at /dev/random, and Windows has one in its CryptoRNG provider.

      A class like this is great for non-secure requirements (like implementing a game), but it’s not secure, and is not a strong quality random number (it’s heavily biased and predictable).

      • http://www.optimalworks.net/ Craig Buckler

        Exactly – it’s useful in situations where you need repeatable random numbers. A game maze generator would be ideal; everyone would see the same maze no matter what.

  • IanFromBarrie

    …but if you’re trying to generate a repeatable random list from a mysql table or query, it looks pretty easy:

    SELECT field1, … etc. FROM `yourtable` order by rand( yourseed) limit 0, NumberOfSamples -1

    Order by rand() scrambles the “eggs”.
    Iincluding a seed argument for rand() seeds the generator to ensure the same run.

    • The Red Devil

      Do not use the SQL RAND() function, avoid it for all cost unless this is a table with only a few records. The reason for this is due to it require moving the data to a temp table and then shuffle the data before pulling the info.

      Instead use LIMIT X, 1 where X is the pre shuffled position you want to pull. The reason we use LIMIT instead of the primary key, is in the events you allow records to be deleted in this table, in that case it is not certain the primary key exists.

  • http://blog.shay.co/ Shay Ben Moshe

    Thanks for the article.
    Some comments:
    First, 2796203 you will never get a bigger number than 2796203, hence you won’t reach the maximum…
    Second, anything special about 125 and 2796203 or are they just some random numbers you choose? I mean, is there any specific reason to use them?

    Thanks again

    • http://www.optimalworks.net/ Craig Buckler

      Those values are defined by the algorithm I found – probably because they result in “better” random results.

  • Dmitri

    Or you can just do this:
    mt_srand($your_seed);
    for ($i = 0; $i < 10; $i++) {
    echo mt_rand(1, 100) . '’;
    }

    As long as you use the same seed you will get same results. This solution is for those who would rather not write unnecessary classes, but hey, if you like to write extra code then you class is fine too.

    • http://leetsee.com/ Leetsee

      unfortunately this doesn’t work on servers with “suhosin.mt_srand.ignore” on.
      http://www.hardened-php.net/suhosin/changelog.html

      “Modified rand()/srand() to use the Mersenne Twister algorithm with separate state
      Added better internal seeding of rand() and mt_rand()”

    • http://www.optimalworks.net/ Craig Buckler

      And it will vary across versions of PHP/hosting platform.
      Of course, that’s not a problem if you only ever have one installation and never intend upgrading PHP.