#!/usr/bin/perl
#Web Board ResVersion (2004/01/19)
$ver = '2.08';
#
#Copyright(C) Knight 2002-2004
#Mail ... knight@big.or.jp
#Home ... http://www.big.or.jp/~knight/
#――――― 設定項目 ――――――――――――――――――――――――
#――――― 基本設定 ―――――――――――――――――――
#タイトル
$title = 'Free Talk Board';
#トップメッセージ
$top_message = '★ み ん な と お は な し が し た い な ぁ ★';
#管理者用パスワード
$admin_pwd = 'sadmin';
#リンクの戻り先
$back_url = '/lmp/infomation.shtml';
#――――― タイトル画像の設定
#掲示板タイトルの画像(タイトルに画像を使用しない場合は空欄にする)
$title_img = 'bbs.gif';
#タイトル画像の幅(タイトルに画像を使用した場合に設定)
$title_width = '725';
#タイトル画像の高さ(タイトルに画像を使用した場合に設定)
$title_height = '100';
#――――― システムの設定 ――――――――――――――――
#スクリプト
$script = './board.cgi';
#ログファイル
$log_file = './board.log';
#ロックファイル
$lock_file = './lock/board.lock';
#スタイルシート
$css_file = './style.css';
#過去ログ作成ディレクトリ(過去ログを作成しない場合は無効)
$past_dir = './past/';
#過去ログファイルの拡張子(過去ログを作成しない場合は無効)
$past_ext = '.log';
#文字コード変換ライブラリ
require './jcode.pl';
#――――― 投稿時の設定
#投稿記事本文の色の指定(0 … 指定不可 / 1 … 指定可)
$color_mode = 1;
#投稿記事本文の色の設定(本文の色の指定機能を使用しない場合は無効)
@color = (
'#808080',
'#B38099',
'#8080B3',
'#80B380',
'#B3B380',
'#FF9955',
'#FF77DD',
'#FF7777',
'',
''
);
#――――― ログ関連の設定
#1ページの表示ログ数
$page_size = 10;
#過去ログの作成機能の使用(0 … 使用しない / 1 … 使用する)
$make_past = 0;
#スレッドの最大保存数(過去ログを作成する場合は無効)
$max_log = 30;
#過去ログスレッドの作成サイズ(過去ログを作成しない場合は無効)
$past_size = 30;
#――――― アクセス制限の設定
#自サイトのURL(設定すると、このURLを含まないサイトからの投稿を拒否します。http:// から指定すること)
$base_url = '';
#ホスト名取得時のgethostbyaddr関数の使用(0 … 使用しない / 1 … 使用する)
$gethostbyaddr = 1;
#――――― クッキーの設定
#クッキー保存日数(30日以上に設定すること)
$hold_days = 90;
#クッキーの識別名
$cookie_id = 'webboard';
#――――― 設定項目終了 ――――――――――――――――――――――
### メイン処理
&decode();
if ($in{'mode'} eq 'res') {
&res();
} elsif ($in{'mode'} eq 'howto') {
&howto();
} elsif ($in{'mode'} eq 'search') {
&search();
} elsif ($in{'mode'} eq 'userdel') {
&userdel();
} elsif ($in{'mode'} eq 'past' && $make_past == 1) {
&past();
} elsif ($in{'mode'} eq 'admin') {
&admin();
} elsif ($in{'mode'} eq 'regist') {
®ist();
}
&html();
### HTML出力
sub html {
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
$parent = 0;
foreach (@logs) {
if ((split(/\t/))[1] == 0) {
$parent++;
}
}
&header();
print <<"_HTML_";
_HTML_
if ($title_img ne '') {
print qq|

\n|;
} else {
print qq|
$title
\n|;
}
print <<"_HTML_";
$top_message
_HTML_
&form();
&navigator();
&showlog();
&navigator();
print qq|ページ移動 /|;
foreach (0 .. int(($parent - 1) / $page_size)) {
$page_info = $_ + 1;
if ($in{'page'} == 0 && $page_info > 10) {
print qq| [
ShowNext]|;
last;
}
if ($in{'page'} == $_) {
print qq| [$page_info]|;
} else {
print qq| [
$page_info]|;
}
}
print qq|
\n|;
&footer();
}
### 投稿フォーム表示
sub form {
if ($ENV{'REQUEST_METHOD'} ne 'POST') {
%cookie = &get_cookie($cookie_id);
if ($cookie{'url'} eq '') {
$cookie{'url'} = 'http://';
}
if ($cookie{'color'} eq '') {
$cookie{'color'} = $color[0];
}
}
if ($in{'mode'} eq 'res') {
$subj = 'Re:' . (split(/\t/, $logs[0]))[6];
$submit = '返信する';
} else {
$subj = '';
$in{'no'} = 0;
$submit = '投稿する';
}
print <<"_HTML_";
_HTML_
return;
}
### 投稿記事表示
sub showlog {
$start = $in{'page'} * $page_size;
$end = $start + $page_size;
$i = 0;
$flag = 0;
foreach (@logs) {
($no, $reno, $date, $name, $mail, $url, $subj, $text, $color, $icon, $file, $rank, $pwd, $host) = split(/\t/);
if ($in{'mode'} eq 'search' || $reno == 0) {
$i++;
}
if ($i <= $start) {
next;
}
if ($i > $end) {
last;
}
($sec, $min, $hour, $day, $mon, $year, $week) = localtime($date);
@week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
$date = sprintf("/ %04d/%02d/%02d/%s/%02d:%02d", $year + 1900, $mon + 1, $day, $week[$week], $hour, $min);
if ($mail ne '') {
$mail = qq|/ Eメール|;
}
if ($url ne '') {
$url = qq|/ URL|;
}
if ($in{'mode'} eq '') {
$res = qq|/ 返信|;
}
$text = &auto_link($text);
if ($color_mode == 1) {
if ($color eq '') {
$color = $color[0];
}
$text = qq|$text|;
}
chop($host);
if (($in{'mode'} eq 'search' && $flag == 1) || ($flag == 1 && $reno == 0)) {
print <<"_HTML_";
_HTML_
}
if ($in{'mode'} eq 'search' || $reno == 0) {
$flag = 1;
print <<"_HTML_";
| ■ $subj |
$res |
No.$no - $name $mail $url $date
|
_HTML_
} else {
print <<"_HTML_";
No.$no - $name $mail $url $date
|
_HTML_
}
}
print <<"_HTML_";
_HTML_
return;
}
### ページナビゲーター表示
sub navigator {
$new = '最新の投稿';
$prev = '↑前のページ';
$next = '↓次のページ';
if ($in{'page'} > 0) {
$new = qq|$new|;
}
if ($in{'page'} > 0) {
$n = $in{'page'} - 1;
$prev = qq|$prev|;
}
if (int(($parent - 1) / $page_size) > $in{'page'}) {
$n = $in{'page'} + 1;
$next = qq|$next|;
}
print qq|$new / $prev / $next
\n|;
return;
}
### 返信フォーム表示
sub res {
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
@res = ();
foreach (@logs) {
($no, $reno) = split(/\t/);
if ($in{'no'} == $no || $in{'no'} == $reno) {
push(@res, $_);
}
}
@logs = @res;
&header();
print <<"_HTML_";
返信フォーム
_HTML_
&showlog();
&form();
&footer();
}
### 使い方表示
sub howto {
if ($color_mode == 1) {
$color_cookie = '本文の色、';
}
&header();
print <<"_HTML_";
掲示板の使い方
■ 記事の投稿
- 入力の必須項目は、名前、本文です。その他の項目は任意となります。
- ブラウザがクッキー対応の場合、名前、Eメール、URL、$color_cookie削除キーの情報は、次回から自動的に入力されます。
- 投稿記事にHTMLタグを使用することはできません。
- 本文にURLを入力すると、自動的にリンクが張られます。
■ 掲示板の機能\
- 投稿記事の返信をクリックすると、その記事に対して返信ができます。
- ログ検索をクリックすると、ログの内容を検索することができます。
- 削除キーを入力しておくと、記事削除から自分の投稿記事を削除することができます。
■ 免責事項
- 他人や組織に対する誹謗中傷、公序良俗に反する発言、その他管理人が著しく不利益と判断した記事は予\告なく削除することがあります。
- この掲示板の利用によって生じた如何なる損害も、管理人はその責を負いませんので予\めご了承ください。
_HTML_
&footer();
}
### ログ検索
sub search {
&header();
print <<"_HTML_";
ログ検索
■ 検索したいキーワードを入力し、検索ボタンを押してください。
■ キーワードは半角スペースで区切って複数指定することができます。
_HTML_
if ($in{'word'} ne '') {
if ($make_past == 0 || $in{'obje'} ne 'past') {
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@search = ;
close(FILE);
}
if ($make_past == 1 && $in{'obje'} ne 'now') {
opendir(DIR, "$past_dir") || &error("過去ログディレクトリを読み出せません");
@dir = readdir(DIR);
closedir(DIR);
@dir = sort {$b <=> $a} (@dir);
@past = ();
foreach (@dir) {
if ($_ =~ /^\d+(\.\w+)$/ && $1 eq $past_ext) {
open(FILE, "$past_dir$_") || &error("過去ログファイルを読み出せません");
@file = ;
close(FILE);
push(@past, @file);
}
}
if ($in{'obje'} eq 'all') {
push(@search, @past);
} elsif($in{'obje'} eq 'past') {
@search = @past;
}
}
$in{'word'} =~ s/ / /g;
@pairs = split(/\s+/, $in{'word'});
@logs = ();
foreach (@search) {
$flag = 0;
foreach $pair (@pairs) {
if (index($_, $pair) >= 0) {
$flag = 1;
if ($in{'cond'} eq 'or') { last; }
} else {
if ($in{'cond'} eq 'and') { $flag = 0; last; }
}
}
if ($flag != 0) { push(@logs, $_); }
}
print qq|ページ移動 /|;
foreach (0 .. int($#logs / $page_size)) {
$page_info = $_ + 1;
if ($in{'page'} == $_) {
print qq| [$page_info]|;
} else {
$inword = $in{'word'};
$inword =~ s/(\W)/'%' . unpack('H2',$1)/ge;
print qq| [
$page_info]|;
}
}
print qq|
\n|;
&showlog();
}
print '
';
&footer();
}
### ユーザー記事削除
sub userdel {
if ($in{'prev'} ne '') { $in{'page'}--; }
if ($in{'next'} ne '') { $in{'page'}++; }
if ($in{'delete'} ne '') {
if ($ENV{'REQUEST_METHOD'} ne 'POST') {
&error("不正なアクセスです");
}
if ($ENV{'HTTP_REFERER'} ne '' && $base_url ne '' && $ENV{'HTTP_REFERER'} !~ /^$base_url/i) {
&error("不正なアクセスです");
}
if ($in{'user_pwd'} eq '') {
&error("削除キーを入力してください");
}
if ($in{'del'} eq '') {
&error("削除したい記事を選択してください");
}
&lock($lock_file);
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
@new = ();
$flag = 0;
$del_list = '';
foreach (@logs) {
($no, $reno, $pwd) = (split(/\t/))[0, 1, 12];
if ($flag == 0 && $in{'del'} == $no) {
&decrypt($in{'user_pwd'}, $pwd);
$flag = 1;
} elsif ($flag == 1 && $in{'del'} == $reno) {
$flag = 1;
} else {
$flag = 0;
}
if ($flag == 0) {
push(@new, $_);
} else {
$del_list .= " [$no]";
}
}
$work_mesg = "$del_list番の記事を削除しました";
open(FILE, ">$log_file") || &error("ログファイルに書き込めません");
print FILE @new;
close(FILE);
&unlock($lock_file);
}
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
$parent = 0;
foreach (@logs) {
if ((split(/\t/))[1] == 0) {
$parent++;
}
}
&header();
print <<"_HTML_";
記事削除
■ 削除キーを入力して削除したい記事にチェックを入れ、削除ボタンを押してください。
■ 投稿時に削除キーを設定していなければ記事を削除することはできません。
_HTML_
&footer();
}
### 過去ログ表示
sub past {
opendir(DIR, "$past_dir") || &error("過去ログディレクトリを読み出せません");
@dir = readdir(DIR);
closedir(DIR);
@dir = sort {$a <=> $b} (@dir);
$past_byte = 0;
foreach (@dir) {
if ($_ =~ /^\d+(\.\w+)$/ && $1 eq $past_ext) {
$past_byte += (stat("$past_dir$_"))[7];
}
}
&header();
print <<"_HTML_";
過去ログ
■ 表\示したい過去ログを選択し、表\示ボタンを押してください。
■ ログ検索によって過去ログを検索することができます。
_HTML_
if ($in{'view'} ne '' && $in{'view'} =~ /^\d+\.\w+$/ && -e "$past_dir$in{'view'}") {
open(FILE, "$past_dir$in{'view'}") || &error("過去ログファイルを読み出せません");
@logs = ;
close(FILE);
$page_size = $past_size;
print '
';
&showlog();
}
print '
';
&footer();
}
### 管理者用
sub admin {
if ($in{'admin_pwd'} eq '') {
&header();
print <<"_HTML_";
管理者パスワードを入力してください
_HTML_
&footer();
} else {
if ($ENV{'REQUEST_METHOD'} ne 'POST') {
&error("不正なアクセスです");
}
if ($ENV{'HTTP_REFERER'} ne '' && $base_url ne '' && $ENV{'HTTP_REFERER'} !~ /^$base_url/i) {
&error("不正なアクセスです");
}
if ($in{'admin_pwd'} ne $admin_pwd) {
&error("パスワードが違います");
}
if ($in{'prev'} ne '') { $in{'page'}--; }
if ($in{'next'} ne '') { $in{'page'}++; }
if ($make_past == 1 && ($in{'create_log'} ne '' || $in{'read_log'} ne '')) {
&lock($lock_file);
opendir(DIR, "$past_dir") || &error("過去ログディレクトリを読み出せません");
@dir = readdir(DIR);
closedir(DIR);
@dir = sort {$a <=> $b} (@dir);
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
if ($in{'create_log'} ne '') {
$dir[$#dir] =~ /([^\/\\]*)\.([^.\/\\]*)$/;
$past_file = ($1 + 1) . $past_ext;
@past = ();
(*logs, *past) = &move_log(*logs, *past, $past_size);
open(FILE, ">$past_dir$past_file") || &error("過去ログファイルを作成できません");
print FILE @past;
close(FILE);
chmod(0666, "$past_dir$past_file");
$work_mesg = "スレッド$past_size件を過去ログに移動しました";
}
if ($in{'read_log'} ne '') {
$past_file = $dir[$#dir];
open(FILE, "$past_dir$past_file") || &error("過去ログファイルを読み出せません");
@past = ;
close(FILE);
(*logs, *past) = &move_log(*logs, *past, 're');
unlink("$past_dir$past_file");
$work_mesg = "スレッド$past_size件を過去ログから読み戻しました";
}
open(FILE, ">$log_file") || &error("ログファイルに書き込めません");
print FILE @logs;
close(FILE);
&unlock($lock_file);
}
if ($in{'delete'} ne '') {
if ($delete[0] eq '') {
&error("削除したい記事を選択してください");
}
&lock($lock_file);
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
@new = ();
$del_list = '';
foreach (@logs) {
($no, $reno) = split(/\t/);
$flag = 0;
foreach $del (@delete) {
if ($no == $del || $reno == $del) { $flag = 1; last; }
}
if ($flag == 0) {
push(@new, $_);
} else {
$del_list .= " [$no]";
}
}
$work_mesg = "$del_list番の記事を削除しました";
open(FILE, ">$log_file") || &error("ログファイルに書き込めません");
print FILE @new;
close(FILE);
&unlock($lock_file);
}
if ($in{'download'} ne '') {
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
print "Content-type: text/download\n\n";
print @logs;
exit;
}
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
$log_byte = &comma(int((stat($log_file))[7] / 1024));
if ($logs[0] ne '' && $log_byte == 0) {
$log_byte = 1;
}
if ($make_past == 1) {
opendir(DIR, "$past_dir") || &error("過去ログディレクトリを読み出せません");
@dir = readdir(DIR);
closedir(DIR);
$past_byte = 0;
foreach (@dir) {
if ($_ =~ /^\d+(\.\w+)$/ && $1 eq $past_ext) {
$past_byte += (stat("$past_dir$_"))[7];
}
}
$past_byte = &comma(int($past_byte / 1024));
}
$parent = 0;
foreach (@logs) {
if ((split(/\t/))[1] == 0) {
$parent++;
}
}
&header();
print <<"_HTML_";
管理者用
■ 削除したい記事にチェックを入れ、削除ボタンを押してください。
■ ダウンロードボタンを押すと、現在のログをダウンロードします。
_HTML_
if ($make_past == 1) {
print qq|■ スレッドが$past_size件以上になると過去ログを作成することができます。
\n|;
} else {
print qq|■ スレッドが$max_log件以上になると古いスレッドから削除されます。
\n|;
}
print <<"_HTML_";
_HTML_
&footer();
}
}
### 記事登録
sub regist {
if ($ENV{'REQUEST_METHOD'} ne 'POST') {
&error("不正なアクセスです");
}
if ($ENV{'HTTP_REFERER'} ne '' && $base_url ne '' && $ENV{'HTTP_REFERER'} !~ /^$base_url/i) {
&error("不正なアクセスです");
}
$host = $ENV{'REMOTE_HOST'};
$addr = $ENV{'REMOTE_ADDR'};
if ($host eq "" || $host eq $addr) {
if ($gethostbyaddr == 1) {
$host = gethostbyaddr(pack("C4", split(/\./, $addr)), 2) || $addr;
}
}
$in{'name'} = &create_line($in{'name'});
$in{'mail'} = &create_line($in{'mail'});
$in{'url'} = &create_line($in{'url'});
$in{'subj'} = &create_line($in{'subj'});
$in{'pwd'} = &create_line($in{'pwd'});
$in{'text'} = &create_text($in{'text'});
if ($in{'name'} eq '') {
&error("名前が入力されていません");
}
if (length($in{'name'}) > 15 * 2) {
&error("名前の長さは全角15文字までにしてください");
}
if (($in{'mail'} ne '' && $in{'mail'} =~ /[^\w\.\@\d\-\_]/ && $in{'mail'} !~ /(.*)\@(.*)\.(.*)/) || length($in{'mail'}) > 50) {
&error("Eメールの入力内容が正しくありません");
}
if (length($in{'url'}) > 70) {
&error("URLの入力内容が正しくありません");
}
if ($in{'reno'} == 0 && length($in{'subj'}) > 20 * 2) {
&error("題名の長さは全角20文字までにしてください");
} elsif (length($in{'subj'}) > 22 * 2) {
&error("題名の長さは全角22文字までにしてください");
}
if ($in{'text'} eq '') {
&error("本文が入力されていません");
}
if (length($in{'text'}) > 3000 * 2) {
&error("本文の長さは全角3000文字までにしてください");
}
if (($in{'text'} =~ s/
/
/g) + 1 > 100) {
&error("本文は100行までにしてください");
}
if (length($in{'pwd'}) > 10) {
&error("削除キーの長さは半角10文字までにしてください");
}
$cookie{'name'} = $in{'name'};
$cookie{'mail'} = $in{'mail'};
$cookie{'url'} = $in{'url'};
$cookie{'color'} = $in{'color'};
$cookie{'pwd'} = $in{'pwd'};
&set_cookie(*cookie, $cookie_id, $hold_days);
&lock($lock_file);
open(FILE, "$log_file") || &error("ログファイルを読み出せません");
@logs = ;
close(FILE);
$no = 0;
$parent = 0;
$name = '';
$text = '';
foreach (@logs) {
if ($_ + 0 > $no) {
($no, $date, $name, $text, $ip) = (split(/\t/))[0, 2, 3, 7, 13];
}
if ((split(/\t/))[1] == 0) {
$parent++;
}
}
$no++;
if ($in{'name'} eq $name && $in{'text'} eq $text) {
&unlock($lock_file);
&error("二重投稿は禁止です");
}
chop($ip);
if (time() - $date < 60 && $host eq $ip) {
&unlock($lock_file);
&error("連続投稿は60秒以上時間をあけてください");
}
$date = time();
if ($in{'subj'} eq '') {
$in{'subj'} = '無題';
}
if ($in{'url'} eq 'http://') {
$in{'url'} = '';
}
if ($in{'pwd'} ne '') {
$in{'pwd'} = &encrypt($in{'pwd'});
}
$line = "$no\t$in{'reno'}\t$date\t$in{'name'}\t$in{'mail'}\t$in{'url'}\t$in{'subj'}\t$in{'text'}\t$in{'color'}\t$in{'icon'}\t$in{'file'}\t$in{'rank'}\t$in{'pwd'}\t$host\n";
if ($in{'reno'} != 0) {
@new = ();
$flag = 0;
foreach (@logs) {
($no, $reno) = split(/\t/);
if ($flag == 0 && $in{'reno'} == $no) {
$flag = 1;
} elsif ($flag == 1 && $in{'reno'} != $reno) {
$flag = 2;
push(@new, $line);
}
push(@new, $_);
}
if ($flag == 1) {
push(@new, $line);
}
@logs = @new;
} else {
if ($make_past == 0 && $parent >= $max_log) {
foreach (0 .. ($parent - $max_log)) {
($no, $reno) = split(/\t/, $logs[$#logs]);
if ($reno == 0) {
pop(@logs);
} else {
while ((split(/\t/, $logs[$#logs]))[1] != 0) {
pop(@logs)
}
pop(@logs);
}
}
}
unshift(@logs, $line);
}
open(FILE, ">$log_file") || &error("ログファイルに書き込めません");
print FILE @logs;
close(FILE);
&unlock($lock_file);
$in{'mode'} = '';
return;
}
### デコード
sub decode {
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
if ($ENV{'CONTENT_LENGTH'} > 15000) {
&error("投稿量が大きすぎます
現在の投稿量:$ENV{'CONTENT_LENGTH'} / 最大投稿量:15000");
}
read(STDIN, $alldata, $ENV{'CONTENT_LENGTH'});
} else {
$alldata = $ENV{'QUERY_STRING'};
}
foreach $data (split(/&/, $alldata)) {
($key, $value) = split(/=/, $data);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack('C', hex($1))/eg;
$value =~ s/\t//g;
&jcode'convert(*value, 'sjis', '', 'z');
$value =~ s/&/&/g;
$value =~ s/</g;
$value =~ s/>/>/g;
$value =~ s/"/"/g;
if ($key eq 'del') {
push(@delete, $value);
}
$in{"$key"} = $value;
}
$in{'page'} += 0;
return;
}
### HTMLヘッダ
sub header {
print <<"_HTML_";
Content-Type: text/html
$title
_HTML_
return;
}
### HTMLフッタ
sub footer {
print <<"_HTML_";
_HTML_
exit();
}
### エラー出力
sub error {
local($_) = @_;
&header();
print <<"_HTML_";
エラーが発生しました
$_
_HTML_
&footer();
}
### INPUT情報正規化
sub create_line {
local($_) = @_;
$_ =~ s/^\s+//;
$_ =~ s/\s+$//;
return $_;
}
### TEXTAREA情報正規化
sub create_text {
local($_) = @_;
$_ =~ s/\r?\n/\r/g;
$_ =~ s/^\r+//;
$_ =~ s/\r+$//;
$_ =~ s/\r/
/g;
return $_;
}
### オートリンク
sub auto_link {
local($_) = @_;
$_ =~ s/(https?:\/\/[\w\.\~\-\/\?\&\#\+\=\:\;\@\%]+)/$1<\/a>/gi;
$_ =~ s/([\w\-]+\@[\w\-\.]+)/$1<\/a>/gi;
return $_;
}
### コンマの付加
sub comma {
local($_) = @_;
while ($_ =~ s/^([-+]?\d+)(\d\d\d)/$1,$2/) {}
return $_;
}
### 削除キー暗号化
sub encrypt {
local($_) = @_;
srand(time + $$);
local $salt = pack('CC', int(rand(26) + 65), int(rand(10) + 48));
return crypt($_, $salt);
}
### 削除キー照合
sub decrypt {
local($inpwd, $pwd) = @_;
if ($pwd eq '') {
&error("該当記事には削除キーが設定されていません");
}
if (crypt($inpwd, $pwd) ne $pwd) {
&error("削除キーが違います");
}
return;
}
### ログ移動処理
sub move_log {
local(*logs, *past, $size) = @_;
if ($size ne 're') {
foreach (1 .. $size) {
while ((split(/\t/, $logs[$#logs]))[1] != 0) {
unshift(@past, pop(@logs));
}
unshift(@past, pop(@logs));
}
} else {
foreach (@past) {
push(@logs, $_);
}
}
return (*logs, *past);
}
### ファイルロック
sub lock {
local($lock_file) = @_;
local $flag = 0;
foreach (1 .. 5) {
if (-e $lock_file) {
if (time() > (stat($lock_file))[9] + 60) {
&unlock($lock_file);
next;
}
sleep(1);
} else {
open(LOCK, ">$lock_file") || &error("ロックファイルが作成できません");
close(LOCK);
$flag = 1;
last;
}
}
if ($flag == 0) {
&error("ファイルがロックされています
時間をおいてもう一度投稿してください");
}
return;
}
### ファイルロック解除
sub unlock {
local($_) = @_;
unlink($_);
return;
}
### クッキー関連の処理
sub get_cookie {
local($cookie_id) = @_;
local %all_cookies = ();
foreach (split(/; /, $ENV{'HTTP_COOKIE'})) {
local($key, $value) = split(/=/);
$all_cookies{"$key"} = $value;
}
foreach (split(/&/, $all_cookies{"$cookie_id"})) {
local ($key, $value) = split(/:/);
$value =~ s/&/&/g;
$value =~ s/</g;
$value =~ s/>/>/g;
$value =~ s/"/"/g;
$cookie{&unescape($key)} = &unescape($value);
}
return %cookie;
}
sub set_cookie {
local(*cookie, $cookie_id, $hold_days) = @_;
if (time() > $cookie{'refresh'} + 60 * 60 * 24 * 30) {
$cookie{'refresh'} = time();
}
local @pairs = ();
foreach (sort keys %cookie) {
push(@pairs, &escape($_) . ':' . &escape($cookie{"$_"}));
}
local $new_cookie = join('&', @pairs);
local $date = &gmt_date(time + 60 * 60 * 24 * $hold_days);
if ($new_cookie ne $all_cookies{"$cookie_id"}) {
print "Set-Cookie: $cookie_id=$new_cookie; expires=$date\n";
}
return;
}
sub escape {
local($_) = @_;
$_ =~ s/([&:;=%\x00-\x21])/sprintf("%%%02X", unpack('C',$1))/ge;
return $_;
}
sub unescape {
local($_) = @_;
$_ =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('C', hex($1))/ge;
return $_;
}
sub gmt_date {
local($_) = @_;
local($sec, $min, $hour, $day, $mon, $year, $wday) = gmtime($_);
local @week = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
local @month = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
return sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT", $week[$wday], $day, $month[$mon], $year + 1900, $hour, $min, $sec);
}