#!/usr/local/bin/perl5 #// ------------------------------------------------------------ #// 寄せ集めのようにも見えるゲストブック #// #// Programed by YOUMEI #// サポートは勘弁気味 #// ------------------------------------------------------------ $strVer='1.02.10'; $strVerDate='2002/01/29'; $ELOCK_MODE=2; #// jcode.pl読み込み require'jcode.pl'; #// ---------------------------------------- #// 各種設定 #// ★部分は各自設定を確認してください #// ---------------------------------------- #// ★このCGIのURL $strCgiUrl ='./guestbook.cgi'; #// ★戻るページ $strHomeUrl ='http://'; #// ★システムファイル名 $strSysFileName ='./gbsys.dat'; #// ★メッセージファイル名 $strMesFileName ='./gbmes.dat'; #// ★ログファイル名 $strLogFileName='./accesslog.txt'; #// ★最大ログ保存行 $nMaxLogLine=300; #// ---------------------------------------- #// ★表示件数/頁 $nPerPage=10; #// ★保存件数 $nMaxMessage=100; #// ☆一件当たりのコメントバイト数 $nMaxMessageSize=1024; #// ---------------------------------------- #// ★タイトル $strTitle ='ゲストブック'; #// ★このゲストブックの説明 $strDescription= << '_HTML_';
_HTML_ #// ---------------------------------------- #// ★body $strBody='text="#000000" bgcolor="#ffffff"'; #// ★項目文字色 $strColorTitle='#ffffff'; #// ★項目名背景色 $strColorTitleBG='#1f4f7f'; #// ★内容文字色 $strColorContent='#000000'; #// ★IP文字色 $strColorIP='#cfcfcf'; #// ★内容背景色 $strColorContentBG='#ffffff'; #// ---------------------------------------- #//☆ 時間調節 #// $nAddTime=9*60*60; #// +9時間 $nAddTime=0; #//☆ 曜日設定 @wd=('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); #// ---------------------------------------- #// ☆NGワード @strNG=(''); #// ---------------------------------------- #// ☆HTML HEADER #// の中身 $strHtmlHeader = << "_HTML_"; $strTitle _HTML_ #// メイン #// ------------------------------------------------------------ %FORM=&ReadPost; @HOST=&host_check; &AccessLog; if( $FORM{'action'} eq 'pas' ) { &RegistPassword;} if (-s $strSysFileName) { if( $FORM{'action'} eq 'adm' ) { &PasswordScreen('adm'); exit;} elsif( $FORM{'action'} eq 'new' ) { &NewMessage; } elsif( $FORM{'action'} eq 'del' ) { &DeleteMessage; } &ReadMessage; } else { &PasswordScreen(''); } exit; #// パスワード登録画面 #// ------------------------------------------------------------ sub PasswordScreen { &PutHeader; print << "_HTML_"; _HTML_ if( $_[0] eq 'adm') { print''; print"\n"; print'' } else { print''; } print << "_HTML_";
旧Password
新Password
確認にもう一度
_HTML_ &PutFooter; } #// パスワード登録 #// ------------------------------------------------------------ sub RegistPassword { my ($line, $counter_num, $crypt_pass, $new_pass, $err); $new_pass=$FORM{'new_pass'}; open(PASS, "+<$strSysFileName"); eval'flock(PASS, $ELOCK_MODE)'; if( $FORM{'act_pass'} eq 'chg' ) { $line=; ($crypt_pass, $counter_num)=split(/\t/, $line); if( &encode2( $FORM{'old_pass'}, $crypt_pass) ne $crypt_pass) {$err='旧Passwordが違います';goto Err;} } if( length($new_pass) < 4 ){$err='Passwordは4文字以上入力してください。';goto Err;} if( $new_pass ne $FORM{'chk_pass'}) {$err='確認用Passwordが違います';goto Err;} $crypt_pass=&encode1($new_pass); truncate( PASS, 0); seek( PASS, 0, 0); print PASS "$crypt_pass\t$counter_num"; close(PASS); return; Err: close(PASS); &error($err); } #// メッセージ投稿処理 #// ------------------------------------------------------------ sub NewMessage { my (@log, @pairs, $w_name, $w_mail, $w_url, $w_message, $w_delkey, $tmp); $w_date=sprintf('%ld', time); $w_ip="$HOST[0]"; $w_name=$FORM{'name'}; $w_mail=$FORM{'mail'}; $w_url=$FORM{'url'}; $w_message=$FORM{'message'}; $w_delkey=$FORM{'delkey'}; if( $w_delkey ne '') { $w_delkey=&encode1($w_delkey)} else { $w_delkey='0'}; $tmp=$w_name; $tmp =~ s/ //ig; $tmp =~ s/ //ig; if( $tmp eq '' ) {error('名前が空欄です。');} $w_url =~ s/http:\/\///i; if( $w_url ne '' ) {$w_url="http://$w_url";} $tmp=$w_message; $tmp =~ s/\r//ig; $tmp =~ s/ //ig; $tmp =~ s/ //ig; if( $tmp eq '' ) {error('メッセージが空欄です。');} if( length($w_message) > $nMaxMessageSize) {error('最大投稿文字数を超えました。');} $tmp=join('|',@strNG); if( $w_message =~ /$tmp/ ) {error('メッセージに使用できない文字列が含まれています。');} open( MESG, "+<$strMesFileName"); eval'flock(MESG, $ELOCK_MODE)'; @log=; @pairs = split(/\t/, $log[0]); if ( $w_message eq $pairs[5] ) {close(MESG);&error('二重投稿は出来ません。');} unshift(@log, "$w_date\t$w_ip\t$w_name\t$w_mail\t$w_url\t$w_message\t$w_delkey\n"); $#log=$nMaxMessage-1 if( @log > $nMaxMessage ); truncate(MESG, 0); seek(MESG, 0, 0); print MESG @log; close(MESG); } #// メッセージ削除処理 #// ------------------------------------------------------------ sub DeleteMessage { my ($admin_pass, $delnum, @log, $line, @pairs, $r_delkey); return unless( @DELLIST ); $r_delkey=$FORM{'exec_delete'}; open( READ, "$strSysFileName"); eval'flock(READ, $ELOCK_MODE)'; $line=; ($admin_pass)=split(/\t/,$line); close(READ); open( MESG, "+<$strMesFileName" ); eval'flock(MESG, $ELOCK_MODE)'; @log=; truncate(MESG, 0); seek(MESG, 0, 0); $deltarget = join('|',@DELLIST); foreach $line (@log) { chomp $line; @pairs=split(/\t/,$line); if( $pairs[0] =~ /$deltarget/) { if( &encode2( $r_delkey, $pairs[6]) eq $pairs[6] || &encode2( $r_delkey, $admin_pass) eq $admin_pass) { next; } } print MESG "$line\n"; } close(MESG); } #// ------------------------------------------------------------ sub ReadMessage { &PutHeader; &PutMessages; &PutPostForm; &PutFooter; } #// ログ表示 #// ------------------------------------------------------------ sub PutMessages { my ($line, @log, @pairs, $pair, @t_name, $mes_id, $logcnt, $page); my ($r_time, $r_ip, $r_name, $r_mail, $r_url, $r_message); $page=int($FORM{'page'}); open( READ, "$strMesFileName"); eval'flock READ, $ELOCK_MODE'; @log=; close(READ); print << "_HTML_";
$strTitle

