#!/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"){

    #---書き込み---

    &regist;

    &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/¥&/&amp;/g;

        $value =‾ s/"/&quot;/g;

        $value =‾ s/</&lt;/g;

        $value =‾ s/>/&gt;/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;

}