#!C:\Perl\bin\perl -w

## -------------------------------------------------------------------
## DREAM COUNTER v2.01
## (C)1997-2000 KENT-WEB.COM (00/02/05)
##   MAIL: webmaster@kent-web.com
##   WWW:  http://www.kent-web.com/
## 1. このスクリプトはフリーソフトです。このスクリプトを使用したいか
##    なる損害も作者はその責を負いません。
## 2. 設置に関する質問は直接メールではお受けできませんので「サポート
##    掲示板」へお願いいたします。
## -------------------------------------------------------------------
## [タグの書き方の例]
##	カウンタ <img src="count/dream.cgi?id=***"> (*** はログファイル名)
##	時刻表示 <img src="count/dream.cgi?mode=time">
##	カレンダ <img src="count/dream.cgi?mode=date">
##      ファイルの更新時間
##               <img src="count/dream.cgi?file=/home/〜/index.html">
##                [注意] --> /home/〜/index.htmlの部分はフルパスを指定
##
##      ＊応用例(id名を kent と仮定)＊
##        1.画像を変更するとき：(以下はgif2ディレクトリの画像指定例)
##          <img src="パス/dream.cgi?id=kent&gif=2">
##        2.数字をランダムに表示するとき：
##          <img src="パス/dream.cgi?mode=rand">
##        3.カウンタ桁数を７桁にするとき：
##          <img src="パス/dream.cgi?id=kent&fig=7">
##
## [ディレクトリ構成例 (かっこ内はパーミッション)]
##
##	public_html / index.html(ここにカウンタ等を表示)
##	    |
##	    +-- count [777] / dream.cgi [755]
##	         |            abc.dat   [666] .. ログファイル1
##	         |            def.dat   [666] .. ログファイル2
##	         |              :                    :
##	         |            xxx.dat   [666] .. ログファイルx
##	         |
##	         +-- gif1 / 0.gif .. 9.gif, a.gif, p.gif, c.gif, d.gif
##	         |
##	         +-- gif2 / 0.gif .. 9.gif, a.gif, p.gif, c.gif, d.gif
##	              :
## -------------------------------------------------------------------

#============#
#  設定項目  #
#============#

# 画像連結ライブラリ取込み
require './gifcat.pl';

# IPアドレスのチェック (0=no 1=yes)
#   → yesの場合当日中の連続したIPアドレスはカウントアップしない
$ip_chk = 1;

# ログの自動生成 (0=no 1=yes)
$id_creat = 0;

# ファイルロック形式 (0=no 1=symlink関数 2=open関数)
$lockkey = 2;

# ログを置くディレクトリ
$maindir = ".";

# 画像指定
sub gif_path {
$gif_path = "./gif$gif";	# gif画像のあるディレクトリのパス
$defo_dir = "./gif1";		# デフォルト（初期値）のディレクトリ
}

# 他サイトからアクセスを排除する場合 (http://から書く)
$base_url = ".";

# エラー画像のURL
$err_gif = "error.gif";

#============#
#  設定完了  #
#============#

# 他サイトからのアクセスを排除
$ref_url = $ENV{'HTTP_REFERER'};
$ref_url =~ s/\?(.|\n)*//ig;
$ref_url =~ s/\%7E/\~/ig;
if (($base_url ne ".") && ($ref_url !~ /$base_url/)) { &error; }

# 引数を取得・解釈
$buffer = $ENV{'QUERY_STRING'};
if ($buffer) {
	@pairs = split(/&/,$buffer);
	foreach $pair (@pairs) {
		($name, $value) = split(/=/, $pair);
		$value =~ tr/+/ /;
		$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
		$FORM{$name} = $value;
	}
	$mode = $FORM{'mode'};
	$gif  = $FORM{'gif'};
	$fig  = $FORM{'fig'};
	$id   = $FORM{'id'};

} else {
	# 引数がなければランダムモード
	$mode = 'rand';
}

## GIFディレクトリを定義
&gif_path;

# デフォルトディレクトリを定義
if ($gif eq "") { $gif_path = "$defo_dir"; }