$strDescription
_HTML_ $delnum=$logcnt=0; if( @log ) { foreach $line (@log) { $logcnt++; if( $logcnt < $page*$nPerPage+1 ) {next;} if( $logcnt > ($page+1)*$nPerPage ) {last;} chomp $line; ($r_time, $r_ip, $r_name, $r_mail, $r_url, $r_message)=split(/\t/,$line); $mes_id=$r_time; if ($r_mail ne ''){$r_name="$r_name";} $r_time=&conv_time($r_time); if( $r_url =~ /^http:\/\//i){$r_url="$r_url";} $r_message=~s/\r/
\r/ig; print << "_HTML_";
_HTML_ if( $r_url ne '' ) { print << "_HTML_"; _HTML_ } print << "_HTML_";
お名前 $r_name    [$r_ip]
時間 $r_time
WebSite $r_url
メッセージ $r_message

_HTML_ $delnum++; } print << "_HTML_";
_HTML_ if( @log > ($page+1)*$nPerPage) { $page++; print << "_HTML_"; _HTML_ } print << "_HTML_";
 
_HTML_ } else { print << "_HTML_";

メッセージはありません。

_HTML_ } print << "_HTML_";
_HTML_ } #// 入力フォーム #// ------------------------------------------------------------ sub PutPostForm { print << "_HTML_";
お名前
メール
メッセージ
(適当に改行を入れてください。タグは使えません。)
WebSite
削除キー (省略した場合は管理者のみが削除できます。)
  


