#!/usr/bin/perl #↑ご自分のサーバーの環境に合わせて変更して下さい。 ################################################## # CGI 100番勝負 (ぱらだいす)Vol.080 Rev.1.0.0.0 # ハイパーゲストブック # Created by Web新撰組(萩原逸郎) ################################################## # 2002/05/22 Rev. 1.0.1.0 # 初心者用に初期設定部分を修正 # HTMLもみなおしました ################################################## #デバッグ用のモジュール読み込み #エラー時は先頭に#をつけてコメントアウトしてください use CGI::Carp qw(fatalsToBrowser); #jcode.plの読み込み require "jcode.pl"; # 新撰組ライブラリ読み込み require 'shinsengumi.pl'; ################################################## # 初期設定ここから ################################################## #ホームページの場所 $HomeUrl='http://www.iinet.ne.jp/~yoshamay/'; #ホームページの名前 $HomeTitle='HomePage'; #このCGIのタイトル $CgiTitle='投稿者様の栽培方法'; #データディレクトリへのパス $DataDir = '../data/'; #sendmailへのパス:サーバーにより異ります $Sendmail='/usr/sbin/sendmail -n -t'; #管理者メイルアドレス $AdminMailAdd='desuhamaya03@yahoo.co.jp '; ################################################## # 初期設定ここまで ################################################## ############################################# # 初期設定2 # 編集しなくても動作します。 ############################################# #このCGIのURL $CgiName='hguest.cgi'; #ログファイルのファイル名 $LogFile=$DataDir . 'hguest.txt'; #パスワードファイル $PasswdFile=$DataDir . 'passwd'; #デザインスタイルシート $DesignFile = $DataDir . 'design.css'; #一度に画面表示するログの数 $Max=20; #####ファイルロック設定 #ロックフラグ #1の時、シンボリックリンクでロック #2の時、$LockFileに1(解除は0)を書き込む #3の時、flockを使ってロック #4の時、何もしない #1〜4以外のときは1と同じ $SHIN_CGI::FileLockMode=2; #ロックファイル $LockFile = $DataDir . 'lock.txt'; #禁止IPアドレスファイル $IPFile = $DataDir . 'ipaddr.txt'; # 発言禁止ファイル $BadwordFile = $DataDir . 'badwords.txt'; #禁止発言クッキーの名前 $bwcookie_name = 'my_guestbook'; #IPチェックする(0のときしない) $SHIN_CGI::IPCHECK_FLAG = 1; #禁止語チェックする(0のときしない) $SHIN_CGI::BWCHECK_FLAG = 1; #禁止語発言回数(この数字になると書込み禁止になる) $SHIN_CGI::BWTIMES = 3; ################################################## # 初期設定2ここまで ################################################## #デザインファイル読み込み open DES,"$DesignFile" || &error(500,'デザインファイルをオープン出来ません'); @style = ; close DES; %FORM=&get_formdata; #フォームからデータを読み込む if($FORM{'action'} eq "write"){ &ShowHtmlForm; #フォーム表示 }elsif($FORM{'action'} eq "regist"){ $cookie = &WriteLogdata; #ログを書き込む &ShowLogdata($cookie); #投稿内容表示 }elsif($FORM{'action'} eq "search"){ &LogSerch; #検索 }elsif($FORM{'action'} eq "adminmenu"){ &AdminMenu; #管理者メニュー表示 }elsif($FORM{'action'} eq "change_passwd"){ &ChangePasswd; #パスワード変更 }elsif($FORM{'action'} eq "change_domains"){ &ChangeDFile; #ドメインファイル変更 }elsif($FORM{'action'} eq "delete_log"){ &DeleteLog; #ログ削除 }else{ &ShowLogdata; #投稿内容表示 } exit; #CGIのメイン部分はここまで #以下はサブルーチン ###################### # ドメインファイル変更 ###################### sub ChangeDFile { local($passwd,$domain,@domains,@newdomain); if($FORM{'passwd'}){ open(IN,"$PasswdFile") || &error(233,'パスワードファイルが開けません'); $passwd=; close(IN); &error(701,"パスワードが違います") if($passwd ne (crypt($FORM{'passwd'},$passwd))); }else{ &error(702,"パスワードを入力して下さい"); } $status = &SHIN_CGI::FileLockLock(1,$LockFile); if (!$status){ &error(500,"ただいまサーバーが込み合っています"); } if($FORM{'domains'}){ @domains=split(/\n/,$FORM{'domains'}); foreach $domain (@domains) { $domain =~ s/\s//g; if($domain){ push(@newdomain,$domain); } } if(@newdomain){ open(OUT,">$IPFile") || &error(231,'IPファイルが開けません',1); foreach $domain (@newdomain) { print OUT $domain,"\n"; } close(OUT); }else{ open(OUT,">$IPFile")|| &error(235,'IPファイルが開けません',1); print OUT ""; close(OUT); } }else{ open(OUT,">$IPFile")|| &error(236,'IPファイルが開けません',1); print OUT ""; close(OUT); } &SHIN_CGI::FileLockLock(0,$LockFile); print <<"EOL"; Content-type: text/html; charset=EUC-JP $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

