#!/usr/bin/perl
#-------------------------------------------------------------------------------
# [タグの書き方の例]
#  総カウント数      <IMG src="パス/counter.cgi?total">
#  本日のカウント数  <IMG src="パス/counter.cgi?today">
#  昨日のカウント数  <IMG src="パス/counter.cgi?ysday">
#-------------------------------------------------------------------------------

#-------------------
# ▼ 設定 START
#-------------------

#画像連結ライブラリ取込み
require './gifcat.pl';

#データファイル
$data_file = './data.cgi';

#バックアップファイル
$backup_file = './data.back';

#トータルカウンターの画像ディレクトリ
$cntimg_total = './image/cnt_total';

#本日カウンターの画像ディレクトリ
$cntimg_day = './image/cnt_day';

#昨日カウンターの画像ディレクトリ
$cntimg_yes = './image/cnt_yes';

#ファイルロックの種類( 0=使用しない / 1=symlink関数使用 / 2=mkdir関数使用)
$lockkey = 2;

#ロックファイル名
$lockfile = './lock/wgcnt.lock';

#-------------------
# ▲ 設定 END
#-------------------


################################################################################
#
# - ご注意 -
# これより下はプログラムです。
# 改造はご自由にされてもかまいませんが、改造によって発生した不具合に関しては
# サポート外になりますので、あらかじめご了承下さい。
#
################################################################################


#-------------------------------------------------
# データファイルの読み込み
#-------------------------------------------------
sub data_read {
	if (!open(IN,"$data_file")) { &error; }
	$DATA = <IN>;
	close(IN);

	($sdate1,$sdate2,$ip1,$ip2,$pass,$totalcnt,$daycnt,$yescnt,$totaldigit,$daydigit,$yesdigit,$tcntplus,$dcntplus,$ipchk,$tclc,$tcrc,$cdc,$dclc,$dcrc,$cyc,$yclc,$ycrc,) = split(/\,/,$DATA);

	#データが壊れていた場合
	if( ($pass eq "") || ($totalcnt eq "") || ($daycnt eq "") || ($yescnt eq "") ){
		&backup_read;
	}
}


#-------------------------------------------------
# バックアップデータファイルの読み込み
#-------------------------------------------------
sub backup_read {
	if (!open(IN,"$backup_file")) { &error; }
	$DATA = <IN>;
	close(IN);

	($sdate1,$sdate2,$ip1,$ip2,$pass,$totalcnt,$daycnt,$yescnt,$totaldigit,$daydigit,$yesdigit,$tcntplus,$dcntplus,$ipchk,$tclc,$tcrc,$cdc,$dclc,$dcrc,$cyc,$yclc,$ycrc,) = split(/\,/,$DATA);

}


#-------------------------------------------------
# メイン
#-------------------------------------------------
$mode = $ENV{'QUERY_STRING'};
if( $mode ne "total" ){ sleep(1); }

#日時を取得
$ENV{'TZ'} = "JST-9";
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
@wday_array = ('日','月','火','水','木','金','土');
$update1 = sprintf("%04d年%02d月%02d日(%s) %02d時%02d分%02d秒",$year+1900,$mon+1,$mday,$wday_array[$wday],$hour,$min,$sec);


#ファイルロック開始
if( $lockkey ){ &lock; }

#データ読込
&data_read;

#二重カウントチェック
$tflg = 0;
$dflg = 0;
if( $ipchk eq '2' ){
	if( $mode eq "total" ){
		$tadd = $ENV{'REMOTE_ADDR'};
		if( $tadd eq $ip1 ){ $tflg = 1; }
	}
	if( $mode eq "today" ){
		$dadd = $ENV{'REMOTE_ADDR'};
		if( $dadd eq $ip2 ){ $dflg = 1; }
	}
}

#日付が変わった場合
if( $sdate2 ne $mday ){
	$yescnt = $daycnt;
	$daycnt = 0;
}

#トータルカウント処理
if( ($tflg ne '1') && ($mode eq "total") ){
	$totalcnt = $totalcnt + $tcntplus;
}else{
	if( $tadd eq "" ){ $tadd = $ip1; }
}

#本日/昨日カウント処理
if( ($dflg ne '1') && ($mode eq "today") ){
	$daycnt = $daycnt + $dcntplus;
	$yescnt = $yescnt;
}else{
	if( $dadd eq "" ){ $dadd = $ip2; }
}

$NEW_DATA = "$update1,$mday,$tadd,$dadd,$pass,$totalcnt,$daycnt,$yescnt,$totaldigit,$daydigit,$yesdigit,$tcntplus,$dcntplus,$ipchk,$tclc,$tcrc,$cdc,$dclc,$dcrc,$cyc,$yclc,$ycrc,";

#データ更新
if( !open(OUT,">$data_file") ){ &error; }
print OUT $NEW_DATA;
close (OUT);

#ファイルロック解除
if( $lockkey ){ &unlock; }


#-------------------------------------------------
# カウンタ出力処理
#-------------------------------------------------
#総カウント数
$cntstr1 = sprintf(sprintf("%%0%dld",$totaldigit),$totalcnt);
#本日カウント数
$cntstr2 = sprintf(sprintf("%%0%dld",$daydigit),$daycnt);
#昨日カウント数
$cntstr3 = sprintf(sprintf("%%0%dld",$yesdigit),$yescnt);

