#!/usr/local/bin/perl
####################################################################
# 程式名稱:RS-Counter 1.10
# 網頁瀏覽次數記錄器 - 不同的網頁可單獨或共同記錄在一個檔內
# 初始設計:1998/12/06 (ver 1.00)
# 最後修改:1999/12/05 (ver 1.10)
# 作 者:傅鴻銘
# 信 箱:redsnow@pemail.net
# 網 頁:http://tacocity.com.tw/redsnow/index.htm
#
# 作者宣告:
# 1.本程式圖形產生與輸出部分參考自 Kevin Meltzer 先生所設計製作之
# img_counter.pl 程式,該作者與程式的相關資料為:
# 最後修改:1 January 1999
# 程式網頁:http://www.perlguy.com/perl/img_cnt.htm
# 聯絡信箱:kmeltz@cris.com
# 2.本程式免費提供給有需要的個人所使用,您可以修改程式碼以便符合您
# 的需求,但是請將本段表頭資料保留不動,表示對作者的尊重,至於您
# 自己的記載事項及其它說明請修改於本段資料之後。
######################################################################
# 1.10 版:1999/12/05
#
# 使用說明:
# 1.修改本程式第一行之 #!/usr/local/bin/perl 為您的網站所適用的設定。
# 2.修改本程式之 rec_file 及 log_file 兩個參數,使其指向您的網頁目錄。
# 3.將本程式及記錄檔(.cnt 及 .log)上傳至網站上。
# 4.更改 RSCounter.pl 屬性為 755。
# 5.更改記錄檔(.cnt 及 .log)屬性為 666 或 777。
# 6.在 HTML 檔欲讓使用者下載檔案之處填入以下敘述:
#
# PATH_TO_SCRIPT = 本 CGI 程式所放置的位置(HTTP 格式的路徑)。
# file: 欲使用之紀錄檔名稱,若 name 參數未予設定時,將不適用於多頁面的計數。
# name: 欲紀錄及計數的識別字樣:
# 1.不可使用中文及空白字元以及 (、)、&、=、+、# 數個符號
# 可用數字及英文字母與 -'":;/\<>~1+-*!?@,.|$%^`_ 符號混合使用的字樣
# 2.大小寫字元將視為不同的識別字樣
# 3.可直接以檔案名稱或是文字簡述為參數,例如:
# 檔案名稱 - index.htm
# 文字簡述 - HomePage
# 4.本參數若省略掉不設定,file 參數所設的紀錄檔將僅紀錄一個數字資料,
# 且每次存取都會重新改寫掉,因此僅適用於紀錄首頁等特定的單頁計數。
# log : 1 = 記錄網頁被載入時之日期時間及瀏覽者 IP 等資料,0 = 不記錄(內定值)
# len : 最小顯示位數(內定值為 5),若累計數字的位數超過本項所設,將會在左方補上 "0"
# high: 0 = 數字高度為 10 pixels,1 = 16 pixels
# (內定值為 1,字型與 10 pixels 同,但是在上下各加三個空行)
# inv : 1 = 黑底白字(內定值),0 = 白底黑字
# add : 1 = 累加數字(內定值),0 = 不累加
# ip : 1 = $wantlog 參數設為 1 時紀錄 IP 位址,0 = 不紀錄
# 範例:
# 若您是 TacoMax 的居民且帳號為 GUEST,並且欲紀錄首頁檔被載入次數,
# 則宣告看起來將如下所示:
#
# 將以上敘設定放到 index.htm 檔適當的位置就可以了。
####################################################################
my($realPath); # 擺放記錄下載次數的實體目錄
my($RecordFile); # 存取紀錄資料的檔案名稱
my($recFile); # 擺放記錄下載次數的檔案
my($logFile); # 擺放記錄下載次數及下載者資訊的檔案
$realPath = "/www/htdocs/sccid/group/NTUHakka/"; # TacoMax 居民適用本設定,其它網站請自行查明後修改之
$RecordFile = "RSCounter"; # 存取紀錄資料的檔案名稱
my($minLen) = 5; # 最小顯示位數,若紀錄數字的位數小於本項所設,將會在左方補上 "0"
my($isHigh) = 1; # 0 = 數字高度為 10 pixels,0 = 16 pixels(字型與 10 pixels 同,在上下各加三個空行)
my($isInverse) = 1; # 1 = 黑底白字,0 = 白底黑字
my($wantlog) = 0; # 1 = 記錄網頁被載入時之日期時間及瀏覽者 IP 等資料,0 = 不記錄
my($ip) = 1; # 1 = $wantlog 參數設為 1 時紀錄 IP 位址,0 = 不紀錄
my($addNumber) = 1; # 1 = 累加數字,0 = 不累加
&initialize;
&incrementCount;
&generateBitmap;
&writeBitmap;
exit(0);
#############################
sub writeBitmap {
print ("Content-type: image/x-xbitmap\n\n");
if($isHigh){
printf ("#define count_width %d\n#define count_height 16\n", $len*8);
}else{
printf ("#define count_width %d\n#define count_height 10\n", $len*8);
}
printf STDOUT "static char count_bits[] = {\n";
for($i = 0; $i < ($#bytes + 1); $i++){
print("0x$bytes[$i]");
if($i != $#bytes){
print(",");
if(($i+1) % $high == 0){
print("\n");
}
}
}
print("};\n");
}
sub generateBitmap {
@bytes = ();
$len = length($count) > $minLen ? length($count) : $minLen;
$formattedCount = sprintf("%0${len}d",$count);
if($isHigh){
for($i = 0; $i < $len*3; $i++){
if($isInverse){
push(@bytes,"ff"); # add three blank rows to each digit
}else{
push(@bytes,"00");
}
}
}
for($y=0; $y < 10; $y++){
for($x=0; $x < $len; $x++){
$digit = substr($formattedCount,$x,1);
if($isInverse){ # $inv = 1 for inverted text
$byte = substr(@invdigits[$digit],$y*3,2);
}else{
$byte = substr(@digits[$digit],$y*3,2);
}
push(@bytes,$byte);
}
}
if($isHigh){
for($i = 0; $i < $len*3; $i++){
if($isInverse){
push(@bytes,"ff"); # add three blank rows to each digit
}else{
push(@bytes,"00");
}
}
}
}
sub initialize {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
if ($buffer eq "") { $buffer = $ENV{'QUERY_STRING'}; }
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
$pair =~ tr/ //;
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
$data{lc($name)} = $value;
}
if($data{'name'} ne ""){
$PageName="$data{'name'}";
}
if($data{'file'} ne ""){ $RecordFile="$data{'file'}";}
if($data{'log'} ne ""){ $wantlog="$data{'log'}";}
if($data{'len'} ne ""){ $minLen="$data{'len'}";}
if($data{'high'} ne ""){ $isHigh="$data{'high'}";}
if($data{'inv'} ne ""){ $isInverse="$data{'inv'}";}
if($data{'add'} ne ""){ $addNumber="$data{'add'}";}
if($data{'ip'} ne ""){ $ip="$data{'ip'}";}
$recFile = "$realPath$RecordFile.cnt"; # 擺放記錄下載次數的檔案
$logFile = "$realPath$RecordFile.log"; # 擺放記錄下載次數及下載者資訊的檔案
if($isHigh){
$high = 16;
}else{
$high = 10;
}
@invdigits = ("c3 99 99 99 99 99 99 99 99 c3", # 0
"e7 e3 e7 e7 e7 e7 e7 e7 e7 c3", # 1
"c3 99 9f 9f cf e7 f3 f9 f9 81", # 2
"c3 99 9f 9f c7 9f 9f 9f 99 c3", # 3
"cf cf c7 c7 cb cb cd 81 cf 87", # 4
"81 f9 f9 f9 c1 9f 9f 9f 99 c3", # 5
"c7 f3 f9 f9 c1 99 99 99 99 c3", # 6
"81 99 9f 9f cf cf e7 e7 f3 f3", # 7
"c3 99 99 99 c3 99 99 99 99 c3", # 8
"c3 99 99 99 99 83 9f 9f cf e3"); # 9
@digits = ("3c 66 66 66 66 66 66 66 66 3c", # 0
"18 1c 18 18 18 18 18 18 18 3c", # 1
"3c 66 60 60 30 18 0c 06 06 7e", # 2
"3c 66 60 60 38 60 60 60 66 3c", # 3
"30 30 38 38 34 34 32 7e 30 78", # 4
"7e 06 06 06 3e 60 60 60 66 3c", # 5
"38 0c 06 06 3e 66 66 66 66 3c", # 6
"7e 66 60 60 30 30 18 18 0c 0c", # 7
"3c 66 66 66 3c 66 66 66 66 3c", # 8
"3c 66 66 66 66 7c 60 60 30 1c"); # 9
}
sub incrementCount{
$count = 0;
if($PageName ne ""){
if(-e $recFile) {
open(FILE,"$recFile") || die("無法開啟 $recFile 這個檔案,系統錯誤訊息為:$!\n");
}
@lines = ;
close(FILE);
$ok=0;
$PageName2 = quotemeta $PageName;
$lastno=@lines;
foreach($j = 0;$j <= @lines;$j++){
if($lines[$j] =~ m#(\d+) \:\: $PageName2\n#o && $ok==0){
splice(@lines, $j, 1);
$j -= 1;
$count = $1;
if($addNumber == 1){
$count++;
}
$ok=1;
}
}
if($count == 0){
$count = 1;
}
$lines[$lastno]=sprintf("% 6d :: %s\n", $count, $PageName);
open (FILE,">$recFile");
flock (FILE, 2);
print FILE @lines;
flock (FILE, 8);
close (FILE);
}else{
open(FILE,"$recFile");
flock (FILE, 1);
$count = ;
flock (FILE, 8);
close(FILE);
$count++;
open(FILE,">$recFile");
flock (FILE, 2);
print FILE "$count";
flock (FILE, 8);
close(FILE);
}
if($wantlog == 1){
# 本註解的下兩行為第一種取得指定地區時間的設定,要使用時下兩行行首不可有 # 字元,
# 並且要將第二種方式的敘述行行首加上 # 字元或刪除
# $ENV{TZ} = 'Asia/Taipei';
# ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
# 本註解的下一行為第二種取得指定地區時間的設定,要使用時下一行行首不可有 # 字元
# 並且要將第一種方式的敘述行行首加上 # 字元或刪除
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time+8*60*60);
$mon++;
$shortdate = sprintf("$year%02d%02d %02d:%02d", $mon, $mday, $hour, $min);
$mtime = (stat($logFile))[9];
$mtime = time unless ($mtime);
($fday,$fmon,$fyear) = (localtime($mtime))[3,4,5];
$fmon++;
$size = -s "$logFile";
# 每月備份才用本行 if ($size > 51200 && $mday == 1 && $fday > 1){
if($size > 51200 && $mday ne $fday){
$bakFile = sprintf("%2d%02d%02d", $fyear, $fmon, $fday);
$bakFile = "$realPath$RecordFile.$bakFile";
rename("$logFile","$bakFile");
}
open (LOG, ">>$logFile");
flock (LOG, 2);
if($PageName ne ""){
print LOG "$PageName-$count";
}else{
print LOG "$count-";
}
$site = $ENV{'REMOTE_HOST'};
if($site eq ""){
$site = $ENV{'REMOTE_ADDR'};
}
if($PageName ne ""){
if($ip == 1){
print LOG "-$site";
}
print LOG "\[$shortdate\]";
}else{
print LOG "\[$shortdate\]";
if($ip == 1){
print LOG " $site";
}
}
print LOG "\n";
flock (LOG, 8);
close (LOG);
}
}