#!/usr/bin/perl
# ----------------------------------------------------------
# バナナの管理者(あなた)の情報です。
# ----------------------------------------------------------
require '../forbidden/forbidden.pl';
$admin_name = '邑波。'; # あなたの名前(ハンドルネーム)を書きます。
$admin_email = 'yuuha@waterblue.net'; # あなたのメールアドレスを書きます。
$master = 'a600c970'; # 管理用のパスワード
# ----------------------------------------------------------
# バナナのカスタマイズ項目です。
# ----------------------------------------------------------
$cgi_title = 'FF連想げーむ'; # バナナのタイトル(タグ不可)
$body_text = '#ffffff'; #
タグの設定
$body_link = ''; # リンクの色
$body_alink = ''; # クリック中のリンクの色
$body_vlink = ''; # 既にクリック済みのリンクの色
$body_bgcolor = '#000000'; # 背景の色
$body_back = ''; # 背景画像
$back_url = "http://union.waterblue.net/";
# 帰りの URL(絶対URL推奨)
$image_banana = 'banana.gif'; # バナナの画像のある URL
$date_color = "#666666"; # 日付の色
$emb_color = "#666666"; # 強調色
$oldcolor = "#3333CC"; # バナナ(連想単語)の色(^-^;; (はじめ)
$newcolor = "#3333CC"; # バナナ(連想単語)の色(^-^;; (あと)
$limit_log = 200; # ログの最大登録数
$page = 50; # 1ページに表示するバナナの数(^-^;;
$ip_check = 1; # IPアドレスの表示 (0:表示しない 1:表示する)
$rh_check = 1; # リモートホストの表示 (0:表示しない 1:表示する)
# ファイル関連の設定
$method = 'POST'; # METHOD の設定('POST' or 'GET')
$tz = 'JST-9'; # TimeZone
$cginame = 'index.cgi'; # この CGI のファイルの名前
$jcode = './jcode.pl'; # jcode.pl のある場所
$savetype = 0; # ログの記録方式 0:標準(推奨) 1:Temp利用
$logdir = './'; # 記録用ファイルの置くディレクトリへのパス(URLじゃないよ)
$logfile = 'banana.log'; # 記録用ファイル名
$lock1 = 'banana1.lock'; # 鍵ファイル名(1)
$lock2 = 'banana2.lock'; # 鍵ファイル名(2)
$lock_flag = 1; # 鍵ファイルの 1:使用 0:不使用
# HTML関連の設定
# -------------------- # タイトル部分の HTML文
$html_title=<<"_EOF_";
FF連想ゲ〜ム
_EOF_
# -------------------- # 説明部分の HTML文(上)
$html_info_top =<<"_EOF_";
前にここに来た人が残した下の言葉から、あなたが連想した言葉を書いて下さい。
ちゃんと書かないと見せてあげません。
連想は基本的にファイナルファンタジーに関するものに限定します.
そうでなくてもぜいぜい一般概念(熱い,赤いなど)にしてください.
_EOF_
# ↑ この _EOF_ はこのままにしておくこと!
# -------------------- # 説明部分の HTML文(下)
$html_info_bottom =<<"_EOF_";
・ タグを使用したり、全角 30字を超えると登録されません。
・ 続けて投稿したり、発想力に乏しいと登録されないらしいです。
_EOF_
# -------------------- # 登録後のサンキューメッセージ
$html_thanks =<<"_EOF_";
これまでの連想を見て楽しんでください。
今度はあなたの言葉からどんな連想がされていくのか楽しみです。
_EOF_
# -------------------- # 独自の JavaScript や スタイルシートはここに
$html_head=<<"_EOF_";
_EOF_
# -------------------- # 上にバナー(広告)をつける必要があるならここに
$html_topbanner=<<"_EOF_";
_EOF_
# -------------------- # 下にバナー(広告)をつける必要があるならここに
$html_bottombanner=<<"_EOF_";
_EOF_
# //////////////////////////////////////////////////////////
# オプションの設定はここまでです。
# 以下は CGI のプログラムです。
# 書き換えは個人の責任で行って下さい。
# //////////////////////////////////////////////////////////
$logdir =~ s/\/$//;
$logfile = "$logdir/$logfile";
$lock1 = "$logdir/$lock1";
$lock2 = "$logdir/$lock2";
if ($limit_log < 30) { $limit_log = 30; }
if ($limit_log > 9900) { $limit_log = 9900; }
&check_code;
&access_check;
&read_form;
if ($FORM{'mode'} eq 'test') { &check_mode; }
elsif ($FORM{'mode'} eq 'admin') { &html_admin_enter; }
elsif ($FORM{'pass'} eq $master) { # 入力欄
@logs = &read_file($logfile);
$FORM{'banana'} = &encode_text($FORM{'banana'});
&edit_editor;
print "Content-type: text/html\n\n";
&html_editor;
} elsif ($FORM{'mode'} eq 'view') { # ログ表示
@logs = &read_file($logfile);
print "Content-type: text/html\n\n";
&html_header;
print $html_title;
print "
\n";
print $html_thanks;
print "
\n";
print "
\n";
&html_banana(&page_banana);
&html_footer;
} elsif ($FORM{'banana'}) { # 登録処理
@logs = &read_file($logfile);
$FORM{'banana'} = &encode_text($FORM{'banana'});
&check_banana;
®ist_banana;
print "Content-type: text/html\n\n";
&html_header;
print $html_title;
print "
\n";
print $html_thanks;
print "
\n";
print "
\n";
&html_banana(&page_banana);
&html_footer;
} else { # DefaultHTML出力
@logs = &read_file($logfile);
print "Content-type: text/html\n\n";
&html_header;
print $html_title;
print $html_info_top;
&html_default;
print $html_info_bottom;
&html_footer;
}
exit 1;
# [ HTMLヘッダー部 ]
#
sub html_header{
print<<"_EOF_";
$cgi_title
$html_head
$html_topbanner
_EOF_
}
# [ 著作権の表示(書き換えずに、必ず表示すること) ]
#
sub html_footer{
print<<"_EOF_";
$html_bottombanner
_EOF_
}
# [ DefaultHTML 出力 ]
#
sub html_default {
# 最近登録されたものを取得する
if (!$logs[0]) {
$logs[0] = "0<>xx/xx xx:xx<>バナナ<><><>$time\n";
&write_file($logfile,$logs[0]);
}
($no,$date,$banana) = split(/<>/,$logs[0]);
$banana = &decode_text($banana);
# HTML出力
print<<"_EOF_";
$banana といったら
_EOF_
}
# [ 管理人入り口 ]
#
sub html_admin_enter {
print "Content-type: text/html\n\n";
print<<"_EOF_";
WeB BaNaNa Editor
管理用パスワードを入力してください。
(管理用のエディタを使用するためには、管理用パスワードが必要です。)
_EOF_
}
# [ バナナページ(^-^;; ]
#
sub page_banana{
$start = $FORM{'page'}; $end = $start + $page + 1;
if ($end >= @logs) { $end = @logs; }
else {
$next =$end - 1;
print "\n";
}
if ($start <= 0) { $start = 0; }
return ($start,$end);
}
# [ バナナ出力 ]
#
sub html_banana {
($start,$end) = @_;
print "
\n";
for($i=$start;$i<$end;$i++) {
($no,$date,$banana,$rhost,$ipad) = split(/<>/,$logs[$i]);
$word = &decode_text($banana);
if ($tword) {
print "";
print "[$tdate] ";
print "$word";
print " といったら ";
print "$tword";
if ($ip_check || $rh_check) {
print " (";
if ($ip_check) { print $ipad ." / "; }
if ($rh_check) { print $rhost; }
print ")";
}
print "\n
\n";
}
$tword = $word; $tdate = $date;
}
}
# [ バナナ登録チェック ]
#
sub check_banana {
# 最近登録されたデータを取得
($no,$date,$banana,$rhost,$ipad,$time) = split(/<>/,$logs[0]);
$nowtime = time;
# 登録順番をチェック
if ($FORM{'no'} != $no) {
&error(1,"残念、誰かが先に連想してしまったみたいです。
一度、戻って再読み込みしてから連想してください。");
}
# 同じサイトからの連続投稿は拒否
if ($ipad eq $ENV{'REMOTE_ADDR'} && $nowtime - $time < 120) {
&error(1,"連続しての投稿はできません。");
}
# 文字制限チェック
if (length($FORM{'banana'}) > 60) {
&error(1,"連想ワードは文字数は全角30字を超えてはいけません。");
}
# タグ制限チェック
if ($FORM{'banana'} =~ / || $FORM{'banana'} =~ />/) {
&error("タグを使ってはいけません。");
}
# 連想ワードを過去の情報と照合する
foreach (@logs) {
$banana = (split(/<>/,$_))[2];
if (($banana =~ /$FORM{'banana'}/i) || ($FORM{'banana'} =~ /$banana/i)) {
&error(1,"前にあなたと同じような発想をした人がいるようです。
戻って発想し直してください。");
}
}
}
# [ バナナ登録処理 ]
#
sub regist_banana {
# 連番のために
$FORM{'no'} = ++$FORM{'no'} % 9999;
# 日付取得
($year,$mon,$day,$hour,$min,$sec,$youbi) = &get_date($tz);
$time = time;
# ホスト情報取得
local($ipad,$rhost) = ($ENV{'REMOTE_ADDR'},$ENV{'REMOTE_HOST'});
$rhost = $rhost eq $ipad?gethostbyaddr(pack('C4',split(/\./,$ipad)),2)||'':$rhost;
# ログ更新
unshift(@logs,"$FORM{'no'}<>$mon/$day $hour:$min<>$FORM{'banana'}<>$rhost<>$ipad<>$time\n");
# ログ制限
while(@logs > $limit_log) { pop(@logs); }
&write_file($logfile,@logs);
}
# [ エディター表示 ]
#
sub html_editor {
print<<"_EOF_";
WeB BaNaNa Editor
WeB BaNaNa Editor
★使い方★
編集する時
1.編集する項目をチェックします。(複数でも可能\)
2.編集内容を書きます(このとき、何も書かなかった場合、削除されます)
3.[編集開始]で書き換えられます。
_EOF_
foreach (@logs) {
($no,$date,$banana,$rhost,$ipad) = split(/<>/,$_);
$banana = &decode_text($banana);
print "\n";
print "$date : ";
print "$banana($rhost/$ipad)\n";
print "
\n";
}
print "\n";
}
# [ エディット ]
sub edit_editor {
$flag = 0;
$no = ((split(/<>/,$logs[0]))[0] + 1) % 9999;
foreach (@logs) {
local($no,$date,$banana,$rhost,$ipad,$time) = split(/<>/,$_);
if ($del{$no}) {
$flag = 1;
if ($FORM{'banana'}) {
push (@new,"$no<>$date<>$FORM{'banana'}<>$rhost<>$ipad<>$time");
}
} else { push (@new,$_); }
}
if ($flag) {
undef (@logs);
@logs = &write_file($logfile,@new);
}
undef (@new);
}
# [ CGI動作チェック ]
#
sub check_mode {
if (!(-f $logfile)) { $axs = "Not Found" }
if (-r $logfile) { $axs = "r" }
if (-w $logfile) { $axs .= "w" }
print "Content-type: text/html\n\n";
print<<"_EOF_";
WeB BaNana Version 2.21 -TestMode-
[Option]
logfile[$axs] LockFlag:$lock_flag SaveType:$savetype
Method:$method FileName:$cginame TimeZone:$tz
Owner:$admin_name ($admin_email)
[Perl]
Path:#!$^X
Version:$]
[TestForm]
TestFormText:$FORM{'test'}
_EOF_
exit;
}
# [ 禁止文字コードの変換処理 ]
#
sub encode_text { # エンコード
local($text) = $_[0];
$text =~ s/\(/(/g; $text =~ s/\)/)/g;
$text =~ s/\*/*/g; $text =~ s/\+/+/g;
$text =~ s/\././g; $text =~ s/\?/?/g;
$text =~ s/\[/[/g; $text =~ s/\\/\/g;
$text =~ s/\]/]/g; $text =~ s/\{/{/g;
$text =~ s/\|/|/g;$text =~ s/\}/}/g;
return $text;
}
sub decode_text { # デコード
local($text) = $_[0];
$text =~ s/(/\(/g; $text =~ s/)/\)/g;
$text =~ s/*/\*/g; $text =~ s/+/\+/g;
$text =~ s/./\./g; $text =~ s/?/\?/g;
$text =~ s/[/\[/g; $text =~ s/\/\\/g;
$text =~ s/]/\]/g; $text =~ s/{/\{/g;
$text =~ s/|/\|/g;$text =~ s/}/\}/g;
return $text;
}
# [ 記録ファイルの処理 ]
#
sub read_file {
local($logfile) = $_[0];
if (!open(IN,$logfile)) {
&error(1,"記録ファイルの読み込み不可");
}
local(@files) = ;
close(IN);
return @files;
}
sub write_file {
local($logfile,@lines) = @_;
&dubble_lock_file;
if ($lock_error) { &error(1,"ロックファイルを検出しました。時間をおいてご利用下さい。"); }
if (!$savetype) {
# 標準タイプ 全 OS 共通
if (!open(OUT,">$logfile")) {
&dubble_unlock_file;
&error(1,"記録ファイルの書き込み不可");
}
print OUT @lines;
close(OUT);
} else {
# 改良タイプ chmod 使用(プロバイダによっては使えない)
$tmpfile = "$$\.tmp";
if (!open(OUT,">$tmpfile")) {
&dubble_unlock_file;
&error(1,"Temp利用ログ記録方式に未対応です。");
}
close(OUT);
chmod 0666,$tmpfile;
if (!open(OUT,">$tmpfile")) {
&dubble_unlock_file;
&error(1,"Temp利用ログ記録方式に未対応です。");
}
print OUT @lines;
close(OUT);
rename($tmpfile,$logfile);
if (-e $tmpfile) { unlink($tmpfile); }
}
&dubble_unlock_file;
return @lines;
}
# [ ロック機構 ]
#
sub dubble_lock_file {
if (!(&lock_file($lock1))) { &dubble_unlock_file; }
elsif (!(&lock_file($lock2))) { &dubble_unlock_file; }
}
sub dubble_unlock_file {
&unlock_file($lock2);&unlock_file($lock1);
}
sub lock_file {
local($lockfile) = $_[0];
if (!$lock_flag) { return 1; }
local($retry) = 3;
# ゴミのロックファイルは除去する
while (-f $lockfile) {
if ($retry-- <= 0) {
local($mtime) = (stat($lockfile))[9];
if ($mtime < time()-60*15) { return 0; }
$lock_error = 1;
return 1;
}
sleep 1;
}
open (LOCK,">$lockfile");
close(LOCK);
return 1;
}
sub unlock_file {
local($lockfile) = $_[0];
unlink($lockfile);
}
# [ 日付を取得する ]
#
sub get_date {
$ENV{'TZ'} = $_[0];
local($sec,$min,$hour,$day,$mon,$year,$youbi) = localtime(time);
$mon++;
if ($sec < 10) { $sec = "0$sec"; }
if ($min < 10) { $min = "0$min"; }
if ($hour < 10) { $hour = "0$hour"; }
if ($day < 10) { $day = "0$day"; }
if ($mon < 10) { $mon = "0$mon"; }
if ($year < 99) { $year += 100; }
$year += 1900;
$youbi = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$youbi];
return ($year,$mon,$day,$hour,$min,$sec,$youbi);
}
# [ フォームからデータ取得 ]
#
sub read_form {
# 標準入力からデータもらう
if ($ENV{'REQUEST_METHOD'} eq "POST") {
if ($ENV{'CONTENT_LENGTH'} > 1024 * 99) { &error(1,"書き込みすぎです。"); }
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
} else { $buffer = $ENV{'QUERY_STRING'}; }
# デコードする
foreach (split(/&/,$buffer)) {
local($name,$value) = split(/=/,$_);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
$value =~ s/<>/<>/g;
$value =~ s/\"/"/g;
$value =~ s/\r\n//;
$value =~ s/\r|\n//;
if ($name eq 'del') { $del{$value} = 1; }
else { $FORM{$name} = &change_code($value); }
}
}
# [ 文字コード関連 ]
#
sub check_code {
if (!(-r $jcode)) { &error(1,"jcode.pl がみつかりません。"); }
require $jcode;
local($text) = ord(substr("中澤重人=じゃわ(^-^;;",0,1));
if ($text == 0xc3) { $mojicode = "euc"; $charset_code = "x-euc-jp"; }
elsif ($text == 0x92) { $mojicode = "sjis";$charset_code = "x-sjis"; }
else { &error(1,"サポートしてない文字コードです"); }
}
sub change_code {
local($text)=$_[0];
&jcode'convert(*text,$mojicode);
if ($mojicode eq 'sjis') { &jcode'h2z_sjis(*text); }
if ($mojicode eq 'euc') { &jcode'h2z_euc(*text); }
return $text;
}
# [ エラー処理 ]
#
sub error {
($err,$err_msg) = @_;
if ($err) { print "Content-type: text/html\n\n"; }
print<<"_EOF_";
坂〇さんに突っ込まれてしまいました。
$err_msg
|
[ WeB BaNaNa ]
_EOF_
exit;
}