PHP random string generator: how the random string generator works under the hood
\n\nEvery developer has encountered the task at least once: generate a random string. For tokens, temporary passwords, session IDs, or just for test data. In PHP, there are about a dozen ways to do this, but which one is correct? And most importantly — why?
\n\nOn Stack Overflow, the question "PHP random string generator" has garnered thousands of views and hundreds of answers. But most of them are just ready-made snippets without explanation. Today, we'll look under the hood of PHP and figure out how random string generators actually work, how rand() differs from random_int(), and why your "random" password might not be random at all.
What is "randomness" in PHP?
\n\nIn programming, randomness comes in two types: pseudo-randomness and cryptographically secure randomness. The difference between them is like the difference between a die and a predictable calculator.
\n\nPseudo-random numbers (PRNG) are generated by an algorithm based on an initial seed. If you know the seed, you know the entire sequence. For simple tasks (randomizing a color in design, test data), this is sufficient. But for authentication tokens and passwords, this is a disaster.
\n\nPHP offers several functions, and each one represents a different level of "randomness":
\n\n- \n
rand()— classic PRNG, fast but predictable \n mt_rand()— improved Mersenne Twister algorithm, faster and with a longer period \n random_int()andrandom_bytes()— cryptographically secure generators (PHP 7+) \n openssl_random_pseudo_bytes()— another cryptographically secure option \n
How does the most popular snippet work?
\n\nHere is the classic code that circulates on the internet:
\n\n<?php\nfunction generateRandomString($length = 10) {\n $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n $charactersLength = strlen($characters);\n $randomString = '';\n for ($i = 0; $i < $length; $i++) {\n $randomString .= $characters[rand(0, $charactersLength - 1)];\n }\n return $randomString;\n}\n?>\n\nAt first glance, it all makes sense. Take a string of characters, randomly select an index, repeat. But let's break down what is actually happening here.
\n\nProblem #1: rand() and its seed
\n\nThe rand() function in PHP by default uses the Linear Congruential Generator (LCG) algorithm. This is one of the oldest and most predictable methods. If you haven't called srand() with a random seed, PHP automatically initializes the generator with the current time (in microseconds).
Knowing the exact script execution time (for example, from server logs), an attacker can reproduce the entire rand() sequence. For a password reset token, this is a direct path to compromise.
Problem #2: Probability Bias
\n\nEven if you don't think about security, there is a mathematical problem. Imagine rand(0, 61) (62 characters in the string). PHP internally uses a range from 0 to getrandmax() (usually 2147483647). 2147483647 is not evenly divisible by 62. The remainder of the division is 31. This means that the first 31 numbers in the range have a slightly higher probability of being selected than the rest.
In practice, the difference is negligible, but if you need a uniformly distributed random string, rand() is not the best choice. random_int() solves this problem by using an algorithm that guarantees uniform distribution.
Cryptographically secure generator: what's under the hood?
\n\nIn PHP 7, the functions random_int() and random_bytes() appeared. They use the system's entropy source:
- \