Jump to...
Extended SSI
Env. variables

Server side includes

I've been using SSI since the early days of an NCSA web server, and now use them on Apache servers. Here's a compact manual for them (at Apache v1.2 and above). It's a quirky, small language, but useful for some web tasks.

A (very) brief introduction

What are they?
SSI are directives embedded in HTML comments that instruct the web server to include particular data in the HTML document. They can provide for including "boilerplate" sections (navigation tools, common headers or footers, etc.), file name and time stamps, and more.

Your web server must be configured to interpret them.
See its documentation for how to do that. Apache allows specifying a suffix for parsed files (typically .shtml), or the use of "XBitHack" to parse (or not) based on file permissions. I prefer my systems to parse all documents, and specify '.html' to be parsed. That might be a performance issue for some installations (a file must be parsed each time someone requests it); it's not for mine.

For example?
Tag pages with a footer, the file name and timestamp. This shows the set, include, and echo directives, and variable substitution in the value of string of the set:

<!--#set var="URL" value="http://$SERVER_NAME$DOCUMENT_URI" -->
<!--#include virtual="/footer.html" -->
Last modified: <!--#echo var="LAST_MODIFIED" -->
This document is: <!--#echo var="URL" -->

(Use curly braces to disambiguate variable names, as needed, like shell syntax. The absence of a space after <-- and the presence of a space before --> are required by the syntax.)


Syntax: config errmsg|sizefmt|timefmt="string"
errmsg: Sets the default error message.
sizefmt: Format for file size data returned by fsize.
"bytes" is the default, "abbrev" gives file sizes to the nearest kB.
timefmt: date/time format for flastmod directive and the DATE_LOCAL and DATE_GMT variables. Values for this parameter include:

%a Abbreviated day of the week, such as "Sun" for Sunday
%A Unabbreviated day of the week
%b Abbreviated month, such as "Jan" for January
%B Unabbreviated month
%d Two-digit, numerical day of the month, such as "01" .
%e Numerical day, such as "1"
%H 24-hour clock hour, such as "17"
%I 12-hour clock hour, such as "11"

and so on. Most references you find (including this one for many years) didn't have the whole list, which is what's defined for strftime(). Here is the whole list. You're welcome.

Syntax: echo var="environment-variable"
Example: <!--#echo var="REMOTE_HOST" -->
(Note the form of the comment wrapper. The '#' before the directive and the space before the comment closing are required.)

If the variable is not assigned, this returns (none).

Syntax: exec cmd|cgi="script"
cgi specifies a (%-encoded) URL relative path to the CGI script. If not beginning with '/', it's taken relative to the current document. The document is invoked as a CGI script even if it would not normally recognize it as such. (The server must have the directory it's in configured to enable CGI scripts, however.) The CGI script is given the QUERY_STRING and PATH_INFO of the original request from the client. If the script returns a Location: header instead of output, this will be translated into an HTML anchor.

