|For Web Designers||My Blog||Mail Delivery Problems?|
This document is copyright © 1998 - 2005 by Art Sackett. Feel free to save it, print it, copy it, and distribute it freely, but do not alter it in any way. If I have missed something or made a factual error, please send the particulars to me via email and I will consider making the appropriate revisions.
Although it is the author's belief that the statements contained within this document are true and correct, use of any of this information is at the user's sole risk. The author does not accept liability for any consequences arising from the use or misuse of this information.
This document is written for those of you who are fortunate enough to be dealing with an Apache or NCSA HTTPd server running under a Unix-like operating system (such as Linux, BSD, FreeBSD, etc.). Some of this will apply if your server was originally written for Unix, and was later ported to some other operating system. Otherwise, it probably won't do you much good.
Server Side Includes ("SSI") give us a means by which to alter our HTML documents while they are being served. The copyright and disclaimer at the top of this page was placed there using SSI -- I'm far too lazy to cut and paste things that the server can cut and paste for me. Using SSI, we can do some cool things like tell the user their IP address (yours is 220.127.116.11), the date and time at which a document was served to them in either the server's local time (Sunday, 19-Apr-2015 08:06:54 MDT) or in GMT (Sunday, 19-Apr-2015 14:06:54 GMT), or even include the output of a CGI application like a hit counter.
Yes, a lot of this is trivial in most cases. In others, it may not be. I don't care if you desire a little trivial coolness or need a non-trivial solution, I'm going to try to get you going with SSI by the time you're done reading this page. You may still have to contact your ISP, either directly or by consulting their FAQ ("Frequently Asinine Questions"). For that, you are on your own. Well, I'll talk to them for you if you pay me...
SSI is also known as "server parsed HTML". What this means is that the server reads the document and takes some action dependent upon the contents of the document -- or takes no action at all if the contents of the document don't require it. All this happens between the time your visitor activates a link and the time the document gets to them, "on the fly". Reading the document and taking the appropriate action will consume more resources (processor time, memory usage, maybe file system access, etc.) than would just finding the file and sending on its way to the TCP stack, so you don't want to indicate to the server that it ought to be parsing documents that don't need to be parsed. Unless the server is configured to just parse everything as a matter of convenience so users like us don't even have to think about it. (My ISP does this, either because they know I'm not real bright, or because they have some pretty awesome hardware and can better accept the resources hit, is something I haven't asked.)
When SSI is working, the markup you placed in your documents to cause an action will be replaced with the output of that action, so no one will even be aware of your wizardry. So much for fortune and glory, huh?
You need to know if your ISP allows you to use SSI, and if so, how to indicate to the server that it ought to parse the document. You may be able to puzzle this out on your own without bothering their tech support folks, or you may not. The first thing to do is to look through the FAQ that they ought to have provided. You might want to bookmark this page before going off on that quest -- I'll be here when you get back.
Okay, you went and looked, right? If you found the answers you need, you might as well skip this part. If not, read on.
Your ISP's site was less than helpful, huh? No worries, we'll try to do their work for them and get the answers we need.
First we're going to run a few tests to see if they have SSI enabled globally, since I prefer to use whatever method(s) the server administrator thinks we ought to be using before resorting to heroic measures that might make them grumpy. On a bad day, a server admin could just decide to close your account without telling you or giving you a second chance. Although this is a rare and drastic measure, there's no sense pushing the issue unnecessarily. (Myself, I consider the server admin the Lord of The Machine, and unless one is a power crazed jerk, his word is Gospel. On the other hand, I have been known to make users unhappy by being a bit too strict in my administration. I've never broken a server, so I do have that in my favor.) If we are not successful in finding a global SSI configuration, we're going to push the issue and hope for the best ;-)
The first thing we need is a test page to mess around with. It has to include some SSI stuff, as well as give us an indication that it's even there. We'll do this with two files, one that is HTML that includes some markup to invoke the SSI mechanism, and the other is a little something to tell us that we have successfully made the thing work. You can cut and paste (if your system is so configured) these things below, or you can create them yourself. In either case, do not copy the row of hashes (#'s) that appear below only to show where the files start and end.
The first is the HTML, which we will name test.html:
<title>This is our SSI test page</title>
<h1>SSI Test Page</h1>
<p>If SSI is working, there will be a line below to tell us so:
<p> <!-- here's the important part, get it right! -->
<!--#include virtual="test.txt" -->
<p>If there is a line above that reads:<br>
[there was an error processing this directive]<br>
check that you saved the file 'test.txt' in the same directory
as this HTML page. It indicates that SSI is mostly working.
And this is the file we're trying to include, which we will name test.txt:
If you can see this line, SSI is now working!
Upload those two files test.html and test.txt to your server and we can begin puzzling out how to get SSI working on your server, if it can be done at all. NOTE: Don't upload the files into your cgi-bin (or cgi) directory. If your ISP is security conscious, they will have disabled SSI in directories that can contain executable files -- it may be that you can use SSI, but our tests will fail because you placed those files into a directory where SSI is not allowed.
This is the easy test. Just give a look with your browser at that page you just uploaded as test.html. If you get success, they parse everything, you're done, and you may as well skip the rest of this section.
On the other hand, if that didn't work, let's check for XBitHack support:
The XBitHack is, well, a hack that allows us to indicate to the server that a given file should be parsed without the need to use the file name extension .shtml. This is handy, because if we later decide to remove that part of the document that will benefit from server parsing, we don't have to choose between updating all of our links (and breaking other people's links to our pages) and wasting server resources parsing a file that won't benefit from it. It works by checking for the user execute bit attached to a file named with the extension .html and parsing any file whose user execute bit is set.
To perform this test, you have to be able to alter the file permissions of files within your directory space. If you have telnet access, or the server is configured to allow you to do these things via an FTP connection, all you need to do is this:
chmod u+x test.html
from within the directory you uploaded our test files to. If you are using a graphical FTP client, you may have another means to accomplish this -- read the appropriate Help file or manual page. (There are far too many FTP clients and server configurations for me to even try to keep up with, so I don't.)
With the user execute bit set, view the file in your browser. You may have to reload the file to make sure that it's not coming from your browser cache. If you get success, make a mental note that the server is configured to use the XBitHack, and skip the rest of this section.
If that didn't work, change the permissions back to what they were before with the command chmod -x test.html and continue on to the next test.
This is it: our last test. This is the least savory option, as explained above in Test 2. Change the name of test.html on the server to test.shtml and view it in your browser (don't forget to reload!). If you are greeted with success, well, at least we know how to make SSI work and you can skip the rest of this section. If you are not, it may be possible to sneak SSI into your bag of tricks by making using of the .htaccess file.
So none of our tests worked. Bummer. Now we're going to play junior sysadmin and see if we can make it work in spite of the real sysadmin's ideas of what is Good, Just, and Right. Remember my guarantee: If you take my advice and it breaks something, you get to keep all of the little pieces. Free advice is worth only what you paid for it.
To limit the scope of our damage, create a new directory on the server named test in the top-most directory where your web accessible documents are stored (usually public_html) and set its permissions to 755 so we can get at it from the web. Move the test files (test.html and test.txt) into it. Give test.html a look with your browser to make sure that we can, in fact, get to it from the web.
We're going to be aggressive and just parse everything that we serve out of this directory. This is probably not how you will want to do things in normal use -- you will want to either use the XBitHack or the extension .shtml to signal to the server that you want a given file parsed. For right now, though, we're primarily concerned with answering the question "Can we even do this?", so we'll just go for it.
On your own machine, create a file named .htaccess -- if your OS is one of those funny things that won't allow this, just call it htaccess and rename it once it's on the server. Into that file, place the following text:
AddHandler server-parsed .html
Upload this file to the server, into the test directory you created a few moments ago. If you were unable to create it with the leading dot in the file name, change the name of the file on the server to .htaccess.
The Moment of Truth: Point your browser at test.html in its new home and see what happens. With any luck, you will see that line "If you can see this line, SSI is now working!" -- otherwise, you may as well call it quits for now and contact your ISP. It's probably a good idea to blow away that .htaccess file before you do, though. No sense poking them in their apparently hypersensitive ribs.
If you did get SSI working just now, good for you! You'll want to make sure that you don't parse any files that don't need to be parsed -- whether to use the XBitHack (if you can) or the extension .shtml is up to you. I like the XBitHack, you might want to use .shtml just to impress your friends. Live like you want to live.
To use the .shtml extension, change the first line in that .htaccess file you just created so that .html reads .shtml. To take advantage of the XBitHack change to first line to read XBitHack on. Then copy this .htaccess file into the top-most directory of each "tree" that you want it to apply to. If, for example, this is your public_html (or its equivalent) directory, the .htaccess file will apply to every file below it in the structure. NOTE: If you also have a cgi-bin directory or any other directory under public_html that contains executable files, you must disable includes in that directory/those directories! To do this, place another .htaccess file in each of the directories affected, and into that file place the text:
This will prevent SSI from working in those directories, which will keep evil crackers from opening a security hole -- and will keep you happy and safe. Imagine if a cracker used your account to send threatening email to the President of the United States, how startled you would be waking up in the middle of the night with the Secret Service in your bedroom.
I said "must" a moment ago, and the truth of the matter is that in most cases nothing will be apparently broken if you don't protect those directories that executables live in. But if the day comes when I'm the sysadmin at your ISP and you didn't take my advice, I'm going to come to your house late at night and beat bumps into your head. And into the head of your big mean dog, if you have one.
In order to ensure that your SSI will work, you will have to follow the conventions for SSI directives. Some servers will give you a little fudge factor, others won't. It's best to make sure you do your job properly so the server can do its job properly, too.
An SSI directive looks a lot like an HTML comment. It starts with a "less than" symbol, followed by an exclamation point, then two hyphens (dashes) and a hash (or "pound sign"). Following the hash is an action, possibly a space and then a modifier, then a quoted argument. After the closing quotation mark comes a space (the space is important!), then two hyphens and a "greater than" symbol. Here's an example:
<!--#echo var="REMOTE_ADDR" -->
If it were a working example, the above SSI directive would have been replaced with your current IP address (or the address of the proxy server you use to connect to the internet) which just happens to be 18.104.22.168
SSI is useful for many things. You've already seen how to include another file into your HTML documents -- if you use HTML markup, the browsers that see your site will never know the difference between included markup and things you wrote into the files themselves. No one needs to know that you're as lazy as I am. This can be useful where you have a large number of pages that should each contain some of the same content, such as a header or a copyright statement intended to scare away content thieves.
Suppose you want to create a "smart" link back to wherever the visitor came from, even if it wasn't your site that brought them here. We're going to reach out and get the environment variable HTTP_REFERER to do just that. (Yes, "referrer" is misspelled in this environment variable. I didn't have anything to do with the HTTP specification!)
We can get the value of environment variables using echo var= to retrieve them. It's important to note that if the variable is not set, you will get either nothing at all or (none) back -- in this example, you will end up with a broken link. To get the URI of the page that brought the user to your extraordinarily cool work:
<!--#echo var="HTTP_REFERER" -->
With that information, we can create that cool link -- it looks a lot better "live" than it does when you write it:
<a href="<!--#echo var="HTTP_REFERER" -->">Back</a>
Which, in action looks just like any other link: Back. (If you entered the URI of this page manually, the preceding link is broken, as I promised earlier. Otherwise, you can see it work by clicking it.) You don't have to concern yourself with whether or not the server will get confused by the nested quotation marks. It won't. I get confused by them sometimes, but I didn't develop your server so we're both in good shape.
Now that we've seen enough of the examples to have a feel for how these things work, here is the list of environment variables that I think you might find handy, with an example of what they look like right now on my server:
Useful Environment Variables:
There are other things you can do with SSI, as well. I've shown how to include the contents of other files and environment variables first simply because those are the things that are most often asked about when people come to alt.html asking about SSI.
Glad you asked, because that's what I'm ready to talk about now.
<!--#fsize file="some_file" -->
Pretty easy, huh? The size of this file is 28K. I could have just looked at the file size and entered it here, but I don't know what it is because at the time I included that directive I was still editing it. Not to mention that I'm too lazy to do things the hard way.
This is also something you've probably seen on those download pages. And I don't know anyone who wants the job of actually entering this information every time something changes. Even a trained monkey would revolt after a few days of that!
<!--#flastmod file="some_file" -->
We've already got the size of this file, and earlier we saw the last modified date of this file, so let's reach out and see when the index of this directory was last changed. Looks like it was Thursday, 02-Aug-2012 11:51:30 MDT. That was easy.
So you're seeking true guru status, huh? The easy way for a long and involved CGI application is to generate the HTML within the application itself. But if it's a short little dude that only outputs a line or two, or even nothing at all, and your server is a newer version, you can use our old friend <!--#include virtual="..." -->. If the server barfs on that, its time to whip out exec cgi:
<!--#exec cgi="some_cgi" -->
If the CGI application supports the GET method, you can even include whatever it expects to see in the URL that calls it in the exec cgi directive. Sorry, the POST method isn't going to work here. If I weren't so lazy, I'd come up with a cool Perl script to run as a CGI and include its output here. It seems kinda trivial though, and you'd have no way to even know for sure that a CGI is what put the output here. Just pretend that this paragraph was printed by a Perl script. Maybe it was.
Sure: <!--#exec cmd="..." --> with the same features and caveats as exec cgi. But it's a hell of a lot more dangerous -- don't even think of using this unless you're sure you know what you're doing.
You ought to have a pretty good handle on using Server Side Includes if you've endured long enough to read the Conclusion. There are a few other goodies that you can accomplish with SSI, including conditional operations like if this (then do) that. I might even add a section about that at some later date -- it can be handy for suppressing the output of an SSI directive that would just fail anyway, for instance. If you're really keen on doing those kinds of things, give a look at http://hoohoo.ncsa.uiuc.edu/docs-1.5/tutorials/includes.html which is a very useful document to look at, but is written at a higher level than the stuff I churn out. Not a lot higher, but enough that I've found myself explaining it more than once. (It could be that I end up explaining this document in spite of my best efforts!).
If you find that something I said here is patently false, somewhat misleading, kinda vague, or needs more work in some way, please let me know. My email address is just a bit below this paragraph. I might even fix whatever it is that you point out to me. Whether or not you get credit for it depends mostly on my mood and your attitude -- if you explain in your email just exactly how stupid I am, you certainly will not get credit. But if you send a large sum of cash in small unmarked bills, you probably will ;-) If you have found this document to be helpful and informative, and especially if it helped you to resolve a problem you were having, please drop me an email. I like having my ego stroked now and then.
That cool on-the-fly "back" link that we opened this whole can of worms with? Here's his twin, that will even work if you didn't enter the URI of this page manually into your browser:
Service to 22.214.171.124 on Sunday, 19-Apr-2015 14:06:54 GMT.