Позвольте мне начать этот пост, сказав, что почти ни одно событие не является случайным. Даже исход классического броска монеты теоретически можно было бы предсказать, если бы мы знали о влиянии каждого фактора, например, трения, гравитации и начальной силы.

То же самое применимо к генерации случайных чисел и буквенно-цифровых строк. Самое лучшее, на что мы можем надеяться, это генерировать числа и строки, которые не следуют шаблону и не могут быть практически предсказаны злоумышленником.

В этом уроке мы рассмотрим различные методы генерации случайных чисел и буквенно-цифровых строк в PHP. Некоторые из них будут криптографически безопасны, а другие предназначены только для случайного использования, например, назначение псевдослучайных имен файлов или создание URL-адресов и предложение имен пользователей.

Создание случайных чисел в PHP

Существуют три различные функции для генерации случайных чисел в PHP. Все они будут принимать минимальное и максимально возможное значение для случайных чисел и выдавать случайное число для вас. Это rand($min, $max), mt_rand($min, $max) и random_int($min, $max).

С rand() минимальные и максимальные значения целых чисел, которые вы можете генерировать, лежат между 0 и значением, возвращаемым функцией getrandmax(). До PHP 7.1.0 эта функция была примерно в четыре раза медленнее, чем mt_rand(). Однако, начиная с PHP 7.1.0, она была создана как псевдоним mt_rand(). В отличие от mt_rand(), вы можете установить значение $max меньше, чем $min, не вызывая ошибки.

С mt_rand() минимальные и максимальные значения целых чисел, которые вы можете генерировать, лежат между 0 и значением, возвращаемым mt_getrandmax(). Функция использует реализацию Mersenne Twister для генерации случайных чисел. Остерегайтесь, до PHP 7.1.0, эта функция реализовывала неверную версию алгоритма для генерации чисел. Однако он был исправлен в более новых версиях.

Функция стала еще лучше в PHP 7.2.0, избавившись от ошибки модульного смещения. Это означает, что для некоторых конкретных значений ваша последовательность случайных чисел теперь будет немного лучше по сравнению со старыми версиями. Однако какой-то специализированный код может действительно полагаться на эту предвзятость. Если это так, вы можете использовать более старый алгоритм, вызвав функцию mt_srand() для задания начального числа для генератора случайных чисел и передачи MT_RAND_PHP в качестве значения второго параметра.

Функция mt_rand() имеет период 219937-1, что в основном означает, что в наилучших сценариях вы получаете целых 219937-1 случайных чисел до того, как последовательность начнет повторяться. Следует отметить, что повторение последовательности не совпадает с повторением определенного числа. Другими словами, вы можете получить одно и то же случайное число дважды, но это не значит, что сама последовательность начала повторяться. Примером может служить следующая последовательность:

187 3276 1267 15 1267 34598 3467 125 17

В приведенной выше последовательности у нас было 1267 два раза на выходе, но это не означает, что после этого вся последовательность начала повторяться. Маловероятно, чтобы такое же число повторялось так быстро в случайной последовательности, но это возможно!

Криптографически безопасные случайные целые числа

Если вы хотите криптографически безопасные псевдослучайные числа, функция random_int() в PHP — ваш лучший выбор. Он будет генерировать случайные числа между предоставленными значениями $min и $max, которые по умолчанию соответствуют PHP_INT_MIN и PHP_INT_MAX. К сожалению, эта функция доступна только с PHP 7.0. Для версий до этого вы можете использовать этот полифилл на GitHub.

Случайные числа с плавающей точкой

Вместо генерации случайных целых чисел вы также можете генерировать числа с плавающей точкой. Это можно сделать легко, просто разделив случайное число на значение, возвращаемое mt_getrandmax(). В следующем примере будет проиллюстрировано, как создать случайное значение с плавающей точкой от 0 до 1 или между любыми другими минимальными и максимальными пределами.

<?php

// Output: 0.69458310943776
echo mt_rand(0, mt_getrandmax())/mt_getrandmax();

function mt_random_float($min, $max) {
$float_part = mt_rand(0, mt_getrandmax())/mt_getrandmax();
$integer_part = mt_rand($min, $max — 1);
return $integer_part + $float_part;
}

