#!/usr/bin/perl
#################################################################
# G-Counter v2.0
# by Adam Watkins
# http://www.watty.com
# Distribute Freely
#################################################################
#################################################################
# Version History:
# v2.0 (5-02-01)
# - Reworked the script with more error checking
# - Completely reworked script
# - Added format and inc option to query string
# - Added Octal, Binary and Hexidecimal support
# - Variable max digit support
# - Added option to turn off on the fly counter adding
# v1.6 (2-20-01)
# -Change printing of the digits method to 1024 at a time
# -Use a -e to see if count file exists first, if not create
# -have it bomb out if if can't open count file
#################################################################
# How to set up?
#
# Or if you don't support SSI of you don't want to use it there is another way!
# Put the following lines into your page:
#
#
#
# How it works! In ?name&d&0&9 the values are name, format, inc, and digit.
# name -> This is the counter name. This can allow you to run many
# counters off this one script. It can be digits or text.
# format -> This is the format the digits should be displayed in.
# d = Decimal, b = binary, h = hexidecimal, o = octal
# inc -> 1 - Increment count, 0 - do not increment count.
# This is used for if you are displaying all the different
# number formats on the same page, you don't increment all of
# them (unless you want to).
# *NOTE* If you display more than one count on a page make sure
# the one that loads LAST is the one that increments
# digit -> Which digit of the count to display.
#
# The ?name&d&0&0 spot is the first decimal digit in the number. You don't need to show all ?0&d&0&0 thru ?0&d&0&9
# If your count is only 55. All that you need to show is ?0&d&0&0 and ?0&d&0&1
# But, you can show them all. If you do, it will display 0000000055
# You can go as high up to the value in $diglimit below.
#
# Also note that the the only once set to increment is the 1st digit (0), so it only increments the counter once. (not 10 times)
# The example shown above will show the counter called "name" in decimal format to 10 digits.
#
# ALSO NOTE: If you do not use my supplied images, you will need to change the height
# and width also.
#
# chmod 777 the file & the directory, $basedir/$baseurl, specified below
# Upload all your images to that directory too
# Upload gcounter.pl and chmod 755
#
# NOTE: If not using $onthefly counter generation mode (default yes, set below) then you must create counter files.
# If the name of your counter is 'name' then create a file called gc_name.txt in the $basedit,
# place a 1 in it (0 will error), and chmod 777 the file
#
# Then... edit these lines...
##########################################
# This is where graphics and count files go
$basedir = "../cgi-bin";
$baseurl = "http://www.lesliehouk.com/cgi-bin";
##########################################
# What kind of graphics files are you using?
# if you are using gif uncommnet the gif lines and
# comment the jpg lines. And visa versa.
# Set Default to the type of the graphics included.
$type = "image/gif";
$ext = ".gif";
#$type = "image/jpg";
#$ext = ".jpg";
##########################################
# What is the width and height of your graphics?
# Set Default to the size of the graphics included.
$imgwidth = "15";
$imgheight = "18";
#########################################
# Use file locking? (flock)
# set equal to yes if your server supports it
$lock = "no";
#########################################
# Make new counters on the Fly?
# You can just put a new counter name and a
# new counter file will be made for it.
$onflynew = "yes";
#########################################
# Digit Limit
# Shouldn't have to change this
$diglimit = 16;
##########################################
# NO Need to edit below here
my $use_ssi = 1; #value to keep track if using ssi to display, default yes
my $limit; #keeps track of how many characters are in the count
my @numstf; #this is the count as an array with leading 0's
my $file; #this is the file of the digit that non-ssi will display
# go and get the count, puts it into @numstf, sets limit and file and use_ssi
&get_cnt;
# displays the count based on use_ssi, limit for ssi mode and file for non-ssi mode.. uses @numstf
&prnt_cnt;
#########################################
# Begin Subroutines
sub get_query {
my $command; #Query string
my $counter_name; #counter name parsed from query string
my $dig2display = ""; #digit 2 display (not using ssi)
my $format; #number format to display (hex, bin, dec)
my $inc; #whether or not to inc
if ($ENV{'QUERY_STRING'} ne '') {
$command = "$ENV{'QUERY_STRING'}";
} else {
#must have command line info to operate
error("No command line information");
}
if ($command =~ /(.*)&(.*)&(.*)&(.*)/) {
$counter_name = $1;
$format = $2;
$inc = $3;
$dig2display = $4;
} elsif ($command =~ /(.*)&(.*)&(.*)/) {
$counter_name = $1;
$format = $2;
$inc = $3;
} elsif ($command =~ /(.*)&(.*)/) {
#legacy/shortcut support for non-ssi
$counter_name = $1;
$format = "d";
$dig2display = $2;
if ($dig2display eq "0") {
$inc = 1;
} else {
$inc = 0;
}
} else {
#legacy/shortcut support for ssi
$counter_name = $command;
$format = "d";
$inc = 1;
}
#error checking the query string input
error("format is illegal") unless ($format eq "b" or $format eq "h" or $format eq "d" or $format eq "o");
if (($dig2display) || ($dig2display eq "0")) {
#mark the global variable that we are not using ssi
$use_ssi = 0;
error("digit to display is invalid") unless ($digit2display >=0 or $digit2display < $diglimit);
}
#return
($counter_name,$format,$inc,$dig2display);
}
sub get_cnt {
my $numtemp; #value recieved from the counter file (cannot be 0)
my $dispnum; #number in format to be displayed in (dec, bin, or hex)
my @numarray; #turn the decimal number into a array of characters for shifting
my $limcnt; #counter to do the character shifting based on the limit
my $du; #each charater in the numarray
my $i; #for loop variable
#get values from the query string
my ($counter_name,$format,$inc,$dig2display) = &get_query;
#see if count file exists, if not try to create it
if (!( -e "$basedir/gc_$counter_name\.txt")) {
if ($onflynew eq "yes") {
&new_file($counter_name);
$numtemp = 1;
} else {
error("No counter file");
}
} else {
#get count
open (CNT, "$basedir/gc_$counter_name\.txt") || error("could not get count");
$numtemp = ;
close(CNT);
#make sure we get a number
error("no counter number") unless ($numtemp);
}
#to strip of excess
$numtemp = int($numtemp);
#if format is not decimal, convert it to another format
if ($format ne "d") {
($dispnum) = num_convert($format,$numtemp);
} else {
$dispnum = $numtemp;
}
#checking for number of digits
$limit = length($dispnum);
$limit = $limit-1;
#split into an array of digits
@numarray = split(//, $dispnum);
#initializing each to 0
for($i=0;$i<16;$i++){
$numstf[$i] = 0;
}
#filling the appropriate spots with digits
$limcnt = $limit;
foreach $du (@numarray) {
$numstf[$limcnt] = $du;
$limcnt--;
}
if ($inc) {
increment_num($counter_name,$numtemp);
}
$file = "$basedir/$numstf[$dig2display]$ext";
}
sub prnt_cnt {
my $size; #size of the file to display in non ssi mode
my $i; #for loop var
if ($use_ssi) {
print "Content-type: text/html\n\n";
print "\n";
for ($i=$limit;$i>=0;$i--){
print " | \n";
}
print "
\n";
} else {
if ( open(IMGF, $file)) {
$size = ( -s $file);
print "Content-type: $type\n";
print "Content-length: $size\n\n";
while(read(IMGF,$data,1024)){ print $data; }
close (IMGF);
}
}
}
sub new_file {
my ($counter_name) = @_;
open (NEWCNT, ">$basedir/gc_$counter_name\.txt") || error("Could not create the new file");
print NEWCNT "1";
close(NEWCNT);
}
sub increment_num {
my ($counter_name, $numtemp) = @_;
$numtemp++;
open (CNT2, ">$basedir/gc_$counter_name\.txt");
if ($lock eq "yes") {
flock CNT2, 2;
}
print CNT2 "$numtemp";
if ($lock eq "yes") {
flock CNT2, 8;
}
close(CNT2);
}
sub error {
($error) = @_;
print "Content-type: text/html\n\n";
print "ERROR: $error\n";
exit;
}
sub num_convert {
my ($format, $numtemp) = @_;
my $dectmp = $numtemp;
my $convnum = "";
my $rmdr;
#format is binary
if ($format eq "b") {
while ($dectmp != 0) {
$rmdr = $dectmp - (int($dectmp / 2) * 2);
$convnum = $rmdr . $convnum;
$dectmp = int($dectmp / 2);
}
#format is hexidecimal
} elsif ($format eq "h") {
while ($dectmp != 0) {
$rmdr = $dectmp - (int($dectmp / 16) * 16);
if ($rmdr eq "10") {
$rmdr = "a";
} elsif ($rmdr eq "11") {
$rmdr = "b";
} elsif ($rmdr eq "12") {
$rmdr = "c";
} elsif ($rmdr eq "13") {
$rmdr = "d";
} elsif ($rmdr eq "14") {
$rmdr = "e";
} elsif ($rmdr eq "15") {
$rmdr = "f";
}
$convnum = $rmdr . $convnum;
$dectmp = int($dectmp / 16);
}
#format is octal
} elsif ($format eq "o") {
while ($dectmp != 0) {
$rmdr = $dectmp - (int($dectmp / 8) * 8);
$convnum = $rmdr . $convnum;
$dectmp = int($dectmp / 8);
}
#format is something else, so how. should never happen
} else {
$convnum = $numtemp;
}
#return
$convnum;
}