カウンター

DB_Fileを使うバージョン。XMLにした方が最近はいいかも。

my_flock()、my_funlock()は「Perlメモ」から拝借(MyLib.pmからexport)。

#!/usr/bin/perl

use strict;
use lib ('../cgi-bin/cgi-lib');
use CGI qw(-no_xhtml);
use CGI::Carp qw(fatalsToBrowser);

use DB_File;
use IO::File;
use File::Path;

use MyLib;

#use Data::Dumper;

my $lock = my_flock();

my $q = new CGI;
print $q->header( -type=> 'text/html', -charset=> 'shift_jis');
$q->autoEscape(0);

my $defaults  = {
 counter       => 'dat/count.db',
 access_log    => 'dat/access.db',
 expire        => 3600,
 number_figure => 7,
 element       => 'span',
 element_class => 'counter'
 };
 
make_files();

my %access_log;
my %counter;

tie %access_log, 'DB_File', $defaults->{access_log} or error('error while accessing %access_log');
tie %counter,    'DB_File', $defaults->{counter}    or error('error while accessing %counter');

$counter{count} ||= 0;


my $remote_addr = $ENV{'REMOTE_ADDR'};
my $access_time = time;

if (exists $access_log{$remote_addr}) {
 if ($access_log{$remote_addr} + $defaults->{expire} < $access_time) {
  $counter{count}++
  }
 }
else {
 $counter{count}++
 }
$access_log{$remote_addr} = $access_time;

my $format = '%0'.$defaults->{number_figure}.'d';
my $html_element = $defaults->{element};
my $element_class = $defaults->{element_class};
print $q->$html_element( { -class=> $element_class }, sprintf $format, $counter{count} );

clean_logs();

#print Dumper %access_log;

untie %access_log;
untie %counter;

sub error {
 my_funlock($lock);
 die(shift);
 }

sub make_files {
 mkpath './dat';
 my $fh;
 unless (-s $defaults->{counter}) {
  $fh = IO::File->new->open ('> ' . $defaults->{counter}) or error('error while creating counter file'); undef $fh;
  }
 unless (-s $defaults->{access_log}) {
  $fh = IO::File->new->open ('> ' . $defaults->{access_log}) or error('error while creating counter file'); undef $fh;
  }
 }
sub clean_logs {
 if (defined $access_log{clean}) {
  if ($access_log{clean} + $defaults->{expire} < $access_time) {
   for (keys %access_log) {
    next if $_ eq $remote_addr;
    delete $access_log{$_} if ($access_log{$_} + $defaults->{expire} < $access_time);
    }
   $access_log{clean} = $access_time;
   }
  }
 else {
  $access_log{clean} = $access_time;
  }
 }
  
my_funlock($lock)


Leave a Reply