// Output: 10.199064863938
echo mt_random_float(10, 11);

// Output: 35.540808309121
echo mt_random_float(15, 50);

?>

При генерации случайного числа с плавающей точкой между заданными пределами мы убеждаемся, что случайные целые числа не превышают $max - 1. Таким образом, мы можем быть уверены, что добавление float-части не займет числа выше максимального предела.

Изменение начального числа генераторов случайных чисел

Одна концепция, которая нуждается в небольшом объяснении, — это начальные числа. Проще говоря, это просто цифры, которые можно использовать для инициализации функций rand() и mt_rand() перед генерированием случайных чисел. Функция, которая изменяет начальное число генератора псевдослучайных чисел rand() называется srand($seed), и функция, которая изменяет начальное число генератора псевдослучайных чисел mt_rand() называется mt_srand($seed, $mode).

Важно помнить, что предоставление начального значения случайного числа за один раз до вызова rand() и mt_rand() не обязательно приведет к получению более качественных случайных чисел. Фактически, использование одного и того же начального случайного числа каждый раз даст вам одно и то же случайное число!

<?php

mt_srand(10);
// Output: 1656398468
echo mt_rand();

mt_srand(10);
// Output: 1656398468
echo mt_rand();

mt_srand(10);
// Output: 1656398468
echo mt_rand();

?>

Изменение случайного числа полезно в ситуациях, когда вы хотите создать случайную, но воспроизводимую последовательность. Следующий фрагмент кода генерирует одну и ту же последовательность случайных чисел при повторном запуске.

<?php

mt_srand(10);

$count = 0;

while($count < 10) {
echo mt_rand(0, 100).» «;
$count++;
}

// Output on First Run:
// 68 58 68 13 3 48 30 37 96 82

// Output on Second Run:
// 68 58 68 13 3 48 30 37 96 82

Генерирование воспроизводимых случайных последовательностей таким образом может помочь отлаживать программы, которые тестировались с использованием случайных данных — если вы отслеживаете начальное случайное число, вы можете воспроизвести тот же ввод, чтобы выяснить, что пошло не так.

Генерация случайных буквенно-цифровых строк в PHP

Существует множество способов генерации случайных буквенно-цифровых строк, и то, что вы используете, будет зависеть от ваших потребностей.

Создание перетасованных строк

Если вы хотите генерировать случайные буквенно-цифровые строки из фиксированного набора символов, вы можете использовать функцию str_shuffle($string). Эта функция предоставит вам случайную перетасованную строку. Начиная с PHP 7.1, алгоритм, который определяет случайный порядок символов в выходной строке, был изменен на Mersenne Twister.

Помните, что случайная строка, сгенерированная таким образом, не является криптографически безопасной. Тем не менее, строка по-прежнему будет довольно непредсказуемой для общего использования, например, для генерации случайных имен файлов или URL-адресов. Вот несколько примеров:

<?php

$permitted_chars = ‘0123456789abcdefghijklmnopqrstuvwxyz’;
// Output: 54esmdr0qf
echo substr(str_shuffle($permitted_chars), 0, 10);

$permitted_chars = ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;
// Output: video-g6swmAP8X5VG4jCi.mp4
echo ‘video-‘.substr(str_shuffle($permitted_chars), 0, 16).’.mp4′;

?>

В обоих случаях ваш результат, скорее всего, будет разным. В первом случае мы просто перетасовали допустимую строку символов, а затем взяли первые 10 символов. Во втором случае мы добавили «video» в начале сгенерированной строки и «.mp4» в конце.

Этот способ генерации случайных буквенно-цифровых строк очень прост, но у него есть несколько проблем. Например, вы никогда не получите одинаковые символы в своей случайной строке дважды. Кроме того, длина строки случайного вывода может достигать только длины входной строки.

Создание случайных строк

Если проблемы, перечисленные выше, являются неприемлемыми, вы можете посмотреть на некоторые другие реализации. Следующий код поможет решить эти проблемы.

<?php

$permitted_chars = ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;

function generate_string($input, $strength = 16) {
$input_length = strlen($input);
$random_string = »;
for($i = 0; $i < $strength; $i++) {
$random_character = $input[mt_rand(0, $input_length — 1)];
$random_string .= $random_character;
}

return $random_string;
}

