#! /usr/bin/perl # # 履歴記録CGI # # 2.008 : 6/19/08 : 変更、一括削除の機能を追加 # 2.007 : 2/2/08 : 年表示、年月表示の時のマス内表示順を日付順に修正 # 2.006 : 8/14/07 : タグ処理を修正 # 2.005 : 7/29/07 : 日付チェック方法を修正 # 2.004 : 6/10/07 : うるう年を修正 # 2.003 : 5/18/07 : 書き込みページを別ページにするオプションを追加 # 2.002 : 5/10/07 : 0から始まる日付を修正。 # 2.001 : 5/9/07 : 0から始まる年を修正。時刻を修正。 # 2.0 : 5/6/07 : 「ヒストリー」より西暦1年から指定できるようにし、 # 2038年問題を修正。カラム数を変更できるように修正。 # # http://www.hidekik.com/ # # $Id: history2.cgi,v 1.14 2008/06/19 06:17:09 Hideki Kanayama Exp $ # Copyright(c) 2005-2008, Hideki Kanayama, All rights reserved. use strict; use CGI qw(:cgi-lib); use CGI::Carp qw(fatalsToBrowser); use File::Basename; use Time::Local; use Date::Calc qw(Delta_Days check_date); my $adminpwd = "adminpwd.dat"; my $setupfile = "hist_setup.pl"; my $version = "2.008"; my $lastupdatedyear = "2008"; my $script = basename($0); my $charset = "Shift_JIS"; # Language 0:Japanese 1:English my $lang = 0; ### デフォルト設定 ### # data file our $datafile = 'history.dat'; # Title our $title = 'ヒストリー2'; # Delete page title our $deltitle = 'ヒストリー削除'; # Background our $bgimage_en = 0; our $bgimage_file = ''; our $bgcolor = "#ffffff"; # Back link our $backlink_en = 1; our $backlink = '..'; our $backlink_name = '戻る'; # Body width our $body_width = '80'; # Display order 0:From new, 1:From old our $order = 0; # Date display 0:年月日 1:年月のみ 2:年のみ our $date_disp = 0; # Header our $headers = '日付,コメント1,コメント2'; # 書き込み別ページ 1:on 0:off our $sep_wrpage = 0; # body_head our $body_head = "

$title

"; # body_tail our $body_tail = ' '; # mode 0:admin only, 1:user mode our $user_mode = 0; # Style Sheet our $style_sheet_en = 0; our $style_sheet = ' '; # Head insert our $head_insert_en = 0; our $head_insert = ' '; # Offset from GMT, Japan:+9 our $offset = 9; ####################### require $setupfile if (-e "$setupfile"); my $LOCK_EX = 2; my $now = time + $offset*3600; my $q = new CGI; my $cgierror = $q->cgi_error; &error($cgierror) if ($cgierror); my $mode = $q->param('mode'); if (! -e "$adminpwd"){ if ($mode eq 'wradminpwd'){ &wradminpwd; } else { &setadminpwd; } } my @header = split /,/, $headers; my $cols = $#header + 1; if ($mode eq 'write'){ &histwrite; } elsif ($mode eq 'delpage'){ &delpage; } elsif ($mode eq 'delete'){ &histdelete; } elsif ($mode eq 'modify'){ &histwrite; } elsif ($mode eq 'setup'){ &setup; } elsif ($mode eq 'setupwrite'){ &setupwrite; } elsif ($mode eq 'wrform'){ &wrform; } else { &display; } sub sortdays { my $histdata = @_[0]; my @alist = @{$histdata->{$a}}; my @blist = @{$histdata->{$b}}; return Delta_Days(@alist[1 .. 3],@blist[1 .. 3]); } sub display { my $histdata = &getdata; my @regtime = keys %{$histdata}; @regtime = sort {sortdays($histdata)} @regtime; @regtime = reverse @regtime if ($order == 1); &htmlhead($title); print "$body_head\n"; my ($d_dev,$d_ino,$d_mode,$d_nlink,$d_uid,$d_gid,$d_rdev,$d_size,$d_atime,$d_mtime,$d_ctime,$d_blksize,$d_blocks)=stat("$datafile"); my ($ssec,$smin,$shour,$sday,$smon,$syear,$swday,$syday,$sisdst)=gmtime($d_mtime+$offset*3600); $syear += 1900 if ($syear < 1900); $smon++; print "

