Уроки по php | Пару слов о генерации случайных чисел в PHP
Случайные числа — это неотъемлемая часть программирования, особенно если это касается систем безопасности. К примеру, криптография основывается на генерации случайных значений, для получения чисел которые невозможно предугадать. Конечно же и в PHP случайные числа играют огромную роль: с помощью них мы можем генерировать токены, соль и другие значения. Генерация случайных чисел основывается на специальных алгоритмах. Входным параметром, от которого будет отталкиваться алгоритм, может быть как случайное значение, так и заранее определённое. В этой статье мы поговорим о случайных числах: как они генерируются и где их можно задействовать. Использование случайных чисел В PHP случайные числа играют огромную роль, т.к. очень часто используются для различных целей. В основном, они связаны с безопасностью. На их основе генерируются токены CSRF, ключи API, значения для аутентификации, значения для сброса паролей и многое другое. Всё это делается, для того чтобы получаемые значение было невозможно предугадать. Самые важные примеры применения случайных значений: Генерация соли для криптографии — случайное число соли используется, как правило, для шифрования “в одну сторону”, а также для хэширования паролей. Это случайное значение используется как вектор инициализации в криптографии. Генерация случайных значений, таких как ID сессии — PHP используется для создания огромного количества приложений, где безопасность стоит на первом месте. Многий функционал базируется на работе с сессиями и сгенерированными ID сессий. Генерация токенов для аутентификации, которые практически невозможно предугадать — многие PHP приложения базируются на работе с другими системами через специальные API интерфейсы. Обычно перед использованием API нужно пройти процесс аутентификации. Получать трудно-подбираемые значения для токенов очень сложно. Именно поэтому в данных задачах используются случайные числа. Генераторы случайных чисел Случайные числа, использующиеся в случаях, описанных выше, в PHP генерируются псевдо-генераторами. Всего доступно несколько алгоритмов: Линейный конгруэнтный метод, при использовании функции lcg_value(). Вихрь Мерсенна, используется функцией mt_rand(). Функция rand(), использующая аналогичную функцию в языке Си. Фактически данные функции возвращают не случайные числа, а числа, распределённые таким образом, что они выглядят как случайные. Последовательность этих чисел зависит от базового случайного числа внутри реализованного алгоритма. Базовые числа для генераторов Базовые числа или вектора таких чисел — это наборы данных, которые используются для генерации случайных чисел. Псевдо-генераторы случайных чисел работают, только отталкиваясь от них. Если злоумышленник узнает это базовое число, то в будущем сможет предугадать значения ваших случайных чисел. В PHP вы можете задать базовые числа двумя способами. Первый — это используя функцию mt_srand(). Этот способ в основном используется при юнит тестах случайного ряда. Второй способ — это предоставление PHP право самому генерировать базовые числа. Начиная с версии 4.2, PHP предоставляет эту возможность. В последствии для генерации случайных чисел будет задействован Вихрь Мерсенна. PHP генерирует базовое число, в зависимости от операционной системы. На платформах Linux можно воспользоваться функциями mcrypt_create_iv() или openssl_pseudo_random_bytes() в /dev/urandom. Windows предоставляет специальный псевдо-генератор, к которому можно получить доступ через функции openssl_pseudo_random_bytes() и the mcrypt_create_iv(). Итог Поскольку случайные числа играют огромную роль в построении безопасных веб приложений, то нам нужно больше знать о том, как они работают. Если вы сами захотите генерировать базовые числа для псевдо-генераторов, то убедитесь в надёжности ваших методов.
Показ случайных неповторяющихся записей из БД (MySQL + PHP)
В связи с часто поступающими вопросами о том, как можно быстро и хорошо показать несколько случайных неповторяющихся записей из БД, рассмотрим классическую задачу: показ нескольких неповторяющихся банеров из множества имеющихся.
Варианты решения:
- Сгенерировать несколько случайных чисел в диапазоне от 1 до количества записей в таблице. НЕ ГОДИТСЯ. Высок риск попасть на «дырку» в последовательности значений первичных ключей, получившуюся из-за того, что какие-то банеры были удалены. Да, можно эти «дырки» устранять, но менять значение суррогатного первичного ключа — извращение. Однако, мы попробуем один хитрый способ (см. пункт E).
- Выбрать несколько записей, отсортировав всю выборку в случайном порядке. Этот способ ОЧЕНЬ НЕ РЕКОМЕНДЕТСЯ специалистами по БД, но часто применяется на практике. РАССМОТРИМ. (См. пункт A).
- Перенести логику определения случайного банера на уровень бизнес-логики приложения. Сначала получаем полный список имеющихся значений поля b_uid, а потом что-то с ним делаем. РАССМОТРИМ. (См. пункты B, C, D).
- Модификация способа 1, основанная на выборке банеров по случайно сгенерированному множеству значений в диапазоне от минимального до максимального значения поля b_uid. Это множество должно превосходить (иногда, значительно) количество показываемых банеров, т.к. может содержать значения поля b_uid, отсутствующие в БД в силу того, что такие банеры были удалены. РАССМОТРИМ. (См. пункт E).
- Модификация способа 4, основанная на выборе банеров не по значениям buid, а по диапазонам значений. РАССМОТРИМ. (См. пункт F).
Допустим, банеры хранятся в такой таблице в MySQL:
CREATE TABLE `banner` (`b_uid` int(11) NOT NULL AUTO_INCREMENT COMMENT ‘Идентификатор’,
`b_url` text NOT NULL COMMENT ‘URL рекламируемого сайта’,
`b_text` text NOT NULL COMMENT ‘Текстовая часть банера’,
`b_pic` varchar(200) NOT NULL DEFAULT » COMMENT ‘Имя файла для графической части банера’,
`b_show` bit(1) NOT NULL DEFAULT ‘1’ COMMENT ‘1 — отображать, 0 — нет’,
`b_to_show` int(11) NOT NULL COMMENT ‘Сколько показов оплачено’,
`b_to_click` int(11) NOT NULL COMMENT ‘Сколько кликов оплачено’,
`b_real_show` int(11) NOT NULL COMMENT ‘Сколько раз банер показан’,
`b_real_click` int(11) NOT NULL COMMENT ‘Сколько раз по банеру кликнули’,
PRIMARY KEY (`b_uid`),
KEY `b_show` (`b_show`,`b_to_show`,`b_to_click`,`b_real_show`,`b_real_click`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Итак, алгоритмы и оценка их производительности. Будем выбирать 20 банеров.
A) Алгоритм 1.
- Начало.
- Выбрать из БД нужное количество случайных записей, отсортированных в случайном порядке.
- Показать записи.
- Конец.
B) Алгоритм 2, модификация 1.
- Начало.
- Выбрать из БД ВСЕ значения поля b_uid.
- Переместить все значения b_uid в массив «ИСХОДНЫЙ».
- Сгенерировать случайное число в диапазоне [0, количество элементов в массиве «ИСХОДНЫЙ» — 1].
- Если в массиве «ИСХОДНЫЙ» есть элемент с таким номером, поместить его в массив «КОНЕЧНЫЙ», иначе — вернуться на шаг 4.
- Повторять шаги 4-5 до накопления в массиве «КОНЕЧНЫЙ» необходимого количества значений b_uid.
- Выбрать из БД записи со значениями b_uid, содержащимися в массиве «КОНЕЧНЫЙ».
- Показать записи.
C) Алгоритм 2, модификация 2.
- Начало.
- Выбрать из БД ВСЕ значения поля b_uid.
- Переместить все значения b_uid в массив «ИСХОДНЫЙ».
- Сгенерировать случайное число в диапазоне [0, количество элементов в массиве «ИСХОДНЫЙ» — 1].
- Получить значение b_uid из элемента массива «ИСХОДНЫЙ» с номером, полученным на шаге 4.
- Поместить значение b_uid, полученное на шаге 4, в массив «КОНЕЧНЫЙ».
- Удалить элемент с номером, полученным на шаге 4 из массива «ИСХОДНЫЙ».
- Переиндексировать массив «ИСХОДНЫЙ».
- Повторять шаги 4-8 до накопления в массиве «КОНЕЧНЫЙ» необходимого количества значений b_uid.
- Выбрать из БД записи со значениями b_uid, содержащимися в массиве «КОНЕЧНЫЙ».
- Показать записи.
- Конец.
D) Алгоритм 2, модификация 3.
- Начало.
- Выбрать из БД ВСЕ значения поля b_uid.
- Переместить все значения b_uid в массив «ИСХОДНЫЙ».
- Сгенерировать случайное число в диапазоне [0, количество элементов в массиве «ИСХОДНЫЙ» — 1].
- Получить значение b_uid из элемента массива «ИСХОДНЫЙ» с номером, полученным на шаге 4.
Если в массиве «КОНЕЧНЫЙ» ещё нет такого значения, поместить его туда. Иначе — вернуться на шаг 4.- Повторять шаги 4-6 до накопления в массиве «КОНЕЧНЫЙ» необходимого количества значений b_uid.
- Выбрать из БД записи со значениями b_uid, содержащимися в массиве «КОНЕЧНЫЙ».
- Показать записи.
- Конец.
E) Алгоритм 3.
- Начало.
- Получить минимальное значение поля b_uid.
- Получить максимальное значение поля b_uid.
- Сгенерировать в пять раз больше, чем требуется показать банеров, случайных чисел в диапазоне [минимальное значение b_uid, максимальное значение b_uid] и поместить их в массив «КОНЕЧНЫЙ».
- Выбрать из БД записи со значениями b_uid, содержащимися в массиве «КОНЕЧНЫЙ».
- Если количество возвращённых БД записей меньше требуемого количества банеров И не исчерпано количество попыток, перейти к шагу 4.
- Показать записи.
- Конец.
Теперь исследуем, как наши алгоритмы ведут себя на разных объёмах данных. Тест проводился на MySQL 5.1.41, PHP 5.3.2, Apache 2.2.14. Скрипты выполнялись в случайном порядке так, чтобы каждый из них выполнился 100 раз. Ниже приведены средние данные (в секундах) по всем 100 выполнениям для каждого скрипта.
Записи \ Метод | A | B | C | D | E |
10000 | 0.059 | 0.014 | 0.021 | 0.014 | 0.005 |
20000 | 0.103 | 0. 043 | 0.028 | 0.005 | |
30000 | 0.158 | 0.040 | 0.064 | 0.041 | 0.005 |
40000 | 16.710 | 0.245 | 0.219 | 0.009 | |
50000 | 107.522 | 0.228 | 0.236 | 0.297 | 0.010 |
60000 | 232.938 | 0. 256 | 0.232 | 0.353 | |
70000 | 362.722 | 0.247 | 0.226 | 0.384 | 0.012 |
80000 | — | 0.239 | 0.223 | 0.379 | 0.014 |
90000 | — | 0.259 | 0.237 | 0.373 | 0.015 |
100000 | — | 0. 270 | 0.279 | 0.389 | 0.017 |
500000 | — | 7.925 | 8.740 | 7.983 | 0.104 |
1000000 | — | 16.294 | 16.947 | 16.143 | 0.557 |
Память при 1000000 записей | — | 12538 Kb | 12538 Kb | 12541 Kb | 347 Kb |
Алгоритм 3 (пункт E) является абсолютным лидером как по производительности, так и по объёму используемой памяти, поэтому именно его мы доработаем и проверим в «условиях, наиболее близких к реальности». Имеющийся миллион банеров мы «проредим», удалив случайные банеры так, чтобы их осталось только сто тысяч. Затем проверим, как работает классический вариант алгоритма 3 (пункт E) и его модификация (алгоритм 4, пункт F), основанная на выборке данных по диапазонам и случайной сортировке средствами СУБД в случае неудачи выборки по конкретным значениям.
F) Алгоритм 4.
- Начало.
- Получить минимальное и максимальное значение поля b_uid.
- Сгенерировать в пять раз больше, чем требуется показать банеров, случайных чисел в диапазоне [минимальное значение b_uid, максимальное значение b_uid] и поместить их в массив «КОНЕЧНЫЙ».
- Выбрать из БД записи со значениями b_uid, содержащимися в массиве «КОНЕЧНЫЙ».
- Если количество возвращённых БД записей меньше требуемого количества банеров, сгенерировать запрос, WHERE часть которого вместо секции IN будет содержать перечень диапазонов в виде (`b_uid`>=1868 AND `b_uid`=5257 AND `b_uid`
- Выполнить запрос.
- Увеличить диапазон вдвое.
- Если количество возвращённых БД записей меньше требуемого количества банеров И не исчерпано количество попыток, перейти к шагу 3.
- Показать записи.
- Конец.
Итак, исследование скорости работы на ста тысячах записей, первичные ключи которых не образуют непрерывную последовательность целых чисел, показало.
Результаты испытаний:
Записи \ Метод | A | B | C | D | E | F |
100000 | 743.944 | 0.191 | 0.332 | 0. 536 | 0.134 | 0.024 |
ВЫВОД
Алгоритм 1 (пункт A) вполне пригоден для работы с небольшим количеством данных. На большом же количестве его использование совершенно исключено.
Алгоритм 2 (в модификациях B, C, D) «продержался» гораздо дольше, но на действительно больших объёмах данных (от ста тысяч записей и больше) он тоже показывает недопустимое время выполнения.
Алгоритм 3 (пункт E) хорош на «непрерывной последовательности первичных ключей». В случае, если таковой нет, этот алгоритм может с достаточно высокой вероятностью не возвратить требуемого количества записей. При проводимом эксперименте на «прореженных ключах» этот алгоритм НИ РАЗУ не вернул 20 банеров. Да, теоретически, можно суммировать банеры, выбранные этим алгоритмом за несколько попыток, но вот будет ли это достаточно эффективно и быстро на больших объёмах данных — вопрос открытый.
Алгоритм 4 (пункт F) наиболее универсален: быстр, занимает мало памяти, прекрасно справляется с поставленной задачей. При проводимом эксперименте на «прореженных ключах» этот алгоритм НИ РАЗУ не был вынужден переходить к повторному увеличению диапазона, т.е. в 100 случаях из 100 он справился с задачей с первой попытки. Пользуйтесь, предлагайте свои усовершенствования.
Все исходные файлы эксперимента.
Готовый дамп БД (сто тысяч записей с «прореженными ключами»).
Создать случайное число в PHP
php2 года назад
Фахмида Йесмин
Генерация разных чисел каждый раз при выполнении скрипта называется случайным числом. Случайное число может использоваться для различных целей в программировании, таких как создание случайного имени файла, случайного пароля и случайного числа, которое нельзя предсказать другим. PHP имеет множество встроенных функций для генерации случайных чисел различными способами. ранд() , 9Функции 0007 random_int() и mt_rand() используются в PHP для генерации случайных чисел. Как эти функции используются для генерации случайных чисел, объясняется в этом руководстве.Использование rand()
Эта функция используется для генерации случайного целого числа. Синтаксис этой функции приведен ниже.
Синтаксис:
int rand()
или
int rand(int min, int max)
Возвращает большое случайное целое число, если в функции не используется параметр. Если в этой функции указаны два значения аргумента, она вернет случайное целое число на основе значений аргумента. Использование этой функции показано ниже.
Пример 1: Различные варианты использования функции rand()
В следующем примере показаны три различных использования функции rand() для генерации случайного числа. Сначала функция rand() вызывается два раза без каких-либо аргументов, чтобы показать, как по умолчанию генерируются случайные числа. Далее он вызывается два раза с двумя разными минимальными и максимальными значениями. Наконец, он вызывается два раза с побитовым оператором.
//Использование функции rand() без аргумента
echo «
Случайное число с использованием rand() без аргумента:
«;echo «
Первое случайное число: «. ранд(). «
«;echo «
Второе случайное число: «. ранд(). «
«;//Использование функции rand() с аргументами
echo «
Случайное число с использованием rand() путем определения аргументов:
«;echo «
Первое случайное число в диапазоне [10-100]: «. ранд (10 100). «
«;echo «
Второе случайное число в диапазоне [100-500]: «. ранд (100 500). «
«;//Использование функции rand() с побитовым оператором
echo «
Случайное число с использованием rand() с использованием побитового оператора:
«;echo «Первое случайное число с использованием побитового оператора (&) с 10: «;
эхо ранд()&10 ;
echo «
Второе случайное число с использованием побитового оператора (&) с 50: «;
эхо ранд()&50 ;
?>
Вывод:
Аналогичный вывод появится после запуска скрипта с сервера. Первый вывод показывает два разных больших числа. На втором выходе первое случайное число сгенерировано в диапазоне от 10 до 100, а второе случайное число сгенерировано в диапазоне от 100 до 500. На третьем выходе первое случайное число сгенерировано в диапазоне диапазоне от 0 до 10, а второе случайное число было сгенерировано в диапазоне от 0 до 50.
Использование random_int()
Эта функция используется для генерации криптографически псевдобезопасного случайного числа. Функция системного вызова getrandom(2) используется в Ubuntu для генерации криптографического случайного числа. Эта функция более безопасна, чем функция rand() , потому что сгенерированное число непредсказуемо. Но random_int() медленнее, чем функция rand() . Синтаксис этой функции приведен ниже.
Синтаксис:
int random_int(int min, int max)
В функции используются два аргумента для установки диапазона генерации криптографического случайного числа. Первый аргумент используется для установки наименьшего значения, а второй аргумент используется для установки наибольшего значения числа. Использование этой функции показано ниже.
Пример 2: Различные варианты использования функции random_int()
В следующем примере показано использование функции random_int() для генерации случайного числа путем задания минимального и максимального значений. Эти значения могут быть целыми или числами с плавающей запятой, но минимальное значение не может быть больше максимального значения. В первые random_int() , в качестве минимального и максимального значений используются положительные целые числа. Во второй функции random_int() отрицательное целое число используется как минимум, а положительное целое число используется как максимальное значение. В третьей функции random_int() плавающие числа используются как минимальное и максимальное значения.
//Установить положительное минимальное и положительное максимальное значения
echo «
Вывод random_int() с положительными минимальным и максимальным значениями: » . random_int(1000, 10000). «
«;//Установите отрицательные минимальные и положительные максимальные значения
echo «
Вывод random_int() с отрицательными минимальными и положительными максимальными значениями: » .random_int(-500, 10000). «
«;//Установите дробные минимальное и максимальное значения
echo «
Вывод random_int() с дробными минимальными и максимальными значениями: » .random_int(0,67, 54,89). «
«;?>
Вывод:
После запуска сценария с сервера появится следующий аналогичный вывод.
Использование mt_rand()
Эта функция используется для генерации высококачественных псевдослучайных чисел с помощью генератора Mersenne Twister . Она работает быстрее, чем функция rand() . Синтаксис этой функции приведен ниже.
Синтаксис:
int mt_rand(int min, int max)
Как и функция rand() , она может принимать два аргумента для установки максимального и минимального значений, и эта функция также может использоваться без каких-либо аргументы. Использование этой функции показано ниже.
Пример 3: Различные варианты использования функции mt_rand()
В следующем примере показано использование функции mt_rand() с аргументами и без них. Первая функция mt_rand() вызывается без каких-либо аргументов, которые будут генерировать большое целое число. Вторая функция mt_rand() вызывается с минимальным и максимальным значением, которое будет генерировать число в пределах заданного диапазона.
//Использование функции mt_rand() без аргумента
echo «
Сгенерированное случайное число с помощью mt_rand() без аргумента:
«;эхо «
«. mt_rand(). «
«;//Использование функции mt_rand() с аргументами
echo «
Сгенерированное случайное число с использованием mt_rand() путем определения аргументов:
«;эхо «
«. mt_rand(15 150). «
«;?>
Вывод:
После запуска сценария с сервера будет сгенерирован следующий аналогичный вывод. Первый вывод показывает, что было сгенерировано большое целое число, когда в 9 не используется аргумент.0007 Функция mt_rand() . Второй вывод показывает, что было сгенерировано число в диапазоне от 15 до 150.
Заключение
В этом руководстве на простых примерах объясняются три различных способа генерации случайных чисел в PHP. Лучше использовать функцию random_int() , когда важна безопасность, но лучше использовать функцию mt_rand() , когда требуется более быстрая генерация случайного числа. рандов() 9Функцию 0008 можно использовать для генерации простого случайного числа.
Об авторе
Фахмида Есмин
Я веду курсы веб-программирования. Мне нравится писать статьи или учебные пособия на различные темы в области ИТ. У меня есть канал на YouTube, на котором опубликовано множество типов руководств по Ubuntu, Windows, Word, Excel, WordPress, Magento, Laravel и т. д.: Tutorials4u Help.
Посмотреть все сообщения
Случайность с PHP | Бен Гилбэнкс
Когда я делал свой генеративный арт, мне нужно было сгенерировать множество случайных вещей. Самый простой способ сделать это с помощью PHP — использовать функцию rand()
.
Функция rand()
выбирает случайное целое число (целое число) от 0 до getrandmax()
или 2 значения, если вы их указали (например, rand( 100, 200 )
). Эта функция действительно полезна, но сама по себе она дает несколько предсказуемые результаты. В этой статье я хотел рассказать о некоторых других методах, которые я использую для генерации случайных чисел с помощью PHP.
random()
Функция случайных чисел PHP по умолчанию — rand(), но в JavaScript это Math.random()
. Разница между ними заключается в том, что rand
выбирает случайные целые числа, а Math.random
выбирает случайные числа с плавающей запятой от 0 до 1. Оба элемента полезны в разных ситуациях, поэтому я хотел воспроизвести случайное число JavaScript для своих проектов PHP.
Shuffle()
Чтобы сгенерировать определенные элементы Iso City, я бы сохранил информацию в массиве, перетасовал содержимое, а затем использовал первый элемент в массиве. Это хороший простой метод для выбора случайного элемента из массива. Вы также можете использовать PHP для выбора случайного числа между 0 и размером массива и использовать его в качестве индекса, но мне нравится простота перемешивания.
Используя массивы и shuffle(), я также могу делать взвешенные выборки. Под этим я подразумеваю, что если я хочу, чтобы один результат появлялся чаще, чем другой, я могу добавить его в массив больше раз, чем другой. Затем таким же образом выберите из перетасованного массива.
Возможно, я мог бы написать функцию для генерации взвешенного списка, но мне нравится, чтобы все было просто, поэтому используйте что-то вроде этого:
Если вы хотите выбрать случайный элемент из массива, вы также можете использовать PHP функция array_rand
. Это возвращает ключ случайного элемента в массиве.
Я использую shuffle, когда хочу использовать весь массив в случайном порядке, и array_rand, когда хочу выбрать один элемент.
Взвешенные случайные числа
Случайные или случайные числа имеют линейное распределение между начальным и конечным значениями. Чтобы сделать вещи немного менее последовательными, я использую функцию взвешенных случайных чисел.
С помощью этой функции я могу генерировать случайные числа со взвешиванием в сторону меньшего значения. Значение pow можно настроить для корректировки веса. Чем выше число, тем больше наклон вниз, чем меньше число, тем плавнее кривая.
Пример дистрибутива можно посмотреть здесь.
Вероятность
Это простой небольшой совет, но иногда я хочу, чтобы что-то происходило с определенной частотой, поэтому я использую однострочное условное выражение, чтобы решить, запускать код или нет.
Заключение
В этой статье я перечислил несколько способов использования случайных чисел в PHP, но я уверен, что есть еще много способов.