#!/usr/bin/perl # counter.cgi -- counts Web page hits # the first line of this script may have to be changed # if your system's Perl interpreter is not located in /usr/bin/perl # Written by P. Lutus Ashland, Oregon lutusp@arachnoid.com 2/21/96 # This is a cute, small, serviceable hits counter program. It uses the x-bitmap format # which is monochrome. It won't look very good if the textcolor and background are the same color # and the browser is made by Netscape. Every other place and browser, OK. # # Call the counter like this: You are Visitor Number # Ownername can have particular web page designators attached to it like this: Ownername_mypagename # This allows you to count pages independently. # The directory in which counter.cgi is stored must have world read, write and execute access. # The file counter.cgi must have world execute access. # $min_width is the minimum number of digits to print -- # the program will always print more as the number grows larger $min_width = 2; # set $collect_stats = 1 if you want to log the origins of accesses # in a file named Ownername.log $collect_stats = 1; $countname = "counter_dat"; # a default name for the counter file # This is a reasonable character set, sort of blocky but OK $counter_width = 16; $counter_height = 20; @dig_arr = ( '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xFA', '0x17', '0xF6', '0x1B', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x06', '0x18', '0x00', '0x00', '0x06', '0x18', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0xF6', '0x1B', '0xFA', '0x17', '0xFC', '0x0F', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x10', '0x00', '0x18', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x18', '0x00', '0x00', '0x00', '0x18', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x18', '0x00', '0x10', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xF8', '0x17', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0xF0', '0x1B', '0xF8', '0x07', '0xF6', '0x03', '0x0E', '0x00', '0x0E', '0x00', '0x0E', '0x00', '0x0E', '0x00', '0xF6', '0x03', '0xFA', '0x07', '0xFC', '0x0F', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xF8', '0x17', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0xF0', '0x1B', '0xF8', '0x07', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0xF0', '0x1B', '0xF8', '0x17', '0xFC', '0x0F', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x02', '0x10', '0x06', '0x18', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0xF6', '0x1B', '0xF8', '0x07', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x18', '0x00', '0x10', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xFA', '0x07', '0xF6', '0x03', '0x0E', '0x00', '0x0E', '0x00', '0x0E', '0x00', '0x0E', '0x00', '0xF6', '0x03', '0xF8', '0x07', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0xF0', '0x1B', '0xF8', '0x17', '0xFC', '0x0F', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xFA', '0x07', '0xF6', '0x03', '0x0E', '0x00', '0x0E', '0x00', '0x0E', '0x00', '0x0E', '0x00', '0xF6', '0x03', '0xF8', '0x07', '0xF6', '0x1B', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0xF6', '0x1B', '0xFA', '0x17', '0xFC', '0x0F', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xF8', '0x17', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x18', '0x00', '0x00', '0x00', '0x18', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x18', '0x00', '0x10', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xFA', '0x17', '0xF6', '0x1B', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0xF6', '0x1B', '0xF8', '0x07', '0xF6', '0x1B', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0xF6', '0x1B', '0xFA', '0x17', '0xFC', '0x0F', '0x00', '0x00', '0x00', '0x00', '0x00', '0x00', '0xFC', '0x0F', '0xFA', '0x17', '0xF6', '0x1B', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0x0E', '0x1C', '0xF6', '0x1B', '0xF8', '0x07', '0xF0', '0x1B', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0x00', '0x1C', '0xF0', '0x1B', '0xF8', '0x17', '0xFC', '0x0F', '0x00', '0x00', ); @digits = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); # So? Anything is possible! @envname = ( 'REMOTE_ADDR', 'REMOTE_HOST', 'HTTP_REFERER', 'HTTP_USER_AGENT', 'HTTP_ACCEPT', ); if ($ENV{COMSPEC} ne '') { # most definitely MSDOS, so use those old funky names @envname = keys(%ENV); } if ($ENV{'QUERY_STRING'} ne '') { $countname = $ENV{'QUERY_STRING'}; # get the file name from counter.cgi?ownername construct } unless (-e $countname) { # unless this file already exists open (COUNT,">$countname"); # directory has to have world write permission for this to work print COUNT "0\n"; close COUNT; } $count = 0; # now get and increment the counter open (COUNT,$countname) || die "Content-type:text/plain\n\nCan't open $countname!\n"; $count = ; close COUNT; $count++; open (COUNT,">$countname"); # I don't lock access so this might break or not count right in busy sites print COUNT "$count\n"; # but locking has problems of its own ... close COUNT; if ($collect_stats) { # owner want to collect data on logons $logname = $countname . ".log"; unless (-e $logname) { # unless this file already exists open (LOG,">$logname"); # directory has to have world write permission for this to work print LOG "Count\tTime"; foreach $envlbl (@envname) { print LOG "\t$envlbl"; } print LOG "\n"; close LOG; } # done initializing stats file open (LOG,">>$logname"); # now enter this stat record $tim = &readtime; print LOG "$count\t$tim"; foreach $envlbl (@envname) { print LOG "\t$ENV{$envlbl}"; } print LOG "\n"; close LOG; } # end of collect_stats block $size = &fill_digits($count); # now show the actual count &print_digits($size); exit; sub fill_digits { $q = @_[0]; $i = 0; do { $digits[$i++] = $q % 10; $q = int($q/10); } while(($q != 0) || ($i < $min_width)); # force width to be at least $min_width $i = $i; # make it the return value } sub print_digits { $width = @_[0]; $cw = $width * $counter_width; $chh = $counter_height * 2; print "Content-type:image/x-xbitmap\n\n"; print "#define counter_width $cw\n"; print "#define counter_height $counter_height\n"; print "static unsigned char counter_bits[] = {\n"; $start = 1; for($i=0;$i<$chh;$i=$i + 2) { for($j=$width-1;$j>=0;$j--) { for($k=0;$k<2;$k++) { if ($start == 0) { print","; } print "$dig_arr[($digits[$j]*$chh)+$i+$k]"; $start = 0; } } print "\n"; } print "};\n"; } sub readtime { local ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); sprintf ("%2.0f/%02.0f/%04.0f %2.0f:%02.0f:%02.0f",$mon+1,$mday,($year > 50)?$year+1900:year+2000,$hour,$min,$sec); # to the stack }