#! /usr/bin/perl # ↑ 一行目は設置するサーバにあわせて書き替えます。 # ConterScript Model4 # 簡易ログ付きカウンタスクリプト # ---------------------------------------------------------- # LastUpdate [2000/09/01] # 今日/昨日のアクセスを表示できるタイプのアクセスカウンタ。 # また、日毎のアクセスをファイルに書き出すこともできます。 # ノーマルモードで表示するときだけ増加処理を行います。(今のところ) # 機能概要 # - 普通のカウンタ機能(TotalCount) # - 当日と前日のカウントを保持&表示(Today&Yesterday) # - 日毎のカウント数を別ファイルに書き出す(オプション) # - 現在のカウント数を一覧表示 # 注意事項/その他 # - データはModel3/隠しカウンタと互換性がありません。 # - 連絡先: nobu@pt.imaginet.ne.jp # - 配布元: http://www.imaginet.ne.jp/~nobu/ # ---------------------------------------------------------- # (C) 1997-2000 Nobutaka Makino. # -------------------------- # 初期化/設定部分 # コメントが多いと動作が遅くなるとかそんなここ無いのでよろしく。 # ---------------------------------------------------------------- # メインデータファイルの指定。カウントを保持するデータファイルを指 # 定します。このファイルはあらかじめ作成しておき、パーミッションを # [666]に指定して置いて下さい。 # # $DataFile = './count4.dat'; $DataFile = './cnt4.dat'; # ---------------------------------------------------------------- # gifcat.pl のパスを指定。このファイルからみた相対パスでも、絶対パ # スでもかまいません。普通のサーバなら変更しなくても動くでしょう。 # # $GifcatPL = './gifcat.pl'; $Gifcat = './gifcat.pl'; # ---------------------------------------------------------------- # ファイルロックを使うかどうか。ロック機構を利用してカウンタがリセッ # トされるのを防ぎます。 flock()関数が使えない場合は、この機能をオ # フにします。 # # $UseFileLock = 1; # ファイルロックを使う。 # $UseFileLock = 0; # ファイルロックを使わない。(リセットされる可能性有り) $UseFileLock = 1; #$UseFileLock = 0; # ---------------------------------------------------------------- # 指定時間内の重複アクセスを無視するかどうか。リロードやブラウザの # BACKボタン等で2回カウントするのを防ぎます。指定されていない場合 # 無視しません。 # # $UseCookLock = 0; # 無視しない(のべ表示数カウント?) # $UseCookLock = 1; # 無視する $UseCookLock = 0; # ---------------------------------------------------------------- # クッキーの有効期限の指定。どれだけの時間、重複アクセスを無視する # かどうかの設定。ここに指定した時間内は再度ページを表示してもカウ # ントされません。ただし、前の設定でこの機能を有効にしていないとき # は関係ありません。 # # $CookLimit = 60*60*2; # 2時間指定する場合。(60x60x2[秒] = 2時間 ) $CookLimit = 60*60*2; # ---------------------------------------------------------------- # クッキー名の先頭部分の設定。他にCookieを発行するCGIを使用してい # る場合に、重複するのを防止する為に使用。特に変更の必要なし。実際 # は指定文字列とカウンタ名を連結したものを使ってCookieを発行する。 # # $CookNameHead = 'CNT4_'; $CookNameHead = 'CNT4_'; # ---------------------------------------------------------------- # クッキーの値の設定。なるべくアルファベットと数字+[_]で指定。 # # $CookValue = 'freeze'; $CookValue = 'freeze'; # ---------------------------------------------------------------- # デフォルト画像フォルダの設定。画像フォルダを指定しないで呼び出し # たときに使う画像フォルダを設定します。 最後は'/'で終わること。 # フォルダのデリミタが[/]で無い場合も[/]を使って下さい。 # # $DEF_ImgDir = 'dir/' $DEF_ImgDir = 'small/'; # $DEF_ImgDir = 'abacus/'; # 点が増えてく # $DEF_ImgDir = 'bangko/'; # どっかの象形文字? # $DEF_ImgDir = 'links/'; # つながってるヤツ # $DEF_ImgDir = 'small/'; # めっちゃ小さい # $DEF_ImgDir = 'style_a/'; # 基本形みたいな # $DEF_ImgDir = 'neuland/'; # アレ # $DEF_ImgDir = 'middle/'; # 中位 # $DEF_ImgDir = 'middle_b/'; # ボールド # ---------------------------------------------------------------- # 画像フォルダの指定。オプション[type]で指定する文字列とその時に使 # う画像フォルダの対応表を作成します。 # # %ImgDir = ( # 'name', 'dir/', # 'name', 'dir/', # 'name', 'dir/', # ); %ImgDir = ( 'abacus', 'abacus/', # 点が増えてくやつ 'bangko', 'bangko/', # どっかの象形文字? 'links', 'links/', # つながってるヤツ 'small', 'small/', # めっちゃ小さい 'style_a', 'style_a/', # 基本形みたいな 'neuland', 'neuland/', # アレ 'middle', 'middle/', # 中位 'middle_b', 'middle_b/', # ボールド ); # ---------------------------------------------------------------- # デフォルトカウンタ幅の指定。 [width]オプションが無いときに何桁の # カウンタを表示するかを指定します。ただし、実際のカウントの桁がこ # れより大きい場合、そちらの桁数を採用します。 # # $DEF_Width = 4; # 4桁に設定 $DEF_Width = 5; # ---------------------------------------------------------------- # サーバとの時間差を調整。取得する時間をここに指定した値の分だけず # らします。海外サーバに設置していて、国内時間とあわせるために6時 # 間遅らせたい、なんて時は下のようになります。プラスの値で進ませる # ことも可能です。 # # $TimeDiff = -60*60*8; $TimeDiff = 0; # ---------------------------------------------------------------- # 表示データ切り替えキーの指定。[mode]オプションに指定して、表示デ # ータを昨日/今日のカウントに切り替える時の文字列を指定。 # 大文字小文字は区別しません。 # # $KEY_default = 'main'; # 普通のカウンタを表示するためのキー # $KEY_yeCount = 'prev'; # 昨日のカウントを表示するためのキー # $KEY_toCount = 'today'; # 今日のカウントを表示するためのキー $KEY_default = 'main'; $KEY_yeCount = 'prev'; $KEY_toCount = 'today'; # ---------------------------------------------------------------- # 初期化項目など。変更しないこと。 $ImgDir{_DEFAULT_} = $DEF_ImgDir; $DEF_Width = $DEF_Width || 1; 1; # ---------------------------------------------------------------- # 更新情報 # # build #006 : 記録する日付の形式を西暦4桁に変更 # build #005 : なんで2回もライブラリロードしてんねん。を修正。 # build #004 : 設定部分が2重になっていたのを修正。 # 以後こんな事が起きないように開発環境も更新。 # build #003 : エラー表示部のHTMLを変更。 # build #002 : ロック処理のファイルハンドルがおかしかったのを修正。 $Build = '#006'; # オプションの取得 &GetOption; &ChkOption; &ChkImgDir($Type); $Mode = '' if( $Mode ne $KEY_toCount && $Mode ne $KEY_yeCount ); # クッキーロック if(!$Mode && $UseCookLock ){ &ChkCook( $CookNameHead.$Name, $CookValue ); &SetCook( $CookNameHead.$Name, $CookValue, $CookLimit ) if(!$CookLock); } # データ取得 if(!$Mode && !$CookLock ){ &getValue($Name,'incr'); } else { &getValue($Name); } $Count = $YeCnt if( $Mode eq $KEY_yeCount ); $Count = $ToCnt if( $Mode eq $KEY_toCount ); $Count = $MainCnt if(!$Mode ); # 出力。 &putCounter( $Count,$Width,$Type); # putImg.pl #--------------- sub putCounter{ #--------------------- # カウンタ画像を出力 local($Count,$Width,$Type) = @_; local(@ImgPath,$Number); eval{ require $Gifcat; }; if( $@ ){ &Err("gifcat.plのロードに失敗しました($@)"); } $Width = length($Count) if( $Width < length($Count) ); $ImgDir = $ImgDir{$Type}; foreach(1..$Width){ $Number = substr( $Count, -$_, 1); $Number = '0' if(!$Number); unshift( @ImgPath, "$ImgDir$Number.gif"); } binmode(STDOUT); print "Content-type: image/gif\n"; print "Expires: 01/01/70 00:00:00 GMT\n\n"; print &gifcat'gifcat(@ImgPath); exit; } 1; # ioData.pl #--------------- sub getValue{ # --------------------------------- # わかりにくいですが、 # ToXxxxは当日のデータ関係 [To]day.. # YeXxxxは前日のデータ関係です [Ye]sterday # なるべく略語は使いたくないんですけどねえ・・。 # local($Date,$OldDate,$SaveFlag); local($Name,$Mode) = (@_); $ToDate = &getToDate; $YeDate = &getYeDate; open( FH, "+<$DataFile" ) || &Err("データファイルが開けません。($DataFile: $!)"); &Lock; @Data = ; for(@Data){ if( /^$Name\t/ ){ ($Name,$MainCnt,$ToCnt,$YeCnt,$OldDate) = split(/\t/,$_); $OldDate =~ s/\n$//; $_ = ''; last; } } if(!$MainCnt){ $MainCnt = 0; $SaveFlag = 1; $ToCnt = 0; $YeCnt = 0; $OldDate = $ToDate; } if( $OldDate != $ToDate && $OldDate == $YeDate ){ $YeCnt = $ToCnt; $ToCnt = 0; $SaveFlag = 1; } if( $OldDate != $ToDate && $OldDate != $YeDate ){ $YeCnt = 0; $ToCnt = 0; $SaveFlag = 1; } if( $Mode eq 'incr' ){ $MainCnt++; $ToCnt++; $SaveFlag = 1; } push( @Data, "$Name\t$MainCnt\t$ToCnt\t$YeCnt\t$ToDate\n"); if( $SaveFlag ){ seek(FH,0,0); truncate(FH,0); print FH @Data; close(FH); } } 1; # output.pl #--------------- sub Err{ &PutMsg('エラーが発生しました。', "・@_"); } sub PutMsg{ #--------------------- # エラー出力。 $Title= shift(@_); print "Content-type: text/html\n\n"; print "\n"; print " $Title \n\n"; print "
\n". "
AccessCounter4 $Build
\n". "(c) 1999 Nobutaka Makino.
"; print ""; exit; } 1; # dircheck.pl #--------------- sub ChkImgDir{ local($Type) = shift(@_); &Err("画像ディレクトリがありません。($ImgDir{$Type})") if( !-e $ImgDir{$Type} ); for( 0..9 ){ &Err("${_}.gifが見つかりません。($ImgDir{$Type}${_}.gif)") if( !-e "$ImgDir{$Type}"."${_}.gif" ); } } 1; # lock.pl #--------------- sub Lock{ #--------------------- # ロック処理。 return if(!$UseFileLock); eval{ flock(FH,2); }; &Err('ロックに失敗しました。この状況が続く場合は「$UseFileLock = 0;」を指定してください。'."( $@ )") if( $@ ); } 1; # cook.pl #--------------- sub SetCook{ #--------------------- # cokkieの出力 local( $Name,$Value,$Limit ) = @_; local($date); local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time + $Limit); $year = sprintf( "%04d", $year + 1900 ); # 2000年問題対応(2) $sec = sprintf( "%02d", $sec ); $min = sprintf( "%02d", $min ); $hour = sprintf( "%02d", $hour ); $mday = sprintf( "%02d", $mday ); $wday = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday') [$wday]; $mon = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')[$mon]; $date = "$wday, $mday\-$mon\-$year $hour:$min:$sec GMT"; print "Set-Cookie: $Name=$Value; expires=$date\n"; } sub ChkCook{ local($Cook); local($CookName,$CookValue) = @_; $Cook = $ENV{'HTTP_COOKIE'}; $Cook =~ s/; /;/g; @CookPart = split( /;/,$Cook ); for( @CookPart ){ if(/^$CookName=$CookValue$/){ $CookLock = 1; return 1; } } return 0; } 1; # decode.pl #--------------- sub GetOption{ #--------------------- # 引数取得 $buffer = $ENV{'QUERY_STRING'}; foreach( split(/&/,$buffer) ){ ($name,$value) = split(/=/); $name =~ tr/[A-Z]/[a-z]/; $value =~ s/\t/ /g; $OPT{$name} = $value; } $Name = $OPT{'name'} || 'default'; $Type = $OPT{'type'} || '_DEFAULT_'; $Mode = $OPT{'mode'} || $KEY_default; $Width = $OPT{'width'} || $DEF_Width; } sub ChkOption{ local($br) = '
'; local($ft) = ''; # &Err("typeの値が不正です ( type = $Type ) $br →数値以外のデータを含んでいませんか? $ft" ) if( $Type =~ /\D/ ); &Err("widthの値が不正です ( width = $Width ) $br →数値以外のデータを含んでいませんか? $ft" ) if( $Width =~ /\D/ ); &Err("nameの値が不正です ( name = $Name ) $br → (, ), [, ], |, ^, \\, \$ はカウンタ名に使えません。$ft") if( $Name =~ /[\(\)\[\]\|\^\\\$]/ ); &Err("nameの値が不正です ( name = $Name ) $br →このカウンタ名では正常にカウントアップできません。 $ft") if( $Name !~ /^$Name$/ ); &Err("対応する画像フォルダ(\$ImgDir{$Type})が設定されていません。" ) if(!$ImgDir{$Type} ); } 1; # getDate.pl #--------------- sub getDate{ local( $Diff ) = shift(@_); # 取得する日付の指定(今日/昨日) local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time + $TimeDiff + $Diff ); $year = sprintf( "%02d", $year + 1900 ); # 2000年問題対応(1) $mon = sprintf( "%02d", $mon+1 ); $mday = sprintf( "%02d", $mday ); return $year.$mon.$mday; } sub getToDate{ return &getDate( 0 ); } sub getYeDate{ return &getDate( -60*60*24 ); } 1;