## 時間処理
if ($mode eq "time") {
	# 時間を取得
	&get_time;

	# 24時間制の場合
	if ($FORM{'type'} == 24) {
		($t1,$t2) = split(//, $hour);
		($t3,$t4) = split(//, $min);

		@caras = ("$t1","$t2","c","$t3","$t4");
	}
	# 12時間制の場合
	else {
		if ($hour >= 12) {
			$hour = sprintf("%02d",$hour -12);
			$head = 'p';
		}
		else { $head = 'a'; }

		($t1,$t2) = split(//, $hour);
		($t3,$t4) = split(//, $min);

		@caras = ("$head","$t1","$t2","c","$t3","$t4");
	}
}
## カレンダ処理
elsif ($mode eq "date") {
	# 時間を取得
	&get_time;

	($dmy1,$dmy2,$d1,$d2) = split(//, $year);

	($d3,$d4) = split(//, $mon);
	($d5,$d6) = split(//, $mday);

	if ($FORM{'year'} eq '4') {
		@caras = ("$dmy1","$dmy2","$d1","$d2","d","$d3","$d4","d","$d5","$d6");
	}
	else {
		@caras = ("$d1","$d2","d","$d3","$d4","d","$d5","$d6");
	}
}

## 更新時間表示処理
elsif ($FORM{'file'}) {
	# ファイルがなければエラー
	unless (-e $FORM{'file'}) { &error; }

	# 更新日数を取得し、秒数化
	$fmt = -M $FORM{'file'};
	$fmt *= 24*60*60;

	# 更新時間を配列化
	&get_time($fmt);
	($y1,$y2,$y3,$y4) = split(//, $year);
	($mon1,$mon2) = split(//, $mon);
	($day1,$day2) = split(//, $mday);
	($hr1,$hr2)   = split(//, $hour);
	($min1,$min2) = split(//, $min);

	@caras = ("$y1","$y2","$y3","$y4","s","$mon1","$mon2","s",
			"$day1","$day2","d","$hr1","$hr2","c","$min1","$min2");
}

## カウンタ処理
if ($id ne "" && $mode ne "rand") {
	# ログを定義
	$logfile = "$maindir\/$id\.dat";

	# ログの存在をチェック
	unless(-e $logfile) {
		# ログ生成 [なし] ならプログラムを終了
		if ($id_creat == 0) { &error; }

		# ログ生成 [あり] ならログを生成
		else {
			open(OUT,">$logfile") || &error;
			print OUT "0";
			close(OUT);

			# パーミッションを 666 へ
			chmod (0666,"$logfile");
		}
	}

 	# ロックファイル名を定義
	$lockfile = "$maindir\/$id\.lock";

	# デフォルト桁数を定義
	if ($fig eq "") { $fig = 5; }

	# IPアドレスを取得
	$addr = $ENV{'REMOTE_ADDR'};

	# ロック開始
	if ($lockkey == 1) { &lock1; }
	elsif ($lockkey == 2) { &lock2; }

	# 記録ファイルから読み込み
	open(IN,"$logfile") || &error;
	$data = <IN>;
	close(IN);

	# 前バージョン変換処理
	if ($data =~ /<>/) { ($daykey,$data) = split(/<>/, $data); }

	# 記録ファイルを分解
	($count,$ip) = split(/:/, $data);

	# IPチェック
	$flag=0;
	if ($ip_chk && $addr eq "$ip") { $flag=1; }

	# ログ更新
	if (!$flag) {
		# カウントアップ
		$count++;

		# ファイルをフォーマット
		if ($ip_chk) { $data = "$count\:$addr"; }
		else { $data = "$count"; }

		# 記録ファイルを更新する
		open(OUT,">$logfile") || &error;
		print OUT $data;
		close(OUT);
	}

	# ロック解除
	if (-e $lockfile) { unlink($lockfile); }
}

## 乱数発生
if ($mode eq "rand") {
	srand;
	$count = rand;
	$count = int($count * 10000);

	# デフォルト桁数を定義
	if ($fig eq "") { $fig = 5; }
}

## GIF画像を出力
&count_view;
exit;

## GIF出力処理サブルーチン
sub count_view {
	# 時間表示およびカレンダ表示処理
	if ($mode eq "time" || $mode eq "date" || $FORM{'file'}) {
		printf("Content-type: image/gif\n\n");
		@files = ();
		foreach (0 .. $#caras) { push(@files, "$gif_path/$caras[$_].gif"); }
	}

	# カウンタ表示処理
	# --> とほほさん (http://www2e.biglobe.ne.jp/~s-hasei/) のwwwcountを
	#     参考にしました
	else {
		$count += 0;
		$cntstr = sprintf(sprintf("%%0%dld", $fig), $count);
		printf("Content-type: image/gif\n\n");
		@files = ();
		for ($i=0; $i<length($cntstr); $i++) {
			$n = substr($cntstr, $i, 1);
			push(@files, "$gif_path/$n.gif");
		}
	}

	# GIFを連結表示
	binmode(STDOUT);
	print &gifcat'gifcat(@files);
}

## ロックファイル（symlink関数）処理
sub lock1 {
	local($retry) = 5;
	while (!symlink(".", $lockfile)) {
		if (--$retry <= 0) { &error; }
		sleep(1);
	}
}

## ロックファイル（open関数）処理
sub lock2 {
	local($retry) = 0;
	foreach (1 .. 5) {
		if (-e $lockfile) { sleep(1); }
		else {
			open(LOCK,">$lockfile");
			close(LOCK);
			$retry = 1;
			last;
		}
	}
	if (!$retry) { &error; }
}

## 時間を取得
sub get_time {
	$ENV{'TZ'} = "JST-9";
	$times = time;

	if ($_[0]) { $times -= $_[0] }

	($sec,$min,$hour,$mday,$mon,$year,$d,$d) = localtime($times);
	$year += 1900;
	$mon++;

	if ($hour < 10) { $hour = "0$hour"; }
	if ($min  < 10) { $min  = "0$min";  }
	if ($mon  < 10) { $mon  = "0$mon";  }
	if ($mday < 10) { $mday = "0$mday"; }
}

## エラー処理
sub error {
	if (-e $lockfile) { unlink($lockfile); }

	# IISサーバ対応
	if ($ENV{PERLXS} eq "PerlIS") {
		print "HTTP/1.0 302 Temporary Redirection\r\n";
		print "Content-type: text/html\n";
	}

	print "Location: $err_gif" . "\n\n";
	exit;
}