// Output: iNCHNGzByPjhApvn7XBD
echo generate_string($permitted_chars, 20);

// Output: 70Fmr9mOlGID7OhtTbyj
echo generate_string($permitted_chars, 20);

// Output: Jp8iVNhZXhUdSlPi1sMNF7hOfmEWYl2UIMO9YqA4faJmS52iXdtlA3YyCfSlAbLYzjr0mzCWWQ7M8AgqDn2aumHoamsUtjZNhBfU
echo generate_string($permitted_chars, 100);

?>

Вы можете изменить его, чтобы добавить определенные суффиксы и префиксы к сгенерированной случайной строке. Люди, которые используют PHP 7, могут улучшить генерацию строк дальше, используя криптографически защищенную функцию random_int() вместо mt_rand().

Создание случайных шестнадцатеричных строк

Если вы хотите генерировать случайные шестнадцатеричные строки в PHP, вы также можете использовать либо md5($string, $raw_output), либо функцию sha1($string, $raw_output). Обе они будут генерировать хэши входной строки.

Вы будете получать уникальные хэши, пока вход уникален. Этого можно добиться, используя результат функции, такой как time() в качестве входного параметра. По умолчанию md5() вернет шестнадцатеричную строку с 32 символами, а sha1() вернет 40-значную шестнадцатеричную строку. Их можно обрезать до определенной длины, используя функцию substr().

Ниже приведен пример вывода, возвращаемого этими функциями:

<?php

// Output: 36e5e490f14b031e
echo substr(md5(time()), 0, 16);

// Output: aa88ef597c77a5b3
echo substr(sha1(time()), 0, 16);

// Output: 447c13ce896b820f353bec47248675b3
echo md5(time());

// Output: 6c2cef9fe21832a232da7386e4775654b77c7797
echo sha1(time());

?>

Как вы можете видеть, генерация случайных и уникальных шестнадцатеричных строк длиной до 40 символов очень проста в PHP.

Генерация криптографически безопасных случайных строк

Три функции генерации случайных буквенно-цифровых строк, которые мы обсуждали до сих пор, не являются криптографически безопасными. К счастью, PHP также имеет функцию random_bytes($length) для генерации криптографически защищенных псевдослучайных байтов. Параметр $length определяет длительность строки вывода.

Как только вы получите выход в виде случайных байтов, вы можете использовать функцию bin2hex(), чтобы преобразовать их в шестнадцатеричные значения. Это удвоит длину строки.

<?php

// Output: b7b33efa07915b60ad55
echo bin2hex(random_bytes(10));

// Output: a2e6cb1f25616324c8a11a2cceb0b47c590949ea
echo bin2hex(random_bytes(20));

// Output: 25af3b86e11884ef5e8ef70a0ad06cba81b89ed6af3781a0
echo bin2hex(random_bytes(24));

?>

Другая функция, которую вы можете использовать для генерации криптографически безопасных случайных байтов, — openssl_random_pseudo_bytes($length, &$crypto_strong). Значение второго параметра можно использовать для определения того, будет ли генерироваться строка вывода с использованием криптографически безопасного алгоритма или нет.

Заключительные мысли

В этом уроке мы рассмотрели генерацию случайных чисел и буквенно-цифровых строк в PHP. Генерация случайных чисел может быть полезна в самых разных ситуациях, например, в играх, в которых вы должны порождать вражеских игроков или произвольно давать пользователям некоторые подсказки о письмах, чтобы они могли сформировать целое слово.

Подобно случайным числам, генерация случайных буквенно-цифровых строк также может быть весьма полезной во многих случаях. С помощью str_shuffle() вы можете выбрать, какой набор символов появится в ваших случайных строках. С помощью sha1() и md5() вы можете легко генерировать случайные шестнадцатеричные последовательности, а с помощью random_bytes() вы можете генерировать криптографически защищенные строки. Это позволит вам генерировать осмысленные, но рандомизированные имена файлов и имена пользователей, которые трудно подобрать.

Надеюсь, вам понравился этот урок. Если у вас есть какие-либо вопросы, не стесняйтесь задавать их в комментариях.

Источник: code.tutsplus.com