紙で作ったものたち
#!/usr/bin/perl
#------------------------------------------------------------------------------
#M氏の掲示板 v.1.0(パスワード認証つき)
#------------------------------------------------------------------------------
# 漢字コードライブラリ(jcode.plの場所にあわせる)
require 'jcode.pl';
$main_url = 'http://windows256.zive.net/‾winmama/cgi-bin/p_board/p_board.cgi';
$main = './main.html'; #---掲示板のフォームの部分-------------------
$list = './list.html'; #---掲示板の発言表示部分---------------------
$foot = './footer.html'; #---フッタ-----------------------------------
$editor = './editor.html'; #--------------------------------------------
$logfile = './log.txt'; #---ログファイル-----------------------------
$plogfile = './plog.txt'; #---過去ログファイル(自動生成)-------------
$max_log = '50'; #---ログファイルの最大記事保持数-------------
$max_plog = '300'; #---過去ログファイルの最大記事保持数---------
$lockfile = 'lck'; #---ロックファイルのためのフォルダ(自動生成)-
$g_password = 'karasu'; #---ゲスト用パスワード-----------------------
$password = 'hato'; #---管理人パスワード-------------------------
$cookiedays = '60'; #---クッキー保持日数------------------------------------
#---!注意!---必要が無いならそのままにしておくこと--------------------------
#---アクセスを禁止するホスト名を正規表現で表した配列-----------------------
#---空要素''を入れると、全てのホストがアクセス禁止されてしまうので注意!----
@noaccess = ('tokyo.+¥.adsl¥.someserver¥.ne¥.jp','gateway.*¥.some_internet_cafe¥.co¥.jp');
#---変数の代入---
$name = $form{'name'};
$mail = $form{'mail'};
$url = $form{'url'};
$user_message = $form{'user_message'};
$user_icon = $form{'user_icon'};
$admin_message = $form{'admin_message'};
$admin_icon = $form{'admin_icon'};
$pass = $form{'pass'};
$g_pass = $form{'g_pass'};
#---デコード処理-----------------------------------------------------------
&decode;
#---処理の分岐-------------------------------------------------------------
if($form{'mode'} eq "g_pass"){
if($form{'g_pass'} eq $g_password){
&html;
}else{
&error("not correct password");
}
}
elsif($form{'mode'} eq "regist"){
#---書き込み---
®ist;
&html;
}
elsif($form{'mode'} eq "pass"){
&html_editor;
}
elsif($form{'mode'} eq "edit"){
if($form{'checkbox'} eq "delete"){
&html_delete;
&html;
}else{
&html_modify;
&html;
}
}else{
print "Content-type: text/html¥n¥n";
open IN, "nishichiba.html" || &error("ファイルがオープンできません");
while(<IN>){
$data=$_;
$PASS .=$data;
}
print "$PASS";
close IN;
}
#---フォームからの入力の記録サブルーチン-----------------------------------
sub regist {
local($no,$date,$name,$mail,$url,$user_message,$user_icon,$admin_message,$admin_icon);
#---IPアドレスなどを取得-----------------------------------------------
&gethost;
#---フォーム内容をチェック---------------------------------------------
if ($form{'name'} eq ""){
&error("名前が入力されていません");
}
if ($form{'user_message'} eq ""){
&error("コメントが入力されていません");
}
#---日時を取得---------------------------------------------------------
&get_time;
#---ファイルをロック---------------------------------------------------
&filelock || &error("ただいま混みあっています");
open(FILE,"+<$logfile") || &error("ログファイルがオープンできません");
@lines = <FILE>;
#---二重投稿禁止処理(文字化けあり・原因不明)-------------------------
@ban=split(/¥,/,$lines[0]);
if(($ban[2] eq $form{'name'})&&($ban[5] eq $form{'user_message'})){
close "$logfile";
&error("You cannot continue the task");
exit;
}
#---投稿番号を取得する-------------------------------------------------
$no = 1;
@data =split(/<>/,$lines[0]);
$log_no = $data[0];
if ($log_no >= $no) {
$no = $log_no + 1;
}
#---更新---------------------------------------------------------------
#---ログが最大数以内ならば---------------------------------------------
if($no<=$max_log){
unshift(@lines,"$no¥<>$date¥<>$form{'name'}¥<>$form{'mail'}¥<>$form{'url'}¥<>$form{'user_message'}¥<>$form{'user_icon'}<>$form{'admin_message'}<>$form{'admin_icon'}<>$ipaddr<>$hostname¥n");
open(FILE,">$logfile") || &error("書きこみができません");
print FILE @lines;
close FILE;
}else{
#---ログが最大数を越えたら最初のものを過去ログへ-----------------------
unshift(@lines,"$no¥<>$date¥<>$form{'name'}¥<>$form{'mail'}¥<>$form{'url'}¥<>$form{'user_message'}¥<>$form{'user_icon'}<>$form{'admin_message'}<>$form{'admin_icon'}<>$ipaddr<>$hostname¥n");
$last = pop @lines;
open(FILE,">$logfile") || &error("書きこみができません");
print FILE @lines;
close FILE;
open(FILE2,"+<$plogfile") || &error("ログファイルがオープンできません");
@lines2 = <FILE2>;
unshift @lines2,$last;
$lines2 = @lines2;
#---過去ログの最大数を越えたら最初のものは削除-------------------------
if($lines2 <= $max_plog){
open(FILE2,">$plogfile") || &error("過去ログの書きこみができません");
print FILE2 @lines2;
close FILE2;
}else{
pop @lines2;
open(FILE2,">$plogfile") || &error("過去ログの書きこみができません");
print FILE2 @lines2;
close FILE2;
}
}
#---ファイルのロック解除-----------------------------------------------
&unlock;
#---クッキーを記憶-----------------------------------------------------
&set_cookie;
}
#---HTML表示サブルーチン---------------------------------------------------
sub html{
#---ファイルをロック---------------------------------------------------
&filelock || &error("ただいま混みあっています");
#---ヘッダ、フォーム部分の表示-----------------------------------------
open IN, "$main" || &error("ファイルがオープンできません");
while(<IN>){
$data=$_;
$MAIN .=$data;
}
&get_cookie;
foreach($MAIN){
$_ =‾ s/¥<¥!¥-¥-¥-name¥-¥-¥-¥>/$ck_name/g;
$_ =‾ s/¥<¥!¥-¥-¥-mail¥-¥-¥-¥>/$ck_mail/g;
}
print "Content-type: text/html¥n¥n";
print "$MAIN";
close IN;
#---ログの読み込み-----------------------------------------------------
open IN,"$logfile" || &error("ログファイルがオープンできません");
@lines = <IN>;
close IN;
local($no,$date,$name,$mail,$url,$user_message,$user_icon,$admin_message,$admin_icon);
foreach (@lines) {
($no,$date,$name,$mail,$url,$user_message,$user_icon,$admin_message,$admin_icon,$ipaddr,$hostname) = split(/<>/,$_);
open IN, "$list";
while(<IN>){
$data=$_;
$LIST .=$data;
}
#---フォーム内のメールアドレスにリンク-----------------------------
if($mail ne ""){
$mail = "<a href=¥"mailto:$mail¥">";
}
#---フォーム内のURLにリンク-------------------------------------
if($url ne ""){
$url = "<a href=¥"$url¥" target=¥"¥_blank¥"><font size=2 color='#336633'><b>Home</b></font></a>";
}
$user_message =‾ s/(http¥:¥/¥/[¥w¥/¥.¥‾¥-¥_¥?¥&¥+¥=¥#¥@¥:¥;¥']+)/<a href="¥1" target=¥"¥_blank¥">¥1<¥/a>/gi;
$admin_message =‾ s/(http¥:¥/¥/[¥w¥/¥.¥‾¥-¥_¥?¥&¥+¥=¥#¥@¥:¥;¥']+)/<a href="¥1" target=¥"¥_blank¥">¥1<¥/a>/gi;
foreach($LIST){
$_ =‾ s/¥<¥!¥-¥-¥-no¥-¥-¥-¥>/$no/g;
$_ =‾ s/¥<¥!¥-¥-¥-date¥-¥-¥-¥>/$date/g;
$_ =‾ s/¥<¥!¥-¥-¥-name¥-¥-¥-¥>/$name/g;
$_ =‾ s/¥<¥!¥-¥-¥-mail¥-¥-¥-¥>/$mail/g;
$_ =‾ s/¥<¥!¥-¥-¥-url¥-¥-¥-¥>/$url/g;
$_ =‾ s/¥<¥!¥-¥-¥-user_message¥-¥-¥-¥>/$user_message/g;
$_ =‾ s/¥<¥!¥-¥-¥-user_icon¥-¥-¥-¥>/$user_icon/g;
$_ =‾ s/¥<¥!¥-¥-¥-admin_message¥-¥-¥-¥>/$admin_message/g;
$_ =‾ s/¥<¥!¥-¥-¥-admin_icon¥-¥-¥-¥>/$admin_icon/g;
}
}
print "$LIST";
close IN;
#---フッタの表示-------------------------------------------------------
open IN, "$foot" || &error("ファイルがオープンできません");
while(<IN>){
$data=$_;
$FOOT .=$data;
}
print "$FOOT";
close IN;
#---ファイルのロック解除-----------------------------------------------
&unlock;
}
#---編集画面表示のサブルーチン---------------------------------------------
sub html_editor{
if($form{'pass'} ne $password){&error("パスワードが違います。");}
if($form{'num'} eq ""){&error("編集番号がありません");}
#---ファイルをロック---------------------------------------------------
&filelock || &error("ただいま混みあっています");
#---ログの読み込み-----------------------------------------------------
open IN,"+<$logfile" || &error("ログファイルがオープンできません");
@lines = <IN>;
close IN;
$num = $form{'num'};
local($no,$date,$name,$mail,$url,$user_message,$user_icon,$admin_message,$admin_icon);
($no,$date,$name,$mail,$url,$user_message,$user_icon,$admin_message,$admin_icon,$ipaddr,$hostname) = split(/<>/,$lines[$no-$num]);
#---メッセージ内の改行タグを置換---------------------------------------
$user_message =‾ s/<(?:[^>'"]*|(['"]).*?¥1)*>/¥n/gs;
$admin_message =‾ s/<(?:[^>'"]*|(['"]).*?¥1)*>/¥n/gs;
open (IN, "$editor") || &error("ファイルがオープンできません");
while(<IN>){
$data=$_;
$EDIT .=$data;
}
foreach($EDIT){
$_ =‾ s/¥<¥!¥-¥-¥-no¥-¥-¥-¥>/$num/g;
$_ =‾ s/¥<¥!¥-¥-¥-date¥-¥-¥-¥>/$date/g;
$_ =‾ s/¥<¥!¥-¥-¥-name¥-¥-¥-¥>/$name/g;
$_ =‾ s/¥<¥!¥-¥-¥-mail¥-¥-¥-¥>/$mail/g;
$_ =‾ s/¥<¥!¥-¥-¥-url¥-¥-¥-¥>/$url/g;
$_ =‾ s/¥<¥!¥-¥-¥-user_icon¥-¥-¥-¥>/$user_icon/g;
$_ =‾ s/¥<¥!¥-¥-¥-user_message¥-¥-¥-¥>/$user_message/g;
$_ =‾ s/¥<¥!¥-¥-¥-admin_icon¥-¥-¥-¥>/$admin_icon/g;
$_ =‾ s/¥<¥!¥-¥-¥-admin_message¥-¥-¥-¥>/$admin_message/g;
$_ =‾ s/¥<¥!¥-¥-¥-ipaddr¥-¥-¥-¥>/$ipaddr/g;
$_ =‾ s/¥<¥!¥-¥-¥-hostname¥-¥-¥-¥>/$hostname/g;
}
print "Content-type: text/html¥n¥n";
print "$EDIT";
close IN;
#---フッタの表示-------------------------------------------------------
open IN, "$foot" || &error("ファイルがオープンできません");
while(<IN>){
$data=$_;
$FOOT .=$data;
}
print "$FOOT";
close IN;
#---ファイルのロック解除-----------------------------------------------
&unlock;
}
#---修正のためのサブルーチン-----------------------------------------------
sub html_modify{
#---ファイルをロック---------------------------------------------------
&filelock || &error("ただいま混みあっています");
open (IN,"+<$logfile") || &error("ログファイルがオープンできません");
while(<IN>){
$data = $_;
chop $data;
@fnum = split(/<>/,$data);
if($fnum[0] == $form{'num'}){
$data = join('<>',$fnum[0],$fnum[1],$form{'mname'},$form{'mmail'},$form{'murl'},$form{'muser_message'},$form{'muser_icon'},$form{'madmin_message'},$form{'madmin_icon'},$form{'mipaddr'},$form{'mhostname'});
}
push @data,$data;
}
close IN;
open (OUT,">$logfile") || &error("書きこみができません");
foreach (@data){
print OUT $_,"<>¥n";
}
close OUT;
#---ファイルのロック解除-----------------------------------------------
&unlock;
}
#---デコード処理サブルーチン-----------------------------------------------
sub decode {
local($name, $value, @pairs);
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $form_data, $ENV{'CONTENT_LENGTH'});
} else {
$form_data = $ENV{'QUERY_STRING'};
}
@pairs = split(/&/, $form_data);
foreach (@pairs) {
($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/</</g;
$value =‾ s/>/>/g;
#---改行処理-------------------------------------------------------
$value =‾ s/¥r//g;
$value =‾ s/¥n/<BR>/g;
#---文字コード処理-------------------------------------------------
&jcode'convert(*value,'euc');
&jcode'h2z_euc(*value);
&jcode'convert(*value,'sjis');
&jcode'h2z_sjis(*value);
$form{$name} = $value;
}
$mode = $form{'mode'};
}
#---日時取得サブルーチン:現在日時を文字列化する---------------------------
sub get_time {
$ENV{'TZ'} = "JST-9";
$times = time;
($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime($times);
@week = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
#---日時のフォーマット-------------------------------------------------
$date = sprintf("%04d/%02d/%02d(%s) %02d:%02d",
$year+1900,$mon+1,$mday,$week[$wday],$hour,$min);
}
#---クッキーの取得のサブルーチン-------------------------------------------
sub get_cookie {
local($key, $val, @pairs);
@pairs = split(/;/, $ENV{'HTTP_COOKIE'});
foreach (@pairs) {
($key, $val) = split(/=/);
$key =‾ s/¥s//g;
$tmp{$key} = $val;
}
@pairs = split(/<>/, $tmp{'CGI_BBS'});
foreach (@pairs) {
($key, $val) = split(/:/);
$ck{$key} = $val;
}
$ck_name = $ck{'name'};
$ck_mail = $ck{'mail'};
if ($form{'name'}) {
$ck_name = $form{'name'};
}
if ($form{'mail'}){
$ck_mail = $form{'mail'};
}
}
#---クッキー発行のサブルーチン---------------------------------------------
sub set_cookie {
local($sec,$min,$hour,$mday,$mon,$year,$wday) = gmtime(time + $cookiedays*24*60*60);
@mon = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
$gmt = sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",
$week[$wday],$mday,$mon[$mon],$year+1900,$hour,$min,$sec);
$cook = "name¥:$form{'name'}¥<>mail¥:$form{'mail'}";
print "Set-Cookie: CGI_BBS=$cook; expires=$gmt¥n";
}
#---IPアドレス、ホスト名取得及び不正アクセス制限機能のサブルーチン---------
sub gethost {
$ipaddr = $ENV{'REMOTE_ADDR'};
unless ($hostname = $ENV{'REMOTE_HOST'}){
$hostname = (gethostbyaddr(pack("C4",split(/¥./,$ENV{'REMOTE_ADDR'})),2))[0];
}
for (@noaccess){
&error('過去に同一ホストから不適切なアクセスがあったため、アクセス制限されています。') if ($hostname =‾ /$_/);
}
return;
}
#---エラー表示サブルーチン-------------------------------------------------
sub error {
($error,$error_fields) = @_;
print "Content-type: text/html¥n¥n";
print "<html><head>¥n";
print "<title>CGIエラー</title></head><body>¥n";
print "<br><br><br><b>error:$error</b><br><br><br>¥n";
print "<center><a href=$main_url>back</center>¥n";
print "</body></html>¥n";
#---ファイルのロック解除-----------------------------------------------
&unlock;
exit;
}
#---ファイルロックのためのサブルーチン-------------------------------------
sub filelock {
if (-e $lockfile) { #---ロック中の場合------------
local $time = (stat $lockfile)[9]; #---ファイルの更新日時--------
&unlock if ($time < time-30); #---異常ロックなら解除--------
}
local $trial = 5; #---試行回数------------------
until (mkdir $lockfile,755) {
return 0 if (0 > --$trial);
sleep(1);
}
}
#---ロック解除のためのサブルーチン-----------------------------------------
sub unlock {
rmdir $lockfile;
}
#---ログ消去のためのサブルーチン-------------------------------------------
sub html_delete{
#---ファイルをロック---------------------------------------------------
&filelock || &error("ただいま混みあっています");
open (IN,"+<$logfile") || &error("ログファイルがオープンできません");
while(<IN>){
$data = $_;
chop $data;
@fnum = split(/<>/,$data);
if($fnum[0] != $form{'num'}){
push @data,$data;
}
}
$new_num=@data;
close IN;
open (OUT,">$logfile") || &error("書きこみができません");
foreach (@data){
print OUT $_,"<>¥n";
}
close OUT;
&modify_num;
}
#---ログ番号書き換えサブルーチン-------------------------------------------
sub modify_num{
open (IN,"+<$logfile") || &error("ログファイルがオープンできません");
while(<IN>){
$data=$_;
chop $data;
@mnum = split(/<>/,$data);
($del,@mnum)=@mnum;
unshift @mnum,$new_num;
$new_num=$new_num-1;
$mnum = join("<>",@mnum);
push @data2,$mnum;
}
close IN;
open (OUT,">$logfile") || &error("書きこみができません");
foreach (@data2){
print OUT $_,"<>¥n";
}
close OUT;
#---ファイルのロック解除-----------------------------------------------
&unlock;
}