                     SERVER EVENT COUNT FILE
----------------------------------------------------------------------

by Darren Duncan <perl@DarrenDuncan.net>

SYNOPSIS

	use CGI::EventCountFile;
	
	MAIN: {
		$self->mail_me_and_reset_counts_if_new_day( "counts.txt" );

		$self->update_one_count_file( "counts.txt", 
			(map { "\$ENV{$_} = \"$ENV{$_}\"" } qw(
			REQUEST_METHOD SERVER_NAME SCRIPT_FILENAME
			HTTP_HOST SCRIPT_NAME SERVER_SOFTWARE HTTP_REFERER )
		) );
	}

	sub update_one_count_file {
		my ($self, $file_path, @keys_to_inc) = @_;

		push( @keys_to_inc, '__total__' );

		my $count_file = CGI::EventCountFile->new( $file_path, 1 );
		$count_file->open_and_lock( 1 ) or return( 0 );
		$count_file->read_all_records();

		foreach my $key (@keys_to_inc) {
			$key eq '' and $key = '__nil__';
			$count_file->key_increment( $key );
		}

		$count_file->write_all_records();
		$count_file->unlock_and_close();
	}
	
	sub mail_me_and_reset_counts_if_new_day {
		my ($self, $file_path) = @_;
	
		my $dcm_file = CGI::EventCountFile->new( $file_path, 1 );
		$dcm_file->open_and_lock( 1 ) or do {
			print "<!-- ".$dcm_file->is_error()." -->\n";
			return( undef );
		};
		$dcm_file->read_all_records();
		if( $dcm_file->key_was_incremented_today( '__total__' ) ) {
			$dcm_file->unlock_and_close();
			return( 1 );
		}
		$dcm_file->key_increment( '__total__' );
		$dcm_file->set_all_day_counts_to_zero();
		$dcm_file->write_all_records();
		$dcm_file->unlock_and_close();
		
		my @mail_body = ();
		push( @mail_body, "\n\ncontent of '$file_path':\n\n" );
		push( @mail_body, $dcm_file->get_sorted_file_content() );
		
		open(MAIL, "|/usr/lib/sendmail -t") or do {
			print "<!-- sendmail can't send daily usage info -->\n";
			return( undef );
		};
		print MAIL "To: site_owner\@their_host\n";
		print MAIL "From: spying anonymous <spy\@anonymous>\n";
		print MAIL "Subject: daily hit count update\n\n";
		print MAIL "@mail_body\n\n";
		close (MAIL);
	}

DESCRIPTION

This Perl 5 object class provides an easy-to-use interface for a plain text file
format that is capable of storing an unordered list of events.  Each event is
identified by a string and has 4 attributes: date of first and last occurances,
count of all occurances between first and last, count of only today's occurances.

A common use for this class is to track web site usage.  Usage events that can be
counted include: which site pages were viewed, which external urls we redirect
visitors to, which external urls have a link to us (that were used), which
internal site pages had links that were clicked on to go to other pages, which
web browsers the visitors are using, where the visitors are from, and
miscellaneous environment details like GET vs POST vs HEAD requests.  However,
events can be anything at all that we want to keep counts of.

This class is designed to facilitate ease of compiling and sorting count
information for being e-mailed to the site owner once per day for backup/report
purposes.

All event names have control characters (ascii 0 thru 31) removed prior to
storage, so they don't interfere with file parsing; no escaping is done to
preserve binary values as it is assumed they won't be used.  Event names can be
any length.

Dates are all stored in ISO 8601 format ("1994-02-03 14:15:29") with precision to
the second, and dates are all in Universal Coordinated Time (UTC), aka Greenwich
Mean Time (GMT).  It is assumed that any dates provided using key_store are in
UTC and formatted as ISO 8601 (six numbers in descending order of importance). 
That format allows for dates to be easily string-sorted without parsing.  If you
want to display in another time zone, you must do the conversion externally.

