Что такое SSI?
Server Side Includes (SSI) - директивы, вставляемые прямо в HTML-код и служащие для передачи указаний веб-серверу.

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

Server Side Include с английского переводится как "включаемый на стороне сервера".Эта технология позволяет Web-серверу включать в текст ваших HTML-страниц любой другой текст: содержимое текстовых файлов или, например, результат работы CGI-скриптов (который, как известно, обычно оформляется в виде HTML-текста). Происходит это "включение" непосредственно перед передачей текста HTML-страницы броузеру пользователя, так что посетитель страницы даже не догадывается об этой серверной "возне".

Какова же польза от SSI? Польза огромна. Предположим, на каждой странице своего сайта вы поместили список доступных разделов сайта. Творение ваше, как и положено, постоянно развивается, и вот вы решили добавить еще один раздел. Что же теперь, открывать все страницы в редакторе и тупо добавлять в текст одно и то же? Советский пионер (любящий трудности) поступил бы именно так, а умный Web-дизайнер станет использовать SSI. Для этого достаточно создать отдельный текстовый файл (например, menu.html) и занести туда HTML-код списка разделов. Непосредственно же в страницы сайта, в том месте, где должен находиться список разделов, нужно вставить следующую инструкцию:

<!--#include virtual="menu.html"-->

Обратите внимание на то, что нужно дословно следовать синтаксису директив SSI. Забудете, например, поставить два тире в конце директивы - и сервер ей буквально "подавится", прекратив анализ страницы.

Когда кто-либо захочет просмотреть эту страницу, сервер заменит инструкцию <#include> содержимым файла menu.html. Если вы измените файл menu.html, то все страницы, где вы использовали<#include>, обновятся автоматически. Обратите внимание: в HTML-файлах, лежащих на диске Web-сервера, ничего не меняется - сервер производит вставку текста "на лету", перед тем, как отправить WWW-страницу в броузер посетителя.

Вместо имени обычного текстового файла в инструкции <#include> можно указывать имя CGI-скрипта. В этом случае сервер сначала выполнит CGI-скрипт, а потом вставит результат работы скрипта в текст WWW-страницы. Это означает, что вы сможете реализовать такие вещи как, например, текстовый счетчик посещений или отображение на странице случайно выбранной фразы.

Есть еще одно косвенное преимущество применения SSI: из-за использования шаблонов типа вышеупомянутого menu.html WWW-страницы будут меньшими по объему, и вы сможете сэкономить немало времени, переписывая файлы на Web-сервер по FTP.

Но не все так прекрасно. Например, вам не удастся поэкспериментировать с механизмом SSI на машине, на которой не установлен Web-сервер. Функционирование SSI обеспечивается именно сервером, поэтому при просмотре HTML-файлов с локального жесткого диска (например, С:), ваш броузер проигнорирует директивы SSI - ведь они, с точки зрения HTML, являются обычными комментариями.

В общем, SSI - действительно полезный инструмент, игнорировать который, если вам дорого свое время (и деньги), не стоит.

Как?

В стандартном дистрибутиве Apache есть модуль mod_include. Начиная с версии 1.2 он имеет расширенное количество директив и называется - XSSI (eXtended SSI). По умолчанию он включен в компиляцию.

Включение механизма Server-Side Includes

Любой документ, у которого будет установлен обработчик "server-parsed" будет сканироваться этим модулем, если включена опция "Includes". Если вы имеете малое количество документов с SSI, то лучше всего в файле httpd.conf указать следующее:

AddType text/html .shtml AddHandler server-parsed .shtml

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

AddHandler server-parsed .html

И не забудьте включить в опции директории узла опцию Includes:

Options +Includes

Конечно в этой строке могут быть и другие нужные вам опции.

Базовые директивы

Директивы SSI включаются в HTML документ в виде комментариев (это не мешает вам использовать обычные комментарии). Синтакс команд имеет следующий вид:

<!--#element attribute=value attribute=value ... -->

Очень часто значение помещается в двойные кавычки. Некоторые команды позволяют иметь только одну пару атрибут-значение. Обратите внимание, что заключительная часть комментария (-->) должна отделяться от директивы пробелом, иначе она будет воспринята, как ее часть.

Рассмотрим определенные в Apache элементы SSI:

config - контролирует различные аспекты сканирования. Его атрибутами могут быть:

errmsg - устанавливает сообщение, выводящееся при возникновении ошибки; в большинстве случаев целесообразно установить в пустую строку;
 

