Конфигурирование веб-сервера Apache Оглавление Основы CGI

Server Side Includes

Server Side Includes - включения на стороне сервера. SSI представляет механизм включения одних документов внутрь других. Чем-то это схоже с фреймами по функциональному назначению, но есть существенные отличия. Во-первых, включать в один HTML-документ можно любой файл с HTML-кодом, совершенно не обязательно, чтобы он(HTML-код) представлял собой законченный HTML-документ. Например, у вас часть таблицы может быть в одном файле, часть в другом, а еще часть в третьем. Во-вторых, включать можно программы, которые, в свою очередь, могут связываться с базами данных, вызывать внутри себя другие программы и выдавать какие-либо отчеты и таблицы. Естественно, что эти программы выдают на STDOUT( поток стандартного вывода, для не программистов это экран монитора с командной строкой ) HTML-код, который затем и включается внутрь нашего исходного HTML-документа. И в третьих, SSI поддерживают переменные и элементарные инструкции языка программирования: if, elif и else. Server Side Includes работают следующим образом. У вас на сервере находится html-файл с командами SSI.

<!--#include virtual="/cgi-bin/head.pl?name=О нас" -->
 <p align=justify>
Веб-студия ITSoft состоит из молодых специалистов, работающих в области
информационных технологий более пяти лет. Мы занимаемся веб-дизайном,
разработкой 
программного обеспечения, предоставляем услуги хостинга и создания локальных 
сетей.
<!--#include virtual="/include/footer.inc"-->
Когда броузер клиента запрашивает у веб-сервера этот документ, то веб-сервер, прежде чем отдать его броузеру проверяет его на наличие SSI-команд. Когда веб-сервер встретит <!--#include virtual="/cgi-bin/head.pl?name=О нас" --> он запустит программу /cgi-bin/head.pl и передаст ей параметр name=О нас. Программа head.pl выдаст HTML-код с заголовком для нашего HTML-документа, в котором будет содержаться меню и название раздела. О том, как писать такие программы вы узнаете в третей части книги. Когда веб-сервер натолкнется на <!--#include virtual="/include/footer.inc"-->, то он просто включит HTML-код из файла /include/footer.inc в наш HTML-документ. Там, собственно, хранится код завершающий любую HTML-страницу нашего веб-сайта. Таким образом, SSI позволяет избежать избыточности. Общий код для всех HTML-страниц нашего сайта хранится в одном месте. Теперь, если нам захочется добавить пункт меню или поменять что-либо еще, то нам не придется бегать по всему сайту и изменять каждый файл отдельно. Достаточно будет внести изменения в один файл. Для того чтобы начать экспериментировать с SSI-командами надо внести изменения в файл httpd.conf и перезапустить веб-сервер Apache. Найдите и раскомментируйте следующие две строчки в файле httpd.conf. Они указывают веб-серверу, что файлы с расширением shtml надо обрабатывать прежде, чем выдавать пользователю.
AddType text/html .shtml
AddHandler server-parsed .shtml 
Если вы собираетесь повсеместно использовать SSI, то добавьте еще и такую строчку. У нас SSI-команды присутствуют в большинстве HTML-документов, поэтому на нашем веб-сервере такая строчка присутствует в файле httpd.conf
AddHandler server-parsed .html
HTML-код для включения в HTML-документы обычно хранится в файлах с расширением inc. Включите и для этих файлов обработку SSI-директив. Это позволит делать рекурсивную обработку SSI-директив. Если в файле footer.inc будет SSI-директива, то она будет обработана.
AddHandler server-parsed .inc
Еще может потребоваться добавить опцию Includes в следующий раздел.
<Directory />
    Options FollowSymLinks Indexes MultiViews Includes
    AllowOverride All
