|
Krasland.ru - красноярский интернет-портал
Интернет-аукцион Asta24.ru:
позволяет выгодно покупать и продавать свои товары, при этом сервис не требует никакой комиссии!
Информация: новости · погода · курсы валют · валютный рынок · справки · телефоны · мобильная связь · о проекте.
Журнал: авто · кино · музыка · мода · секс · спорт · технологии · бытовая техника · кулинария · сделай сам · я и мир · творчество.
Сервисы: каталог сайтов · рейтинг · поиск · работа · объявления · голосования · SMS · рассылка.
Досуг: фотогалерея · гороскопы · открытки · он-лайн игры · знакомства · анекдоты · тосты · чаты · конкурсы.

ВОКРУГ СВЕТА: О путешествии в Лион

МУЗЫКА: 50 главных песен 2013!

КИНО: Лучшие фильмы 2013! TOP-30!

СПОРТ: 10 главных матчей футбольного сезона 2012/2013

КИНО 2013: 10 лучших DVD в октябре 2013
Настроить панель ПОИСК:
 
Советы Что ищут?
Веб-разработка | К списку статей

Случайные данные

Автор: Дмитрий Турецкий
Источник: .hostinfo

Необходимость вывести на странице сайта какие-то случайные данные возникает довольно часто. Достаточно вспомнить, например, рекламу, анонсы, генерацию паролей... И в сегодняшней заметке мы поговорим о различных случайных вещах, которые помогут сделать ваш сайт интереснее.

Мы не будем касаться алгоритмов генерации случайных чисел - вряд ли они будут сильно интересовать веб-мастера, которому нужно просто вывести на странице случайную картинку. Единственное, о чем необходимо упомянуть - это необходимость "запустить" генератор случайных чисел перед использованием - если этого не сделать, то выдаваемые им значения будут повторяться при каждом прогоне скрипта. В большинстве языков для этого используется функция seed или srand, которой передается какое-то случайное число - как правило, текущее время. Стоит отметить, что в современных версиях PHP (выше, чем 4.2) делать это не обязательно - генератор случайных чисел инициализируется автоматически.

В PHP случайное число можно получить с помощью функции rand(). Эта функция может принимать два необязательных параметра - минимальное и максимальное значение. Для того чтобы узнать самое большое случайное число, которое можно получить с помощью этой функции, можно воспользоваться функцией getrandmax(). Впрочем, вряд ли это потребуется на практике.

Второй полезной в деле "ослучайвливания" сайта функцией является array_rand(). Она занимается тем, что возвращает индекс (или массив индексов) одного или нескольких случайных элементов заданного массива. Использовать ее удобно, например, для случайного выбора фонового цвета какого-то элемента. Так как автоматическое генерирование цветов - занятие неблагодарное (слишком легко получить неподходящие для сайта варианты), то значительно проще создать массив с заранее подобранными сочетающимися цветами, а потом выбирать из него случайные элементы. Например


$colors = array('#93FAE4', '#96E3FF', '#96C1FF', '#9990F5');
$color = $colors[array_rand($colors)];
echo "<table bgcolor=$color>"
...

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

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


$f = fopen('jokes.txt', 'r');
$i = 0;
while(!feof($f)) {
$tmp = fgets($f, 8196);
if (!rand(0, $i++)) $string = $tmp;
}
fclose($f);
$string = trim($string);

Давайте разберемся, как этот пример работает. Первым делом мы открываем для чтения файл jokes.txt и инициализируем нулем внутреннюю переменную $i. Затем запускаем цикл, который должен прерваться, как только будет достигнут конец файла: while(!feof($f)). Внутри цикла мы читаем текущую строку (предположив, что ее максимальная длина не превышает 8 кб): fgets($f, 8196) и сохраняем ее во временной переменной $tmp.

Теперь начинается самое интересное. Мы выбираем случайное число в диапазоне от нуля до нашей внутренней переменной $i, в которой, как мы дальше увидим, хранится порядковый номер текущей строки: rand(0, $i++). Затем мы проверяем, не равно ли это случайное число нулю, и если равно, то записываем в переменную $string значение текущей строки (которая хранится в $tmp). Так как в функции rand() в качестве максимального значения у нас указано $i++, то сервер сначала выберет какое-то значение от 0 до $i, a потом уже увеличит $i на единицу - и, следовательно, при следующем проходе цикла $i будет снова содержать порядковый номер текущей строки (отсчет ведется с нуля).

Вероятность выпадения какого-то числа (в нашем случае - нуля) из N имеющихся равна 1/N. А это означает, что при первом проходе цикла (нулевая строка) мы с вероятностью, равной единице, сохраним в переменной $string эту строку. При втором проходе - с вероятностью в 50% в переменную $string запишется первая строка. При третьем - с вероятностью 33% запишется вторая строка. И так далее. Можете сами убедиться, что такой подход действительно выбирает случайную строку из файла, и при этом память тратится только на хранение текущей строки!

Ну и, разумеется, после использования файл нужно закрыть с помощью fclose(). И в самом конце, так как функция fgets сохраняет символ перевода строки, мы его убираем с помощью функции trim().

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

Еще одним распространенным случаем является выборка случайных записей из базы данных. Довольно часто для этого пытаются использовать оператор SELECT без указания ORDER BY, что в корне неверно: в спецификации SQL сказано, что в этом случае порядок записей будет неопределен, а не случаен! В этом легко убедиться и на практике - при последовательных выполнениях этого оператора в течение более или менее длительного времени вам будут возвращаться одни и те же данные...

Как и в случае с файлами, при работе с базой существует тривиальный и максимально неэкономный способ: выполнить SELECT, определить общее число записей и прочитать случайную запись из полученного набора. Или, что еще хуже, прочитать все записи в массив и выбрать случайный элемент. Подобный подход страшно прожорлив и крайне не рекомендуется к использованию, особенно если выборка производится из большой таблицы.

Значительно более эффективное и элегантное решение получится, если воспользоваться встроенной в СУБД функцией генератора случайных чисел - как правило, она называется random() (в PostgreSQL) или rand() (в MySQL). В других базах эта функция может вызываться по-другому - смотрите документацию. Современные версии СУБД (как минимум MySQL и PostgreSQL) понимают специальную конструкцию ORDER BY:

SELECT * FROM table ORDER BY rand()

а если требуется получить какое-то определенное число записей, то можно еще добавить оператор LIMIT:

SELECT * FROM table ORDER BY rand() LIMIT 1

Если же у вас на сервере стоит старая версия, то можно использовать другой трюк:

SELECT *, id*0+rand() as rnd ORDER BY rnd LIMIT 1

Конструкция id*0+rand() выглядит глупо, но без нее некоторые версии СУБД будут работать некорректно - они один раз высчитают случайное число, а потом добавят его ко всем записям. Чтобы этого не происходило, в выражении необходимо использовать значение какого-то поля текущей записи.

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


function randstr($length = 8) {
$a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
for($i=0; $i<$length; $i++) $ret .= substr($a, rand(0, strlen($a)), 1);
return $ret;
}

Здесь $a - это строка разрешенных к использованию символов, а $length - длина. И использование и работа этой функции, думаю, не вызовет у вас никаких сложностей...

Ну и, наконец, еще одна функция, которая может оказаться полезной - это shuffle(). Занимается она тем, что тасует переданный ей в качестве аргумента массив, располагая его элементы "в строгом беспорядке". Использование этой функции никаких проблем или сложностей не вызывает...