sizefmt - устанавливает формат, в котором будет выводиться размер файла. Формат соответствует передаваемому библиотечной функции strftime;
 

timefmt - устанавливает формат, в котором будет выводиться дата.

echo - выводит значение установленной переменной SSI. Допустимым атрибутом является var.

fsize - выводит размер файла в определенном с помощью sizefmt формате. Допустимые атрибуты:

file - определяет путь к файлу, относительно сканируемого документа;
 

virtual - определяет стандартный кодированный URL, относительно сканируемого документа, или, при наличии в начале слеша (/) - относительно корня документов узла.

flastmod - выводит дату последней модификации файла в определенном с помощью timefmt формате. Атрибуты аналогичны атрибутам fsize.

include - включает текст другого документа или файла в сканируемый файл. К включаемому файлу применяются все установленные правила ограничения доступа. Если для каталога, из которого включается файл, установлена опция IncludesNOEXEC, и включение данного документа привело бы к запуску программы, то документ не включается, и выводится сообщение об ошибке. CGI сценарии вызываются, как обычно с помощью URL, который может содержать кодированную строку запроса (query string). Положение файла указывается с помощью атрибутов:

file - указывает путь, относительно сканируемого документа; путь не может содержать ../ и не может быть абсолютным путем; всегда предпочтительнее использовать атрибут virtual;
virtual - содержит кодированный URL, относительный или абсолютный; URL не может содержать имя протокола или имя хоста, и может содержать строку запроса.

printenv - выводит содержимое переменных окружения. Вызывается без параметров.

set - устанавливает значение переменной. Ее атрибутами являются var, определяющий имя переменной, и value, определяющий ее значение.

Переменные включения

В дополнение к стандартным окружения CGI, модуль SSI делает доступными для директив и условий, а также для вызываемых через SSI сценариев следующие переменные:

DATE_GMT - текущее время по Гринвичу;
DATE_LOCAL - текущее локальное (для сервера) время;
DOCUMENT_NAME - имя файла (без каталогов) документа, запрошенного пользователем;
DOCUMENT_URI - декодированный URL запрошенного пользователем документа;
LAST_MODIFIED - дата последней модификации документа, запрошенного пользователем. То есть во вложенном SSI эта переменная будет содержать имя "главного" документа, а не вложенного.

Подстановка переменных

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

<!--#if expr="$a = \$test" -->

Для предотвращения двусмысленности можно заключать имя переменной в фигурные скобки:

<!--#set var="Zed" value="${a}bc_${abc}" -->

В результате такого присвоения переменная Zed будет иметь значение "Xbc_Y", если переменная a равна X, а переменная abc равна Y.

Условные операторы

Базовыми элементами контроля являются:

<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->

Элементы elif и else являются необязательными.

Элемент endif заканчивает элемент if и является обязательным.

test_condition может быть одним из следующих:

string - истинно, если string не пуста;
string1 = string2
string1 != string2
string1 < string2
string1 <= string2
string1 > string2
string1 >= string2

- истинно, если выполняется условие сравнения. Если string2 имеет форму /string/, то тогда она интерпретируется, как регулярное выражение. Их синтаксис аналогичен синтаксису регулярных выражений в Unix команде egrep;
( test_condition ) - истинно, если test_condition истинно;
! test_condition - истинно, если test_condition ложно;
test_condition1 && test_condition2 - истинно, если как test_condition1, так и test_condition2 истинны;
test_condition1 || test_condition2 - истинно, если хотя бы test_condition1 или test_condition2 истинно.
"=" и "!=" имеют больший приоритет, чем "&&" и "||", а "!" имеет наивысший приоритет.

Все, что не распознается, как переменная, считается строкой. Если строка имеет пробелы или символы табуляции, то ее надо заключать в кавычки.

Практическое использование SSI

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

<html>
<body>
<p>Документ с баннером внизу страницы</p>
<!--#include virtual="/cgi-bin/ibanner.pl?webclub" -->
</body>
</html>

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

Вот текст упомянутого выше сценария:

