□Perl 講座 特別編 > 最終組み立て

一つにまとめよう!

いよいよ、大詰めです!今までご紹介してきました、各パーツを一つにまとめていきたいと思います。メインの流れと、プログラムの繋がりにやっている処理を注意しながら見てくださいね。まとまったら、実際にアップロードして、ちゃんと動くか確かめてみましょう!

>最終組み立て>第一段階

まずは、始めにお約束の物を記述していきます!
#!/usr/local/bin/perl

#--------------------------#
#   簡易掲示板プログラム
#--------------------------#

$|=1; #データのフラッシュ
require './jcode.pl'; #jcode.plへのパス
print "Content-type: text/html\n\n"; # データ形式

exit;

一行目は、ご利用いただいているサーバで指定してされている物を間違いなく記述してください。例えば、@niftyでしたら、#!/usr/local/bin/perlとなります。

>最終組み立て>第二段階

次に今まで書き溜めたサブルーチンを下に書き加え(コピー)ます。
#!/usr/local/bin/perl

#--------------------------#
#   簡易掲示板プログラム
#--------------------------#

$|=1; #データのフラッシュ
require './jcode.pl'; #jcode.plへのパス
print "Content-type: text/html\n\n"; # データ形式

exit;

#デコードするためのプログラム
sub decode {

    # プラウザからのデータ取込み
    if ($ENV{'REQUEST_METHOD'} eq "POST") {
        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
    }
    else {
        $buffer = $ENV{'QUERY_STRING'};
    }

    # プラウザからのデータ変換
    @pairs = split(/&/,$buffer);
    foreach $pair (@pairs) {
        #1行毎に$name,$valueを取り出す
        ($name, $value) = split(/=/, $pair);
        # 変換演算子  tr  +  を  スペースに置き換え
        $value =~ tr/+/ /;
        # 変換演算子  s/// 単語の構成文字にマッチ
        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

        # " を " に変換
        $value =~ s/"/"/g;
        #\n を "" に変換
        # $value =~ s/\n//g;

        # 日本語に変換(デコード処理部分)
        &jcode'convert(*value,'sjis');
        &jcode'convert(*name,'sjis');
        $FORM{$name} = $value;
    }
}

#書込み処理プログラム
sub write {

    #ファイルのオープン  予め$fileにログファイル名が代入されている物とします。
    open(IN,"$file") || &error("Can't open $file");
    open(OUT,">$temp") || &error("Can't write Temp File");

    #ログファイルを配列@linesに代入
    @lines = <IN>;

    #ログの逆順処理
    @lines = reverse(@lines);

    #2重書込み禁止ルーチン
    foreach $line (@lines) {
        &jcode'convert(*line,'sjis');
        local($s1,$s2,$s3,$s4) = split(/<>/,$line);
        if (($s1 eq $s1) && ($s4 eq $msr)){
            &error("二重書き込みは禁止です!!");
        }
    }
    #書き込むデータの順番を決定
    $newrecode="$name<>$email<>$url<>$msr<>\n";

    #配列@linesにデータをPUSH
    push (@lines,$newrecode);

    #ログの逆順処理
    @lines = reverse(@lines);

    #ログの書込処理
    print OUT @lines;
    close(OUT);
    close(IN);
    rename($temp,$file) || &error("Rename Error");
    chmod (0666,$file);
    if (-e $temp) { unlink($temp); }
}

#メイン表示プログラム
sub html {

    #ヘッダの読込
    &header;

    #ログの読込
    open(IN,"$file") || &error("Can't open $file");
    @lines = <IN>;
    close(IN);

    #ログ全部?
    foreach $line (@lines) {
        local($name<>$email<>$url<>$msr) = split(/<>/,$line);
        &output;
    }

    #フッタの読込
    &footer;
exit;
}

