Server-Side Includes

Don't want to learn CGI but still want dynamic web pages? Mr. Lerner introduces us to server-side includes.
Tips and Tricks When Including Files

If your site uses CGI programs to create dynamic pages, you might be tempted to include your standard headers and footers in the programs' output using #include. Unfortunately, because CGI programs and SSIs use different handlers, there isn't any way for this to work. If you decide to use HTML fragments as headers and footers, you might want to define some short subroutines that can be included in your CGI programs.

Also, because different handlers are used for SSIs (“server-parsed”) and CGI programs (“cgi-script”), you cannot include server-side includes in the output from CGI programs and expect them to be interpreted. If you decide to create a uniform look and feel for your site using HTML fragments (described below), any CGI programs you write will be able to include those fragments. If you write CGI programs in Perl, such a subroutine could look like Listing 2. Your CGI programs would then look like Listing 3. Now when you change header.htmlf or footer.htmlf, all output on the server—from HTML files and CGI programs alike—will immediately reflect the changes.

In case you are wondering, fragments are imported verbatim, and any SSIs they might contain are passed along as HTML comments. Assume we defined header.htmlf to be the following two-line fragment:

<P>This is the header.</P>
<!--#printenv -->

If this fragment were retrieved directly through Apache, the #printenv SSI would print the current list of environment variables. But since header.htmlf is imported via a #include SSI, the #printenv function is sent to the user's browser uninterpreted. This might seem unnecessary, until you consider that allowing SSIs inside of included files might lead to infinite loops or other unexpected results.

Variables and Conditionals

One of the more interesting recent additions to server-side includes is a limited programming language allowing for the setting and testing of variables.

Setting variables is fairly simple; you can do it with the following syntax:

<!--#set var="varname" value="value" -->

You can see the results with #echo (for a specific list of variables) or #printenv (for all defined variables), as in the following example:

<Head><Title>Setting variables</Title></Head>
<!--#set var="pi" value="3.14159" -->
<pre><!--#printenv --></pre>
<P>pi = <!--#echo var="pi" --></P>
<!--#set var="e" value="2.71828"
<pre><!--#printenv --></pre>
<P>e = <!--#echo var="e"
The above example also demonstrates how SSIs are interpreted in the same order as they appear in the file. The output from #printenv changes after each variable setting.

Setting variables is useful when used in conjunction with if-then statements. These statements can be used to create conditional text within HTML files without having to use CGI programs. The syntax is rather simple, for example:

<!--#if expr="$SERVER_PORT=80"
<P>You are using server port 80</P>
<!--#else -->
<P>You are using a non-standard server port</P>
<!--#endif -->

Note that the variable name in an #if statement must be preceded by a dollar sign, much as with shell scripts. The #else statement is optional, but the #endif is mandatory, indicating the end of the conditional text.

You can even perform pattern-matching within variables, using regular expressions, as in the following:

<Head><Title>Browser check</Title></Head>
<!--#if expr="$HTTP_USER_AGENT = /^Mozilla/"
<P>You are using Netscape</P>
<!--#else -->
<P>You are using another browser</P>
<!--#endif -->

If the value of HTTP_USER_AGENT (normally set to a string identifying the user's browser) is set to

Mozilla/4.04 [en] (X11; I; Linux 2.0.30 i586; Nav)
as is the case on my system, the above will evaluate to “true”, and thus print the first string. Otherwise, it will print the second string. In this way, you can create menus customized for each browser. For instance, you could make life easier for users of Lynx (a text-only browser) by giving them a separate menu structure that does not rely on images.