FILE FORMAT EXAMPLE

	/guestbook	2000-05-16 12:31:41 UTC	2000-05-30 11:36:55 UTC	16	0
	/guestbook/sign	2000-05-16 20:37:25 UTC	2000-05-30 11:36:32 UTC	7	0
	/links	2000-05-16 14:18:48 UTC	2000-05-30 18:02:12 UTC	14	0
	/mailme	2000-05-16 14:17:57 UTC	2000-05-30 16:54:39 UTC	17	0
	/myperl	2000-05-16 09:16:22 UTC	2000-05-31 17:54:12 UTC	103	3
	/myperl/base/1	2000-05-29 08:07:51 UTC	2000-05-29 08:07:51 UTC	1	0
	/myperl/eventcountfile/1	2000-05-29 23:54:38 UTC	2000-05-29 23:54:38 UTC	1	0
	/myperl/guestbook/1	2000-05-17 13:17:59 UTC	2000-05-29 08:40:39 UTC	3	0
	/myperl/hashofarrays/1	2000-05-16 11:35:40 UTC	2000-05-30 20:58:32 UTC	6	0
	/myperl/htmlformmaker/1	2000-05-17 06:41:04 UTC	2000-05-17 06:49:05 UTC	2	0
	/myperl/htmltagmaker/1	2000-05-16 18:18:54 UTC	2000-05-31 17:05:23 UTC	4	1
	/myperl/mailme/1	2000-05-16 11:36:08 UTC	2000-05-29 08:35:09 UTC	2	0
	/myperl/methodparamparser/1	2000-05-16 15:31:58 UTC	2000-05-18 04:47:10 UTC	2	0
	/myperl/segtextdoc/1	2000-05-18 03:11:53 UTC	2000-05-18 03:11:53 UTC	1	0
	/myperl/sequentialfile/1	2000-05-16 15:30:54 UTC	2000-05-29 08:08:29 UTC	3	0
	/myperl/static/1	2000-05-16 12:31:07 UTC	2000-05-16 15:47:29 UTC	2	0
	/myperl/webpagecontent/1	2000-05-29 22:48:30 UTC	2000-05-30 11:11:16 UTC	2	0
	/myperl/websiteglobals/1	2000-05-16 15:33:02 UTC	2000-05-29 18:57:29 UTC	5	0
	/myperl/websitemanager/1	2000-05-16 17:37:05 UTC	2000-05-29 22:46:04 UTC	7	0
	/mysites	2000-05-15 22:58:30 UTC	2000-05-31 01:40:52 UTC	78	1
	/resume	2000-05-15 23:26:23 UTC	2000-05-30 16:52:11 UTC	57	0
	__nil__	2000-05-15 07:57:37 UTC	2000-05-31 17:59:02 UTC	201	5
	__total__	2000-05-15 07:57:37 UTC	2000-05-31 17:59:02 UTC	720	11
	external	2000-05-15 22:59:16 UTC	2000-05-31 01:41:03 UTC	186	1

For a complete description, please refer to the POD that is contained in the
module itself.

KEEPING UP TO DATE

These modules are constantly under development.  You should be able to find the
newest versions at my website, "http://www.DarrenDuncan.net", on the page called
"Perl Libraries I Made" (name subject to change).  They can also be found on CPAN
under the author name of "DUNCAND".

I am inclined to update the copies on my web site more often, but those
intermediate versions are more likely to have been tested less, and the modules
may be updated day by day without increasing the version numbers.  However, the
copies on CPAN are guaranteed to have unique version numbers when the module has
changed.

REQUIREMENTS

This module requires Perl 5.004 or newer due partly to bug fixes implemented
there with regards to file management (eg: flush before unlock).  This module
also requires the standard Fcntl module to provide it with some constant values.

INSTALLATION

I haven't gotten around to doing makefiles, so you will have to install this the
old fashioned way, by copying.  The file "EventCountFile.pm" goes inside the
"CGI" folder which is in the "lib" folder that came with your Perl 5
distribution.  Or alternately, put it anywhere you want, but you will need to
have that location added to your include path by your main program using
something like this:

use lib '/users/me/www_files/lib';

Any existing POD is embedded in the module itself, so you will have to look there
to see it, or run a POD extractor on it yourself, or look at the copy on CPAN
that is dutifully extracted and turned to HTML.

SUPPORT

Currently I don't have any support arranged with other people, lists, newsgroups,
or otherwise.  Feel free to ask me if you can't figure things out on your own, or
another person whom you know has used this.

AUTHOR

Copyright (c) 1999-2000, Darren R. Duncan. All rights reserved. These modules are
free software; you can redistribute them and/or modify them under the same terms
as Perl itself.  However, I do request that their copyright information remains
attached to the files.  If you modify this module and redistribute a changed
version then please attach a note listing the modifications.

I am always interested in knowing how my work helps others, so if you put this
module to use in any of your own code then please send me the URL.  Also, if you
make modifications to the module because it doesn't work the way you need, please
send me a copy so that I can roll desirable changes into the main release.

Address comments, suggestions, and bug reports to perl@DarrenDuncan.net.

Share and Enjoy!