#ヘッダ部分プログラム
sub header {
    print <<"EOT";
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<TITLE>簡易掲示板</TITLE>
</HEAD>
<BODY>
<P>簡易掲示板</P>
<FORM action="bbs.cgi" method="POST">
<INPUT type="hidden" name="mode" value="write">
なまえ:<INPUT size="20" type="text" name="name"><BR>
E-mail:<INPUT size="20" type="text" name="email"><BR>
URL:<INPUT size="50" type="text" name="url" value="http://"><BR>
メッセージ:<BR>
<TEXTAREA rows="5" cols="50" name="msr"></TEXTAREA><BR>
<INPUT type="submit" value="投稿する"><INPUT type="reset" value="クリア">
</FORM>
<HR>
EOT
}

#リピート部分プログラム
sub output {
  print <<"EOT";
投稿者:$FORM{'name'}
E-mail:<A href="mailto:$FORM{'email'}">$FORM{'email'}</A><BR>
Homepage:<A href="$FORM{'url'}" target="_blank">$FORM{'url'}</A><BR>
投稿内容<BR>
$msr
<HR>
EOT
}

#フッタ部分プログラム
sub footer {
  print <<"EOT";
<HR>
</BODY>
</HTML>
EOT
}

#エラー処理プログラム
sub error {
  print <<"EOT";
<HTML>
<HEAD><TITILE>ERROR</TITLE></HEAD>
<BODY>
<CENTER>
<H3>ERROR !</H3>
<FONT color=red><B>$_[0]</B></FONT>
<HR width=\"90%\">
</CENTER>
</BODY>
</HTML>
EOT
  exit;
}
なんかプログラムっぽくなってきたでしょ?(^-^;;;

>最終組み立て>最終段階

フローチャート1さて、最終段階!!

左図は一番最初に説明した、全体の流れのフローチャートです。これに沿って、第二段階で書き加えた物に流れのプログラムと設定をしていってあげます。

判りやすいように、書き加えたところは文字の色を変えてありますので、流れと見比べてみてください。

書き加える物は
  • ログファイル名の指定など
  • メインルーチン(流れのプログラム)
  • サブルーチンのつなぎ部分
背景色など良く変えるところ?変えたいところなどは、変数に色コードを代入してあげて、それに対応する場所(HTML部分)に変数を挿入しておくと、後々の編集や改造が楽になります。



#!/usr/local/bin/perl

#--------------------------#
#   簡易掲示板プログラム
#--------------------------#

$|=1; #データのフラッシュ
require './jcode.pl'; #jcode.plへのパス
print "Content-type: text/html\n\n"; # データ形式

$file = "bbs.log"; #ログファイルの設定
$temp = "./temp.dat"; #テンポラリーファイル
$bgcolor = "#ffffff"; #掲示板の背景色設定
$home = "../indec.htm"; #戻り先URL

#メインルーチン
&decode;
if ($FORM{'mode'} eq 'write') { &write; }
&html;


exit;

#デコードするためのプログラム
sub decode {

    # プラウザからのデータ取込み
    if ($ENV{'REQUEST_METHOD'} eq "POST") {
        read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
    }
    else {
        $buffer = $ENV{'QUERY_STRING'};
    }

    # プラウザからのデータ変換
    @pairs = split(/&/,$buffer);
    foreach $pair (@pairs) {
        #1行毎に$name,$valueを取り出す
        ($name, $value) = split(/=/, $pair);
        # 変換演算子  tr  +  を  スペースに置き換え
        $value =~ tr/+/ /;
        # 変換演算子  s/// 単語の構成文字にマッチ
        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

        # " を &quot; に変換
        $value =~ s/"/&quot;/g;
        #\n を "" に変換
        # $value =~ s/\n//g;

        # 日本語に変換(デコード処理部分)
        &jcode'convert(*value,'sjis');
        &jcode'convert(*name,'sjis');
        $FORM{$name} = $value;
    }
}

#書込み処理プログラム
sub write {

    #フォームの入力状況確認
    if ($FORM{'name'} eq '') { &error("お名前が入力されていません。"); }
    if ($FORM{'msr'} eq '') { &error("メッセージが入力されていません。"); }


    #ファイルのオープン  予め$fileにログファイル名が代入されている物とします。
    open(IN,"$file") || &error("Can't open $file");
    open(OUT,">$temp") || &error("Can't write Temp File");

    #ログファイルを配列@linesに代入
    @lines = <IN>;

    #ログの逆順処理
    @lines = reverse(@lines);

    #2重書込み禁止ルーチン
    foreach $line (@lines) {
        &jcode'convert(*line,'sjis');
        local($s1,$s2,$s3,$s4) = split(/<>/,$line);
        if (($s1 eq $name) && ($s4 eq $msr)){
            &error("二重書き込みは禁止です!!");
        }
    }
    #書き込むデータの順番を決定
    $newrecode
    ="$FORM{'name'}<>$FORM{'email'}<>$FORM{'url'}<>$FORM{'msr'}<>\n";

    #配列@linesにデータをPUSH
    push (@lines,$newrecode);

    #ログの逆順処理
    @lines = reverse(@lines);

    #ログの書込処理
    print OUT @lines;
    close(OUT);
    close(IN);
    rename($temp,$file) || &error("Rename Error");
    chmod (0666,$file);
    if (-e $temp) { unlink($temp); }
}

#メイン表示プログラム
sub html {

    #ヘッダの読込
    &header;

    #ログの読込
    open(IN,"$file") || &error("Can't open $file");
    @lines = <IN>;
    close(IN);

    #ログ全部?
    foreach $line (@lines) {
        local($name,$email,$url,$msr) = split(/<>/,$line);
        &output;
    }

    #フッタの読込
    &footer;
exit;
}

#ヘッダ部分プログラム
sub header {
    print <<"EOT";
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<TITLE>簡易掲示板</TITLE>
</HEAD>
<BODY bgcolor="$bgcolor">
<A href="$home">HOME</A><BR>
<P>簡易掲示板</P>
<FORM action="bbs.cgi" method="POST">
<INPUT type="hidden" name="mode" value="write">
なまえ:<INPUT size="20" type="text" name="name"><BR>
E-mail:<INPUT size="20" type="text" name="email"><BR>
URL:<INPUT size="50" type="text" name="url" value="http://"><BR>
メッセージ:<BR>
<TEXTAREA rows="5" cols="50" name="msr"></TEXTAREA><BR>
<INPUT type="submit" value="投稿する"><INPUT type="reset" value="クリア">
</FORM>
<HR>
EOT
}

#リピート部分プログラム
sub output {
    print <<"EOT";
投稿者:$name
E-mail:<A href="mailto:$email">$email</A><BR>
Homepage:<A href="$url" target="_blank">$url</A><BR>
投稿内容<BR>
$msr
<HR>
EOT
}

#フッタ部分プログラム
sub footer {
    print <<"EOT";
<HR>
</BODY>
</HTML>
EOT
}

#エラー処理プログラム
sub error {
    print <<"EOT";
<HTML>
<HEAD><TITILE>ERROR</TITLE></HEAD>
<BODY>
<CENTER>
<H3>ERROR !</H3>
<FONT color=red><B>$_[0]</B></FONT>
<HR width=\"90%\">
</CENTER>
</BODY>
</HTML>
EOT
    exit;
}
※注意・・・ソースをコピー&ペーストして使いたい場合はこちらからコピーしてください。
>最終組み立て>最後に
さぁ、完成したら実際に動かしてみてください。

[Sample]
[Download]

フォルダ ファイル名 パーミッション
bbs/ bbs.cgi 755
/ log_bbs1.dat 666
/ jcode.pl 644

※格納するフォルダは777にして下さい。サーバ側で777を禁止している場合はこの限りではありません。

□特別編 一緒に簡易掲示板を作ってみよう