Руководство Apache httpd: введение в Server Side Includes
Server-side includes позволяют добавлять динамическое содержимое в существующие HTML-документы.
Введение
| Связанные модули | Связанные директивы |
|---|---|
В этой статье рассматриваются Server Side Includes, обычно называемые просто SSI. Здесь я расскажу, как настроить сервер для поддержки SSI, и представлю несколько основных приемов SSI для добавления динамического содержимого на существующие HTML-страницы.
Во второй части статьи мы поговорим о некоторых более сложных возможностях SSI, например об условных операторах в директивах SSI.
Что такое SSI?
SSI (Server Side Includes) — это директивы, размещаемые в HTML-страницах и обрабатываемые сервером при их отправке. Они позволяют добавлять динамически генерируемое содержимое в существующую HTML-страницу, не отправляя всю страницу через программу CGI или другую технологию динамической генерации.
Например, в существующую HTML-страницу можно добавить такую директиву:
<!--#echo var="DATE_LOCAL" -->
При отправке страницы этот фрагмент будет обработан и заменен его значением:
Tuesday, 15-Jan-2013 19:28:54 EST
Выбор между SSI и полной генерацией страницы какой-либо программой обычно зависит от того, какая часть страницы остается статической, а какую нужно пересчитывать при каждой отправке страницы. SSI отлично подходит для добавления небольших фрагментов информации, например текущего времени, как показано выше. Но если большая часть страницы генерируется непосредственно при ее отправке, стоит поискать другое решение.
Настройка сервера для поддержки SSI
Чтобы включить SSI на сервере, необходимо добавить следующую директиву в файл httpd.conf либо в файл .htaccess:
Options +Includes
Эта директива сообщает Apache, что нужно разрешить обработку файлов для поиска директив SSI. Обратите внимание: в большинстве конфигураций содержится несколько директив Options, которые могут переопределять друг друга. Чтобы директива Options обрабатывалась последней, вероятно, потребуется применить ее к конкретному каталогу, в котором нужно включить SSI.
Директивы SSI обрабатываются не во всех файлах. Нужно указать Apache, какие файлы следует обрабатывать. Это можно сделать двумя способами. Можно указать Apache обрабатывать все файлы с определенным расширением, например .shtml, с помощью следующих директив:
AddType text/html .shtml AddOutputFilter INCLUDES .shtml
Недостаток этого подхода в том, что для добавления директив SSI на существующую страницу придется изменить имя этой страницы и все ссылки на нее, присвоив ей расширение .shtml, чтобы эти директивы выполнялись.
Другой способ — использовать директиву XBitHack:
XBitHack on
Директива XBitHack указывает Apache обрабатывать файлы на наличие директив SSI, если у них установлен бит выполнения. Поэтому, чтобы добавить директивы SSI на существующую страницу, не меняя имя файла, достаточно сделать файл исполняемым с помощью chmod.
chmod +x pagename.html
Небольшое замечание о том, чего делать не следует. Иногда можно встретить рекомендацию просто указать Apache обрабатывать все файлы .html на наличие SSI, чтобы не возиться с именами файлов .shtml. Похоже, эти люди не слышали о XBitHack. Следует помнить, что в этом случае Apache будет читать каждый файл, который отправляет клиентам, даже если в нем нет директив SSI. Это может заметно замедлить работу и не является хорошей идеей.
Разумеется, в Windows нельзя установить бит выполнения, поэтому выбор будет несколько ограничен.
В стандартной конфигурации Apache не отправляет HTTP-заголовки с датой последнего изменения или длиной содержимого для страниц SSI, поскольку эти значения трудно вычислить для динамического содержимого. Из-за этого документ может не кэшироваться, что приводит к снижению воспринимаемой клиентом производительности. Есть два способа решить эту проблему:
- Использовать конфигурацию
XBitHack Full. Она указывает Apache определять дату последнего изменения только по дате исходного запрошенного файла, не учитывая даты изменения включенных файлов. - Использовать директивы, предоставляемые
mod_expires, чтобы задать для файлов явное время истечения срока действия и тем самым сообщить браузерам и прокси-серверам, что их можно кэшировать.
Основные директивы SSI
Директивы SSI имеют следующий синтаксис:
<!--#function attribute=value attribute=value ... -->
Директива оформлена как HTML-комментарий, поэтому, если SSI настроен неправильно, браузер проигнорирует ее, но она все равно будет видна в исходном коде HTML. Если SSI настроен правильно, директива будет заменена результатом ее выполнения.
Функция может выполнять разные действия; большинство из них мы подробнее рассмотрим в следующей статье этой серии. А пока приведем несколько примеров того, что можно делать с помощью SSI.
Сегодняшняя дата
<!--#echo var="DATE_LOCAL" -->
Функция echo просто выводит значение переменной. Существует ряд стандартных переменных, в том числе весь набор переменных окружения, доступных программам CGI. Кроме того, можно определять собственные переменные с помощью функции set.
Если вас не устраивает формат вывода даты, его можно изменить с помощью функции config и атрибута timefmt.
<!--#config timefmt="%A %B %d, %Y" --> Today is <!--#echo var="DATE_LOCAL" -->
Дата изменения файла
This document last modified <!--#flastmod file="index.html" -->
На эту функцию также влияют настройки формата timefmt.
Включение результатов выполнения программы CGI
Это один из наиболее распространенных способов применения SSI — вывод результатов работы программы CGI, например всеми любимого «счетчика посещений».
<!--#include virtual="/cgi-bin/counter.pl" -->
Дополнительные примеры
Ниже приведены конкретные примеры того, что можно делать с помощью SSI в HTML-документах.
Когда этот документ изменялся?
Ранее мы упоминали, что с помощью SSI можно сообщить пользователю, когда документ изменялся в последний раз. Однако конкретный способ реализации остался не вполне ясным. Следующий код, размещенный в HTML-документе, добавит на страницу такую отметку времени. Разумеется, SSI должен быть настроен правильно, как описано выше.
<!--#config timefmt="%A %B %d, %Y" --> This file last modified <!--#flastmod file="ssi.shtml" -->
Разумеется, вместо ssi.shtml нужно указать фактическое имя файла, о котором идет речь. Это неудобно, если вам нужен универсальный фрагмент кода, который можно вставить в любой файл. Поэтому, вероятно, лучше использовать переменную LAST_MODIFIED:
<!--#config timefmt="%D" --> This file last modified <!--#echo var="LAST_MODIFIED" -->
Подробнее о формате timefmt можно узнать, выполнив поиск по запросу strftime на любом удобном поисковом сайте. Синтаксис тот же.
Добавление стандартного нижнего колонтитула
Если вы управляете сайтом, состоящим более чем из нескольких страниц, вносить изменения на всех этих страницах может быть довольно утомительно — особенно если вы стараетесь поддерживать на них единый стиль оформления.
Использование файла включения для верхнего и/или нижнего колонтитула упрощает такие обновления. Достаточно создать один файл нижнего колонтитула, а затем включить его в каждую страницу с помощью команды SSI include. Функция include может определить включаемый файл с помощью атрибута file или virtual. Атрибут file задает путь к файлу, относительный к текущему каталогу. Это означает, что путь не может быть абсолютным (начинаться с /) и не может содержать ../. Атрибут virtual, вероятно, полезнее: он должен задавать URL относительно отправляемого документа. Он может начинаться с /, но файл должен находиться на том же сервере, что и отправляемый документ.
<!--#include virtual="/footer.html" -->
Я часто объединяю эти два последних приема, помещая директиву LAST_MODIFIED в файл нижнего колонтитула, который будет включен. Включенный файл может содержать директивы SSI, а включения могут быть вложенными: то есть включенный файл может включать другой файл и так далее.
Что еще можно настроить?
Помимо возможности config формат времени, можно также config еще две вещи.
Обычно при ошибке в директиве SSI появляется сообщение:
[an error occurred while processing this directive]
Если вы хотите заменить это сообщение другим, используйте атрибут errmsg функции config:
<!--#config errmsg="[It appears that you don't know how to use SSI]" -->
Надеемся, конечные пользователи никогда не увидят это сообщение, поскольку вы устраните все проблемы с директивами SSI до запуска сайта. (Верно?)
Атрибут sizefmt позволяет config формат, в котором возвращаются размеры файлов. Можно указать bytes, чтобы получить точное значение в байтах, или abbrev, чтобы получить сокращенное значение в КБ или МБ, в зависимости от размера.
Выполнение команд
Функция exec позволяет делать и кое-что еще. С ее помощью SSI может выполнять команды в оболочке (точнее, в /bin/sh; в Win32 используется оболочка DOS). Например, следующая команда выведет список файлов в каталоге.
<pre> <!--#exec cmd="ls" --> </pre>
или в Windows:
<pre> <!--#exec cmd="dir" --> </pre>
В Windows эта директива может выводить странно отформатированный результат, поскольку вывод dir содержит строку «<dir>», которая сбивает браузеры с толку.
Обратите внимание: эта функция чрезвычайно опасна, поскольку она выполняет любой код, помещенный в тег exec. Если пользователи могут редактировать содержимое ваших веб-страниц, например в «гостевой книге», обязательно отключите эту функцию. Поддержку SSI можно оставить включенной, отключив функцию exec с помощью аргумента IncludesNOEXEC директивы Options.
Расширенные приемы работы с SSI
Помимо вывода содержимого, SSI в Apache позволяет задавать переменные и использовать их в сравнениях и условных выражениях.
Задание переменных
С помощью директивы set можно задавать переменные для последующего использования. Они понадобятся нам далее, поэтому рассмотрим эту директиву здесь. Ее синтаксис:
<!--#set var="name" value="Rich" -->
Значения можно не только задавать буквально: для присваивания переменным можно использовать другие переменные, в том числе переменные окружения или упомянутые выше переменные (например, LAST_MODIFIED). Чтобы указать, что перед нами переменная, а не строковый литерал, поставьте перед именем переменной знак доллара ($).
<!--#set var="modified" value="$LAST_MODIFIED" -->
Чтобы поместить в значение переменной буквальный знак доллара, его нужно экранировать обратной косой чертой.
<!--#set var="cost" value="\$100" -->
Наконец, если нужно поместить переменную внутрь более длинной строки и есть вероятность, что имя переменной сольется с соседними символами и будет принято за их часть, заключите имя переменной в фигурные скобки. Это устранит неоднозначность. (Трудно придумать наглядный пример, но, надеюсь, суть понятна.)
<!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" -->Условные выражения
Теперь, когда у нас есть переменные и мы можем задавать и сравнивать их значения, можно использовать их в условных выражениях. Это превращает SSI в своего рода миниатюрный язык программирования. mod_include предоставляет структуру if, elif, else, endif для построения условных операторов. Это позволяет фактически создавать несколько логических страниц на основе одной реальной страницы.
Структура этого условного выражения выглядит так:
<!--#if expr="test_condition" --> <!--#elif expr="test_condition" --> <!--#else --> <!--#endif -->
test_condition может быть любым логическим сравнением: сравнением значений друг с другом или проверкой «истинности» определенного значения. (Строка считается истинной, если она не пуста.) Полный список доступных операторов сравнения приведен в документации mod_include.
Например, чтобы менять текст веб-страницы в зависимости от времени суток, можно поместить в HTML-страницу следующий фрагмент:
Good <!--#if expr="%{TIME_HOUR} <12" -->
morning!
<!--#else -->
afternoon!
<!--#endif -->В условных операторах можно использовать любые другие переменные — как заданные вами, так и стандартные переменные окружения. Дополнительные сведения о механизме вычисления выражений см. в разделе Выражения в Apache HTTP Server.
Возможность Apache задавать переменные окружения с помощью директив SetEnvIf и других связанных директив позволяет создавать разнообразное динамическое содержимое на стороне сервера, не прибегая к полноценному веб-приложению.
Заключение
SSI, безусловно, не заменяет CGI и другие технологии генерации динамических веб-страниц. Но это отличный способ добавить на страницы небольшие фрагменты динамического содержимого, не прилагая больших усилий.
© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/howto/ssi.html