DOC.PROTOTYPES.RU

Главная > Сервера > Apache > SSI и .htaccess >

Случайная выборка в SSI Apache

Часто перед разработчиком стоит задача установить определенный элемент на сайте, который случайным образом выводит информацию. Будь то коллаж в шапке, изречения философов и т.д. Задача тривиальная, но для обычных языков программирования, а если вожможности использовать их нет? Java Script не в счет, зависеть от настроек пользователя в таких задачах - не кошерно. На помощь приходит SSI, хотя, положа руку на сердце, это не те задачи, которые должен выполнять.

Итак, что у нас есть, и что можно сделать:

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

Использовать будем как внешнюю компоненту, т.е. определяем список, вызываем копоненту, получаем переменную:

Код (1)
    <!-- Объявляем переменные списка -->
    <!--#set var="RND_0" value="Значение 0" -->
    <!--#set var="RND_1" value="Значение 1" -->
    <!--#set var="RND_2" value="Значение 2" -->
    
    <!-- Вызываем компоненту -->
    <!--#include virtual="/rnd.shtml"-->
    
    <!-- Вот наше случайное значение -->
    [ <!--#echo var="RND_X"--> ]

Компоненту рекомендую делать на 10 элементов, она объемом 14 Кб, а на 60 элементов уже больше 500 Кб, вот так-то (хотя надо подумать над оптимизацией еще).

Компонента:

Код (2)
    <!--
        Объявляем дополнительные переменные для псевдо списков существующих
        и использованных элементов
    -->
    
    <!--#set var="RND_LIST_INDEX" value="x" -->
    <!--#set var="RND_LIST_INDEX_TMP" value="x" -->
    
    <!--
        Заполняем переменную существующих элементов и объявляем дополнительные
        переменные "флаги" существования переменных. Ввиду того, что циклов нет,
        приходится делать такой длинный копипаст.
    -->
    
    <!--#if expr="$RND_0" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}0" -->
        <!--#set var="RND_0_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_0_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_1" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}1" -->
        <!--#set var="RND_1_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_1_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_2" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}2" -->
        <!--#set var="RND_2_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_2_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_3" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}3" -->
        <!--#set var="RND_3_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_3_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_4" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}4" -->
        <!--#set var="RND_4_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_4_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_5" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}5" -->
        <!--#set var="RND_5_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_5_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_6" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}6" -->
        <!--#set var="RND_6_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_6_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_7" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}7" -->
        <!--#set var="RND_7_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_7_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_8" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}8" -->
        <!--#set var="RND_8_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_8_EX" value="0" -->
    <!--#endif -->
    <!--#if expr="$RND_9" -->
        <!--#set var="RND_LIST_INDEX" value="${RND_LIST_INDEX}9" -->
        <!--#set var="RND_9_EX" value="1" -->
    <!--#else -->
        <!--#set var="RND_9_EX" value="0" -->
    <!--#endif -->

    <!--
        Теперь по порядку устанавливаем значение переменных списка, если у переменной
        значения нет. Значение устанавливаем при условии, что мы не устанавливали
        его до этого, ввиду того, что у нас жестко определена последовательность
        от 0 до 9.
    -->
    
    <!--#if expr="$RND_0_EX = 0 && $RND_0_EX = 1 && $RND_LIST_INDEX_TMP != /0/" -->
        <!--#set var="RND_0" value="$RND_0" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}0" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_1_EX = 1 && $RND_LIST_INDEX_TMP != /1/" -->
        <!--#set var="RND_0" value="$RND_1" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}1" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_2_EX = 1 && $RND_LIST_INDEX_TMP != /2/" -->
        <!--#set var="RND_0" value="$RND_2" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}2" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_3_EX = 1 && $RND_LIST_INDEX_TMP != /3/" -->
        <!--#set var="RND_0" value="$RND_3" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}3" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_4_EX = 1 && $RND_LIST_INDEX_TMP != /4/" -->
        <!--#set var="RND_0" value="$RND_4" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}4" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_5_EX = 1 && $RND_LIST_INDEX_TMP != /5/" -->
        <!--#set var="RND_0" value="$RND_5" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}5" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_6_EX = 1 && $RND_LIST_INDEX_TMP != /6/" -->
        <!--#set var="RND_0" value="$RND_6" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}6" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_7_EX = 1 && $RND_LIST_INDEX_TMP != /7/" -->
        <!--#set var="RND_0" value="$RND_7" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}7" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_8_EX = 1 && $RND_LIST_INDEX_TMP != /8/" -->
        <!--#set var="RND_0" value="$RND_8" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}8" -->
    <!--#elif expr="$RND_0_EX = 0 && $RND_9_EX = 1 && $RND_LIST_INDEX_TMP != /9/" -->
        <!--#set var="RND_0" value="$RND_9" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}9" -->
    <!--#endif -->

    <!--
        Теперь проверяем, не заполнен ли уже список и не надо ли последовательность
        устанавливать сначала
    -->
    
    <!--#if expr="$RND_LIST_INDEX_TMP = $RND_LIST_INDEX" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="x" -->
    <!--#endif -->
    
    <!--
        Дальше точно такие же блоки для каждой их переменных по порядку для всего
        диапазона от 0 до 9. Не забываем после каждого блока проверять заполненность
        последовательности.
    -->    
    
    <!--#if expr="$RND_1_EX = 0 && $RND_0_EX = 1 && $RND_LIST_INDEX_TMP != /0/" -->
        <!--#set var="RND_1" value="$RND_0" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}0" -->
    <!--#elif expr="$RND_1_EX = 0 && $RND_1_EX = 1 && $RND_LIST_INDEX_TMP != /1/" -->
        <!--#set var="RND_1" value="$RND_1" -->
        <!--#set var="RND_LIST_INDEX_TMP" value="${RND_LIST_INDEX_TMP}1" -->
    <!--#elif expr="$RND_1_EX = 0 && $RND_2_EX = 1 && $RND_LIST_INDEX_TMP != /2/" -->
    ...
    
    <!--
        Весь список элементов заполнен, можно выбрать нужный относительно секунд.
    -->    
    
    <!--#config timefmt="%S" -->
    <!--#set var="NUM_SEC" value="$DATE_LOCAL" -->
    <!--#if expr="$NUM_SEC = /0$/" -->
        <!--#set var="RND_X" value="$RND_0" -->
    <!--#elif expr="$NUM_SEC = /1$/" -->
        <!--#set var="RND_X" value="$RND_1" -->
    <!--#elif expr="$NUM_SEC = /2$/" -->
        <!--#set var="RND_X" value="$RND_2" -->
    <!--#elif expr="$NUM_SEC = /3$/" -->
        <!--#set var="RND_X" value="$RND_3" -->
    <!--#elif expr="$NUM_SEC = /4$/" -->
        <!--#set var="RND_X" value="$RND_4" -->
    <!--#elif expr="$NUM_SEC = /5$/" -->
        <!--#set var="RND_X" value="$RND_5" -->
    <!--#elif expr="$NUM_SEC = /6$/" -->
        <!--#set var="RND_X" value="$RND_6" -->
    <!--#elif expr="$NUM_SEC = /7$/" -->
        <!--#set var="RND_X" value="$RND_7" -->
    <!--#elif expr="$NUM_SEC = /8$/" -->
        <!--#set var="RND_X" value="$RND_8" -->
    <!--#elif expr="$NUM_SEC = /9$/" -->
        <!--#set var="RND_X" value="$RND_9" -->
    <!--#else -->
        <!--#set var="RND_X" value="$RND_0" -->
    <!--#endif -->

    <!--
        ВАЖНО!!!
        Теперь желательно обнулить список, т.к. переменные все глобальные, и если
        мы будем использовать компоненту несколько раз на одной странице для разных
        списков, то может произойти смешение списков. Хотя оставим возможность не
        обнулять его.
    -->    

    <!--#if expr="$RND_DO_NOT_CLEAN_LIST"-->
        <!--#set var="RND_DO_NOT_CLEAN_LIST" value="" -->
    <!--#else -->
        <!--#set var="RND_0" value="" -->
        <!--#set var="RND_1" value="" -->
        <!--#set var="RND_2" value="" -->
        <!--#set var="RND_3" value="" -->
        <!--#set var="RND_4" value="" -->
        <!--#set var="RND_5" value="" -->
        <!--#set var="RND_6" value="" -->
        <!--#set var="RND_7" value="" -->
        <!--#set var="RND_8" value="" -->
        <!--#set var="RND_9" value="" -->
    <!--#endif -->

    <!--
        Собственно все, случайное значение находится в переменной RND_X
    -->    

Конечно, вероятность получения элементов сильно зависит от общего количества элементов, так для списка из трех 9 элементов мы получим последовательность

Как видно, вероятность показа переменной RND_0 - 1/5, а всех остальных - 1/10.

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

Собственно, саму компоненту можно скачать тут.

Сергей Томулевич aka Phoinix (24.08.2009 г.)

Еще статьи по теме:

Valid HTML 4.01 Transitional
Copyright © 2011 Сергей Томулевич