SSI в примерах. 2001
Дата последней модификации документа
Сегодняшнее число в нужном формате
Дата модификации внешнего файла
Борьба с noframes
Борьба с прямыми ссылками на документы на веб-узле с фреймами
Версия страницы для печати
Борьба с пунктами меню
Контекстный вывод текста в зависимости от условий
Борьба с разными версиями дизайна для разных браузеров
Борьба с оформлением результатов работы скриптов
Что можно сделать, используя Cookie и SSI
Баннеры, кэширование и SSI
1 шаблон отображения - разное содержание
Для начала о причинах, побудивших написать меня эту статью: в обсуждениях членов Всероссийского Клуба Вебмастеров не раз возникали споры о том, что лучше применять в случае повторяющейся разметки (информации) на большом количестве страниц - фреймы, JavaScript или SSI (Server Side Includes). Моим глубоким убеждением является то, что фреймы следует использовать только там, где без этого действительно никак не обойтись, JavaScript (да и любые другие клиентские скрипты) слишком капризен и зависит от настроек браузера, поэтому его можно использовать только для дополнительных возможностей, но никак для простроения, допустим, системы навигации. Я приведу решения с применением этой технологии.
(Сразу предвижу возмущение со стороны приверженцев технологий ASP и PHP, с использованием которых также возможны решения подобных задач, поэтому специально для них: технология SSI значительно проще, в ней всего десяток операций, поэтому для не программиста это более удачный выбор хотя бы потому, что ее можно быстрее освоить).
Дата последней модификации документа
Простая директива:
<!--#echo var="LAST_MODIFIED"-->
Сегодняшнее число в нужном формате
Если нам нужно вывести дату не в стандартном для данной конфигурации программных средств виде, а в том, какой нам нужен (например, "вторник, 30 мая, 2000"), то можно воспользоваться следующей конструкцией:Получение дня недели
<!--#config timefmt="%u"-->
<!--#set var="NUM_DAY" value="$DATE_LOCAL"-->
<!--#if expr="$NUM_DAY=1"-->
<!--#set var="DAY" value="понедельник"-->
<!--#elif expr="$NUM_DAY=2"-->
<!--#set var="DAY" value="вторник"-->
<!--#elif expr="$NUM_DAY=3"-->
<!--#set var="DAY" value="среда"-->
<!--#elif expr="$NUM_DAY=4"-->
<!--#set var="DAY" value="четверг"-->
<!--#elif expr="$NUM_DAY=5"-->
<!--#set var="DAY" value="пятница"-->
<!--#elif expr="$NUM_DAY=6"-->
<!--#set var="DAY" value="суббота"-->
<!--#else-->
<!--#set var="DAY" value="воскресенье"-->
<!--#endif-->
Получение числа:
<!--#config timefmt="%e"-->
<!--#set var="DATE" value="$DATE_LOCAL"-->
Получение названия месяца:
<!--#config timefmt="%m"-->
<!--#set var="NUM_MONTH" value="$DATE_LOCAL"-->
<!--#if expr="$NUM_MONTH=01"-->
<!--#set var="MONTH" value="января"-->
<!--#elif expr="$NUM_MONTH=02"-->
<!--#set var="MONTH" value="февраля"-->
<!--#elif expr="$NUM_MONTH=03"-->
<!--#set var="MONTH" value="марта"-->
<!--#elif expr="$NUM_MONTH=04"-->
<!--#set var="MONTH" value="апреля"-->
<!--#elif expr="$NUM_MONTH=05"-->
<!--#set var="MONTH" value="мая"-->
<!--#elif expr="$NUM_MONTH=06"-->
<!--#set var="MONTH" value="июня"-->
<!--#elif expr="$NUM_MONTH=07"-->
<!--#set var="MONTH" value="июля"-->
<!--#elif expr="$NUM_MONTH=08"-->
<!--#set var="MONTH" value="августа"-->
<!--#elif expr="$NUM_MONTH=09"-->
<!--#set var="MONTH" value="сентября"-->
<!--#elif expr="$NUM_MONTH=10"-->
<!--#set var="MONTH" value="октября"-->
<!--#elif expr="$NUM_MONTH=11"-->
<!--#set var="MONTH" value="ноября"-->
<!--#else-->
<!--#set var="MONTH" value="декабря"-->
<!--#endif-->
Получение года:
<!--#config timefmt="%G"-->
<!--#set var="YEAR" value="$DATE_LOCAL"-->
Вывод получившейся строки:
<!--#echo var="DAY"-->, <!--#echo var="DATE"--> <!--#echo var="MONTH"-->, <!--#echo var="YEAR"-->
Форматы параметров для config timefmt надо смотреть для каждой конфигурации веб-сервера отдельно. Приведенный пример - FreeBSD, Apache. Более подробно см. man timefmt
Дата модификации внешнего файла
Часто на компьютерных сайтах выкладывают прайс-лист в формате MS Excel или Word и каждый раз руками прописывают дату его изготовления. С помощью SSI это делается примерно следующим образом:
<a href=pricelst.doc>Прайс-лист</a>
<!--#config timefmt="%d.%m.%y"-->
(MS Word 6.0/95, <!--#flastmod virtual="pricelst.doc"-->)
Борьба с <noframes>
Как правило, в этом контейнере пишут "извините, но вам следует обновить браузер", по идее же там должны быть альтернатива для пользователей старых версий браузеров. Поскольку на нормальном сервере информация часто меняется, а вебмастеру лениво каждый раз вносить правки в 2 местах. С помощью SSI проблема решается раз и навсегда: в контейнер <noframes></noframes> вносится директива, вставляющая тот самый файл, в котором делаются правки или попросту линейку навигации.
Борьба с прямыми ссылками на документы на веб-узле с фреймами
1 из аргументов против использования фреймовых структур при создании веб-узлов является неудобство прямых ссылок на содержательные файлы. Например, при ссылке из поисковых машин или на конкретный (не корневой) документ с другого веб-узла пользователь попадает на страницу, лишенную оформления или элементов навигации, которые обычно помещаются в отдельный навигационный фрейм. С помощью нехитрой конструкции SSI эту проблему можно решить. Для этого необходимо проанализировать, откуда пришел пользователь (переменная HTTP_REFERER) Если он пришел не с нашего сервера, а извне - построить фреймовую структуру и в качестве содержательного фрейма подставить документ, запрошенный пользователем.
В примере ниже файл content.html - это тот документ, на который стоит прямая ссылка (допустим, из поисковой машины), frame.html - файл в котором строится фреймовая структура. В QUERY_STRING подставляется значение done для того, чтобы избежать бесконечной вложенности фреймовых структур.
Файл content.html
<!--#include virtual=frame.html-->
…
Файл frame.html
<!--#if expr="$QUERY_STRING!=done && $HTTP_REFERER!=/your_domain\.ru/"-->
<frameset rows=150,*>
<frame name=NAVIGATION src=navigation.html>
<frame name=CONTENT src="<!--#echo var=DOCUMENT_URI-->?done">
</frameset>
<!--#endif-->
Версия страницы для печати
Часто возникает прикладная задача - красивый многоколоночный дизайн с верхней и нижней шапками, туча баннеров, но при печати все это не нужно - лишняя бумага, ненужная информация. Поэтому хочется сделать простой альтернативный вид страницы специально для печати. Чтобы это проделать, достаточно подготовить 2 варианта верхней и нижней шапок, 1 - для экранного отображения, другой - для печати. В качестве переключения между этими вариантами используем переменную QUERY_STRING. Ниже приведены принципиальные структуры для самой страницы (file.html) и для верхней и нижней шапок (top.html и bottom.html).
Структура самой страницы (file.html):
<!--#include virtual=top.html?$QUERY_STRING-->
здесь тело документа
<!--#include virtual=bottom.html?$QUERY_STRING-->
Структура top.html и bottom.html
<!--#if expr="$QUERY_STRING == /for_printing/"-->
шапка для печати
<!--#else-->
шапка для просмотра
<!--#endif-->
Ссылка на каждой странице должна быть вида <a href=<!--echo var="$DOCUMENT_URI"-->?for_printing>версия для печати</a>
Борьба с пунктами меню
Предположим, у нас есть несколько разделов веб-узла, документы, относящиеся к разделам, лежат в разных директориях. Задача: сделать так, чтобы в меню навигации по этим разделам пропадала (или не подсвечивалась, выделялась другим цветом и т.д.) ссылка на тот раздел, в котором находится пользователь в данный момент. Для этого можно использовать переменную DOCUMENT_URI.
<!--#if expr="$DOCUMENT_URI!=/^\/index.html/"-->
<a href="/">Первая страница</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/about\/index.html/"-->
<a href="/about/">О нас</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/done\/index.html/"-->
<a href="/done/">Работы</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/partner\/index.html/"-->
<a href="/partner/">Партнеры</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/client\/index.html/"-->
<a href="/client/">Клиенты</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/price\/index.html/"-->
<a href="/price/">Цены</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/contacts\/index.html/"-->
<a href="/contacts/">Координаты</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/history\/index.html/"-->
<a href="/history/">История</a><p>
<!--#endif-->
<!--#if expr="$DOCUMENT_URI!=/\/search.html/"-->
<a href="/search.html">Поиск</a><p>
<!--#endif-->
Контекстный вывод текста в зависимости от условий
Предположим, у нас стоит задача менять внешний вид 1-й страницы узла в зависимости от того, откуда пришел пользователь. Для реализации этой задачи используется следующая конструкция:
<!--#if expr="$HTTP_REFERER=/www.zzz.ru/"-->
Здесь совершаются необходимые действия
<!--#endif-->
Т.е. сравнивается переменная HTTP_REFERER
Борьба с разными версиями дизайна для разных браузеров
Разыне браузеры по-разному отображают 1 и ту же HTML-разметку документа, начиная от специальных тагов и атрибутов и заканчивая поддержкой различных версий JavaScript. Для того, чтобы веб-узел выглядел нормально и для 1 версии браузера и для другой или чтобы не сыпались ошибки JavaScript средствами SSI можно сделать проверку версий или браузеров и выдавать различные варианты HTML-разметки. Для этого анализируется переменная HTTP_USER_AGENT, в которой содержится информация о типе и производителе браузера: <!--#if expr="$HTTP_USER_AGENT=/Mozilla\/4/ || $HTTP_USER_AGENT=/Mozilla\/5/"-->
Если версия браузера не ниже 4 или 5, то вывести вариант дизайна, использующий, например, DHTML.
<!--#else-->
Здесь вывести простой дизайн.
<!--#endif-->
Борьба с оформлением результатов работы скриптов
Самая большая проблема со скриптами заключается в том, что если есть большое количество наработанного ПО, то при смене дизайна требуется их перенастройка. Хорошо, если ПО сделано правильно и изменение шаблонов отображения не касается самой математики, однако и в таких случаях существуют проблемы. Например, на странице поиска было бы неплохо крутить баннеры рекламных сетей, но директивы SSI не отрабатываются в файлах .cgi. Решить подобные проблемы можно использованием SSI следующим образом: не скриптом обрабатывать шаблоны отображения, а вызывать скрипт из HTML-документа через SSI (к сожалению, таким образом можно работать только с теми скриптами, которые используют метод GET - переменная CONTENT_LENGTH не доступна в SSI) Итак, как это делается. Есть HTML-документ, который размечен в общем стиле дизайна. В него вставляется директива
<!--#include virtual="/cgi-bin/script.cgi?$QUERY_STRING"-->
На 1-м шаге, пока QUERY_STRING пуста - вызывается 1-й шаг скрипта, на последующих шагах работы скрипта - передаются необходимые параметры. В самом скрипте важны 3 строчки:
…
#определение адреса, куда направлять данные
$query=$ENV{QUERY_STRING};
#определение места, из которого был вызван скрипт
$uri=$ENV{DOCUMENT_URI};
…
#отправка данных в тот же HTML-документ, из которого был вызван скрипт
print "<form action=$uri method=get>\n";
…
Что можно сделать, используя Cookie и SSI
Часто встречается конструкция на JavaScript, которая выводит "Здравствуйте, Иван Иваныч!" при заходе на страницу сайта. То же самое можно проделать с помощью SSI директивой
<!--#echo var=HTTP_COOKIE-->
Баннеры, кэширование и SSI
Как известно, баннерные системы предлагают включать в код некоторую случайную величину в URL скрипта показа - защита от кеширования.
Можно генерировать всю страницу скриптом, от 1-го до последнего символа.
Можно сделать, как советуют страницы помощи баннерных систем, включить by SSI скрипт, генерящий случайный баннер
Динамически записать часть документа с кодом банера JavaScrip-ом.
А можно еще так:
<!--#config timefmt="%s"-->
<!--#set var="RND" value="$DATE_LOCAL"-->
<!--Russian LinkExchange code START-->
<iframe src=http://1.ru/cgi-bin/erle.cgi?some_id?
<!--#echo var="RND"-->
frameborder=0 vspace=0 hspace=0 width=468 height=60 marginwidth=0 marginheight=0 scrolling=no>
<a href=http://1.ru/users/some_id/goto.map target=_top>
<img src=http://1.ru/cgi-bin/rle.cgi??<!--#echo var="RND"-->
></a>
</iframe>
<!--Russian LinkExchange code END-->
Т.е. не тратится время и память на запуск скрипта-генератора (Java-Script может быть выключен).
1 шаблон отображения - разное содержание
Часто шаблоны используют таким образом: есть только 1 файл, который описывает структуру страницы, а основное содержание включается директивой
<!--#include virtual="$QUERY_STRING.html"-->
ссылки будут иметь вид:
href="www.2.ru/index.html?page1"
href="www.2.ru/index.html?page2"
…
Проблема возникает, если пользователь набирает адрес непосредственно http://2.ru, т.е. QUERY_STRING=""
Решение:
<!--#if expr="$QUERY_STRING"-->
<!--#include virtual="$QUERY_STRING.html"-->
<!--#else-->
<!--#include virtual=default.html-->
<!--#endif-->
где default.html - страница корневого индекса (оглавления) и просто заглушка.