include virtual is recommended over exec cgi. (Again, the directory the script is in must be CGI-enabled.

cmd The server will execute the given string using /bin/sh. The include variables are available to the command.

<!--#exec cmd="ls -lRt /home/www" -->
would give a verbose file listing of the specified directory. (Hint: you'd want <pre> tags around that!)

Syntax: fsize file="path"
Size of the file specified, in bytes, or as config'd (above).

Syntax: flastmod file="path"
Modification date for the file specified

Syntax: include file|virtual="path/file"
"file" indicates a relative URL path (cannot contain '../' or start with '/'), "virtual" an absolute one.
For example:
<!--#include file="file.html" -->
<!--#include virtual="/path/file.html" -->

Prints a complete list of all SSI variables and values. <!--#printenv -->

Syntax: set var="variable" value="value"
Example: <!--#set var="country" value="United States" -->

Extended SSI

Extended SSI includes four programming flow control elements.
<!--#if expr="test-condition" -->
<!--#elif expr="test-condition" -->
<!--#else -->
<!--#endif -->

Test-condition can be a string (true if not empty) or string comparison (=, !=). Conditions can be compounded (&&, ||), parenthesized or negated (!). For string comparison, the second string can be an extended regular expression, delimited with / /. In that case, the test is for matching rather than equality. For example, to print certain text for any documents with "confid" in their paths (or filenames):

<!--#if expr="$DOCUMENT_URI = /confid/" -->
Company Confidential
<!--#endif -->

While '\' escapes what follows in a regexp, there is no substitute delimiter, making unix-style paths look like malformed regexps. If you want to test for exact equality to /path/file.html, you can't do that. You can match /\/path\/file.html/ though, which might be just as good...

SSI environment variables

DOCUMENT_NAME of the current HTML document.
DOCUMENT_URI of the current HTML document.
QUERY_STRING_UNESCAPED An unencoded query string whose metacharacters are escaped with '\'
LAST_MODIFIED date/time the current file was last modified.

Note that some of these "help" documents that everyone's copied from someone else say DOCUMENT_URL instead of DOCUMENT_URI; even mine did for a long time. No such thing.

CGI environment variables

AUTH_TYPE The authentication method used in this request, if any
CONTENT_LENGTH The size, in bytes, of any data attached to the request header
CONTENT_TYPE The MIME type of any data attached to the request header
HTTP_ACCEPT One or more MIME types that the client can accept. Typically "*/*", meaning any.
HTTP_HOST The host being addressed in this request, which may be the main host or a virtual host, either as a fully-qualified domain name or an IP address
HTTP_USER_AGENT The name, version number, and platform of the client software
QUERY_STRING=string The query-string for this transaction, embedded in the requested URL
REMOTE_ADDR The IP number of the client host
REMOTE_HOST The hostname or IP number of the client host or proxy server that originated the request
REMOTE_IDENT The remote username as supplied by identd, if available
REMOTE_PORT The client-side port number that originated the request
REMOTE_USER The remote username, if the script is subject to basic authentication
REQUEST_METHOD The method used in this request, typically GET or POST
SCRIPT_FILENAME The absolute path to the requested script
SCRIPT_NAME, SCRIPT_URI The URI of the requested script
SCRIPT_URL The URL of the requested script
SERVER_PROTOCOL The protocol and version number used to send the request, useful to ensure compatibility with the client. Typically, "HTTP/1.1"
SERVER_SOFTWARE The name and version number of the server software

xSSI example: dynamic menus

Include files are a simple way to provide navigation elements on every page without duplicating code (that must then be maintained) in every file; you simply point to a single file that contains navigation links. One problem created with this approach is that the navigation can have a link to the current page; a self-referential link that may frustrate users by acting as a no-op, just reloading the page they're on.

Extended SSI provides a simple means to deactivate links to the current page:

<!--#if expr="$DOCUMENT_NAME = /home.shtml/" -->
<!--#else -->
  <a href="/home.shtml">Home</a>
<!--#endif -->

xSSI example #2: expiring events

If you have text on a page that you don't want to show after a given date, here's a way to have that happen without needing to do a manual update of the page on schedule. Thanks to Wes Gamble for this elegant solution.

<!--#config timefmt="%Y%m%d" -->
<!--#set var="cutoff_date" value="20051211" -->
<!--#if expr="${DATE_LOCAL} <= ${cutoff_date}" -->
<h2>December 11: Annual Book Sale</h2>
<p>Come browse for selections from the Book Cart as well as many selections from Southwest Books on display.</p>
<!--#endif -->

xSSI example #3: include file unless it's stale

A third party sends me periodic updates via ftp. I want to include those in a page unless something's gone wrong and the file hasn't been updated "lately." Let's say 4 hours, which is 14400 sec.

<!--#config timefmt="%s" -->
<!--#set var="stale" value="14400" -->

And then what? SSI doesn't do arithmetic, so it seems we're stuck. Bad example. :-/

xSSI example #4: include file if possible, fail quietly

An #include command for a non-existent file gives that unsightly "An error occurred" message. You can refigure the error message to something more pleasant, say, the empty string. The error still occurs, but nothing gets splatted out to your page.

<!--#config errmsg="" -->
<!--#include file="reportfile" -->