Генерация случайных чисел: от базовых до безопасных решений
Основные подходы к генерации случайных чисел в PHP
Наиболее эффективное и безопасное решение для большинства задач — функция random_int(). Она гарантирует криптографически стойкие случайные целые числа в заданном диапазоне, используя системный источник энтропии. Для случаев, где безопасность не критична (например, игровая механика, не влияющая на безопасность), можно применять mt_rand() — она быстрее и имеет лучший период псевдослучайной последовательности.
// Криптостойкое случайное число от 1 до 100
echo random_int(1, 100);
74
// Быстрое небезопасное случайное число от 1 до 100
echo mt_rand(1, 100);
42
Типичная ошибка — использование rand() без аргументов, что даёт число от 0 до getrandmax(). При попытке получить число в нужном диапазоне через остаток от деления (rand() % 100) возникает смещение распределения из-за неравномерного остатка. Функции random_int() и mt_rand() решают эту проблему.
Как сгенерировать случайное целое число в заданном диапазоне?
Используйте random_int($min, $max) для безопасных целей или mt_rand($min, $max) для обычных.
$number = random_int(5, 15); // от 5 до 15 включительно
echo $number;
12
Ошибка: передача нецелых аргументов или min > max вызывает исключение (random_int) или предупреждение (mt_rand). Всегда проверяйте типы и корректность границ.
Как получить случайное число с плавающей точкой от 0 до 1?
Разделите результат mt_rand() на mt_getrandmax(). Для криптостойкости используйте random_int() с делением.
// Небезопасный вариант
$float = mt_rand() / mt_getrandmax();
echo $float;
0.473829104
// Безопасный вариант
$float = random_int(0, PHP_INT_MAX) / PHP_INT_MAX;
echo $float;
0.189234023
Проблема: при использовании PHP_INT_MAX как делителя возможно переполнение при умножении. Лучше использовать random_int(0, 1e12) / 1e12 для получения числа с ограниченной точностью.
Как перемешать массив случайным образом?
Функция shuffle() перемешивает массив на месте, используя внутренний генератор случайных чисел.
$cards = ['A', 'K', 'Q', 'J'];
shuffle($cards);
print_r($cards);
Array
(
[0] => Q
[1] => A
[2] => J
[3] => K
)
Ошибка: shuffle() использует тот же генератор, что и rand() — по умолчанию mt_rand(). Для криптостойкого перемешивания (например, в лотерее) применяйте array_rand() в сочетании с random_int() или специальную функцию.
Как получить случайный элемент из массива?
Функция array_rand() возвращает один или несколько случайных ключей массива. По умолчанию она использует mt_rand(), но можно передать random_int через коллбек.
$fruits = ['apple', 'banana', 'cherry'];
$key = array_rand($fruits);
echo $fruits[$key];
banana
Проблема: array_rand() не использует криптостойкий генератор. Для безопасного выбора (например, генерация токена) создайте собственный вызов с random_int().
$key = random_int(0, count($fruits) - 1);
echo $fruits[$key];
Расширенные примеры генерации случайных чисел
Создание случайного пароля заданной длины
Используйте random_bytes() для получения криптостойких байтов, затем закодируйте их в строку.
function generatePassword($length = 12) {
$bytes = random_bytes(ceil($length * 3/4));
return substr(base64_encode($bytes), 0, $length);
}
echo generatePassword(16);
A3xR9kLmN2Pq
Ошибка: использование base64_encode() может включать символы + и /, которые не подходят для паролей. Можно заменить их на безопасные символы с помощью strtr().
Генерация UUID v4 (случайный идентификатор)
Стандарт RFC 4122 требует 122 бита случайных данных. Реализуйте через random_bytes().
function uuidV4() {
$data = random_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
echo uuidV4();
f47ac10b-58cc-4372-a567-0e02b2c3d479
Воспроизводимая последовательность случайных чисел (seed)
Функция mt_srand($seed) задаёт начальное состояние для mt_rand(), что полезно для тестирования.
mt_srand(42);
echo mt_rand(1, 100) . "\n";
echo mt_rand(1, 100) . "\n";
// Сброс seed для повторения
mt_srand(42);
echo mt_rand(1, 100) . "\n";
56 22 56
Проблема: mt_srand() не влияет на random_int() и random_bytes(). Для воспроизводимости криптостойких чисел используйте ручные алгоритмы (например, AES в режиме CTR с известным ключом).
Генерация случайного числа с нормальным распределением
Метод Бокса-Мюллера преобразует два равномерных случайных числа в нормально распределённые.
function gaussRandom($mean = 0, $stddev = 1) {
$u1 = mt_rand() / mt_getrandmax();
$u2 = mt_rand() / mt_getrandmax();
$z = sqrt(-2 * log($u1)) * cos(2 * M_PI * $u2);
return $mean + $z * $stddev;
}
echo gaussRandom(100, 15);
118.4723
Ошибка: если $u1 = 0, логарифм даст -INF. Добавьте минимальное значение, например max($u1, 1e-10).
Безопасное получение случайных байтов для криптографии
Функция random_bytes($length) возвращает строку сырых байтов. Используйте для создания ключей, соли, nonce.
$salt = random_bytes(16);
echo bin2hex($salt);
a1b2c3d4e5f6071829
Проблема: на некоторых системах (например, в изолированных окружениях) вызов random_bytes() может выбросить исключение из-за отсутствия источника энтропии. Обрабатывайте через try/catch.