CGI and Perl

Listing 7.6. CGI script that displays a graphical hit counter.

my($count)=&pageCount("/index.html");
 my($len)=length($count);
 my($i);
 my($imageStr)="";
 for ($i=0;$i<$len;$i++) {
     my($digit)=substr($count,$i,1);
     $imageStr .= "<IMG SRC=digit$digit.gif>";
 }
 print "$imageStr\n";

Therefore, if the hit count turns out to be 342, this code results in HTML that looks like

<IMG SRC=digit3.gif><IMG SRC=digit4.gif><IMG SRC=digit2.gif>

which will appear in the browser as in Figure 7.3.

Figure 7.3. Demonstration of a graphical hit counter.

You can also use printf formatting to pad the number with zeros prior to producing the image string. This would give the effect of an odometer look.

In order to keep your Web server from being bogged down by this script on every page access, it might be wise to run this code as a cron job every 15 minutes or so. With the cron job, you can also keep track of the current seek point in the file and avoid having to count hits multiple times. You can then access the counter file that the cron job maintains. If you need up-to-the-second results, you can have the CGI script use the same logic as the cron job and go to a particular seek point in the log to begin the counting. It is also always a good idea for the Web server administrator to rotate the logs every so often. When rotating the logs, it is important to then reset the seek position of your counter file back to zero. To move the current read position of an open file, use the Perl seek function as in the following code:

seek LOGHANDLE, $seekPoint, 0;

There is a useful package available in the CPAN from Gisle Aas called CounterFile.pm. This module provides an easy programmable interface for maintaining a counter file. By using this module, you can easily lock the file while you increment the counter. A CounterFile object is used as in the following example:

Use File::CounterFile;
 $counter = new File::CounterFile "page1.count", "0";
 $counter->lock;
 $current_count = $counter->inc;
 $counter->unlock;

You can decrement the counter by using the dec method. You can also use the value method to peek at the counter value without incrementing or decrementing the counter.