</Directory>
На нашем сервере под управлением FreeBSD такая опция стоит. У меня дома на Windows98 ее нет и SSI работают. Возможно тут дело в различных версиях Apache. Теперь перезапустите веб-сервер. Давайте рассмотрим SSI еще на одном примере, заодно разберем одну из самых распространенных структур организации HTML-документов. На большинстве сайтов, документы состоят из трех частей: заголовок, тело и завершающая часть. Для эксперимента создайте директорию на вашем веб-сайте и назовите ее ssi. В этой директории создайте head.inc со следующим содержанием:
<html>
<body>

<table bgcolor=#0000FF width=600 height=100>
<tr><td> Здесь будет заголовок и главное меню нашего вебсайта
</table>

<table width=600 height=200>
<tr><td width=120 bgcolor=#CCCCCC>
Левое меню<br>
пункт1<br>
пункт2<br>
пункт3<br>
пункт4<br>
пункт5<br>
<td>
Все SSI-директивы имеют следующую семантику <!--#команда параметр="значение" параметр="значение"--> Создайте index.html:
<!--#include virtual="head.inc"-->
 Основное содержание HTML-документа.
<!--#include virtual="footer.inc"-->
И footer.inc:
</table>


<table bgcolor=#0000FF width=600>
<tr><td> Здесь будет завершающая часть HTML-документа, 
      обычно это реклама
</table>


</body>
</html>
В результате, при запросе этого документа, веб-сервер выдаст:
<html>
<body>

<table bgcolor=#0000FF width=600 height=100>
<tr><td> Здесь будет заголовок и главное меню нашего вебсайта
</table>

<table width=600 height=200>
<tr><td width=120 bgcolor=#CCCCCC>
Левое меню<br>
пункт1<br>
пункт2<br>
пункт3<br>
пункт4<br>
пункт5<br>
<td>

 Основное содержание HTML-документа.
</table>


<table bgcolor=#0000FF width=600>
<tr><td> Здесь будет завершающая часть HTML-документа,
 обычно это реклама
</table>