管理メニュー


ドメインファイルを変更しました


CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ################# # ログ削除 ################# sub DeleteLog { local($passwd,$num,$line,@lines,@newlines); if($FORM{'passwd'}){ open(IN,"$PasswdFile") || &error(230,'パスワードファイルが開けません'); $passwd=; close(IN); &error(601,"パスワードが違います") if($passwd ne (crypt($FORM{'passwd'},$passwd))); }else{ &error(602,"パスワードを入力して下さい"); } if(!$FORM{'lognumber'}){ &error(603,"削除するログの番号を入れて下さい"); }else{ $status = &SHIN_CGI::FileLockLock(1,$LockFile); if (!$status){ &error(500,"ただいまサーバーが込み合っています"); } $FORM{'lognumber'} =~ s/\n//g; @delnums = split(/\,/,$FORM{'lognumber'}); open(IN,"$LogFile") || &error(238,'ログファイルが開けません',1); while(){ $del_flag = 1; $line=$_; $num=(split(/Enc_Sep_Code/,$line))[0]; foreach $del (@delnums){ if($num == $del){ $del_flag = 0; last; } } if ($del_flag == 1){ push(@newlines,$line); } } close(IN); open(OUT,">$LogFile") || &error(239,'ログファイルが開けません',1); foreach $line (@newlines) { print OUT $line; } close(IN); &SHIN_CGI::FileLockLock(0,$LockFile); } print <<"EOL"; Content-type: text/html; charset=EUC-JP $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

管理メニュー


$FORM{'lognumber'} 番を消去しました。


CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ################# # パスワード変更 ################# sub ChangePasswd { local($oldpasswd,$passwd_a,$passwd_b); local($filepasswd,$newpasswd); open(IN,"$PasswdFile") || &error(261,'パスワードファイルが開けません'); $filepasswd=; close(IN); if($filepasswd !~ /^null/){ if(!$FORM{'oldpasswd'}){ &error(501,"今までのパスワードを入力して下さい"); }else{ $oldpasswd=$FORM{'oldpasswd'}; } } if(!$FORM{'newpasswd_a'}){ &error(502,"新しいパスワードを入力して下さい"); }else{ $passwd_a=$FORM{'newpasswd_a'}; } if(!$FORM{'newpasswd_b'}){ &error(503,"新しいパスワードを入力して下さい"); }else{ $passwd_b=$FORM{'newpasswd_b'}; } if($passwd_a ne $passwd_b){ &error(504,"パスワードを入力しなおして下さい"); } if($filepasswd !~ /^null/){ &error(505,"パスワードが違います") if($filepasswd ne (crypt($oldpasswd,$filepasswd))); } $newpasswd=&make_passwd($passwd_a); $status = &SHIN_CGI::FileLockLock(1,$LockFile); if (!$status){ &error(500,"ただいまサーバーが込み合っています"); } open(OUT,">$PasswdFile")|| &error(262,'パスワードファイルが開けません',1); print OUT $newpasswd; close(OUT); &SHIN_CGI::FileLockLock(0,$LockFile); print <<"EOL"; Content-type: text/html; charset=EUC-JP $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

管理メニュー


パスワードを変更しました


CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ################# # パスワード生成 ################# sub make_passwd{ local($plaintext)=@_; local($key,$i,$passwd,@keys); $key='a'; for($i=0;$i<=25;$i++){ $keys[$i]=$key++; } $key='A'; for($i=26;$i<=51;$i++){ $keys[$i]=$key++; } $key='0'; for($i=52;$i<=61;$i++){ $keys[$i]=$key++; } $keys[++$i]='.'; $keys[++$i]='/'; srand(time|$$); $i=rand(@keys); $key=$keys[$i]; $i=rand(@keys); $key=$key . $keys[$i]; $passwd=crypt($plaintext,$key); return($passwd); } #################### # 管理者メニュー表示 #################### sub AdminMenu { local($domain,@domains); open(IN,"$IPFile") || &error(263,'IPファイルが開けません'); @domains=; close(IN); print <<"EOL"; Content-type: text/html; charset=EUC-JP $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