\n"; print "$backlink_name

\n" if ($backlink_en); print "${syear}年${smon}月${sday}日更新\n"; print "

\n"; print "\n"; print ""; foreach (@header){ print ""; } print "\n"; # ($id,$dyear,$dmonth,$dday,$dhour,$dmin,$dtime,$dnow,$dpwd,$host,$ip,$dcomment); foreach (@regtime){ print "\n"; print "\n"; my @comarray = split /<>/, $histdata->{$_}[11]; for (my $i=0;$i<$cols-1;$i++){ print "\n"; } print "\n"; } print "
$_
"; print "$histdata->{$_}[1]年"; print "$histdata->{$_}[2]月" if ($date_disp == 0 or $date_disp == 1); print "$histdata->{$_}[3]日" if ($date_disp == 0); print ""; # print "$comarray[$i]:$#comarray:$histdata->{$_}[11]"; if ($comarray[$i] eq ''){ print " "; } else { print "$comarray[$i]"; } print "

\n"; &wrform unless ($sep_wrpage); print "$body_tail\n"; print "\n"; print "\n"; print "\n"; print "
"; if ($sep_wrpage){ print "登録ページ \n"; } print "削除変更ページ"; print "管理用
\n"; &htmltail; } sub wrform { if ($sep_wrpage and $mode eq 'wrform'){ &htmlhead($title); print "

$title書き込み

\n"; print "$titleへ

\n"; } my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst)=gmtime($now); $mon++; $year += 1900 if ($year < 1900); print "\n"; print "\n"; print "
"; print "
\n"; print "年"; print "月"; print "
\n"; shift @header; my $i=0; foreach (@header){ print "$_

\n"; $i++; } print "パスワード
\n"; print "\n"; print "\n"; print "
\n"; print "
\n"; &htmltail if ($sep_wrpage and $mode eq 'wrform'); } sub delpage { my $histdata = &getdeldata; my @regtime = @{$histdata}; @regtime = sort {Delta_Days($a->[1],$a->[2],$a->[3],$b->[1],$b->[2],$b->[3])} @regtime; @regtime = reverse @regtime if ($order == 1); &htmlhead($deltitle); print "

$deltitle

\n"; my ($d_dev,$d_ino,$d_mode,$d_nlink,$d_uid,$d_gid,$d_rdev,$d_size,$d_atime,$d_mtime,$d_ctime,$d_blksize,$d_blocks)=stat("$datafile"); my ($ssec,$smin,$shour,$sday,$smon,$syear,$swday,$syday,$sisdst)=gmtime($d_mtime+$offset*3600); $syear += 1900 if ($syear < 1900); $smon++; print "
\n"; print "${title}へ
\n"; print "

\n"; print "

\n"; my $headcols = $cols + 4; print "\n"; print ""; foreach (@header){ print ""; } print ""; print ""; print ""; print "\n"; # ($id,$dyear,$dmonth,$dday,$dhour,$dmin,$dtime,$dnow,$dpwd,$host,$ip,$dcomment); foreach my $refkey (@regtime){ print "\n"; print "\n"; my @comarray = split /<>/, $refkey->[11]; for (my $i=0;$i<$cols-1;$i++){ print "\n"; } print ""; print ""; print ""; print ""; print "\n"; } print "
$_   "; print "\n"; print "
↑パスワード\n"; print "
"; print "$refkey->[1]年"; print "$refkey->[2]月"; print "$refkey->[3]日"; print ""; if ($comarray[$i] eq ''){ print " "; } else { print "$comarray[$i]"; } print ""; print "[0]\" size=10>\n"; print ""; print "[0]\" value=\"削除\">\n"; print ""; print "[0]\" value=\"変更\">\n"; print ""; print "[0]\" value=\"on\">\n"; print "

\n"; print "削除・変更したい行のテキストボックスににパスワードを入れて削除、変更ボタンをクリックしてください。"; print "\n"; print "

