Perl/ActivePerl For UNIX/Linux/Windows
 
TryThe Homepage
初めてのCGI
CGI 研究室
ダイナミックCGI
ダウンロード
サービス
サーバ構築(Windows)
データベースアクセス
有料サービス
FAQ
お問い合わせ
このページを印刷
落書き張で学ぶPerl講座
書き込みボードを生成する方法は、大きく分けて2つ有ります。 1つは、入力データをHTMLコードに変換して、HTMLドキュメントに追加する方法。 もう1つは、入力されたデータをデータファイルに保存し、ブラウザから呼び出されたとき、HTMLドキュメントを生成する方法です。
当サイトで紹介するスクリプトは、すべて後者のデータベース形式を採用しています。 前者は、書き込まれるHTMLドキュメントファイルが必要なため、入力フォームと、表示するドキュメントファイルが別々に必要です。 しかも、書き込み後、結果が「すぐに」反映されません。ブラウザが一度読み込んだドキュメントは、キャッシュに保存し、 二度目からはキャッシュのドキュメントを展開するからです。(リロードすれば話しは別)
また、ブラウザからの条件を取得し、表示するデータや、形式を変更できないのでデータ互換を持つバージョンアップも行なえません。
ここで紹介する「落書き帳」も、rakugaki.cgi スクリプトと、rakugaki.txt データファイルで動作し、 ブラウザから呼び出されるのは、スクリプトだけです。