</body>
</html>
Это одно из самых основных применений SSI. Теперь давайте рассмотрим использование переменных и условных операторов. Команда <!--#printenv --> выводит все переменные окружения, которые доступны по умолчанию. Ниже приведен результат действия этой команды на моем домашнем компьютере.
COMSPEC=C:\WINDOWS\COMMAND.COM
DOCUMENT_ROOT=c:/projects/www/web-tehnolog
HTTP_ACCEPT=*/*
HTTP_ACCEPT_ENCODING=gzip, deflate
HTTP_ACCEPT_LANGUAGE=ru
HTTP_CONNECTION=Keep-Alive
HTTP_COOKIE=testparam=testvalue
HTTP_HOST=web.ru
HTTP_USER_AGENT=Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)
PATH=C:\Program Files\Apache Group\Apache;C:\WINDOWS;C:\WINDOWS\COMMAND;
C:\ARCH;C:\JDK12\BIN;C:\PROGRA~1\ULTRAE~1
REMOTE_ADDR=127.0.0.1
REMOTE_PORT=1546
SCRIPT_FILENAME=c:/projects/www/web-tehnolog/chapter6.html
SERVER_ADDR=127.0.0.1
SERVER_ADMIN=igor@itsoft.ru
SERVER_NAME=web.ru
SERVER_PORT=80
SERVER_SIGNATURE=
Apache/1.3.12 Server at web.ru Port 80
SERVER_SOFTWARE=Apache/1.3.12 (Win32) WINDIR=C:\WINDOWS GATEWAY_INTERFACE=CGI/1.1 SERVER_PROTOCOL=HTTP/1.1 REQUEST_METHOD=GET QUERY_STRING= REQUEST_URI=/chapter6.html SCRIPT_NAME=/chapter6.html DATE_LOCAL=Monday, 26-Feb-2001 19:26:02 Московское время (зима) DATE_GMT=Monday, 26-Feb-2001 16:26:02 GMT LAST_MODIFIED=Monday, 26-Feb-2001 19:25:58 Московское время (зима) DOCUMENT_URI=/chapter6.html DOCUMENT_PATH_INFO= DOCUMENT_NAME=chapter6.html
Для того чтобы вывести значение отдельной переменной дайте команду <!--#echo var="var_name" -->. Например, <!--#echo var="LAST_MODIFIED" --> выдаст Monday, 26-Feb-2001 19:25:58 Московское время (зима).
Также вы можете определять и использовать свои собственные переменные. В файл index.html, который мы рассматривали выше, вставьте самой первой строкой <!--#set var="title" value="Заголовок нашего веб-сайта." -->. В head.inc добавьте следующую строчку <title><!--#echo var="title" --></title> после команды <html> и где идут слова "здесь будет заголовок" вставьте <h1><!--#echo var="title" --></h1> В результате у вас должно получится для index.html
<!--#set var="title" value="Заголовок нашего веб-сайта." -->
<!--#include virtual="head.inc"-->
 Основное содержание HTML-документа.
<!--#include virtual="footer.inc"-->
и
<html>
<title><!--#echo var="title" --></title>
<body>

<table bgcolor=#0000FF width=600 height=100>
<tr><td><h1><!--#echo var="title" --></h1>
  главное меню нашего веб-сайта
</table>

<table width=600 height=200>
<tr><td width=120 bgcolor=#CCCCCC>
Левое меню<br>
пункт1<br>
пункт2<br>
пункт3<br>
пункт4<br>
пункт5<br>
<td>
Таким образом можно передавать параметры во включаемые куски HTML-кода.

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

Пример для графического меню с подсветкой:

<!--#if expr="$DOCUMENT_URI!=/\/about.html/" --><a 
href=/about.html onMouseOut="MM_swapImgRestore()" 
onMouseOver="MM_swapImage('about','','/images/about2.gif',0)"
><!--#endif --><img src=/images/about1.gif width=212 height=38 
border=0 name=about
><!--#if expr="$DOCUMENT_URI!=/\/about.html/" --></a
><!--#endif -->

Данный SSI-код используется на сайте http://my-elecon.ru.

Другой не менее важный SSI-код применяется для организации версии страниц для печати. Версия страницы сайта для печати отличается от обычной страницы отсутствием колонститулов, навигации, баннеров и прочей лишней информации. Рассмотрим, как организована версия для печати на примере сайта http://alavus.ru.

===Файл /include/head.inc ===
<html> 
<head>
<title><!--#echo var="title"--></title>
<meta http-equiv="Content-Type" content="text/html; 
charset=windows-1251">
<link rel=stylesheet href=/styles.css>
</head>

<body bgcolor=FFFFFF text=474C54 link=566A89 vlink=96A7C1 
leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<basefont face=Arial>

<!--#if expr="$QUERY_STRING!=/for_printing/" -->
...здесь навигационный блок, графика, Flash-анимация и т.д. ...

<p align=right>
<a href=?for_printing=1&<!--#echo var="QUERY_STRING"-->>
Версия для печати
</a></p>
<!--#endif -->

При нажатии на гиперссылку "версия для печати" страница, на которой находится пользователь, перегружается. Но поскольку в строке запроса присутствует параметр for_printing, то лишний HTML-код не включается на страницу. Обратите внимание <!--#echo var="QUERY_STRING"-->. Это строка запроса CGI-параметров. В обычном случае, у вас никаких параметров, кроме for_printing нет, но когда появляются на сайте CGI-модули, то появляются и дополнительные параметры. Забегая вперед расскажу, как делать "Версию для печати" В CGI-программе. Пока веб-сервер Apache не может обрабатывать на SSI-директивы вывод CGI-программ. Такую возможность обещают в новых версиях Apache. У CGI-программистов есть два пути либо самим разобрать SSI-директивы в файле head.inc либо, что значительно проще, создать ручками файл phead.inc и подключать его в CGI-программах.

Условные операторы записываются следующим образом:

<!--#if expr="условие1" -->
  <!-- Здесь HTML-код1 -->
<!--#elif expr="условие2" -->
  <!-- Здесь HTML-код2 -->
<!--#else -->
  <!-- Здесь HTML-код3 -->
<!--#endif -->
Для примера приведу SSI-код для вывода времени последней модификации документа в приемлемом виде. Как вы уже видели, команда <!--#echo var="LAST_MODIFIED" --> выдает совершенно не приемлемую строчку - Monday, 26-Feb-2001 19:25:58 Московское время (зима), для размещения ее на солидном веб-сайте. Нам бы хотелось получить что-нибудь, вроде 26 Февраля 2001 года. Для этого существует команда config с параметром timefmt, которая задает формат вывода даты. Например, в нашем случае нам требуется следующий вариант <!--#config timefmt="%e %B %Y"-->, тогда результат <!--#echo var="LAST_MODIFIED" --> будет 26 February 2001. Но это пока все равно не то, что бы нам хотелось. Для определения месяца мы воспользуемся условными операторами. Вот, как будет выглядеть этот код:
<!--#config timefmt="%m" --> 
<!--#set var="NUM_MONTH" value="$LAST_MODIFIED"--> 
<!--#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 -->
Соответственно, чтобы получить дату в формате 26 Февраля 2001.
<!--#config timefmt="%e"--><!--#echo var="LAST_MODIFIED" -->
<!--#echo var="month" --> 
<!--#config timefmt="%Y"--><!--#echo var="LAST_MODIFIED" -->

Вот полный список значение параметра timefmt:
Формат
Описание
Пример
%a Аббревиатура названия дня недели Sun
%A Полное название дня недели Sunday
%b Аббревиатура названия месяца Jan
%B Полное название месяца January
%d День месяца 01 (не 1)
%D Дата в формате "%m/%d/%y" 01/31/90
%e День месяца 1
%H Часы в 24-часовом формате 13
%I Часы в 12-часовом формате 01
%j День года 235
%m Номер месяца 01
%M Минуты 03
%p AM|PM AM
%r Время в формате "%I:%M:%S %p" 11:35:46 PM
%S Секунды 34
%s Время в секундах с 01.01.1970 957228726
%T Время в формате "%H:%M:%S" 14:05:34
%U Неделя года 49
%w Номер дня недели 5
%y Год в формате ГГ 95
%Y Год в формате ГГГГ 1995
%Z Временная зона MSK
Далее приведены несколько полезных SSI-директив. Допустим, вы распространяете какие-либо утилиты и выкладываете ссылки на файлы для скачивания. Например, такие ссылки вы найдете на сайте http://www.oxygensoftware.com. Для удобства пользователей неплохо было бы указать размер файла и иногда, дату его последней модификации. Каждый раз после выкладывания на сервер новых версий файла, модифицировать самому ручками все размеры и даты долго и мучительно. Server Side Includes приходят на помощь.
<a href=0.gif>Прозрачный gif-файл</a><br>
Дата модификации:<!--#config timefmt="%d %B %Y" --> 
 <!--#flastmod file="0.gif" --><br>
Размер:<!--#config sizefmt="bytes"--> <!--#fsize file="0.gif" --> байта<br>


Прозрачный gif-файл
Дата модификации: 12 February 2002
Размер: 43 байта
Если у вас файлы больших размеров, то информацию лучше выводить в килобайтах. Для этого установите формат вывода размера файла следующим образом.
<!--#config sizefmt="abbrev"-->

При возникновение какой-либо ошибки, например, при попытки включить в HTML-документ файл, которого не существует веб-сервер выдаст следующее сообщение:
[an error occurred while processing this directive]
Сообщение не слишком информативно и пугает пользователя, не так ли? Давайте изменим сообщение об ошибке следующей SSI-директивой
<!--#config errmsg="<b>На сервере произошла ошибка связанная с SSI,
 пожалуйста, напишите </b>
<a href=mailto:igor@itsoft.ru>администратору</a>."-->
Теперь сообщение об ошибке вылядит так:
На сервере произошла ошибка связанная с SSI, пожалуйста, напишите администратору.