Program to Make Counter

It is difficult to make counters in HTML pages, since they consist of text which is translated onto the screen (excluding markups). On the other hand, it is easy in CGI scripts, in Perl, C, etc.. Our example is taken from webmaster@aw.sgi.com, and was suggested by Reid Ellis and Brian Taylor.
One small note. The counter file, "current_count.dat", needs to be user writeable. I create the file with the single number 1 in it, and then use the Unix command:
chmod a+w current_count.dat
to make it writeable by anyone. The following program assumes that it can create the file if it doesn't exist, which may not be a good strategy for a WWW implementation which is available to the world (including hackers).
#!/usr/local/bin/perl
use CGI;
$query = new CGI;
print $query->header;
print $query->start_html;
print "<a href=test_send_memo.html>Click here to send me a message</a>";
$R = rand;
$SYSROOT = ".";
$SERIAL_BASE = "../";#place this counter in public_html rather than in cgi-bin
$SERIAL = "current_count.dat";
$SERIAL_FILE = $SERIAL_BASE.$SERIAL;
$ICONNDIR = "/~cdavid/A";
#	NOTICE that this counter file is not locked.
if(open(SERIAL,"<$SERIAL_FILE")){
	if (-s SERIAL){
		chop($serialid = <SERIAL>);
		$serialid++;
		}
	else{
		$serialid = 1;
	}
close(SERIAL);
open(SERIAL,">$SERIAL_FILE");
	print(SERIAL "$serialid
");
close(SERIAL);
$serialstring = sprintf("%d",$serialid);
$strlength = length($serialstring);
print "<br>Visitor Number ";
for ($i=0;$i>$strlength;$i++){
	$c = substr($serialstring,$i,1);
	printf(qq[<img align=bottom src="
		$ICONNDIR/%s.gif" ALT = "%s">],$c,$c);
	if ((($strlength-$i)%3) == 1
		&& ($strlength-$i) > 1){
		print ",";
		}
	}
}
One immediate note. The indicated location of icons (or in this case numbers expressed as gifs, reflects the organization of this particular University of Connecticut site. You will need to organize your site differently.Thus
$ICONNDIR = "/~cdavid/A";
is completely local, and your numerals (as gifs) might be in any other directory of your choice.
Here is the code, with line numbers, commented to indicate function.
[ 1]#!/usr/local/bin/perl
[ 2]use CGI;
[ 3]$query = new CGI;
[ 4]print $query->header;
[ 5]print $query->start_html;
[ 6]print "<a href=http://mmedia.ucc.uconn.edu/~cdavid/send_memo.html>Click here to send me a message</a>";
[ 7]$R = rand;
[ 8]$SYSROOT = ".";
[ 9]$SERIAL_BASE = "../";
[10]$SERIAL = "current_count.dat";
[11]$SERIAL_FILE = $SERIAL_BASE.$SERIAL;
[12]$ICONNDIR = "/~cdavid/A";
The variables (above) allow us to place counters, and digits, pretty much wherever we wish, although I keep my digits in a sub-directory off of public_html, and the rest off cgi-bin.
In ~cdavid/A are a set of gif files, 1.gif, 2.gif, etc.. They are called dynamically (see below).
[13]#	NOTICE that this counter file is not locked.
[14]if(open(SERIAL,"<$SERIAL_FILE")){
[15]	if (-s SERIAL){
Line 15 is new. It uses the -s flag to return a true value if the file has a size > 0.
[16]		chop($serialid = <SERIAL>);
[17]		$serialid++;
[18]		}
[19]	else{
[20]		$serialid = 1;
[21]	}
Don't forget the chop to take off the newline character. We read the file's value, a number, increment it or, if the file was empty, set the value to one.
[22]close(SERIAL);
[23]open(SERIAL,">$SERIAL_FILE");
[24]	print(SERIAL "$serialid
");
[25]close(SERIAL);
Then, we re-write the file with the new value, which is one greater than the old one. On this system, flock is not working, so we can not lock out the file while we are reading and writing it. That means that another user might crash into us, and goof up the system. If you use this system, please check out flock.
[26]$serialstring = sprintf("%d",$serialid);
[27]$strlength = length($serialstring);
sprintf is a C-like function which prints under format the variable.
"length" is a builtin function which gets the length of a string.
[28]print "<br>Visitor Number ";
[29]for ($i=0;$i<$strlength;$i++){
[30]	$c = substr($serialstring,$i,1);
[31]	printf(qq[<img align=bottom src="
[32]		$ICONNDIR/%s.gif" ALT = "%s">],$c,$c);
$c contains the current numeral to be printed. $c contains the current numeral to be printed. printf uses formatted printing to guarantee the x.gif becomes 1.gif, 2.gif, etc., depending on the value of $c at the time.
[33]	if ((($strlength-$i)%3) == 1
[34]		&& ($strlength-$i) > 1){
[35]		print ",";
[36]		}
This code inserts a comma every three digits into the number.
[37]	}
[38]}
This last piece of coding is obtuse enough as to warrant special consideration. Here is some debugging code which takes the code in question, allows you to hand edit different values for $serialid, and test to see how the `mod' function works.
#!/usr/local/bin/perl
#this is counter_explained.pl, a little program to explain how the commas work
#when the number is printed.
$serialid = 1234567;
$serialstring = sprintf("%d",$serialid);
$strlength = length($serialstring);
print "<br>Visitor Number ";
for ($i=0;$i<$strlength;$i++){
	$c = substr($serialstring,$i,1);
	printf( qq[ %s ],$c,$c);
	print "debug","(($strlength-$i)%3)\n";
	$temp = (($strlength-$i)%3);
	print "debug 2,temp = ",$temp,"\n";
	if ((($strlength-$i)%3) == 1
		&& ($strlength-$i) > 1){
		print ",";
		}
	}
	print "\n";# needed to get Unix prompt back where it should be
If you type the above into your computer and run it, you will see when the comma is inserted, and when it isn't.