#! /usr/bin/perl # # PNGカウンタ+ Ver 1.4 (2002/5/18) # (c) 2000-2002 桜月 # http://www.aurora.dti.ne.jp/~zom/Counter/ # #----------------------------------------------------------- # 設置者による設定。 $keta = 4; # カウンタの表示桁を設定します。 # 0以外を指定すると、指定された桁数になるよう0で埋めます。 $ketah = 4; # 今日/昨日一日のアクセス数を表示する際の表示桁設定。 # 0以外を指定すると、指定された桁数になるよう0で埋めます。 $logdir = 'logxxx'; # ログファイルの入っているサブディレクトリ名。 # (このスクリプトからの相対パス) # これを変更する場合、kaiseki.cgiの方にも同じ設定が # ありますので、そちらも変更してください。 $pgc = 'pngcntr';# 数字画像用PNGファイル名(拡張子はつけぬこと)。 $pngdir = '.'; # そのPNGの入っているサブディレクトリ名。 # (このスクリプトからの相対パス) $relup = 0; # 再読込に対してもカウントアップするなら1にする。 # 以下はログの保存に関する設定です。 $locktype = 1; # ロック法。0ならflock, 1ならrename. $jisa = 0; # 時差調節設定。 # 海外サーバに置く場合、(現地時間 - 日本時間)の # 分数(ふんすう)をここで指定する。 # (サマータイムは自動調整されます)。 $saidai = 300; # ログの最大保持数。 $hozon = 0; # ログのバックアップを取るための設定。 # たとえばここに50と指定すると、50件ごとに # "(ログファイル名).(カウント数)"という名前で # バックアップファイルを作るようになります。 # (定期的にサーバからログを回収するのをお忘れなく) # 設置者による設定箇所ここまで。 #----------------------------------------------------------- # グローバル。 $logFile = ''; # ログファイル。 $lockFile = ''; # ロック用ファイル。 %opts = (); # オプション。 @touka = (); # 透過。 $errorBangou = 0; # エラー番号。 @crcTable = (); # CRCテーブル。 $pngData = ''; # SI-PNGデータ。 $ch_data = ''; # チャンクデータ。 # メイン。 &CrcTable(); &Option(); &Suuji(); if(!$errorBangou){ &Tsunagu(); } if($errorBangou) { &Error($errorBangou); } exit($errorBangou); # チャンク出力ルーチン(FTRM)。 sub Pr_chunk(){ my($crc) = 0xffffffff; print pack('N', length($ch_data) - 4).$ch_data; foreach(unpack('C*', $ch_data)){ $crc = $crcTable[($crc ^ $_) & 0xff] ^ ($crc >> 8); } print pack('N', ~$crc); undef($ch_data); } # CRC用初期設定(FTRM)。 sub CrcTable(){ my($i, $j, $crc); for($i = 0; $i < 256; $i++){ $crc = $i; for($j = 0; $j < 8; $j++){ if($crc & 1){ $crc = 0xedb88320 ^ ($crc >> 1); } else{ $crc = $crc >> 1; } } $crcTable[$i] = $crc; } } # オプション取り出し(FTR)。 sub Option(){ my($env, $wake); ($logFile, $env) = split(/;/, $ENV{'QUERY_STRING'}, 2); foreach(split(/;/, $env)){ if(substr($_, 0, 1) eq 'T'){ push(@touka, split(/,/, substr($_, 1))); } else{ if($wake = index($_, '=') + 1){ $opts{substr($_, 0, $wake - 1)} = substr($_, $wake); } else{ $opts{$_} = 1; } } } $logFile = '' if(index($logFile, '/') + 1); } # カウントアップと数字の整形(FTM)。 sub Suuji(){ my($nagasa); unless($logFile){ $kazu = 1234567890; } else{ if(!&CountUp()){ $errorBangou = 1; return 0; } $kazu -= 0; } # 桁の調整。 $nagasa = length($kazu); $keta = $opts{'keta'} || $keta; if($keta){ if($keta < $nagasa){ $keta = $nagasa } # $kazu = sprintf("%0$keta"."s", $kazu); $kazu = substr(('0' x $keta).$kazu, -$keta); } else{ $keta = $nagasa; } return 1; } # PNG読みとり(FT)。 sub ReadSIPNG(){ $pgc = "./$pngdir/".($opts{'png'} || $pgc).'.png'; if(!open(IN, $pgc)){ $errorBangou = 2; return 0; } binmode(IN); seek(IN, 0, 0); read(IN, $pngData, -s $pgc); close(IN); if(substr($pngData, 0, 8) ne "\x89PNG\x0d\x0a\x1a\x0a"){ $errorBangou = 4; # PNGではない。 return 0; } elsif(substr($pngData, 0x18, 5) ne "\x08\x03\0\0\0"){ $errorBangou = 4; } elsif(substr($pngData, 0x25, 3) ne 'pgC'){ $errorBangou = 4; } elsif(substr($pngData, 0x28, 1) ne 'I'){ $errorBangou = 5; } else{ return 1; } return 0; } # PNG出力(FT)。 sub Tsunagu(){ my($pgcHdr) = 0x29; my($x_kei, $y_kei, $nagasa); my($pltehjmr, $pltengsa, $trnshjmr, $trnsngsa); local($idatData); if(!&ReadSIPNG()){ return 0; } $idatData = ''; ($x_kei, $y_kei) = &Renketsu(*idatData, $pgcHdr); if($x_kei == -1){ $errorBangou = 6; return 0; } # ここから後は、Error()に処理を渡してはならん。 &MIMEtoHeader(); $ch_data = 'IHDR'.pack('N2', $x_kei, $y_kei)."\x08\x03\0\0\0"; &Pr_chunk(); # PLTE. ($pltehjmr, $pltengsa, $trnshjmr, $trnsngsa) = unpack('V4', substr($pngData, $pgcHdr, 16)); print substr($pngData, $pltehjmr - 8, $pltengsa + 12); # tRNS. if($#touka < 0){ if($trnsngsa){ print substr($pngData, $trnshjmr - 8, $trnsngsa + 12); } } # &Tオプションによる透過機能が不要なら以下19行(*1まで)は不要。 else{ my($pal, $atai); $ch_data = "\xff" x 0x100; substr($ch_data, 0, $trnsngsa) = substr($pngData, $trnshjmr, $trnsngsa); $trnsngsa--; foreach(@touka){ ($pal, $atai) = split(/=/, $_, 2); $pal &= 255; substr($ch_data, $pal, 1) = pack('C', $atai & 255); if($trnsngsa < $pal){ $trnsngsa = $pal; } } $pltengsa /= 3; if(++$trnsngsa > $pltengsa){ $trnsngsa = $pltengsa; } $ch_data = 'tRNS'.substr($ch_data, 0, $trnsngsa); &Pr_chunk(); } # *1 # IDAT. # 無圧縮zlib化。 $s1 = 1; $s2 = 0; foreach(unpack('C*', $idatData)){ $s1 += $_; if($s1 > 65520){$s1 -= 65521; } $s2 += $s1; if($s2 > 65520){$s2 -= 65521; } } $nagasa = length($idatData); # $len=pack('S', $nagasa); どうやらNifはSが使えんらしい。 # $len=pack('C2', $nagasa & 255, $nagasa >> 8); もし下のvも駄目ならこれで。 $len=pack('v', $nagasa); $ch_data = "IDATx\x01\x01".$len.~$len.$idatData.pack('n2', $s2, $s1); &Pr_chunk(); # IEND. print "\0\0\0\0IEND\xaeB`\x82"; # ここまで。 return 1; } # 連結(FT)。 sub Renketsu(){ local(*idatData, $pgcHdr) = @_; my($x_kei, $y_kei, $x_saidai, $i, $j, $suuji); my($x, $y, $menseki, $ichi, $yomiIchi, $kakiIchi); my($pngHaba, $pgcIchi); my(@ichi, @x, @y) = ((), (), ()); $pngHaba = unpack('N', substr($pngData, 0x10, 4)) + 1; $pgcIchi = unpack('V', substr($pngData, $pgcHdr + 16, 4)); $x_saidai = $x_kei = $y_kei = 0; for($i = 0; $i < $keta; $i++){ $suuji = substr($kazu, $i, 1); unless($x[$suuji]){ ($ichi[$suuji], $x, $y) = unpack('vCC', substr($pngData, $pgcHdr + 20 + ($suuji << 2), 4)); $x[$suuji] = $x; $y[$suuji] = $y; $x_saidai = $x if($x_saidai < $x); } $x_kei += $x[$suuji]; $y_kei += $y[$suuji]; } if($opts{'tate'}){ $x_kei = $x_saidai; $menseki = $x_kei * $y_kei; return (-1, -1) if($menseki >> 15); $idatData = "\0" x $menseki; $kakiIchi = 1; for($i = 0; $i < $keta; $i++){ $suuji = substr($kazu, $i, 1); $yomiIchi = $pgcIchi + $ichi[$suuji]; $x = $x[$suuji]; for($j = $y[$suuji]; $j > 0; $j--){ substr($idatData, $kakiIchi, $x) = substr($pngData, $yomiIchi, $x); $kakiIchi += $x_kei; $yomiIchi += $pngHaba; } } } else{ $x_kei++; $y_kei = unpack('N', substr($pngData, 0x14, 4)); $menseki = $x_kei * $y_kei; return (-1, -1) if($menseki >> 15); $idatData = "\0" x $menseki; $ichi = 1; for($i = 0; $i < $keta; $i++){ $suuji = substr($kazu, $i, 1); $yomiIchi = $pgcIchi + $ichi[$suuji]; $kakiIchi = $ichi; $x = $x[$suuji]; for($j = $y[$suuji]; $j > 0; $j--){ substr($idatData, $kakiIchi, $x) = substr($pngData, $yomiIchi, $x); $kakiIchi += $x_kei; $yomiIchi += $pngHaba; } $ichi += $x; } } $x_kei--; return ($x_kei, $y_kei); } # 戻り値はBOOL. sub RenLock(){ $lockFile = "$logFile.lock"; for(0 .. 9){ if(rename($logFile, $lockFile)){ # ロック成功。 utime(time, time, $lockFile); return 1; } sleep(1); } if(time - (stat($lockFile))[9] > 300){ # 5分以上前のものなら遺物と見なし、 utime(time, time, $lockFile); # そのまま横取り。 return 1; } return 0; } sub UnRenLock(){ rename($lockFile, $logFile); } sub LocktoOpen(){ $lockFile = $logFile = "./$logdir/$logFile"; # ニフのftp1のflockは使えん。 if(index($ENV{'SERVER_NAME'}, 'nifty') + 1){ $locktype = 1; } if($locktype == 1){ unless(&RenLock()){ # rename lock失敗。 $opts{'mirudake'} = 1; $locktype = -1; # 後で解除させんため。 } } # 無ければ作っておく #if(!-e $logFile){ # open(LOG, ">$logFile"); # close(LOG); #} # ダメっぽいのでなしに unless(open(LOG, "+<$lockFile")){ if($locktype == 1){ &UnRenLock(); } return 0; } if($locktype == 0){ eval{ flock(LOG, 2); }; } return 1; } sub UnlocktoClose(){ close(LOG); if($locktype == 1){ &UnRenLock(); } } # カウントアップ(T)。 sub CountUp(){ my(@log, $hi, $wake, $ima, $mae, $maeLog, $sute); if(!&LocktoOpen()){ return 0; } @log = ; $ima = time - $jisa * 60; if((localtime(time))[8]){ $ima -= 3600; } # 日ごとのアクセスを数える。 if($hi = $opts{'hi'}){ my($mday, $mon, $year, $ngsa); ($sute, $sute, $sute, $mday, $mon, $year, $sute, $sute, $sute) = localtime($ima - (($hi - 1) * 86400)); $mon++; $year += 1900; $hi = "$year-$mon-$mday-"; # '-'までを含めることにより、 # 1?日が1日として数えられるのを防ぐ。 $kazu = 0; $ngsa = length($hi); foreach(@log){ if($wake = index($_, "\t") + 1){ if(substr($_, $wake, $ngsa) eq $hi){ $kazu++; } elsif($kazu){ last; } } } $keta = $ketah; } else{ $sute = $log[0]; chomp($sute); ($kazu, $mae, $sute, $sute, $maeLog) = split(/\t/, $sute); &Host(); # $host, $addr, $fwrd, $clnt, $afc, $hostT if(($relup || ($mae ne $afc)) && (!$opts{'mirudake'})){ my($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst); if($hozon){ # 0除算せんために絶対必要。 unless($kazu % $hozon){ open(BACKUP, ">$logFile.$kazu"); eval { flock(BACKUP, 2); }; # 念のため。 select(BACKUP); $| = 1; print BACKUP @log; close(BACKUP); $maeLog = $kazu; } } $maeLog -= 0; $kazu++; &UserAgent(); # $ua, $browser, $os splice(@log, $saidai); # この行を消すと際限なくログを取り続ける。 ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($ima); $mon++; $year += 1900; $jikoku = "$year-$mon-$mday-$wday-$hour-$min-$sec"; $logstr = "$kazu\t$jikoku\t$hostT\t$browser\t$os\t$opts{'ref'}"; $log[0] = "$kazu\t$afc\t$jikoku\t$jisa\t$maeLog\t\n" . $logstr . "\n"; select(LOG); $| = 1; truncate(LOG, 0); seek(LOG, 0, 0); print LOG @log; select(STDOUT); # add by K.S. # host の出力 $ref = $opts{'ref'}; # referer 解析 my @path = split('/',$logFile); open( HOSTLOG,">>./$logdir/detail." . $path[-1]); print HOSTLOG $logstr . "\t$host\t$addr\n"; close(HOSTLOG); } } &UnlocktoClose(); return 1; } # ホスト名の取得 ($host, $addr, $fwrd, $clnt, $afc, $hostT)。 sub Host(){ my($d1, $d2, $d3); $host = $ENV{'REMOTE_HOST'}; $addr = $ENV{'REMOTE_ADDR'}; $fwrd = $ENV{'HTTP_X_FORWARDED_FOR'}; $clnt = $ENV{'HTTP_CLIENT_IP'}; $afc = "$addr/$fwrd/$clnt"; # ホスト名の取得(Niftyではこの機能せず)。 if((!$host) || ($host eq $addr)){ $host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2); } # ここまで。 if($host){ $d1 = rindex($host, '.', length($host)) + 1; if($d1){ $d2 = rindex($host, '.', $d1 - 2) + 1; if($d2){ $d3 = rindex($host, '.', $d2 - 2) + 1; if($d3){ # ドメインは4ブロック以上。 $hostT = '*.'.substr($host, $d3); } else{ # ドメインは3ブロック。 $hostT = '*.'.substr($host, $d2); } } # 2ブロック以下ならホスト名じゃないと見なす。 else{ $hostT = $host; } } else{ $hostT = $host; } } else{ $hostT = '-'; } } # ブラウザ/OSの取得 ($ua, $browser, $os)。 sub UserAgent(){ my($wake, $kugri); $ua = $ENV{'HTTP_USER_AGENT'}; if($ua =~ /[<\x80-\xff]/){ # 改変されているとおぼしいものは蹴る。 $browser = $os = '?'; return; } if($ua eq 'Mozilla/3.01 (compatible;)'){ $browser = $os = 'CacheFlow'; return; } $os = ''; if(rindex($ua, 'Gecko') + 1){ # Mozilla or Galeon. if($ua =~ /(.+?) \(.*?; .*?; (.*?); .*?; (.*?)\)/o){ # Mozilla. $browser = $1.' Gecko '.$3; $os = $2; } elsif(($ua =~ /(.+?) \(.*?; (.*?); .*?;\)/o) || ($ua =~ /(.+?) \((.*?); .*?;\)/o)){ # Galeon. $browser = $1.' Gecko'; $os = $2; } # Mozilla/Galeonはこれで確定。 } else{ if($ua =~ /\(compatible; (.*?);/o){ # MSIEやiCab. $browser = $1; } elsif($ua =~ /\(compatible; (.*?)\)/o){ $browser = $1; $os = '-'; return; } else{ # Netscape等。 if($ua =~ /(.+?) *?\(/o){ $browser = $1; } else{ $browser = $ua; $os = '-'; return; } } } # Opera対応(不要なら下二行削除)。 $wake = rindex($ua, ' Opera'); if($wake + 1){ $browser .= substr($ua, $wake); } # OSの取得。 if(index($ua, 'Win 9x 4.90') + 1){ # Win ME対策。 $os = 'Windows ME'; return; } unless($os){ # Mozilla以外。 $wake = index($ua, '(') + 1; $kugri = rindex($ua, ')'); $os = substr($ua, $wake, $kugri - $wake).';'; if ($os =~ /(Win.*?);/o) { $os = $1; } elsif($os =~ /X11; .; (.*?);/o) { $os = $1; } elsif($os =~ /Macintosh; .; (.*?);/o){ $os = 'Mac_'.$1; } else{ $os =~ s/compatible; (.*?); //o; $os =~ s/AOL(.*?); //go; $os = substr($os, 0, index($os, ';')); } } # 揃え。 if($os =~ /WinNT *(.*)/o){ if($1){ $os = 'Windows NT '.$1; } else { $os = 'Windows NT'; } } elsif($os =~ /Win(9.*)/o){ $os = 'Windows '.$1; } # PPCはブラウザによって表記がバラバラ。 elsif(index($os, 'PPC') + 1){ $os = 'Mac_PowerPC'; } } # PNGヘッダ出力(FTR)。 sub MIMEtoHeader(){ binmode(STDOUT); $| = 1; print "Content-Type: image/png\n\n"; print "\x89PNG\x0d\x0a\x1a\x0a"; } # エラー処理(FTR)。 sub Error(){ my($err) = $_[0]; if ($err == 1){$rgb = "\0\0\xff"; } # 青(指定されたログがない) elsif($err == 2){$rgb = "\0\xff\xff"; } # 水色(指定されたPNGがない) elsif($err == 3){$rgb = "\0\xff\0"; } # 緑(PNGではない) elsif($err == 4){$rgb = "\xff\0\0"; } # 赤(使えぬPNG) elsif($err == 5){$rgb = "\xff\0\xff"; } # 紫(このカウンタ用ではない) elsif($err == 6){$rgb = "\xff\xff\0"; } # 黄色(データ大きすぎ) else {$rgb = "\xff\xff\xff"; } # 白(未定義なエラー) &MIMEtoHeader(); print "\0\0\0\x0dIHDR\0\0\0 \0\0\0 \x01\x03\0\0\0I\xb4\xe8\xb7"; $ch_data = "PLTE\0\0\0$rgb"; &Pr_chunk(); print "\0\0\0)IDATx\xdac\xf8\x0f\x04\x0c\x0d"; print "\x0c\x0c\x8c\xe8D\xfb\xff\xff\x0f\xd1\x89\x06\xe6\x03\x8c\x94"; print "\x13\xf3\xff\xff\xff\x89N`s\x01\xc8i\0\xeb[9"; print "\xa9\xb9\xc5K\xc5\0\0\0\0IEND\xaeB`\x82"; } # # PNGカウンタ多機能版 改訂履歴 # # Ver.0.1(2000/2/24) # # Ver.0.5(2000/9/3) # 従来版から分離。 # 今日と昨日のカウント数を表示できるようにする。 # アクセス解析機能用のログを取るようにする。 # # Ver.0.51(2000/9/4) # アクセスログのフォーマットを若干変更。 # ブラウザ識別ルーチンの改善。 # 他にも細々とした改良。 # # Ver.0.6(2000/9/5) # 透過機能の強化。 # (1) 複数の色を透過できるようにする。 # (2) 各色ごとに透過率を決められるようにする。 # # Ver.0.7(2000/9/10) # 一度読んだpgcはキャッシュしておくようにする。 # Ver.0.5以降、複雑化したオプションの指定方法を改良。 # 忘れられがちなerror.pgcを内蔵してしまう。 # pgcのあるディレクトリをオプションで指定できるようにする。 # ->複数のpgcが使い分けられるように(指定せねば従来通り)。 # ついでにログファイルのディレクトリもオプションで # 指定できるようにする。 # # Ver.0.71(2000/9/13) # ログファイルを指定する振りをして、カレントディレクトリの # ファイルを破壊できてしまうという凶悪な欠陥の修正。 # 同様の理由からlogdirオプションを廃止する。 # # Ver.0.72(2000/9/17) # 通常のカウント表示と一日のアクセス数表示とで、 # 表示桁をそれぞれ別々に設定できるようにする。 # # Ver.0.73(2000/10/1) # 外部呼び出し防止機能を削除。 # # Ver.0.74(2000/10/7) # 一部の特殊なブラウザにおいて、ブラウザ名の後ろに # ")"が残ってしまうことがあったのを修正。 # # Ver.1.0(2000/10/8) # 大幅な仕様変更。 # pgcの使用をやめ、無圧縮pngを使って画像を合成するようにする。 # これによってPLTEをカウンタ側で計算する必要が # なくなったので、高速化が期待できるように。 # 他にもsplitの廃止などにより、高速化を図る。 # # Ver.1.01(2000/10/9) # Ver.1.0で入れ忘れた機能を改めて追加。 # # Ver.1.02(2000/10/15) # Nifty対策コードを入れる。 # # Ver.1.03(2000/10/16) # splitの廃止により、 # 日ごとのアクセス数集計速度 約3.5倍 # ブラウザの判別速度 約1.1〜1.85倍(ブラウザによる) # などの処理高速化を実現。 # # Ver.1.04(2000/10/17) # オプションの取り出しと透過処理はsplitも併用した方が # 速いようなので書き換え。 # # Ver.1.05(2000/10/20) # Niftyでこのスクリプトが使われているときだけ # 対策処理を行うように仕様変更。 # # Ver.1.1(2000/10/20) # renameによるロックを可能にする。 # ログのバックアップ作成機能追加。 # # Ver.1.2(2000/11/4) # ロックをかけた状態でログファイルのオープンに # 失敗した時、ロックを解除せぬままにエラーに # 飛んでいたのを修正。 # エラー処理部でexitするのをやめた。 # エラー番号を1ずらし、エラーが起きた時エラー番号 # そのものでexitするようにする。 # 出力されるIDATの長さチェックを画像合成中に行うように変更。 # これにより桁数がオプション指定できるように。 # 容量制限を32768バイトに緩和。 # # Ver.1.21(2001/5/12) # OS情報も集計するようにする。 # # Ver.1.22(2001/5/12) # OS情報取得ルーチンの小修正。 # # Ver.1.23(2001/5/13) # ブラウザ/OS取得ルーチンの改良。 # # Ver.1.23B(2001/5/13) # さらにブラウザ/OS取得ルーチンの改良。 # # Ver.1.24(2001/5/14) # MSIEとMozillaとで、WindowsNT4.0の表記法が # 微妙に異なる問題に対応。 # さらにブラウザ/OS取得ルーチンの改良。 # # Ver.1.25(2001/5/14) # CacheFlowに対応。 # さらにブラウザ/OS取得ルーチンの改良。 # # Ver.1.3(2001/6/6) # オプションの区切りを以下のように変える。 # '&' → ';' # '|' → ',' # # Ver.1.31(2001/9/1) # リロード時にカウントアップするかどうかを # 選択できるようにする。 # # Ver.1.32(2002/1/13) # コードを整理する。 # # Ver.1.33(2002/5/7) # galeon対策をする。 # 改変されているとおぼしいUAは除外するようにする。 # (UAにタグを仕込まれると、解析結果を表示したとき # ブラウザがクラッシュする危険性があるため) # # Ver.1.4(2002/5/18) # ログファイル指定に関するセキュリティーホールを塞ぐ。 # #----------------------------------------------------------- # # オプションの指定法([]内は省略可)。 # # http://www.dokozo.ne.jp/~darezo/counter.cgi?(logfile)[option(s)] # # (logfile) # その名の通りログファイル。必須。 # # [option(s)] # 表示オプション。現在対応しているオプションは以下の通り。 # # ;Tパレット番号[=透明度] # パレット番号は0〜255まで。透明度は0(透明)〜255(不透明)まで。 # このオプションは','で区切ることにより複数指定できる。 # # ;keta=N # 数値をN桁で表示する。 # カウンタの値が指定された桁数に満たぬ時は数字の前を0で埋める。 # # ;tate # 画像縦連結指定。 # # ;png=FILE # 数字用画像ファイル(SI-PNG)の指定。省略時はpngcntr.pngが使われる。 # なお拡張子(.png)はカウンタ内部で補うので不要。 # (例) ;pgc=gothic -> gothic.pngを使ってカウンタを表示する。 # # ;mirudake # その名の通り数値を「見るだけ」で、カウントアップされぬようにする。 # # # ;hi # ぴんぐカウンタ+専用オプション。 # ;hi=1で今日一日の、;hi=2で昨日一日のアクセス数を表示する。 # なお;hi=3でおとつい、4でその前日……というように遡ることもできる。 # # ;ref=URL # URLをリンク元情報としてログに取ることを指示するオプション。 # この機能を使うには、JavaScriptのdocument.referrerを # 併用する必要がある。 # # # 例 # http://〜/counter.cgi?log;T1=23,3=52;tate;png=train # # これは、 # train.pngという数字画像を使い、 # 1番パレットの透明度を23に、3番パレットの透明度を52に設定した上で、 # 画像を縦連結表示する、 # という指定を意味する。 # #-----------------------------------------------------------