[an error occurred while processing this directive] [an error occurred while processing this directive]
This section deals with initial configuration of Apache to support SSI on Linux (RedHat 6.2 and 7.1 to be precise other distributions may vary), the use of the XBitHack directive, detecting browser types using the 'BrowserMatchNoCase' directive and including and conditionally generating pages using SSI.
You need to edit your Apache configuration (httpd.conf) file (for RedHat distributions this is in /etc/httpd/conf/httpd.conf). Someone has done a great job with the standard httpd.conf file, in general for non-exotic stuff all you have to do is find the appropriate lines and uncomment them.
Note: As a general rule we always comment changes to all config files with the date, person's initials and brief reason for the change.
Make the following changes to httpd.conf:
General section:
The first change defines the type of files that contain SSI and how they are recognised, 'server-parsed' is the shortform and tells Apache to parse for SSIs any file with a suffix of .shtml.
# To use server-parsed HTML files (SSI) add or uncomment # the following lines AddType text/html .shtml AddHandler server-parsed .shtml
..and here also..(this makes sure the SSI module (mod_include) is present and used at run time)
# To use server-parsed HTML files (SSI) add or uncomment # the following lines # They are in separate locations in the file but shown together # for convenience # LoadModule includes_module modules/mod_include.so .... .... AddModule mod_include.c
Finally you have to tell Apache to enable the Includes feature using the following directive:
Options +Includes
You can place this directive in the root directory section in which case it will enable SSI for all sub-directories (typically the whole server) or you can place it in a <VirtualHost> section with a <Directory> entry. We chose to enable SSIs for the whole server so we placed the directive in our root directory section as follows:
# # DocumentRoot: All our web servers operate as sub-directories of this # root DocumentRoot /var/www # all permissions defined here operate on all web servers unless # we define more restrictive permissions in other <directory> sections # inside or outside <virtualhost> sections <Directory "/var/www"> # # This enables a number of features as well as 'Includes' (SSIs) # on all sub-directories (server-wide) # Options Indexes Includes FollowSymLinks # This controls which options the .htaccess files in directories can # override. # AllowOverride All # # Controls who can get stuff from this server. # Order allow,deny Allow from all </Directory>
When using SSI in theory you have to make every file containing SSI directives have the suffix .shtml but those Apache folks are smart and 'cos mugs like you and me haven't discovered scripting languages (to rename every file in a directory) they allow you to use the XBitHack directive. The 'XBitHack On' directive tells Apache to look at every file with execute permission and parse it for SSIs. On a busy server this can be quite a load.
However as with most Apache directives it depends where you put the directive. If you place it in the General section the rule applies to all servers and virtual servers hosted. If you place the directive in a <VirtualHost> section then it only applies to that virtual host. For performance reasons we chose to place the directive in a virtual host section as follows:
<VirtualHost xxx.xx.xx.xx> ServerAdmin webmaster@smokeyjoe.com DocumentRoot /var/www/smokeyjoe ServerName www.smokeyjoe.com XBitHack On ErrorLog logs/smokejoe-error_log CustomLog logs/smokeyjoe-access_log common </VirtualHost>
NOTE: to set the execute permission for a single file use:
chmod +x filename.xxxTo change permissions for a whole directory use:
chmod +x -R /directory/name
Now you are almost ready for bear ...but don't restart your Apache server yet....
Apache really is a very good piece of software with more features than you can shake a stick at. You can get Apache to set some variables that you can then use to generate your SSI code conditionally.
To perform this magic you use the Apache directive <BrowserMatchNoCase> or <BrowserMatch> which will apply a regular expression check (for a survival guide to regular expressions read the grep man page under unix or go here) to the environmental variable HTTP_USER_AGENT which is supplied by every browser (a full list of Apache environmental variables is here).
By judicious checking you can find out the browser, its version, its platform even and anything else that may take your fancy. Again you can add the lines to the 'General section' or a <VirtualHost> section. We have never seen a comprehensive list of Browser ID (or user-agent) strings so we started one here. In our case we added them to the 'General Section' to provide a single consistent set of variables to all the <VirtualHosts> on our server (and hopefully reduce load by everyone doing the same thing over and over again. We modified the 'General section' of httpd.conf as follows:
BrowserMatchNoCase Mozilla/[4-6] isJS BrowserMatchNoCase MSIE isIE BrowserMatchNoCase Gecko isW3C BrowserMatchNoCase MSIE.((5\.[5-9])|([6-9])) isW3C BrowserMatchNoCase W3C_ isW3C
For a full explanation of these tests and an overview of regular expressions go here.
Now you can restart your Apache server 'cos you are ready for some action.
To generate code conditionally you can now place SSI statements in any file with a .shtml, .htm or .html (or even .php) file. SSI statements look like HTML comments and take the general format (full SSI list)
<!--#element attribute=value attribute=value ... -->
There MUST NOT be a space between the '#element' and the second opening '-' and there MUST BE a space between the last character of the last 'attribute=value' pair and the first closing '-'.
We make extensive use of only two elements, 'include' and 'conditional expressions' but have included an SSI 'blow-by-blow' explanation.
The following shows a sample of one of our standard template .htm files, we just load it and 'save as' the target file name and then add the content:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <html> <head> <meta http-equiv="Content-Language" content="en-us"> <meta http-equiv="Content-Type" content="text/html"> <meta name="GENERATOR" content="company name"> <meta name="keywords" content="blah blah, blah"> <title>Level 1 template</title> <!-- conditionally generated style sheet --> <!--#include virtual="/templates/styles.shtml" --> <!-- conditionally generated javascript code --> <!--#include virtual="/scripts/js.shtml" --> </head> <body> <!--#include virtual="/templates/level_1.html" --> <!-- begin body div --> <div class="l-c"> <!-- insert body text here --> <!-- end body (l-c) div --> </div> <!--#config timefmt="%B %d %Y" --> <!--#set var=\"real_date\" value=\"$LAST_MODIFIED\" --> <!--#include virtual="/templates/footer.shtml" --> </body> </html>
We always include the css style sheet, the javascript code, the page header and the page footer from standard files. You can use the <LINK> tag for the style sheet and the 'src=file.js' in the <SCRIPT> section but we chose to minimise the number of web server accesses at the cost of exposing all our javascript code.
The #config and #set lines before the #include for the "footer.shtml" file is our way ensuring that the LAST_MODIFIED date is for this file not the footer file. We format the date (month day, year), save the current LAST_MODIFIED to the variable 'real_date' and then use "#echo var="real_date" in the footer file (go here for more info on SSI directives including this technique).
The more observant among you may have noticed that some include files have an .shtml suffix and others not. If you want to use SSI expressions in an 'included' file then that file MUST have a .shtml suffix (even if you are using the XBitHack). We did not find this out until very late and had to modify 'include' lines in over 100 html files (well actually we found a fantastic 10 line PHP script to do it for us).
The following code snippet shows how we generate browser conditional css style data from an styles.shtml file (remember we are nesting SSI directives so must use a .shtml file suffix):
<!-- Different browser values here --> <!--#if expr="${isW3C} && !${isIE}" --> /* W3C compliant browsers - currently just Gecko */ .n-l-s {font:bold 9pt Verdana,sans-serif; text-decoration:none} .popup {font:bold small Verdana,sans-serif; background:cyan; color:black;text-indent:4; text-decoration:none;} <!--#elif expr="${isIE}" --> /* Explorer and other DHTML browsers */ .n-l-s {font-family:Verdana,sans-serif; font-size:7pt;font-weight:bold;text-decoration:none} .popup {font-family:Verdana,sans-serif;font-size:small; font-weight:bold;background:cyan; color:black;text-indent:4; text-decoration:none;} <!--#else --> /* NS4.x CSS and display options here */ .n-l-s {font-family:Verdana,sans-serif; font-size:8pt;font-weight:bold; text-decoration:none} .popup {position:relative;font-family:Verdana,sans-serif; font-size:small;font-weight:bold; background:blue;color:white; text-decoration:none; text-indent:4;} #lnav0 {position:relative;top:0;left:0;} <!--#endif -->
The code is trivial but will get a tad more complex as we add additional capability (we now support the W3C'ish DOM (Gecko) IE 5.5+ and NS4.x). In the above simple example we test the variable 'isIE' (which Apache has kindly set for us above) and directly branch to the #else or #endif statements.
[an error occurred while processing this directive]