\n"; &htmltail; } sub histdelete { if ($q->param('delete_checked') ne ''){ &delete_checked; } my ($fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$fnow,$fpwd,$fhost,$fip,$fcomment); open (FILE, "< $datafile") or &error("${datafile}が開けません。"); while (){ my @line = split /,/; my $modname = 'mod_' . $line[0]; if ($q->param($modname) ne ''){ close(FILE); &histmodify(@line); } } close(FILE); my @tmparray = (); open (DATAFILE, "+< $datafile") or &error("${datafile}が開けません。"); flock DATAFILE, $LOCK_EX; while (){ chomp; ($fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$fnow,$fpwd,$fhost,$fip,$fcomment) = split /,/; my $subname = 'sub_' . $fid; my $pwdname = 'pwd_' . $fid; my $inpwd = $q->param($pwdname); if (!$q->param($subname)) { push @tmparray, "$fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$now,$fpwd,$fhost,$fip,$fcomment\n"; } elsif (! &checkcrypt($inpwd,$fpwd)) { close(DATAFILE); &error('パスワードが違います。'); } } truncate DATAFILE, 0; seek DATAFILE, 0, 0; print DATAFILE @tmparray; close(DATAFILE); print "Location: $script\n\n"; exit; } sub delete_checked { my @tmparray = (); open (DATAFILE, "+< $datafile") or &error("${datafile}が開けません。"); flock DATAFILE, $LOCK_EX; my $inpwd = $q->param('pwd_checked'); while (){ chomp; my ($fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$fnow,$fpwd,$fhost,$fip,$fcomment) = split /,/; my $chkname = 'chk_' . $fid; if ($q->param($chkname) ne 'on') { push @tmparray, "$fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$now,$fpwd,$fhost,$fip,$fcomment\n"; } elsif (! &checkcrypt($inpwd,$fpwd)) { close(DATAFILE); &error("「$fyear年$fmonth月$fday日:$fcomment」のパスワードが違います。"); } } truncate DATAFILE, 0; seek DATAFILE, 0, 0; print DATAFILE @tmparray; close(DATAFILE); print "Location: $script\n\n"; exit; } sub histmodify { my ($fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$fnow,$fpwd,$fhost,$fip,$fcomment) = @_; my $pwdname = 'pwd_' . $fid; my $inpwd = $q->param($pwdname); if (! &checkcrypt($inpwd,$fpwd)) { &error('パスワードが違います。'); } &htmlhead('変更'); print "\n"; print "\n"; print "
"; print "
\n"; print "年"; print "月"; print "
\n"; my @comarray = split /<>/, $fcomment; shift @header; my $i=0; foreach (@header){ print "$_

\n"; $i++; } print "

\n"; print "\n"; print "\n"; print "\n"; print "

