CGIのサンプルプログラム(名簿作成)

  1. 目的
    ここでは、htmlのファーム入力とCGIによるファイルへの登録と表示例を紹介します。この例だけで、閉じた説明をしますが、Perl言語の詳細な説明はこちらを参照してください。
     対象は名簿の作成です。名簿の名前は住所は本人は入力が慣れていますが、他の人は入力しずらいものです。そこで、ホームページから自分の名簿を登録できるようにしました。ただし、名簿情報は個人情報ですので、第三者には見えないよう、また、イタズラ書込みを防止するため、キーワードによる制限を付けます。

  2. 入力用ホームページ

    1. 入力用html

      入力には、htmlのFORMとINPUTタグを利用します。次にページのhtml記述を示します。入力用の記述は<FORM>タグの内部で記述されます。先頭の<FORM METHOD=GET ACTION="adrsBook.cgi">で、以下の入力を CGI に送る方法(GET)と、それを処理する CGIi プログラム(adrsBook.cgi)を指定します。
       以下、テーブル形式に、<INPUT TYPE="text" NAME="yomi" SIZE=10> で、文字入力を指定します。この場合、1行入力(text)タイプで、yomiの名前で、名前の読みを入力する10文字の入力領域を設定します。同様に、名前(漢字)、住所、電話番号、等を設定する領域を作成します。
       TYPE="hidden"は、表示をしない入力で、CGI に対する「隠し」情報を設定します。この例の場合、 mode = record (この入力は record モードで利用する)の情報を、CGI に送ります。TYPE="password" パスワードの入力用で、入力した文字が伏せ字で表示されます。
       TYPE="submit" は特殊なボタンの役割を果たします。「登録」の名前のボタンが表示され、このボタンを押すと、webサーバーを経由して、FORMで指定した CGI がサーバー上で起動され、入力された文字情報が cgi (adrsBook.cgi)に渡されます。 
      <html>
      <head>
       <title>名簿作成</title>
      </head>
      <body>
      
      <h3>名簿への入力をお願いします</h3>
      
        <FORM METHOD=GET ACTION="adrsBook.cgi">
        <TABLE>
          <TR><TD>名前(よみ)*</TD><TD><INPUT TYPE="text" NAME="yomi" SIZE=10></TD><TR>
          <TR><TD>名前(漢字)*</TD><TD><INPUT TYPE="text" NAME="name" SIZE=20></TD><TR>
          <TR><TD>住所</TD><TD><INPUT TYPE="text" NAME="adrs" SIZE=40></TD><TR>
          <TR><TD>E-Mail*</TD><TD><INPUT TYPE="text" NAME="mail" SIZE=30></TD><TR>
          <TR><TD>電話番号</TD><TD><INPUT TYPE="text" NAME="phone" SIZE=16></TD><TR>
          <TR><TD><INPUT TYPE="hidden" NAME="mode" VALUE="record">パスワード*</TD>
          <TD><INPUT TYPE="password" NAME="pwd" SIZE=12>
          <INPUT TYPE="submit" VALUE="登録"></TD>
        </TABLE></FORM>
        
       <h3>名簿を見る</h3>
       <TABLE>
       <FORM METHOD=GET ACTION="adrsBook.cgi">
       <INPUT TYPE="hidden" NAME="mode" VALUE="view">
       <TR><TD>パスワード*</TD><TD><INPUT TYPE="password" NAME="pwd" SIZE=12>
          <INPUT TYPE="submit" VALUE="見る"></TD>
       </TABLE></FORM>
       </body>
       </html>

    2. 表示用のhtml
      上のhtmlの後半は、名簿の表示用の CGI の呼び出しです。といっても、利用しているのは同じプログラムで、
       <INPUT TYPE="hidden" NAME="mode" VALUE="view">
      により、modeの値をviewにして、同じCGIプログラムを実行します。このときは、他にパスワードの値を渡します。

    3. FORM情報とURLエンコード
       textタイプのINPUTタグに入力した情報は、NAME=入力文字 の形で、CGI に渡されます。例えば、 
        <INPUT TYPE="text" NAME="yomi" SIZE=10>
      で、abcと入力すると、 yomi=abc の文字列が CGI に渡されます。複数の INPUT タグが指定されている場合、これらの値が & で結合された文字列が渡されます。ただし、漢字は英数字以外の文字列を含むため、16進文字に変換されます。また、空白は区切り文字として利用されるため、 + 文字に変換されます。この変換を URLエンコードといいます。

    4. Form入力ページへの接続
      ここから、Form入力ページにリンクします。項目を入力し、パスワード(1234)を入力して「登録」ボタンを押すと登録され、名簿を見る、の「見る」ボタンで、登録した内容を表示できます。適当に入力し実行してください。追加すると、先頭の記事が削除されます。


  3. CGIプログラム
    1. Perlプログラム
      Perlは Practical Extraction and Report Language で、文字列のパターン照合と生成が得意な言語です。正規表現によるパターンパッチング、連想記憶機能、などを持ち、webと連携した小規模のサーバー側の処理(CGI)の記述によく利用されています。ここでは、Perl言語の詳細は説明できませんが、どのような処理をしているか、を中心に CGI の処理を説明します。

    2. CGIの主要な処理
      以下が、CGIの先頭のPerlプログラミングです。最初の #!/usr/local/bin/perl は、Perlの処理系の存在する場所を示すもので、サーバーにより異なります。次の use はライブラリの指定で、strict は、厳密な変数のチェックを指示します。Perlの場合、一般には変数の宣言をしないで利用することができますが、strictはあらかじめ変数を宣言しないで利用すると、エラーとして処理します。C言語などになれている人は strict の指定を推奨します。次の use CGI は CGI でよく利用されるCGI系の関数(サブルーティン)を利用するとき、指定します。# 以後の文字は注釈として扱われます。

      #!/usr/bin/perl
      use strict;#定義のない変数はエラーとする
      use CGI qw(:standard);#CGIライブラリを利用する
      use CGI::Carp qw(fatalsToBrowser);#重要なエラーを表示する
      CGI全体のソースプログラムはこちらを参照してください。

    3. 変数と関数呼び出し

       my $postData は変数$postData を宣言します。my が変数の宣言で、Perlでは変数の先頭には必ず$が必要です。変数は文字列を記録します。数字も文字列として扱われます。

        my $postData = &get_PostData();#フォームデータ取得
        my $hash_ref = &set_FormData($postData);#フォームデータを連想配列に記録
        my %form = %$hash_ref;#連想配列をformの名前で参照する
        my $pass='1234';#パスワード
      &get_PostData()は、サブルーティン(関数)の呼び出しで、サーバー経由で渡される、フォーム入力の文字列を取得します。 my $postData = &get_PostData(); はその文字列を変数  $postData に記録します。

        my $hash_ref = &set_FormData($postData); #フォームデータを連想配列に記録
        my %form = %$hash_ref; #連想配列をformの名前で参照する

      では、フォーム入力された文字列を、名前毎に「連想配列」に記録し、その配列を form の名前で参照することを指示します。「連想配列」の利用法は、後で説明します。
       my $pass='1234' は、表示や登録で利用するパスワードを設定します。

    4. 隠しタグによる処理の選択
       次に、CGIの処理に入ります。$form{'mode'} は、連想配列の利用で、modeの名前に対応する値を意味します。この値は、Form入力の hidden タイプで指定されています。$form{'mode'} eq 'record' は $form{'mode'} の値が record に等しい(equal)のとき、真になります。このとき、if( ) はこの条件が満たされたとき、サブルーティン record() を実行します。

       if($form{'mode'} eq 'record') {&record();} #フォームデータをファイルに保存
       if($form{'mode'} eq 'view') {&view();} #名簿を表示

      同様に、if($form{'mode'} eq 'view') {&view();} は、modeの値がview のときサブルーティン view() を実行します。Perlでは if() の後の実行部に必ず {..} が必要です。

    5. サブルーティン record()
       サブルーティン recordで、名簿を記録するファイルに、Formで入力された文字を追記します。まず、

        open (InFile,"adrsBook.txt");
       my @cont=<InFile>;
       close InFile;

      で、名簿用のファイル adrsBook.txt を開き(open)、その内容を文字配列 @cont に記録し、いったんファイルを閉じます(close)。InFileはファイルを指定する特殊な変数です。@cont=<InFile> でファイルの内容がすべて @cont にコピーします。次に、項目の入力を確認します。

       if(($form{'yomi'} eq "")||($form{'name'} eq "" )|| ($form{'mail'} eq "")){#項目確認
        &message('入力のない項目があります');
        }

      各必須項目が 空でないか調べ、空なら、&message('入力のない項目があります'); をホームページに表示して CGI の処理を完了します。次にパスワードをチェックします。ne はnot equal で等しくないと 真 になります。

       if(($form{'pwd'} ne $pass)){#パスワード確認
        &message('入力を確認して下さい');
       }

      次に、フォームで入力された各文字列を、<> で区切りながら1行も文字に合成して変数 $newst に記録し、先に読み出したファイルの内容 @cont の末尾に push で追加し、これを、名簿ファイル adrsBook.txt に書き出します。

      my $newst="$form{'yomi'}<>$form{'name'}<>$form{'adrs'}<>$form{'mail'}<>$form{'phone'}<>\n";
       open (OutFile,">adrsBook.txt");
       shift @cont; #先頭行を削除する
       push (@cont,$newst); #最後に$newstを付加する
       print OutFile @cont; #ファイルに記録する
       close OutFile; #ファイルを閉じる

       >adrsBook.txt の > はファイルに書き込むことを意味します。print OutFIle で書き込み、close でファイルを閉じます。
      最後に、処理終了を示す html 記述を作成します。html作成については、次の項目で説明します。

    6. サブルーティン view()
       
      サブルーティンviewでは、名簿ファイルを読み出し、表示する html 記述を生成します。まず、先頭で、パスワードをチェックし、一致しない場合、メッセージを表示し終了します。
       次に、openでファイルを開き、&headerで html のヘッダ記述を生成し、&start_html('名簿')で <BODY>タグまで生成します。
       while(<InFile>) でファイルから1行ずつ読みながら、各行を <> で項目に分解し、$yomi,$name..などの変数に記録します。
        my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/);
      printは、qq( ) の内容を標準出力に出力します。
       Perlからの標準出力は、webサーバーに接続され、そのまま、ブラウザに送られます。したがって、<TABLE>以下の html タグがブラウザに送られます。これ以前の、html記述は header() や start_html() サブルーティンで送られています。header や start_htmlは CGI ライブラリで定義されているサブルーティンです。以下はファイルを読みながら、htmlは吐き出すプログラムです。

       open (InFile,"adrsBook.txt");#名簿ファイルを開く
       print &header(-type=>'text/html;charset=Shift_JIS');#htmlヘッダーを生成
       print &start_html('名簿');#html出力を開始
       while(<InFile>){
        print qq(<TABLE>);#表の出力を開始
        my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/);#項目に分解
        print qq(<TR><TD>名前(よみ)</TD><TD>$yomi<BR></TD>);
        print qq(<TR><TD>名前(漢字)</TD><TD>$name<BR></TD>);
        print qq(<TR><TD>住所</TD><TD>$adrs</TD>);
        print qq(<TR><TD>E-Mail</TD><TD>$mail</TD>);
        print qq(<TR><TD>電話番号</TD><TD>$phone</TD>);
        print qq(</TABLE><BR><BR>);
       }
       close InFile;

      最後に、元のページに戻るリンクを作成し、end_html() で </BODY></HTML>を出力して、ページをしめます。

       print qq(<a href=adrsBook.htm> 戻る</a>);
       print &end_html();#html出力を終了

      1. ファイルとデフォルト変数
        <InFile>はファイルの内容を意味し、 $st=<IN> で<IN>からの次の1行が $st に記録されます。while(<InFile>)は、while($_=<InFile>) の意味で、ファイルからの行が $_ に記録されます。変数が省略されている場合は、自動的に $_ が省略されたものとして扱われます。したがって、次の
         my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/)

         my ($yomi,$name,$adrs,$mail,$phone)=split(/<>/,$_)
        の意味で、ファイルからの1行が各変数に記録されます。

    7. get_PostData()
       get_PostDataは、環境変数のREQUEST_METHODの値を $ENV{'REQUEST_METHOD'} で取得し、GETであれば 環境変数の $ENV{'QUERY_STRING'} から、そうでなければ(POSTなら) 標準入力:STDIN から、FORMの入力を 読みとります。
       read( STDIN, $data, $ENV{'CONTENT_LENGTH'});
      は、STDINから、$ENV{'CONTENT_LENGTH'} の文字数だけ、$data にデータを読みとります。
       
      1. 環境変数
        環境変数は、システムからアプリケーションに渡す変数で、システム(この場合webサーバー)から種々の値が渡されます。Perlおではそれの値を連想配列 $ENV から受け取ることができます。

    8. set_FormData()
       Formからのデータを容易に参照できるよう、連想配列に記録します。まず、引数で受け取ったFormデータの文字列を shift して、$dataに保存します。Formの各項目の値は & によって連結されていますから、これを split(/&/,$data) で分割し、各項目の値を配列 @pair に記録します。
        my $data=shift;
        my @pair=split(/&/,$data);
        my %hash;my $key;
        foreach(@pair){
          my($key,$value)=split(/=/);
          $key=&uri_decode($key);    
          $hash{$key}=&uri_decode($value);
          #print "form:$key\n";
        };
        return \%hash;  
       }
       各項目の値は 名前 = 値 の形式で記録されていますから、@pairの各項目ごとに(foreach)、 split(/=/) で = の前後に分割し、($key,$value)に記録します。$keyがFormのInput項目の名前、$value がその値となります。&key の値を URLデコードし(後述)、 $hash{$key}=&uri_decode($value); で、hash配列に記録します。これで、たとえば、$hash{'name'} で、'name'の名前で記録されている値を取り出すことができます。

      1. サブルーティンの引数
        Perlでは、サブルーティンの引数を、@_ の名前の配列から受け取ります。この名前はデフォルトになっており、配列名の指定が場合は、@_が指定されたものとして扱われます。(配列でない単なる変数の場合はデフォルト変数は $_ となります)この関数で先頭の $data=shift; は $data=shift @_ ; の意味で、@_が省略されています。

      2. 配列とshift.push
        Perlでは配列はリストとして実現されています。配列の先頭のデータを取り出すのは shift() 、先頭にデータを追加するには unshift() サブルーティンを利用します。一方、配列の最後にデータを追加するのは push()、取り出すには pop() サブルーティンを利用します。
         C言語と同様、配列 @A に対して、@a[i] のような処理も可能ですが、Perlでは配列はリストで構成されていますから、配列の先頭や最後へのアクセスには、これらのサブルーティンを利用する方が効率が良いのです。


    9. uri_decode()
       ここでは、Perlの強力な文字列のマッチング処理を用いて、指定した文字列を他の文字列に変換します。たとえば、 $str =~ tr/+/ /g は、文字 + を 空白の文字(スペース)に変換します。/g はすべての + を置き換えることを指定します。
       $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))
      は少しわかりずらい処理ですが、%で始まる16進文字に変換されている漢字を、元の漢字コードに戻します。これらは、URLエンコードされたFormデータを元に戻す処理に相当します。以下は、htmlのタグに利用されてる特殊文字を、同じ記号の表示用文字列に変換します。たとえば < は &lt; に変換されます。この変換で、入力にタグを指定しても、htmlのタグではなく文字列と解釈されます。tr/ による処理は文字単位で、 s/ による処理より高速です。

       $str =~ s/&/&amp;/g;#タグ用記号
       $str =~ s/"/&quot;/g;#タグ用記号
       $str =~ s/</&lt;/g;#タグ用記号
       $str =~ s/>/&gt;/g;#タグ用記号

    10. message()
       このサブルーティンは、引数のメッセージをホームページとして表示し、表示後 exit で処理をうち切ります。主にエラーメッセージの表示に利用します。

  4. CGIのファイル属性とセキュリティ
    1. htmlファイル属性
       多くのwebサーバーは、Unix系のOSで実行されています。この場合、Unix系のシステムではファイルの属性でアクセス保護をしています。例えば、第三者(ファイル所有者以外)の人は、ファイルに第三者に対する 「読みとり許可」が設定されていないと、読むことができません。したがって、公開するhtmlファイルには、この第三者に対する 「読みとり許可」を設定する必要があります。

    2. cgi ファイルとデータファイルの属性
       cgiファイルの場合は、さらに、第三者に対するファイルの「実行権」や「書込み権」も設定する必要があります。例えば、Perlのソースファイルには「実行権」、名簿ファイルには「書込み権」を設定する必要があります。これらの属性の設定は、ファイルの所有者(作成者)なら、TelnetやFTPを用いて設定可能です。

    3. セキュリティ対策
       cgiのプログラムには、イタズラや妨害行為に対する対策が必要であり、これを怠るとシステムのセキュリティホールとなってしまいます。多くのプロバイダがCGIの利用を許可していないのは、対策のないCGIプログラムを恐れるからです。ここで紹介するCGIプログラムも、ほとんど、セキュリティの対策をしていません。
       Perlのセキュリティ対策としては、 宮前著「プログラミングによるセキュリティ対策」技術評論社 等をご覧下さい。

    4. このCGIの実行環境
      htmlファイル(adrsBook.htm)とCGIファイル(adrsBook.cgi)が必要です。また、データファイルとして、adrsBook.txtファイルが必要です。ここでは、これらのファイルは、同じフォルダに配置することとしてプログラムされていますが、セキュリティに注意すると、すべて別のファイルにおく必要があります。また、ファイルには、先に述べたファイル属性が必要です。
       また、CGIを実行するには、webサーバーがCGIの利用を許可していること、Perlの処理系が組み込まれている必要があります。CGIの先頭の Perlへのパスは実際のサーバーにあわせる必要があります。