最大記事保存数:[ $nMaxMessage ]

_HTML_ } #// ---------------------------------------------------------------------- #// サブルーチン #// ---------------------------------------------------------------------- #// エラー #// ------------------------------------------------------------ sub error { &PutHeader; print "

$_[0]


"; &PutFooter; exit; } #// MIME/HTMLヘッダ #// ------------------------------------------------------------ sub PutHeader { print << "_HTML_"; Content-Type: text/html; charset=Shift_JIS $strHtmlHeader

> 戻る

_HTML_ } #// HTMLフッタ #// ------------------------------------------------------------ sub PutFooter { print << "_HTML_";

> 戻る

$strVer $strVerDate
guestbook.cgi Programed By YOUMEI

_HTML_ } #// アクセスログ記録 #// ------------------------------------------------------------ sub AccessLog { my ($date_now, $data_line, @logall); #//アクセスログ用変数初期化、設定 $date_now=&conv_time(time); open( LOG, "+<$strLogFileName"); eval'flock LOG, $ELOCK_MODE'; @logall=; unshift(@logall, "$date_now,$FORM{'action'},$HOST[0],$HOST[1],$HOST[2],$HOST[3],$HOST[4],$ENV{'HTTP_FROM'},$ENV{'HTTP_USER_AGENT'},$ENV{'HTTP_REFERER'}\n"); $#logall=$nMaxLogLine-1 if(@logall > $nMaxLogLine); truncate( LOG, 0); seek( LOG, 0, 0); print LOG @logall; close (LOG); } #// ------------------------------------------------------------ sub ReadPost { my ($value, $name, $pair, @pairs, $buffer, %form); read(STDIN,$buffer,$ENV{'CONTENT_LENGTH'}); @pairs = split(/&/,$buffer); foreach $pair (@pairs) { ($name,$value) = split(/=/,$pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; &jcode'convert(*value,'sjis'); $value =~ s/\&/&/g; $value =~ s/\"/"/g; $value =~ s//>/g; $value =~ s/\t//g; $value =~ s/\r\n/\r/g; $value =~ s/\n/\r/g; if ($name eq 'delnum') { push(@DELLIST, $value); } else { $form{$name} = $value; } } return %form; } #// パスワードエンコード #// ------------------------------------------------------------ sub encode1 { my ($now_t, $low, $high, @seed); @seed = ( 'a'..'z', 'A'..'Z', '0'..'9', '+', '-'); #// 64種類 $now_t = time; $low = $now_t & 63; $high = ($now_t >> 6) & 63; return crypt($_[0], "$seed[$low]$seed[$high]"); } sub encode2 { my $seed; $seed = substr( $_[1], 0, 2); return crypt($_[0], $seed); } #// 時間変換 #// ------------------------------------------------------------ sub conv_time { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $wdy); ($sec, $min, $hour, $mday, $mon, $year, $wday)=localtime($_[0]+ $nAddTime); $year+=1900; $mon++; $wdy=$wd[$wday]; return sprintf("%04d/%02d/%02d(%s) %02d:%02d:%02d", $year, $mon, $mday, $wdy, $hour, $min, $sec); } # # 環境変数からIPアドレス取得 # Release 1.0.3 #// ------------------------------------------------------------ sub host_check { my ($n_ip, $n_host, $x_ip, $x_ip1, $x_ip2, $x_host); my ($http_via, $http_for, $http_con, $http_ua, $http_cip); my ($tmp_ip, $is_proxy, $key, $value); my ($proxy_label, $local_label); $proxy_label='(proxy)'; $local_label='(local)'; $is_proxy=0; $n_ip =$ENV{'REMOTE_ADDR'}; $x_ip =$ENV{'HTTP_X_FORWARDED_FOR'}; $http_ua =$ENV{'HTTP_USER_AGENT'}; $http_via=$ENV{'HTTP_VIA'}; $http_for=$ENV{'HTTP_FORWARDED'}; $http_con=$ENV{'HTTP_CONNECTION'}; $http_cip=$ENV{'HTTP_CLIENT_IP'}; $n_host =gethostbyaddr(pack('C4',split(/\./,$n_ip)),2); $x_host =''; #// $ENV{'HTTP_X_FORWARDED_FOR'}処理 $x_ip=~s/ //g; ($x_ip1, $x_ip2)=split(/,/, $x_ip); $x_ip2='' if( $x_ip2=~/unknown/i); $x_ip1=$x_ip2 if($x_ip1=~/^192\.168\.|^172\.16\.|^10\./ && length($x_ip2)>6 ); $x_ip=$x_ip1; $x_ip='' if( $x_ip=~/unknown/i); $x_ip=~s/(\d+\.\d+\.\d+\.\d+)/$1/; #//-- 漏れている #//-- HTTP_X_FORWARDED_FOR if( $x_ip ne '') { $x_host= $x_ip=~/^192\.168\.|^172\.16\.|^10\./ ? $x_ip : gethostbyaddr(pack('C4',split(/\./,$x_ip)),2); $is_proxy|=1; } #//-- HTTP_FORWARDED if( $http_for =~ /(\w+)\s+for\s+/) { $x_host=$1; $tmp_ip= (gethostbyname($x_host))[4]; $x_ip=join('.', unpack('C4', $tmp_ip)); $is_proxy|=2; } #//-- HTTP_CLIENT_IP if($http_cip =~ /^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i) { $x_ip=join('.', hex($1),hex($2),hex($3),hex($4)); $x_host= $x_ip=~/^192\.168\.|^172\.16\.|^10\./ ? $x_ip : gethostbyaddr(pack('C4',split(/\./,$x_ip)),2); $is_proxy|=4; } #//-- 漏れていない if( $is_proxy==0) { #//-- プロキシの疑い有り $is_proxy|=8 if($n_host=~/(proxy|cache|^ns)/i); $is_proxy|=16 if(($http_ua=~/(via\s|proxy\s|gate)/i)); $is_proxy|=32 if($http_con!~/keep-alive/i); #// HTTP_環境変数を文字配列にして代入 while(($key,$value)=each(%ENV)){if($key=~/^HTTP_/){push(@httpenv,"$key=$value")}} foreach (@httpenv) { $is_proxy|=64 if(/HTTP_(VIA|CACHE_INFO|SP_HOST|FORWARDED_FOR|CLIENT_IP)=/); } } #//-- プロキシの疑い無し(無処理) #//-- 後処理 $x_ip='' if($x_ip eq '...'); $proxy_label='' if($is_proxy==0); $local_label='' unless( $x_ip=~/^192\.168\.|^172\.16\.|^10\./ ); $n_host=$n_ip if( $n_host eq ''); $x_host=$x_ip if( $x_host eq ''); return ($n_host, $n_ip, $proxy_label, $x_host, $x_ip, $local_label); } __END__