CGI Security : Better Safe than Sorry
Creating a Page Counter In Perl
Speed Thrills : CGI Please ... and Fast!
CGI Programming Made (Relatively) Easy Using Libraries
Server-Side Includes and its Extensions
Random and Recursive Crypting using Salt on Unix and Win32
Creating a mailing list using Perl
You are here: irt.org | Articles | CGI & Perl | Timestamping an HTML Document [ previous next ]
Published on: Saturday 14th November 1998 By: Pankaj Kamthan
Timestamping an HTML document that one has created conforms to a "good" style of HTML markup [Ref. 1]. It gives the viewer a sense as to how old the document is. Perhaps, more importantly, this is of relevance to a returning user who may first wish to know if the document has been modified since he/she visited it the last time before browsing through. Many HTML editors in current use (such as Emacs with the html-helper-mode or Microsoft FrontPage 98) have a built-in capability of including-in the date of last modification automatically when one saves the document. In this article, we show two ways of how it can be done without the use of special-purpose HTML editors.
This method uses SSIs. For this, an appropriate WWW server directive should be enabled. (For example, the Apache WWW server has such a directive.) Please contact your WWW server administrator, if you are not familiar with it.
Create a file called lastmodified.shtml with the following line:
Last Modified: <!--#echo var="LAST_MODIFIED" -->
Include the line
<!--#include virtual="lastmodified.shtml"-->
at the end of your HTML document in which you wish to include the last modification date and save it with extension .shtml. You can also introduce different colours and fonts in your lastmodified.shtml file to make the output more attractive.
Using the flastmod directive, you can also inserts the
last modification date and time of other documents. (The difference between the
SSI environment variable LAST_MODIFIED
and this command is that, flastmod
allows you to choose any file, while LAST_MODIFIED
displays the
information for the current file.) For example:
<!--#flastmod virtual="/path_to/foo.html"-->
This can be useful if you have an index or table of contents page which not only lists what documents are available, but also when were they last modified, as the next example illustrates:
<HTML> <HEAD> <TITLE>Table of Contents</TITLE> </HEAD> <H1>Table of Contents</H1> We have the following information for you: <UL> <LI>Document 1 (Last Modified : <PRE><!--#flastmod virtual="/path_to/1.html"--></PRE>) <LI>Document 2 (Last Modified : <PRE><!--#flastmod virtual="/path_to/2.html"--></PRE>) . . . </UL> . . . <PRE> <!--#echo var="LAST_MODIFIED"--> </PRE> </BODY> </HTML>
In dynamically generated HTML documents using CGI in Perl 5, you can insert a time stamp by including:
$last_modified = localtime (time); print "Last Modified : $last_modified\n";
in your CGI script.
Use of SSI's is not always recommended as it puts a load on
the server each time a file of the type *.shtml
is accessed. (SSI's, of
course, have many other uses - as an alternate or in conjunction to CGI scripts.) The same
argument holds for dynamically generated HTML documents using CGI, particularly if they
are generating a page (such as the home page for a site) that is frequently accessed. It
is not much of a hindrance in this case, since the file size (of lastmodified.shtml
)
is small.
To use this method, the browser should be JavaScript-compatible (such as Netscape Communicator 2.0+ or Microsoft Internet Explorer 3.0+). Including the following segment of code in your HTML document does the work:
Script 1.
<SCRIPT language="JavaScript"><!-- document.write(document.lastModified); //--></SCRIPT>
This is simplest form of script that is possible. The above script will return the exact time of modification down to the hours, minutes and seconds. Variants of this script can make the output more "user-friendly". For example, if you wish to have an output as Month Date, Year (say July 4, 1998) only, it can be done by including the following segment of code in your HTML document:
Script 2.
<SCRIPT LANGUAGE = "JavaScript"><!-- function makeArray() { for (i = 0; i < makeArray.arguments.length; i++) this[i + 1] = makeArray.arguments[i]; } var modifiedMonth = new makeArray('January','February','March','April', 'May','June','July','August','September', 'October','November','December'); var modifiedDate = new Date(document.lastModified); document.write('Last Modified : ' + modifiedMonth[modifiedDate.getMonth() + 1] + ' ' + modifiedDate.getDate() + ', ' + modifiedDate.getFullYear()); //--></SCRIPT>
You can also introduce different colours and fonts to make the output more attractive. With a little bit of more work on the script, corresponding day and date suffixes (st, nd, rd, th) can also be added (so that the above example appears as Saturday, July 4th, 1998).
By adding appropriate functions for the day prefixes and date suffixes to the Script 2, and modifying the output the final form of Script 2 then becomes:
Script 2'.
<SCRIPT LANGUAGE="JavaScript"><!-- function makeArray() { for (i = 0; i < makeArray.arguments.length; i++) this[i + 1] = makeArray.arguments[i]; } var modifiedMonth = new makeArray('January','February','March','April', 'May','June','July','August','September', 'October','November','December'); var modifiedDate = new Date(document.lastModified); function modifiedDay(day) { if (day == 0) return 'Sunday'; else if (day == 1) return 'Monday'; else if (day == 2) return 'Tuesday'; else if (day == 3) return 'Wednesday'; else if (day == 4) return 'Thursday'; else if (day == 5) return 'Friday'; else return 'Saturday'; } function modifiedDateSuffix(date) { if (date == 1 || date == 21 || date == 31) return 'st'; else if (date == 2 || date == 22) return 'nd'; else if (date == 3 || date == 23) return 'rd'; else return 'th'; } function getCorrectedYear(year) { year = year - 0; if (year < 70) return (2000 + year); if (year < 1900) return (1900 + year); return year; } document.write('Last Modified : ' + modifiedDay(modifiedDate.getDay()) + ', ' + modifiedMonth[modifiedDate.getMonth() + 1] + ' ' + modifiedDate.getDate() + modifiedDateSuffix(modifiedDate.getDate()) + ', ' + getCorrectedYear(modifiedDate.getFullYear())); //--></SCRIPT>
With JavaScript 1.2-compatible browsers (such as Netscape Communicator 4.0+ or Microsoft Internet Explorer 4.0+), such scripts don't have to be included in the document directly and can be reused. All that is needed, is (a pointer to) the path to the file containing the script. However, you may have to configure your server and add a MIME type to your configuration in order to prevent it from returning a plain-text file. Including the following segment of code in your HTML document
<SCRIPT language="JavaScript 1.2" SRC="scripts/lastmodified.js"></SCRIPT>
where the file lastmodified.js contains any of the above portions of the scripts that are between the tags <SCRIPT LANGUAGE="JavaScript"><!-- and //--></SCRIPT>, and resides in the scripts directory.
Unfortunately, it seems that the JavaScript technique doesn't work if the file is already using SSIs (say for some other purpose). That is, the above technique will not work if the file is of the type *.shtml and includes
document.write(document.lastModified)
One can use one of the above techniques or the other. Suppose we have a collection of files (over a file system) in which we previously used the SSI technique and want now to use the JavaScript technique. The task, after inserting the appropriate <SCRIPT> tag, then becomes of renaming these *.shtml files to *.html files. Using a Perl script this can be accomplished easily as follows:
Step 1. Copy (though maintain the copyright) the following script [Ref. 2] to a file, call it rename and change the path: #!/usr/bin/perl to wherever you have Perl on your system.
#!/usr/bin/perl -w # rename - Larry's filename fixer $op = shift or die "Usage: rename expr [files]\n"; chomp(@ARGV = <STDIN>) unless @ARGV; for (@ARGV) { $was = $_; eval $op; die $@ if $@; rename($was,$_) unless $was eq $_; }
Step 2. On the shell prompt (for UNIX platforms; on other platforms a variant of find should work) type the following where the directory_name is the top level directory (with subdirectories where *.shtml files are residing):
find ./directory_name -name '*shtml' -print | rename 's/shtml/html/'
Of course, the same idea applies if you wish to rename *.html files to *.shtml files:
find ./directory_name -name '*html' -print | rename 's/html/shtml/'
In the server-side approach, the compliance depends directly on the operating system and hardware on which the script is being run.
In the client-side approach, use of getFullYear() assures the Y2K-compliance to a large extent, but requires (1) "appropriate" use of the Date() object, and (2) that the browsers support JavaScript 1.2 and above (to be precise, the ones that support ECMAScript as defined in ECMA-262 standard). The issue of Y2K-compliance in JavaScript will be addressed in detail elsewhere.
With some basic knowledge of SSIs or JavaScript, you can add customized timestamps to your HTML documents.
Please let me know if you have any comments, suggestions or questions about this article. Contributions for any additional techniques are most welcome.
I would like to thank Alan Liu, and particularly Dave Campbell, for their suggestions regarding Y2K compliance in JavaScript scripts presented here.
[Ref. 1] HTML: The Definitive Guide, 3rd Edition, By Chuck Muschiano and Bill Kennedy, O'Reilly & Associates, 1998.
[Ref. 2] Perl Cookbook, By Tom Christiansen & Nathan Torkington, O'Reilly & Associates, 1998, p. 327.
CGI Security : Better Safe than Sorry
Creating a Page Counter In Perl
Speed Thrills : CGI Please ... and Fast!
CGI Programming Made (Relatively) Easy Using Libraries
Server-Side Includes and its Extensions
Random and Recursive Crypting using Salt on Unix and Win32
Creating a mailing list using Perl
Reading and Writing to Files on the Server
Server Side Includes and CGI Security