\n"; print "
\n"; &htmltail; exit; } sub check_indate { my ($year,$month,$day) = @_; if (($year =~ /\D/ or $month =~ /\D/ or $day =~ /\D/) or (! check_date($year,$month,$day))){ &error("日付が適切ではありません。${year}年${month}月${day}日") } } sub histwrite { my $year = $q->param('year'); my $month = $q->param('month'); my $day = $q->param('day'); &check_indate($year,$month,$day); $year = sprintf("%d",$year); $month = sprintf("%d",$month); $day = sprintf("%d",$day); my $hour = 0; my $min = 0; my @comment; for (my $i=0;$i<$cols-1;$i++){ $comment[$i] = $q->param("comment_$i"); } my $pwd = $q->param('pwd'); my $infid = $q->param('id'); my $id; my $regtime; my $host; my $ip; my $encpwd; for (my $i=0;$i<$cols-1;$i++){ $comment[$i] =~ s/,/,/g; $comment[$i] =~ s/\r\n/
/g; $comment[$i] =~ s/\r/
/g; $comment[$i] =~ s/\n/
/g; $comment[$i] =~ s/<(\s*\/? *t)/<$1/ig; # Do not allow table tag $comment[$i] =~ s/<(\s*plaintext)/<$1/ig; $comment[$i] =~ s/<(\s*script)/<$1/ig; $comment[$i] =~ s/<(\s*input)/<$1/ig; $comment[$i] =~ s/<(\s*pre)/<$1/ig; $comment[$i] =~ s/<(\s*embed)/<$1/ig; $comment[$i] =~ s/<>/<>/ig; } $host = $ENV{'REMOTE_HOST'}; $ip = $ENV{'REMOTE_ADDR'}; # This colum is not used. # $regtime = timegm(0,$min,$hour,$day,$monthn1,$year); $regtime = 0; $encpwd = &makecrypt($pwd); &error('管理人オンリーモードなので管理人しか書き込めません。') if ($user_mode == 0 and !&checkadmin($pwd)); # &error('パスワードが違います。') # if ($user_mode == 1 and !&checkcrypt($pwd,$encpwd)); if ($mode eq 'modify'){ my @tmparray = (); open (DATAFILE, "+< $datafile") or &error("${datafile}が開けません。"); flock DATAFILE, $LOCK_EX; while (){ chomp; my ($fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$fnow,$fpwd,$fhost,$fip,$fcomment) = split /,/; my $modname = 'mod_' . $fid; if ($fid != $infid) { push @tmparray, "$fid,$fyear,$fmonth,$fday,$fhour,$fmin,$ftime,$now,$fpwd,$fhost,$fip,$fcomment\n"; } elsif (&checkcrypt($pwd,$fpwd)) { my $jcomment = join '<>', @comment; push @tmparray, "$fid,$year,$month,$day,$hour,$min,$regtime,$now,$encpwd,$host,$ip,$jcomment\n"; } else { close(DATAFILE); &error("$fid:$infidパスワードが違います。"); } } truncate DATAFILE, 0; seek DATAFILE, 0, 0; print DATAFILE @tmparray; close(DATAFILE); } else { if (open DATA, "< $datafile"){ while (){ my @dummy; ($id,@dummy) = split /,/; } close DATA; $id++; } else { $id = 1; } open (FILE, ">> $datafile") or &error("${datafile}が開けません。"); # ($id,$dyear,$dmonth,$dday,$dhour,$dmin,$dtime,$dnow,$dpwd,$host,$ip,$dcomment); flock FILE, $LOCK_EX; my $jcomment = join '<>', @comment; print FILE "$id,$year,$month,$day,$hour,$min,$regtime,$now,$encpwd,$host,$ip,$jcomment\n"; close(FILE); } print "Location: $script\n\n"; } sub sortdata { my @alist = split /,/, $a; my @blist = split /,/, $b; return Delta_Days(@blist[1 .. 3],@alist[1 .. 3]); } sub getdata { my %histdata; my @dataarray; my $id; my $host; my $ip; my $id; my @alldata; if (open DATA, "< $datafile"){ @alldata = ; close DATA; } foreach (sort sortdata @alldata) { chomp; # ($id,$dyear,$dmonth,$dday,$dhour,$dmin,$dtime,$dnow,$dpwd,$host,$ip,$dcomment); @dataarray = split /,/; next if ($dataarray[11] eq ''); my $key; if ($date_disp == 0) { $key = join '_', @dataarray[1 .. 3]; } elsif ($date_disp == 1) { $key = join '_', @dataarray[1 .. 2]; } elsif ($date_disp == 2){ $key = $dataarray[1]; } if (exists $histdata{$key}){ my @orgcomment = split /<>/, $histdata{$key}->[$#dataarray]; my @newcomment = split /<>/, $dataarray[11]; my $max; if ($#orgcomment >= $#newcomment){ $max = $#orgcomment; } else { $max = $#newcomment; } my @replacecomment; for (my $i=0;$i<=$max;$i++){ if ($orgcomment[$i] ne ''and $newcomment[$i] ne ''){ $replacecomment[$i] = $orgcomment[$i] . "
" . $newcomment[$i]; } elsif ($orgcomment[$i] eq '' and $newcomment[$i] ne ''){ $replacecomment[$i] = $newcomment[$i]; } else { $replacecomment[$i] = $orgcomment[$i]; } } my $replacecomment = join '<>', @replacecomment; $histdata{$key} = [ @dataarray[0 .. $#dataarray-1], $replacecomment, ]; } else { $histdata{$key} = [@dataarray]; } } return (\%histdata); } sub getdeldata { my @histdata; my @dataarray; if (open DATA, "< $datafile"){ @histdata = (); while (){ chomp; # ($id,$dyear,$dmonth,$dday,$dhour,$dmin,$dtime,$dnow,$dpwd,$host,$ip,$dcomment); @dataarray = split /,/; next if ($dataarray[11] eq ''); push(@histdata, [@dataarray]); } close DATA; return (\@histdata); } } sub htmlhead { my $title = shift; my $bgimage; if ($bgimage_en == 1){ $bgimage = "background=\"$bgimage_file\""; } else { $bgimage = "bgcolor=\"$bgcolor\""; } # print "Content-type:text/html\n\n"; print $q->header(-charset=>"$charset"); print "\n"; print "\n"; print "$title\n"; if ($head_insert_en == 1){ print "$head_insert\n"; } if ($style_sheet_en == 1){ print "\n"; } print "\n"; print "\n"; print "
\n"; } sub htmltail { my $mysite = ('http://www.hidekik.com/','http://www.hidekik.com/en/')[$lang]; print "
history2.cgi Ver. $version
\n"; print "
Copyright(C) 2005-$lastupdatedyear, hidekik.com
\n"; print "
\n"; exit; } sub makecrypt { my $plain = shift; my $salt = join "", ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64]; my $result = crypt($plain,$salt) or crypt($plain,'$1$'.$salt.'$'); return $result; } sub checkcrypt { my ($pwd,$encpwd)=@_; return(crypt($pwd,$encpwd) eq "$encpwd" or &checkadmin($pwd)); } sub checkadmin { my $pwd = shift; if (open(FILE,"< $adminpwd")){ my $filepwd = ; close(FILE); my $inpwd = crypt($pwd,$filepwd); return ("$inpwd" eq "$filepwd"); } else { &error('パスワードファイルが存在しません'); } } sub setadminpwd { &htmlhead('管理者用パスワードを入力してください'); print "
\n"; if ($mode eq 'setup'){ print "
管理者用パスワードを入力してください。
\n"; print "\n"; print "\n"; print "\n"; } else { print "
管理者用パスワードを設定してください。
\n"; print "\n"; print "\n"; print "\n"; } &htmltail; } sub wradminpwd { my $plain = $q->param('pwd'); my $passwd = &makecrypt($plain); if (open(FILE,"> $adminpwd")){ print FILE "$passwd"; close(FILE); } else { &error('パスワードファイル作成に失敗しました'); } print "Location: $script\n\n"; } sub error { my ($msg) = shift; &htmlhead($msg); print "
$msg
\n"; &htmltail; exit; } sub setup { my $inpwd = $q->param('pwd'); &setadminpwd if ($inpwd eq ''); &error('管理用パスワードが違います。') unless &checkadmin($inpwd); &htmlhead('管理用セットアップ'); my %check; $check{bgimage}[$bgimage_en] = "checked"; $check{backlink}[$backlink_en] = "checked"; $check{order}[$order] = "checked"; $check{date_disp}[$date_disp] = "checked"; $check{user_mode}[$user_mode] = "checked"; $check{style_sheet}[$style_sheet_en] = "checked"; $check{head_insert}[$head_insert_en] = "checked"; $check{sep_wrpage}[$sep_wrpage] = "checked"; print "\n"; print "\n"; print "\n"; print <
  • 数字やカラー指定は必ず半角で指定してください。全角やブランクだとCGIが起動しなくなります。万一間違って全角で書いてしまった場合は、${setupfile}をエディタで開きその場所を半角に正しく修正してください。それで直ります。