#トータルカウント処理
if( $mode eq "total" ){
printf("Content-type: image/gif\n");
printf("\n");
	for( $i=0 ; $i<length($cntstr1) ; $i++ ){
		$n = substr( $cntstr1,$i,1 );
		if( $tclc eq '1' ){	if( $i eq '0' ){ push(@files,"$cntimg_total/l.gif"); } }
		push(@files,"$cntimg_total/$n.gif");
		if( $tcrc eq '1' ){ if( $i eq ($totaldigit-1) ){ push(@files,"$cntimg_total/r.gif"); } }
	}
}

#本日カウント処理
if( $mode eq "today" ){
printf("Content-type: image/gif\n");
printf("\n");
	for( $i=0 ; $i<length($cntstr2) ; $i++ ){
		$n = substr( $cntstr2,$i,1 );
		if( $cdc eq '1' ){
			if( $tclc eq '1' ){	if( $i eq '0' ){ push(@files,"$cntimg_total/l.gif"); } }
		}else{
			if( $dclc eq '1' ){	if( $i eq '0' ){ push(@files,"$cntimg_day/l.gif"); } }
		}
		if( $cdc eq '1' ){ push(@files,"$cntimg_total/$n.gif"); }else{ push(@files,"$cntimg_day/$n.gif"); }
		if( $cdc eq '1' ){
			if( $tcrc eq '1' ){	if( $i eq ($daydigit-1) ){ push(@files,"$cntimg_total/r.gif"); } }
		}else{
			if( $dcrc eq '1' ){	if( $i eq ($daydigit-1) ){ push(@files,"$cntimg_day/r.gif"); } }
		}
	}
}

#昨日カウント処理
if( $mode eq "ysday" ){
printf("Content-type: image/gif\n");
printf("\n");
	for( $i=0 ; $i<length($cntstr3) ; $i++ ){
		$n = substr( $cntstr3,$i,1);
		if( $cyc eq '1' ){
			if( $tclc eq '1' ){	if( $i eq '0' ){ push(@files,"$cntimg_total/l.gif"); } }
		}else{
			if( $yclc eq '1' ){	if( $i eq '0' ){ push(@files,"$cntimg_yes/l.gif"); } }
		}
		if( $cyc eq '1' ){ push(@files,"$cntimg_total/$n.gif"); }else{ push(@files,"$cntimg_yes/$n.gif"); }
		if( $cyc eq '1' ){
			if( $tcrc eq '1' ){	if( $i eq ($yesdigit-1) ){ push(@files,"$cntimg_total/r.gif"); } }
		}else{
			if( $ycrc eq '1' ){	if( $i eq ($yesdigit-1) ){ push(@files,"$cntimg_yes/r.gif"); } }
		}
	}
}

#カウンタを出力
binmode(STDOUT);
print &gifcat'gifcat(@files);

#バックアップ作成
&backup;

#-------------------------------------------------
# バックアップ
#-------------------------------------------------
sub backup {
	#ファイルロック開始
	if( $lockkey ){ &lock; }

	#データ読込
	&data_read;

	if( ($pass ne "") && ($totalcnt ne "") && ($daycnt ne "") && ($yescnt ne "") ){
		#バックアップ作成
		if( !open(OUT,">$backup_file") ){ &error; }
		print OUT $DATA;
		close (OUT);
	}

	#ファイルロック解除
	if( $lockkey ){ &unlock; }
}


#-------------------------------------------------
# ファイルロック開始
#-------------------------------------------------
sub lock {
	#リトライ回数
	local($retry) = 5;

	#古いロックは削除する
	if( -e $lockfile ){
		local($mtime) = (stat($lockfile))[9];
		if ($mtime < time - 30) { &unlock; }
	}

	#symlink関数
	if( $lockkey == 1 ){
		while( !symlink(".", $lockfile) ){
			if (--$retry <= 0) { &error; }
			sleep(1);
		}

	#mkdir関数
	}elsif( $lockkey == 2) {
		while( !mkdir($lockfile, 0755) ){
			if( --$retry <= 0 ){ &error; }
			sleep(1);
		}
	}

	$lockflag = 1;
}


#-------------------------------------------------
#  ロック解除
#-------------------------------------------------
sub unlock {
	if( $lockkey == 1 ){
		unlink($lockfile);
	}elsif( $lockkey == 2 ){
		rmdir($lockfile);
	}

	$lockflag = 0;
}


#-------------------------------------------------
# エラー処理
#-------------------------------------------------
sub error {
	#ロック中であれば解除
	if( $lockflag ){ &unlock; }

	@err_gif = ('47','49','46','38','39','61','2d','00','0f','00','80','00','00','00','00','00','ff','ff','ff','2c', '00','00','00','00','2d','00','0f','00','00','02','49','8c','8f','a9','cb','ed','0f','a3','9c','34', '81','7b','03','ce','7a','23','7c','6c','00','c4','19','5c','76','8e','dd','ca','96','8c','9b','b6', '63','89','aa','ee','22','ca','3a','3d','db','6a','03','f3','74','40','ac','55','ee','11','dc','f9', '42','bd','22','f0','a7','34','2d','63','4e','9c','87','c7','93','fe','b2','95','ae','f7','0b','0e', '8b','c7','de','02','00','3b');

	print "Content-type: image/gif\n\n";
	foreach (@err_gif) {
		$data = pack('C*',hex($_));
		print $data;
	}
	exit;
}
