□Perl 講座 特別編 > ページ機能

◆ページ処理も目印があれば簡単

書き込み数が多くなってくれば、いつまでも1つのページに記事出力させるわけには行きません。もちろん出来ますが、重たいページになってしまいますよね?そこで、1ページに出力する数を決めてあげて分割して出力するようにしてあげましょう!
ページ処理の最もポピュラーな方法として、次ぎの10件・前の10件などのフォームボタンでページ移動できる方法を今回は説明していきます。この他にも、何ページ目かを選択して直接そのページに飛べるようにする方法などもありますが、それはいつか何処かで・・・。

>記事削除>第一段階

ページを表現するにはどうしたら良いでしょうか?表現方法は色々ありますが、大雑把に言うと、目印を付けてあげてそれで出力部分を判別させる!につきます。まず決めなくてはならないのが、1ページあたり幾つの投稿記事を出力するか?です。
後々自由に変更できるように$viewと言う変数にその値を代入してあげることにします。また、何ページ目(目印)を出力したいのか?を$pageにして考えてみます。ですから5ページ目だったら$page=5という訳です。

記事を出力する始点と終点を$viewと$pageで表すことができます。

始点:$start
$start = $view*($page-1)+1;

終点:$fin
$fin = $view*$page;

これらの4つの変数を使って始点から終点までの条件を満たしていれば出力させることにしてあげれば良いわけです。つまりここで一緒に作っていっているプログラム上では表示処理のリピート部分の呼び出し(&output)をしている場所に4つの変数を用いて条件を課してあげればいい事になります。

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

    #始点・終点の計算
    $start = $view*($page-1)+1;
    $fin = $view*$page;


    #ヘッダの読込
    &header;

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

    #ログ全部?
    foreach $line (@lines) {
        local($name,$email,$url,$msr) = split(/<>/,$line);
        #カウント処理
        $count = $count + 1;
        if (($count >= $start) && ($count <= $fin)) {
            &output;
        }
    }

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

>記事削除>第二段階

次へや戻るのボタンを表示させなくてはなりません。それは現在表示されているページが何ページかが解れば、当然前後するページの値$pageの値が解ります。但し気をつけなくてはならない点は1ページ目です。

ボタンを表示させたい場所によっても変わりますが、今回はフッタ部分に表示させることにしましょう。
#フッタ部分プログラム
sub footer {

    #前のページと次のページの計算
    $forward = $page + 1;
    $back = $page - 1;

    print <<"EOT";
<HR>
<TABLE><TR>
<TD>
<FORM action="bbs.cgi" method="POST">
<INPUT type=hidden name="page" value="$back">
<INPUT type=submit value="前の$view件">
</FORM>
</TD>
<TD>
<FORM action="bbs.cgi" method="POST">
<INPUT type=hidden name="page" value="$forward">
<INPUT type=submit value="次の$view件">
</FORM>
</TD>
</TR></TABLE>
</BODY>
</HTML>
EOT
}

当然一ページ目には前へのボタンは不要ですし、最後のページには次へのボタンは不要になってきます。ですから、ページが一番目の場合は前へのボタンは表示しないように制限をかけ、同様に最後のページも一緒です。最後のページに関しては、現在のページでは$countと投稿記事数(@lines)が一致するはずですから、その際に表示をしないようにします。

#フッタ部分プログラム
sub footer {

    #前のページと次のページの計算
    $forward = $page + 1;
    $back = $page - 1;

    print <<"EOT";
<HR>
<TABLE><TR>
<TD>
EOT
    if ($page != 1) {
    print <<"EOT";

<FORM action="bbs.cgi" method="POST">
<INPUT type=hidden name="page" value="$back">
<INPUT type=submit value="前の$view件">
</FORM>
EOT
    }

    print <<"EOT";

</TD>
<TD>
EOT

    $last = @lines;
    $seki = $page * $view;
    if ($seki < $last) {
    print <<"EOT";

<FORM action="bbs.cgi" method="POST">
<INPUT type=hidden name="page" value="$forward">
<INPUT type=submit value="次の$view件">
</FORM>
EOT
    }

    print <<"EOT";
</TD>
</TR></TABLE>
</BODY>
</HTML>
EOT
}

>記事削除>最後に

最後にボタンでページ数の情報をやり取りするわけですから、デコード部分も書き加えなければなりません。また、1ページ目は$pageに値が入ってない状態が考えられますので、$pageに値が入っていなければ1ページ目だと言うことを決めてあげなくてはなりません。

#デコードするためのプログラム
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;
    }
    #ページ数を$pageに代入
    $page = $FORM{'page'};

    #$pageに何も入っていなければ、1を代入
    if ($page eq '') { $page = 1; }

}

以上で、ページ処理の追加改造ができました。他にもいろいろ考えられると思います。試してみてください。やっても上手く動かない場合はお気軽に掲示板で質問してください。

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