#!/usr/bin/perl
#    ↑サーバーのperlまでのパス
#    動かなかったら #!/usr/local/bin/perlに変更してみたください

###############################################
#   CGI's  TextCounter                        #
#   E-Mail:info@cgis.biz                      #
#   HomePage:http://www.cgis.biz/             #
#   (C)CGI's 2009/2/27                        #
###############################################

# 利用方法は以下をご覧ください
# http://www.cgis.biz/scripts/text_counter/

# 開発時モジュール
#use strict;
#use CGI::Carp qw(fatalsToBrowser);
#use Data::Dumper;

my %config;

#------------------------------ ここから設定 ---------------------------------------------

# データファイルのパス
# count.cgiと異なるフォルダに設置するときは変更

$config{'file'} = "./count.dat";

# 表示
# 0 = total
# 1 = total & today
# 2 = total & today & yesterday

$config{'show'} = 2;

# 重複カウント回避時間
# cookieによる同一クライアントの重複カウント回避時間
# 単位は分 / (例) 60 を設定すると1時間重複カウントしない
# 設定時間内は重複カウントしない。
# 0 を設定すると常にカウントする。

$config{'limit'} = 0;

# カウンタテキストの色
# 上から、total/today/yesterday

$config{'color'}{'total'}     = '#666666';
$config{'color'}{'today'}     = '#ff6666';
$config{'color'}{'yesterday'} = '#6666ff';

#------------------------------ ここまで設定 ---------------------------------------------

# ファイル読込み
open(CNT,'+<'.$config{'file'}) or &printError('Error','データファイルが開けませんでした。');
flock(CNT,2);
my @counts=<CNT>;

# データ分割
my %datas = &divideData(@counts);

# カウントアップ
if(&cookieCheck($config{'limit'})) {
	%datas = &countUp(%datas);
	# ファイルへ書き込み
	truncate(CNT, 0);
	seek(CNT,0,0);
	print CNT &makeData(%datas);
}
close(CNT);

# 出力
print "Content-Type: text/html\n";
# cookie
print 'Set-cookie:_count='.time.'; expires='.&makeExpire(60*60*24*30)."\n\n";

print &putCounter(\%config,\%datas);

exit;

# ----------------------------------------------------------------#
# CGI内にHTMLを記述する場合は以下のHTML〜HTML間に記述してください #
# ----------------------------------------------------------------#

# HTMLヘッダ
#
#
sub htmlHeader {
    
    my $title = shift;
    
    my $html;

$html = <<"HTML";
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" />
<title>$title</title>
</head>
<body>
HTML

    return $html;
}

# HTMLフッタ
#
#
sub htmlFooter {
    
    my $html;
    
$html = <<"HTML";
</body>
</html>
HTML

    return $html;
}

# カウンタ出力
#
#
sub putCounter {
	
	my $config_ref = shift;
	my $datas_ref = shift;
	
	my %config = %{$config_ref};
	my %datas  = %{$datas_ref};
	
	my $html;
	
	my $link = 'http://www.cgis.biz/';
	
	$html .= &htmlHeader('カウンタ');
	
	# total
	$html .= '<a href="'.$link.'" style="color:'.$config{'color'}{'total'}.'">Total: '.sprintf("%05d",$datas{'total'}{'count'}).'</a><br />'."\n";
	
	# today
	if($config{'show'} > 0) {
		$html .= '<a href="'.$link.'" style="color:'.$config{'color'}{'today'}.'">Today: '.sprintf("%05d",$datas{'today'}{'count'}).'</a><br />'."\n";
	}
	
	# yesterday
	if($config{'show'} > 1) {
		$html .= '<a href="'.$link.'" style="color:'.$config{'color'}{'yesterday'}.'">Yesterday: '.sprintf("%05d",$datas{'yesterday'}{'count'}).'</a><br />'."\n";
	}
	
	$html .= &htmlFooter;
	
	return $html;
}

# expire作成
#
#
sub makeExpire {
	my $time = shift;
	my ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst) = gmtime(time + $time);
	my @wdays = ("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
	my @months = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
	
	my $expire = sprintf("%s\,%02d\-%s\-%04d %02d:%02d:%02d GMT", $wdays[$wday],$day,$months[$mon],$year+1900,$hour,$min,$sec);
	
	return $expire;
}

# 書き込み用データ作成
#
#
sub makeData {
	
	my %datas = @_;
	
	my $data;
	
	foreach my $key (keys %datas) {
		$data .= $key.','.$datas{$key}{'date'}.','.$datas{$key}{'count'}."\n";
	}
	
	return $data
}

# カウントアップ
#
#
sub countUp {
	
	my %datas = @_;
	
	# 日付取得
	my %date;
	$date{'today'} = &getDate(0);
	$date{'yesterday'} = &getDate(-60*60*24);
	
	# データ内の今日と実際の今日が違う場合
	if($datas{'today'}{'date'} ne $date{'today'}) {
		# データ内の今日のカウントを昨日のカウントに、今日のカウントを0にする
		$datas{'yesterday'}{'count'} = $datas{'today'}{'count'};
		$datas{'today'}{'count'} = 0;
		# 日付データも変更
		$datas{'yesterday'}{'date'} = $date{'yesterday'};
		$datas{'today'}{'date'} = $date{'today'};
	}
	
	# それぞれカウントアップ
	$datas{'today'}{'count'}++;
	$datas{'total'}{'count'}++;
	
	return %datas;
	
}

# cookieの判定
#
#
sub cookieCheck {
	
	my $limit = shift;
	
	my $cookie = $ENV{'HTTP_COOKIE'};
	
	my $re = 0;
	
	# 設定が0か、Cookieなしで常にカウント
	if($limit == 0 || $cookie eq '') {
		$re = 1;
	}
	else {
		my @cookies = split(/;/,$cookie);
		foreach my $c (@cookies) {
			my ($key,$value) = split(/=/,$c);
			$key = &trim($key);
			if($key eq '_count') {
				if(time - $value > $limit*60) {
					$re = 1;
				}
				last;
			}
		}
	}
	
	return $re;
}

# データ分割
#
#
sub divideData {
	
	my @data = @_;
	
	if(!scalar(@data)) {
		return 0;
	}
	
	my %datas;
	foreach my $line (@data) {
		
		
		chomp $line;
		my ($name, $date, $count) = split(/,/,$line);
		$datas{$name}{'date'} = $date;
		$datas{$name}{'count'} = $count;
	}
	
	return %datas;
}

# エラー表示
#
#
sub printError {
    #エラータイトル
    my $title = shift;
    #エラー内容
    my $comment = shift;
    
    #表示内容
    my $html;
    
    $html .= &htmlHeader($title);
    $html .= '<p style="color:#f33">'.$title.'</p>'."\n";
    $html .= '<p>'.$comment,'</p>'."\n";
    $html .= &htmlFooter;
    
    print "Content-Type: text/html\n\n";
    print $html;
}

# 日付取得
#
#
sub getDate {
    
    my $time_plus = int(shift);
    
    my ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdst) = localtime(time + $time_plus);
    
    return ($year+1900).(sprintf("%02d",($mon+1))).(sprintf("%02d",($day)));
}

# 前後のスペース等削除
#
#
sub trim {
	my $val = shift;
	$val =~ s/^\s*(.*?)\s*$/$1/;
	return $val;
}