管理メニュー


書き込み禁止用ドメイン名 追加/削除

書き込み禁止したいIPアドレスを、1行につきひとつづつ記入してください。

パスワード:


書き込み内容削除

削除したい書き込みの番号を半角数字で記入してください。
「,(カンマ)」で区切れば、複数の書き込みを一度に削除する事ができます。

パスワード:


管理パスワード変更

管理パスワードを変更します。

今までのパスワード:

新しいパスワード:

新しいパスワード(確認用):

 

CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ################## # メール転送 ################## sub send_mail { local($Subject,$From,$To,$Message)=@_; require 'mimew.pl'; $Message =~ s/
/\n/g; &jcode::convert(*Subject,"jis"); $Subject = &mimeencode($Subject); &jcode::convert(*Message,"jis"); open(SNDML,"| $Sendmail") || &error(401,"sendmailを使用出来ません",1); print SNDML <<"EOL"; Content-Type: text/plain; charset="ISO-2022-JP" Content-Transfer-Encoding: 7bit From: $From To: $To Subject: $Subject $Message EOL close(SNDML); return(1); } ################## # ドメインチェック ################## sub DomainCheck { local($ip)=@_; local($remote_host); $remote_host=gethostbyaddr(pack("C4",split(/\./,$ip)),2); &error(301,"proxy経由での書き込みは出来ません") if($remote_host =~ /proxy/i); $ips = split(/\./,$ip); $c_ip = join('.',$ips[0],$ips[1],$ips[2]); open(IN,"$IPFile") || &error(241,'IPファイルが開けません'); while(){ $data=$_; $data =~ s/\n//; if($c_ip =~ /$data/i){ close(IN); &error(302,"あなたと同じサーバー利用者に悪質な書き込みをする人がいますので、現在書き込み出来なくなっています。ごめんね。呪うならそいつを呪ってね。"); } } close(IN); } ################# # 検索 ################# sub LogSerch { local($no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$location,$mess,$data); local($key_uname,$key_mess,$key_sex,$key_location); local($flag_uname,$flag_mess,$flag_sex,$flag_location); $key_uname=$key_mess=$key_sex=$key_location="null"; #なまえ if($FORM{'uname'} ne "null"){ $key_uname=$FORM{'uname'}; $key_uname=~s/\n$//; if($key_uname !~ /[^\s ]/){ $key_uname="null"; } } #おところ $FORM{'location'} =~ s/\n$//; if($FORM{'location'} ne "この中から選んでね"){ $key_location=$FORM{'location'}; } #性別 $key_sex=$FORM{'sex'}; #メッセージ if($FORM{'mess'} ne "null"){ $key_mess=$FORM{'mess'}; $key_mess =~ s/\n$//; if($key_mess !~ /[^\s ]/){ $key_mess="null"; } } &error(200,"検索キーを1つ以上指定して下さい") if(($key_uname eq "null") &&($key_mess eq "null") && ($key_sex eq "null") && ($key_location eq "null")); print <<"EOL"; Content-type: text/html; charset=EUC-JP $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

検索結果は次の通りです!


