TheCounter (which we used on Haifux site) have stopped giving their
services for free, so if we want a counter, we need to have another
service, or run the software on vipe.

I found some free (as in beer) services, some with open source. Does
anybody know of a free-as-in-speach software to do that?

I wrote the attached counter, and am using it. I hope I've applied the GPL correctly but I'm not that well informed so there may be issues I'm unaware of.


Note that it is _not_ a 'Server-Side Include' counter, which is, AFAICT, a Good Thing.

Eyal
#!/usr/bin/perl
#
# PNG-outputting counter 
# by Eyal Rozenberg <[EMAIL PROTECTED]>
# 2003-01-09
#
# Notes:
# 1. Make sure the script has permissions to write to the count file
#    or to create it (if it doesn't exist).
# 2. This script requires the Perl GD package, available from
#    the Stein lab: http://stein.cshl.org/WWW/software/GD/
#
# Sample Usage:
#
# <img src="/cgi-bin/pngcount.cgi?recount_delay=3" alt="counter failed">
#
# count file format:
#
# count-value
# ignore-addr-1 ignore-addr-2 etc
# visit-addr-1 visit-time
# visit-addr-2 visit-time
# visit-addr-3 visit-time
# etc etc

##########################################################################
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You can get a copy of the GNU General Public License here:
#
# http://www.gnu.org/licenses/gpl.txt
#
# or write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA

##########################################################################
#
# fixed settings and default values

# the time period after the increase of a counter by a specific host
# in which accesses from that host will not alter the counter
$recount_delay = 10; 

# do we need to add a prefix to the URI so as to access the file locally?
# if not, comment this out. This setting is invalid if a count_file is
# specified as a parameter to the script.
$uri_prefix = '/var/www/';

# the image file containing the images of the digits 0 through 9
# (note that only formats supported by the GD library can be read)
$digit_set_file = "/var/www/images/count_charset/set.png";

# minimum number of displayed digits (0 means no 0-padding will be done)
$min_ndigits = 5;

##########################################################################

use CGI qw(:standard);
use Fcntl qw(:flock :seek);
use GD;
#use for debugging the script
#use CGI::Carp 'fatalsToBrowser';

# initializations 

if ( defined param('count_file') ) {
        $count_file = param('count_file');
}
else {
        $count_file =    $ENV{'DOCUMENT_URI'}
                      || $ENV{'REQUEST_URI'} 
                      || die "can't determine count file: $!";
        $count_file .= '.count';
        $count_file = $uri_prefix . $count_file if (defined $uri_prefix);
}
$addr =    $ENV{'HTTP_FROM'}
        || $ENV{'REMOTE_HOST'}
        || $ENV{'REMOTE_ADDR'}
        || die "no remote address";
$curtime = time();
$recount_delay = param('recount_delay') if (defined param('recount_delay'));
$digit_set_file = param('digit_set_file') if (defined param('digit_set_file'));
$min_ndigits = param('digits') if (defined param('digits'));
$dont_advance = defined param('dont_advance');
if (defined $newroot) {
        chroot($newroot) || die "can't chroot to $newroot : $!";
}

# if we're only displaying the value, do only that and exit

if ( $dont_advance ) {
        if (-e $count_file) {
                open(CF, "<${count_file}") ||
                        die "can't open count file $count_file: $!"; 
                flock CF, LOCK_SH;
                chomp($count = <CF>);
                flock CF, LOCK_UN;
                close CF;

                # a little sanity check...

                $count = 0 if ($count < 0);
        }
        else { $count = 0; }
        &generate_output;
        exit;
}

# lock the count file and read its contents

# if the file doesn't exit, let's create it
$openmode = ((!(-e $count_file)) ? ">" : "+<"); 

open(CF, "${openmode}${count_file}") || die "can't open count file $count_file: $!"; 
flock CF, LOCK_EX;
@cdata = <CF>;
chomp($old_count = shift @cdata);
chomp($ignore_list = shift @cdata);
# a little sanity check...
$old_counter = 0 if ($old_counter < 0); 

# flood prevention & counter increase 

foreach $line (@cdata) {
        ($laddr,$ltime) = split / /, $line ;
        $count = $old_count if (    $line =~ /^$addr/ 
                                 && ($curtime - $ltime < $recount_delay) );
}
$count = $old_count if ( $ignore_list =~ /$addr/ );

unless ( defined $count ) {
        $count = $old_count+1;
        @cdata = (@cdata, "$addr $curtime\n");
}

# write new count file contents, discarding aged entries

seek CF, 0, SEEK_SET; # rewind the count file 
truncate CF, 0; # clear the count file
print CF "$count\n";
print CF "$ignore_list\n";
foreach $line (@cdata) {
        $ltime = (split(/ /,$line))[1];
        if ( $curtime - $ltime < $recount_delay ) {
                print CF $line;
        }
}

# truncate the file and release it

truncate CF, tell(CF);
flock CF, LOCK_UN;
close CF;

# finish up

&generate_output;
exit;

sub generate_output {

        # pad count value with 0's if needed
        
        if ( $min_ndigits > 0 ) {
                $count = sprintf "%.$min_ndigits"."d", $count;
        }

        # open the digit-set image file
        # and determine the digit image dimensions
        
        $digit_set = new GD::Image($digit_set_file) || die "can't open 
${digit_set_file}: $!";
        ($dw,$dh) = $digit_set->getBounds();
        $dw /= 10; #the digit-set image is 10-digit long

        # create the output image and copy each digit image into place
        
        $im = new GD::Image($dw*(length $count),$dh) || die "can't create image: $!";

        for($i = 0; $i < (length $count) ; $i++) {
                $digit = substr $count, $i, 1;
                $im->copy($digit_set,$i*$dw,0,$digit*$dw,0,$dw,$dh);
        }
 
        # write the output image

        print header('image/png');
        print $im->png;
}

<<inline: set.png>>

Reply via email to