2019年06月16日

perl再入門(6)・・・perlのプログラムを追う(説明の続き)

nanako1.jpg

競馬も気になり,カープの試合もラジオ放送を聞きながら、perlのプログラムの説明の続きをやります。

プログラムを再掲します。


------------------------------------------------------------

#-----------------------------------------------------------
# 解析
#-----------------------------------------------------------
sub analyze_log {
# ランダムモード
if ($cf{rand} > 0) {
srand;
my $rand = int(rand($cf{rand}));
if ($rand != 0) { load_img(); }
}

# リンク元取得
my $ref;
if ($cf{ssi}) {
$ref = $ENV{HTTP_REFERER};
} else {
$ref = $ENV{QUERY_STRING};

# escapeで取得のためURLデコードしておく
$ref = $cgi->url_decode($ref) if ($ref);
}

# リンク元解析
if ($ref =~ /^https?:\/\/[-.!~*'()\w;\/?:\@&=+\$,%#]+/i) {

# URLデコード
$ref = $cgi->url_decode($ref);

# コード変換
require Jcode;
$ref = Jcode->new($ref)->sjis;

# 無害化
$ref = $cgi->htmlize($ref);
$ref =~ s/'/'/g;

} else {
$ref = '';
}

# リンク元集計での除外指定
if ($cf{myurl}) {
my $flg;
foreach ( split(/\s+/, $cf{myurl}) ) {
if (index($ref,$_) >= 0) { $flg++; last; }
}
if ($flg) { $ref = ''; }
}

# ホスト/IP除外
my ($addr,$host) = get_host();

# ブラウザ情報取得
my $hua = $ENV{HTTP_USER_AGENT};

my ($os,$agent);
if ($hua =~ /AOL/) { $agent = 'AOL'; }
elsif ($hua =~ /Opera/i) { $agent = 'Opera'; }
elsif ($hua =~ /PlayStation/i) { $agent = 'PlayStation'; }
elsif ($hua =~ /Googlebot/i) { $agent = 'Googlebot'; }
elsif ($hua =~ /slurp\@inktomi\.com/i) { $agent = 'Slurp/cat'; }
elsif ($hua =~ /Infoseek SideWinder/i) { $agent = 'Infoseek SideWinder'; }
elsif ($hua =~ /FAST\-WebCrawler/i) { $agent = 'FAST-WebCrawler'; }
elsif ($hua =~ /ia_archiver/i) { $agent = 'ia_archiver'; }
elsif ($hua =~ /Chrome/i) { $agent = 'Chrome'; }
elsif ($hua =~ /Safari/i) { $agent = 'Safari'; }
elsif ($hua =~ /Firefox/i) { $agent = 'Firefox'; }
elsif ($hua =~ /MSIE (\d+)/i) { $agent = "MSIE $1"; }
elsif ($hua =~ m|Mozilla/5.+Trident/7|i) { $agent = "MSIE 11"; }
elsif ($hua =~ /Netscape/i) { $agent = 'Netscape'; }
elsif ($hua =~ /Mozilla/i) { $agent = 'Mozilla'; }
elsif ($hua =~ /Gecko/i) { $agent = 'Gecko'; }
elsif ($hua =~ /Lynx/i) { $agent = 'Lynx'; }
elsif ($hua =~ /Cuam/i) { $agent = 'Cuam'; $os = 'Windows'; }
elsif ($hua =~ /Ninja/i) { $agent = 'Ninja'; $os = 'Windows'; }
elsif ($hua =~ /WWWC/i) { $agent = 'WWWC'; $os = 'Windows'; }
elsif ($hua =~ /DoCoMo/i) { $agent = $os = 'DoCoMo'; }
elsif ($hua =~ /^MOT-|^J-PHONE|^SoftBank|^Vodafone|NetFront/i) { $agent = $os = 'SoftBank'; }
elsif ($hua =~ /^UP\.Browser|^KDDI/i) { $agent = $os = 'EZweb'; }
elsif ($hua =~ /L\-mode/i) { $agent = $os = 'L-mode'; }
elsif ($hua =~ /ASTEL/i) { $agent = $os = 'ASTEL'; }
elsif ($hua =~ /PDXGW/i) { $agent = $os = 'H"'; }

$agent = $cgi->htmlize($agent) if ($agent);
$agent =~ s/['\r\n\0]//g;

if ($hua =~ /win[dows ]*95/i) { $os = 'Win95'; }
elsif ($hua =~ /win[dows ]*9x/i) { $os = 'WinMe'; }
elsif ($hua =~ /win[dows ]*98/i) { $os = 'Win98'; }
elsif ($hua =~ /win[dows ]*XP/i) { $os = 'WinXP'; }
elsif ($hua =~ /win[dows ]*NT ?5\.1/i) { $os = 'WinXP'; }
elsif ($hua =~ /Win[dows ]*NT ?5/i) { $os = 'Win2000'; }
elsif ($hua =~ /win[dows ]*2000/i) { $os = 'Win2000'; }
elsif ($hua =~ /Win[dows ]*NT ?5\.2/i) { $os = 'Win2003'; }
elsif ($hua =~ /Win[dows ]*NT 6\.0/i || $hua =~ /Vista/i) { $os = 'WinVista'; }
elsif ($hua =~ /Win[dows ]*NT 6\.1/i) { $os = 'Win7'; }
elsif ($hua =~ /Win[dows ]*NT 6\.2/i) { $os = 'Win8'; }
elsif ($hua =~ /Win[dows ]*NT 6\.3/i) { $os = 'Win8.1'; }
elsif ($hua =~ /Win[dows ]*NT/i) { $os = 'WinNT'; }
elsif ($hua =~ /Win[dows ]*CE/i) { $os = 'WinCE'; }
elsif ($hua =~ /shap pda browser/i) { $os = 'ZAURUS'; }
elsif ($hua =~ /Mac/i) { $os = 'Mac'; }
elsif ($hua =~ /X11|SunOS|Linux|HP-UX|FreeBSD|NetBSD|OSF1|IRIX/i) { $os = 'UNIX'; }
elsif ($hua =~ /iPhone/i) { $os = 'iPhone'; }
elsif ($hua =~ /iPad/i) { $os = 'iPad'; }
elsif ($hua =~ /Android/i) { $os = 'Android'; }

# 時間取得
$ENV{TZ} = "JST-9";
my $tm01 = (localtime(time))[0];
my $tm02 = (localtime(time))[1];
my $hour = (localtime(time))[2];

# ログ読み込み
my @data;
open(DAT,"+< $cf{logfile}") or die "open err: $cf{logfile}";
eval 'flock(DAT, 2);';
my $top = ;

# IPチェック
if ($cf{ip_chk}) {
chomp($top);
if ($addr eq $top) {
close(DAT);
&load_img;
}
}

# 記事数を調整
my $i = 0;
while () {
$i++;
push(@data,$_);

last if ($i >= $cf{maxlog} - 1);
}

# 更新
seek(DAT, 0, 0);
print DAT "$addr\n";
print DAT "$agent<>$os<>$host<>$ref<>$hour<>\n";
print DAT @data;
truncate(DAT, tell(DAT));
close(DAT);

# 表示
&load_img;
}

------------------------------------------------------------


# ブラウザ情報取得
my $hua = $ENV{HTTP_USER_AGENT};

my ($os,$agent);
if ($hua =~ /AOL/) { $agent = 'AOL'; }
elsif ($hua =~ /Opera/i) { $agent = 'Opera'; }
elsif ($hua =~ /PlayStation/i) { $agent = 'PlayStation'; }
elsif ($hua =~ /Googlebot/i) { $agent = 'Googlebot'; }
elsif ($hua =~ /slurp\@inktomi\.com/i) { $agent = 'Slurp/cat'; }
elsif ($hua =~ /Infoseek SideWinder/i) { $agent = 'Infoseek SideWinder'; }
elsif ($hua =~ /FAST\-WebCrawler/i) { $agent = 'FAST-WebCrawler'; }
elsif ($hua =~ /ia_archiver/i) { $agent = 'ia_archiver'; }
elsif ($hua =~ /Chrome/i) { $agent = 'Chrome'; }
elsif ($hua =~ /Safari/i) { $agent = 'Safari'; }
elsif ($hua =~ /Firefox/i) { $agent = 'Firefox'; }
elsif ($hua =~ /MSIE (\d+)/i) { $agent = "MSIE $1"; }
elsif ($hua =~ m|Mozilla/5.+Trident/7|i) { $agent = "MSIE 11"; }
elsif ($hua =~ /Netscape/i) { $agent = 'Netscape'; }
elsif ($hua =~ /Mozilla/i) { $agent = 'Mozilla'; }
elsif ($hua =~ /Gecko/i) { $agent = 'Gecko'; }
elsif ($hua =~ /Lynx/i) { $agent = 'Lynx'; }
elsif ($hua =~ /Cuam/i) { $agent = 'Cuam'; $os = 'Windows'; }
elsif ($hua =~ /Ninja/i) { $agent = 'Ninja'; $os = 'Windows'; }
elsif ($hua =~ /WWWC/i) { $agent = 'WWWC'; $os = 'Windows'; }
elsif ($hua =~ /DoCoMo/i) { $agent = $os = 'DoCoMo'; }
elsif ($hua =~ /^MOT-|^J-PHONE|^SoftBank|^Vodafone|NetFront/i) { $agent = $os = 'SoftBank'; }
elsif ($hua =~ /^UP\.Browser|^KDDI/i) { $agent = $os = 'EZweb'; }
elsif ($hua =~ /L\-mode/i) { $agent = $os = 'L-mode'; }
elsif ($hua =~ /ASTEL/i) { $agent = $os = 'ASTEL'; }
elsif ($hua =~ /PDXGW/i) { $agent = $os = 'H"'; }

$agent = $cgi->htmlize($agent) if ($agent);
$agent =~ s/['\r\n\0]//g;

if ($hua =~ /win[dows ]*95/i) { $os = 'Win95'; }
elsif ($hua =~ /win[dows ]*9x/i) { $os = 'WinMe'; }
elsif ($hua =~ /win[dows ]*98/i) { $os = 'Win98'; }
elsif ($hua =~ /win[dows ]*XP/i) { $os = 'WinXP'; }
elsif ($hua =~ /win[dows ]*NT ?5\.1/i) { $os = 'WinXP'; }
elsif ($hua =~ /Win[dows ]*NT ?5/i) { $os = 'Win2000'; }
elsif ($hua =~ /win[dows ]*2000/i) { $os = 'Win2000'; }
elsif ($hua =~ /Win[dows ]*NT ?5\.2/i) { $os = 'Win2003'; }
elsif ($hua =~ /Win[dows ]*NT 6\.0/i || $hua =~ /Vista/i) { $os = 'WinVista'; }
elsif ($hua =~ /Win[dows ]*NT 6\.1/i) { $os = 'Win7'; }
elsif ($hua =~ /Win[dows ]*NT 6\.2/i) { $os = 'Win8'; }
elsif ($hua =~ /Win[dows ]*NT 6\.3/i) { $os = 'Win8.1'; }
elsif ($hua =~ /Win[dows ]*NT/i) { $os = 'WinNT'; }
elsif ($hua =~ /Win[dows ]*CE/i) { $os = 'WinCE'; }
elsif ($hua =~ /shap pda browser/i) { $os = 'ZAURUS'; }
elsif ($hua =~ /Mac/i) { $os = 'Mac'; }
elsif ($hua =~ /X11|SunOS|Linux|HP-UX|FreeBSD|NetBSD|OSF1|IRIX/i) { $os = 'UNIX'; }
elsif ($hua =~ /iPhone/i) { $os = 'iPhone'; }
elsif ($hua =~ /iPad/i) { $os = 'iPad'; }
elsif ($hua =~ /Android/i) { $os = 'Android'; }

ここは長いですが、やってることは難しくありません。

その前にまず $ENV{HTTP_USER_AGENT} がどういうデータかを確認しておきましょう。

一例ですが、次のようなデータです。

Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36

このデータの場合だと、「Chrome」から $agent = 'Chrome' , 「Windows NT 6.1」から $os = 'Win7' になります。

$agent = $cgi->htmlize($agent) if ($agent);
$agent =~ s/['\r\n\0]//g;

ですが、$cgi->htmlize($agent) はHTMLエスケープをしています。 $agent =~ s/['\r\n\0]//g; は改行とかを削除しています。

# 時間取得
$ENV{TZ} = "JST-9";
my $hour = (localtime(time))[2];

ここは例えばアクセスした時間を求めています。 例えば、15:20にアクセスしていたら $hour は 15 になります。

# ログ読み込み
my @data;
open(DAT,"+< $cf{logfile}") or die "open err: $cf{logfile}";
eval 'flock(DAT, 2);';
my $top = ;

ログファイル log.cgi を読み込んでいます。$topにはログファイルの先頭の行が入ります(たぶん)。

# IPチェック
if ($cf{ip_chk}) {
chomp($top);
if ($addr eq $top) {
close(DAT);
&load_img;
}
}

$addr は

# ホスト/IP除外
my ($addr,$host) = get_host();

で出てきた $addr です。サブルーチン get_host に

# ホスト名取得
my $host = $ENV{REMOTE_HOST};
my $addr = $ENV{REMOTE_ADDR};

とあるので、$addr は $ENV{REMOTE_ADDR} です。

$cf{ip_chk} は init.cgi を見ると

# IPアドレスチェックによる二重記録排除 (0=no 1=yes)
$cf{ip_chk} = 1;

というコメントがありますので二重記録排除をやっています。ログファイルの先頭に最新アクセスのIPアドレスが入っています。

# 記事数を調整
my $i = 0;
while () {
$i++;
push(@data,$_);

last if ($i >= $cf{maxlog} - 1);
}

$cf{maxlog} は、init.cgi を見ると

# 最大ログ保持数(これ以上大きくしない方が無難)
$cf{maxlog} = 500;

とあるので、ログファイルのデータ数の最大値を決めています。最初は1000になっていました。私が500にしています。

# 更新
seek(DAT, 0, 0);
print DAT "$addr\n";
print DAT "$agent<>$os<>$host<>$ref<>$hour<>$mday<>$mon2<>$year<>$monmday<>$hua\n";
print DAT @data;
truncate(DAT, tell(DAT));
close(DAT);

ネットで調べると、次の記述がありました。

open(OUT, "+< $datafile"); # 読み書きモードで開く
flock(OUT, 2); # ロック確認。ロック
seek(OUT, 0, 0); # ファイルポインタを先頭にセット
print OUT "$data\n"; # 書き込む
truncate(OUT, tell(OUT)); # ファイルサイズを書き込んだサイズにする
close(OUT); # closeすれば自動でロック解除
 
このコメントが参考になりますね。

# 表示
&load_img;

load_img は、したの方にあります。

sub load_img {
if ($cf{ssi}) {
print "Content-type: text/plain\n\n";
} else {
# 透過GIF定義
my @img = qw(
47 49 46 38 39 61 02 00 02 00 80
00 00 00 00 00 ff ff ff 21 f9 04
01 00 00 01 00 2c 00 00 00 00 02
00 02 00 00 02 02 8c 53 00 3b
);

print "Content-type: image/gif\n\n";
binmode (STDOUT);
foreach (@img) {
print pack('C*',hex($_));
}
}
exit;
}

SSIでない場合、すなわちJavaScriptの場合に透過GIFをロードするらしいのですが、実際にやってみると何もしません。

この処理はもう少し勉強しないといけませんので、後で説明します。


ごちゃごちゃした説明になっていてすみませんが、私も思い出しながらやっていますので、ご了承願います。

では、次回にまたお会いしましょう。(カープ同点かあ。今日は勝って欲しいなあ。競馬はいよいよ重賞レースが始まりますね。)

posted by tsurutsuru at 15:06| Comment(0) | 日常茶飯事

perl再入門(5)・・・どんなアクセスレポートが出力されるのか

nanako1.jpg

いま説明していますCGIプログラムですが、どのようなアクセスレポートが表示されるのかご紹介しておきます。なかなか綺麗なレポートですよ。

アクセスレポート
https://trtr2030.com/report2/list2.cgi

最初の入室画面のパスワードは "1234" です。

ではぜひご覧になってくださいね。

説明の続きは次回で。


posted by tsurutsuru at 09:04| Comment(0) | 日常茶飯事