#!/usr/local/bin/perl
$login=$ENV{"QUERY_STRING"};
print "Content-type: text/html\n\n";
($IP)=($ENV{"REMOTE_ADDR"}=~s/\.//g);
srand($$+$IP+time);
$seed=int rand(10000000);
print "<a href=\"http://www.reklama.ru/cgi-bin/href/$login?$seed\">\n";
print "<img src=\"http://www.reklama.ru/cgi-bin/banner/$login?$seed\" width=468 height=60 border=0>\n";
print "</a>\n";

Как видно из примера даже во включаемых сценариях необходимо выводить HTTP заголовок.

В результате сканирования нашего простейшего документа пользователю будет возвращен примерно (с точностью до случайной величины) следующий документ:

<html>
<body>
<p>Документ с баннером внизу страницы</p>
<a href="http://www.reklama.ru/cgi-bin/href/webclub?348593">
<img src="http://www.reklama.ru/cgi-bin/banner/webclub?348593" width=468 height=60 border=0>
</a>
</body>
</html>

Вторым распространенным применением SSI является формирование страницы из шаблона. В простейшем случае - это документ в начало и конец которого вставляются шапка и концевик:

<html>
<head>
<title>Test Page</title>
</head>
<!--#include virtual="/ssi/header.html" -->
<h1>Тестовая страница</h1>
<p>Некий текст</p>
<!--#include virtual="/ssi/global_menu.html" -->
<!--#include virtual="/ssi/footer.html" -->
</body>
</html>
 

Вставляемые блоки не обязательно должны быть законченными, например, header.html может заканчиваться тэгом <td>, а global_menu.html или footer.html начинаться с тэга </td>. Таким образом, какими бы навороченными не были шапка и концевик документа, редактируемый документ выглядит чрезвычайно просто, и его легко редактировать.

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

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

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

<link rel=stylesheet type="text/css" href="/css/cf.css">
</head>
<!--#if expr="$DOCUMENT_URI=/\/internet\//" -->
<body bgcolor="#FFFFFF" link="#099771" vlink="#006741" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header2.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/database\//" -->
<body bgcolor="#FFFFFF" link="#719709" vlink="#416700" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header3.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/ofis\//" -->
<body bgcolor="#FFFFFF" link="#98650A" vlink="#683500" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header4.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/abtec\//" -->
<body bgcolor="#FFFFFF" link="#98340A" vlink="#680400" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header5.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/programming\//" -->
<body bgcolor="#FFFFFF" link="#099607" vlink="#006600" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header6.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/operating_systems\//" -->
<!--#elif expr="$DOCUMENT_URI=/\/abtec\//" -->
<body bgcolor="#FFFFFF" link="#98340A" vlink="#680400" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header5.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/ftp\//" -->
<body bgcolor="#FFFFFF" link="#970941" vlink="#670011" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header8.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/news\//" -->
<body bgcolor="#FFFFFF" link="#970941" vlink="#670011" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header8.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/finnews\//" -->
<body bgcolor="#FFFFFF" link="#970941" vlink="#670011" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header8.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/events\//" -->
<body bgcolor="#FFFFFF" link="#970941" vlink="#670011" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header8.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/lists\//" -->
<body bgcolor="#FFFFFF" link="#970941" vlink="#670011" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header8.jpg" width="100%">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header8.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/hardware\//" -->
<body bgcolor="#FFFFFF" link="#950995" vlink="#650065" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header9.jpg" width="100%">
<!--#elif expr="$DOCUMENT_URI=/\/nets\//" -->
<body bgcolor="#FFFFFF" link="#390A98" vlink="#090068" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header10.jpg" width="100%">
<!--#else -->
<body bgcolor="#FFFFFF" link="#006890" vlink="#003860" alink="#800000" text="#000000">
<table cellspacing=0 cellpadding=0 border=0 background="/pictures/menu/header0.jpg" width="100%">
<!--#endif -->
<tr><td align="center">
<table cellspacing=0 cellpadding=4 border=0 width="100%" background="">
<tr><td align="left">
<img src="/pictures/menu/logo.gif" width=157 height=53 border=0 alt="Server for Information Technologies">
</td><td align="right">
<!--#include virtual="/cgi-bin/Look_new.cgi"-->
</td></tr>
</table>
<table cellspacing=0 cellpadding=4 border=0 width="100%" background="">
<tr valign=top><td align="left">
<font size="-1">Сервер содержит море(!) аналитической информации</font></td>
<td align="right">
<font size="-1"><a href="/rubricator/index.shtml">Рубрикатор всех документов</a></font></td>
</tr>
</table>
</td></tr>
</table>

Данный пример иллюстрирует работу с условными операторами, с шаблонами, а также возможность использования вложенных SSI.

[Закрыть]