rakugaki.cgi
  1. メインルーチン
    基本的なデータの取得や、処理の流れを決めています。 あなたが加入しているプロバイダのperlが実行できるパスを指定します。
    一般的に、#!/usr/bin/perや、#!/usr/local/bin/perlが多いようです。
    #!/usr/local/bin/perl
    ここからが本文。この上に空行を1行開けましょう。
    日本語変換ライブラリの宣言
    require 'jcode.pl';
    登録ボタンが押され、データを書き込み後ブラウザをリフレッシュするために「落書き帳」を設置するURLを指定します。
    $rakugakiurl = 'http://www.tryhp.net/cgi-bin/rakugaki.cgi';
    #データを保存するファイルの名前を指定します。
    $rakugakifile = 'rakugaki.txt';
    #現在日付と時刻をシステムから取得し、フォーマットを整えます。
    #localtime関数が返す値をそれぞれ変数に代入します。
    ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    $year += 1900;
    #取得した数値を2桁に統一します。2桁に統一するのは、見た目をよくするだけでなく、
    #日付による昇順、降順の並び替えを行なうためです。
    #並び替えは、アスキーコードで行なわれますので、
    #「2」と「10」では「10」が小さいと判断されるからです。
    #「月」のデータは、0から11なので、1プラスする。
    $mon = sprintf("%02d", $mon + 1);
    $day = sprintf("%02d", $day);
    $hour = sprintf("%02d", $hour);
    $min = sprintf("%02d", $min);
    #フォーマットを整えます。
    #ダブルクォート「”」で囲まれた定数の中の変数は自動で展開されます。
    $date_now = "$year年$mon月$day日 $hour時$min分";
    フォームからのデータを変数$formdataに取得
    メソッドプロパティーによって取得方法が異なりますので、どちらでも取得できるようにします。
    if ($ENV{'REQUEST_METHOD'} eq "POST") {
      read(STDIN, $QUERY_DATA, $ENV{'CONTENT_LENGTH'});
    } else { $formdata = $ENV{'QUERY_STRING'}; }
    フォーから送られてきたデータは、name=京子&email=kyouko@abc.biglobe.ne.jp&comment=始めまして京子です。
    のように、「&」で区切られて送られてきます。このデータを分解し、ペアにします。
    @pairs = split(/&/,$QUERY_DATA);
    foreach $pair (@pairs) {
      ($name, $value) = split(/=/, $pair);
      #不必要な文字を削除し、デコードします。
      $value =~ tr/+/ /;
      $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
      #タグが入力されていれば、それを無効にします。
      $value =~ s/</&lt;/g;
      $value =~ s/>/&gt;/g;
      $value =~ s/\n//g;
      $value =~ s/\,//g;
      #最初に宣言した日本語変換ライブラリを呼び出し、シフトjisに変換
      &jcode'convert(*value,'sjis');
      #分解したデータをキーで呼び出せるよう、連想配列に格納します。
      $FORM{$name} = $value;
    }
    このスクリプトが何処から呼び出されたかで処理を分岐します。
    フォームから呼び出されたのであれば、$FORM{'action'}が「true」に、 初めて呼び出されたのなら$FORM{}変数に'action'という名前すら存在しない。
    $FORM{'action'}が「true」ならフォームからなので書き込みルーチンへ、
    if ($FORM{'action'} eq "true") { &regist; }
    #それ以外ならHTMLドキュメントを生成する
    else { &html; }

  2. HTMLドキュメント生成ルーチン
    sub html {
      #データファイルを読み込みモードオープンし、
      #すべてのデータを配列変数@DATAに格納します。
      if (!open(NOTE,"$rakugakifile")) { &error(bad_file); }
      @DATA = <NOTE>;
      close(NOTE);
      #読み込まれたデータは、登録順(古い順)に保存されているので、新しい順に並び替えます。
      @DATA = reverse(@DATA);
      #HTMLドキュメントを生成します。
      print "Content-type: text/html\n\n";
      print "<!DOCTYPE HTML PUBLIC -//IETF//DTD HTML//EN>\n";
      print "<html>\n";
      print "<head>\n";
      print "<meta http-equiv=Content-Type content= text/html; charset=x-sjis>\n";
      print "<title>落書き帳</title></head>\n";
      #バックグランドと文字色を指定
      print "<body bgcolor=#000000 text=#FFFFFF>\n";
      #ドキュメントの上部、コメント入力フォームを生成
      #[言いたい]ボタンが押されると入力されたデータを持ってrakugaki.cgiを再度呼び出します。
      print "<form action=rakugaki.cgi method=POST>\n";
      #1つのスクリプトで処理を分岐するため、見えないフラグを設定
      print "<input type=hidden name=action value=true>\n";
      print "<div align=center><center>\n";
      print "<table border=1 cellspacing=1>\n";
      print "<tr>\n";
      print "<td align=center>ニックネーム</td>\n";
      print "<td><input type=text size=29 name=name></td>\n";
      print "</tr>\n";
      print "<tr>\n";
      print "<td align=center>E-mail</td>\n";
      print "<td><input type=text size=29 name=email></td>\n";
      print "</tr>\n";
      print "<tr>\n";
      print "<td align=center>言いたい</td>\n";
      print "<td><textarea name=comment rows=4 cols=68></textarea></td>\n";
      print "</tr>\n";
      print "<tr>\n";
      print "<td align=center colspan=2><input type=submit value=書いちゃえ></td>\n";
      print "</tr>\n";
      print "</table></center></div>\n";
      print "</form>\n";
      #ここまでが入力フォーム
      #ここからが、落書き記事を生成します。
      print "<div align=center><center>\n";
      #保存されているデータがなくなるまで繰り返す。
      foreach $line (@DATA) {
        #ファイルから読み込んだデータの最後には改行文字がついているので除去
        chop($line);
        #1行のデータを各項目に分解します。
        #日付、名前、メール、コメントの順に格納されます。
        #それ以降の$d1〜$d4は将来のバージョンアップのためダミーのデータにします。
        ($date,$name,$email,$comment) = split(/\,/,$line);
        #コメント変数の中の改行文字「\r」を「<br>」に変換して、
        #訪問者が入力した通りに表示します。
        $comment =~ s/\r/<br>/g;
        print "<table border=0 width=80% bgcolor=#FFFFFF>\n";
        print "<tr>\n";
        print "<td><font color=#000000>\n";
        #メールアドレスが入力されていればリンクを付けます。
        if ($email ne "") {
          print "<a href=mailto:$email><strong>$name</strong></a>\n";
        } else { print "<strong>$name</strong>\n"; }
        print "  $date<br>\n";
        print "<blockquote>$comment</blockquote>\n";
        print "</font>\n";
        print "</td>\n";
        print "</tr>\n";
        print "</table>\n";
        print "<p>";
      }
      print "</center></div>\n";
      print "</body></html>\n";
      exit;
    }

  3. データ書き込みルーチン
    sub regist {
      #名前か、コメントが入力されていなければエラーを出力します。
      if ($FORM{'name'} eq "") { &error(bad_name); }
      if ($FORM{'comment'} eq "") { &error(bad_comment); }
      #データファイルを追加モードオープンして、入力データを最後の行に追加します。
      if (!open(NOTE,">>$rakugakifile")) { &error(bad_file); }
      $value = "$date_now\,$FORM{'name'}\,$FORM{'email'}\,$FORM{'comment'}\n";
      print NOTE $value;
      close(NOTE);
      #追加したデータをブラウザに反映させるため落書き帳をリロードします。
      print "Location: $rakugakiurl" . '?' . "\n\n";
    }

  4. エラー処理
    sub error {
      #サブルーチンに渡された引数参照のための配列
      $error = $_[0];
      #引数によるエラーメッセージの生成
      if ($error eq "bad_file") { $msg = 'ファイルのオープン、入出力に失敗しました。'; }
      elsif ($error eq "bad_name") { $msg = 'ニックネームが記入されていません。'; }
      elsif ($error eq "bad_comment") { $msg = 'コメントが記入されていません。'; }
      else { $msg = '原因不明のエラーで処理を継続できません。'; }
      #エラーメッセージ表示のHTMLドキュメントの生成
      print "Content-type: text/html\n\n";
      print "<html><head><title>落書き帳</title></head>\n";
      print "<body bgcolor=#000000 text=#FFFFFF LINK=#FFAAAA VLINK=#FF8888>\n";
      print "<p>\n";
      print "<center><h2>error</h2><hr>\n";
      print "<i>" . $msg . "</i></hr></center>\n";
      print "</body></html>\n";
      exit;
    }
Copyright 2004 Terra. All rights reserved. No reproduction or republication without written