データファイル タイトル 削除ページタイトル バックグランド 画像を使う カラー設定にする
画像を使う場合の画像ファイル
カラー設定の場合のカラー番号(白:#ffffff 又は white) トップへのリンク 表\示 非表\示
リンク名
URL
表\示幅 ブラウザ全体の% 表\示する順序 新しい順 古い順 年月日表\示 年月日 年月のみ 年のみ カラムのタイトル 半角カンマで区切ってください。日付と最低もう一つは指定してください。指定した数だけコメントがその日に記入でいるようになります。
管理人モード 管理人オンリーモード ユーザーモード
管理人オンリーでは管理人しか書き込めません。ユーザーモードでは誰でも書き込めます。 書き込み別ページ 書き込みフォームは表\示ページの下 書き込みページは別ページ
ページ上部 ページ上部に表\示させるものをHTML表\記

ページ下部 ページ下部に表\示させるものをHTML表\記

スタイルシート 有効 無効

<head>内挿入文 有効 無効
HTML書式
ポップアップ広告やJavascript、<META>を挿入したい場合にここに記述する。
以下の記述が<head>〜</head>内に挿入される。

時間設定 GMTより時間(日本:+9時間) END print ""; print ""; &htmltail; } sub setupwrite { my %in = $q->Vars; open (SETUP, "> $setupfile") or &error("${setupfile}が開けません。"); print SETUP <