EOL $c_flag = 0; open(LOG,"$LogFile"); while(){ $data = $_; $data =~ s/\n//; &jcode::sjis2euc(*data); ($no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$sex,$location,$mess)=split(/Enc_Sep_Code/,$data); $flag_uname=$flag_mess=$flag_sex=$flag_location=0; if($key_uname ne "null"){ if($uname !~ /$key_uname/){ next; } } if($key_mess ne "null"){ if($mess !~ /$key_mess/){ next; } } if($key_sex ne "null"){ if($sex ne $key_sex){ next; } } if($key_location ne "null"){ if($location ne $key_location){ next; } } # if(($flag_uname)||($flag_mess)||($flag_sex)||($flag_location)){ $c_flag = 1; ($no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$sex,$location,$mess)=split(/Enc_Sep_Code/,$data); print <<"EOL"; EOL if ($hurl ne 'NULL'){ print <<"EOL"; EOL } print <<"EOL"; EOL # } } close(LOG); if ($c_flag == 0){ print <<"EOL"; EOL } print <<"EOL";

$no

$unameさん

訪問日:$date

 

Homepage:

$htitle

 

$mess

 

条件に合うデータが見つかりませんでした

CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ################# # ログを書き込む ################# sub WriteLogdata { local($no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$location,$mess,$dmy); local(@lines,%LTIME); #なまえ $FORM{'uname'}=~s/\n//g; if(!$FORM{'uname'}){ &error(100,"名前を入れて下さい"); }else{ $uname=$FORM{'uname'}; if($uname !~ /[^\s ]/){ &error(101,"名前を入れて下さい"); } $uname =~ s/[  ]//g; } #おところ $FORM{'location'} =~ s/\n//g; if($FORM{'location'} eq "この中から選んでね"){ &error(102,"おところを選んで下さい"); }else{ $location=$FORM{'location'}; } #メイル $FORM{'mailadd'}=~s/\n//g; if(!$FORM{'mailadd'}){ &error(103,"メイルアドレスを入力して下さい"); }else{ $mailadd=$FORM{'mailadd'}; if($mailadd !~ /[\w\-\~]+@[\w\-\~\.]+/){ &error(104,"そのメールアドレスは受付出来ません"); } } #ホームページのURL(なければNULL) $hurl="NULL"; $FORM{'hurl'} =~ s/\n//g; if($FORM{'hurl'}){ if($FORM{'hurl'} ne "http://"){ $hurl = $FORM{'hurl'}; } } #ホームページのタイトル(なければNULL) $FORM{'htitle'} =~ s/\n//g; if($FORM{'htitle'}){ $htitle=$FORM{'htitle'}; }else{ $htitle="NULL"; } #メッセージ if(!$FORM{'mess'}){ &error(105,"メッセージを書いて下さい"); }else{ $mess=$FORM{'mess'}; $mess =~ s/\n/
/g; $dmy = $mess; $dmy =~ s/[\s ]//g; $dmy =~ s/
//g; if(!$dmy){ &error(106,"何かメッセージを書いて下さい"); } } #ipアドレスを取得 $ip=$ENV{'REMOTE_ADDR'}; &DomainCheck($ip); #ドメインチェック if(&SHIN_CGI::CheckIP($IPFile)){ &error(501,'現在接続中のIPアドレスは、書き込みできません'); } $badtime = &SHIN_CGI::GetBWCookie($bwcookie_name); $bad1 = &SHIN_CGI::CheckBadWords($uname,$BadwordFile,$IPFile,$bwcookie_name); $bad2 = &SHIN_CGI::CheckBadWords($mess,$BadwordFile,$IPFile,$bwcookie_name); $bad3 = &SHIN_CGI::CheckBadWords($htitle,$BadwordFile,$IPFile,$bwcookie_name); if ($bad1 > $badtime){ $badtime = $bad1; }elsif($bad2 > $badtime){ $badtime = $bad2; }elsif($bad3 > $badtime){ $badtime = $bad3; } if($badtime >= $SHIN_CGI::BWTIMES){ &error(502,'だめよ'); } $line = &SHIN_CGI::SetBWCookie($bwcookie_name,$badtime); #時間を取得 %LTIME=&GetTime; $date="$LTIME{'year'}年$LTIME{'mon'}月$LTIME{'mday'}日($LTIME{'jwday'})$LTIME{'hour'}:$LTIME{'min'}"; $status = &SHIN_CGI::FileLockLock(1,$LockFile); if (!$status){ &error(500,"ただいまサーバーが込み合っています"); } #ログの番号を調べて、新しい番号を作る(最後のに1を足すだけ) open(LOG,"$LogFile") || &error(251,'ログファイルが開けません',1); @lines=; close(LOG); $no=(split(/Enc_Sep_Code/,$lines[$#lines]))[0]; $no++; #メールで書き込み内容を送る &send_mail("$unameさんからゲストブックに書き込みです",$mailadd,$AdminMailAdd,$mess); #もしもログが1000件以上であればメインテナンスを催促するメールを送る if($#lines > 999){ &send_mail("ゲストブックをメインテナンスして下さい",$AdminMailAdd,$AdminMailAdd,"ゲストブックの件数は、只今$#lines件です。\nメインテナンスして下さい。\n"); } #ログの書き込み $dmy=join('Enc_Sep_Code',$no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$FORM{'sex'},$location,$mess); &jcode::euc2sjis(*dmy); open(LOG,">> $LogFile")|| &error(252,'ログファイルが開けません',1); print LOG $dmy,"\n"; close(LOG); &SHIN_CGI::FileLockLock(0,$LockFile); return ($line); } ############# # 日付の取得 ############# sub GetTime { local(@week,$gtime,$sec,$min,$hour,$mday,$mon, $emon,$yeart,$year,$wday,$ewday,$jwday, %LTIME); @week=('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); @jweek=('日','月','火','水','木','金','土'); @month=('Jan','Feb','Mar','Apl','May','June','Jul', 'Aug','Sep','Oct','Nov','Dec'); $gtime = (time)+(9*3600); ($sec,$min,$hour,$mday,$mon,$yeart,$wday)=(gmtime($gtime))[0..6]; $emon=$month[$mon]; $mon++; $year = $yeart + 1900; $ewday=$week[$wday]; $jwday=$jweek[$wday]; %LTIME=('sec',$sec, 'min',$min, 'hour',$hour, 'mday',$mday, 'mon',$mon, 'emon',$emon, 'year',$year, '2year',$yeart, 'ewday',$ewday, 'jwday',$jwday); return(%LTIME); } ########################## # フォームの内容を読み込む ########################## sub get_formdata{ local($buffer,@pairs,%FORM,$name,$value); if ($ENV{'REQUEST_METHOD'} eq "POST"){ read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); } else { $buffer = $ENV{'QUERY_STRING'}; } @pairs = split(/&/,$buffer); foreach (@pairs) { ($name, $value) = split(/=/, $_); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; &jcode::convert(*value,'euc'); $value =~ s//>/g; #htmlタグを禁止する $value =~ s/\r\n/\n/g; #改行コードの\rを消去 $FORM{$name} = $value; } return(%FORM); } ###################### # 過去の登録を表示 ###################### sub ShowLogdata { ($cookieline) = @_; local($num,$i,$no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$sex,$location,$mess); local($line,@lines); open(LOG,"$LogFile") || &error(514,'データファイルが開けません'); @lines=; close(LOG); @lines=reverse(@lines); print <<"EOL"; Content-type: text/html; charset=EUC-JP $cookieline $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

当分の間休止いたします。


いままでに登録して下さった方を検索することができます。
検索項目は以下の通りです。

おなまえで?

メッセージで?

性別で?

男性 女性 両方

お住まいで?


EOL if(@lines){ $num=$#lines; $start=$FORM{'start'}; $start=0 if(!$start); $start = $num if($num < $start); for($i=$start;$i<($start+$Max);$i++){ last if($i>$num); $line=$lines[$i]; &jcode::sjis2euc(*line); ($no,$date,$ip,$uname,$mailadd,$hurl,$htitle,$sex,$location,$mess)=split(/Enc_Sep_Code/,$line); $mess =~ s/\n//; print <<"EOL"; EOL if ($hurl ne 'NULL'){ print <<"EOL"; EOL } print <<"EOL"; EOL } } print <<"EOL";

$no

$unameさん

訪問日:$date

 

Homepage:

$htitle

 

$mess


EOL $dmys = $start; $dmys = $dmys + $Max; if ($dmys <= $num){ print <<"EOL"; EOL } if (($start-$Max) >= 0 ){ $start = $start-$Max; print <<"EOL"; EOL } print <<"EOL";
EOL print <<"EOL";

CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ######################## # 入力フォーム部分を表示 ######################## sub ShowHtmlForm { print <<"EOL"; Content-type: text/html; charset=EUC-JP $CgiTitle @style
$CgiTitle
HomepageAdministratorGuestBook

訪問の記念に栽培している方は、ひとこと教えてください!


おなまえ:

おところ:

性別:

男性 女性

メイルアドレス:

ホームページURL:

ホームページタイトル:

メッセージ:

CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL } ######################### # エラー ######################### sub error { local($num,$word,$lflag)=@_; if($lflag){ &SHIN_CGI::FileLockLock(0,$LockFile); } print <<"EOL"; Content-type: text/html; charset=EUC-JP エラー @style
$CgiTitle
HomepageAdministratorGuestBook

Error!!!

Error No:$num
$word

Back


CGI Paradise Vol.080 Rev.1.0.0.0 Web新撰組

EOL exit; }