Perl/CGI

CGIとは

CGIとは、Webサーバーのサーバーサイド処理としてPerlスクリプトCGIスクリプト)を実行し、そのCGIスクリプトが吐き出した結果をWebブラウザに表示させる仕組み。
Webサイトを動的に作るのに使える。たとえば、たくさんの人が同じWebサイトにアクセスして、トピックごとにコメントを残して指定のコメントを表示させる「メッセージ掲示板」や、たくさんの人間がリアルタイムに最新のメッセージを投稿し表示し合う「チャット」のようなものを作ることができる。
こうしたWebサービスにはたくさんの人が同時にアクセスし、みんなでメッセージを共有するため、「楽しい」という一面があるが、不特定多数がその掲示板を利用するため、「犯罪のような書き込み」をされることもあり、運営者には正しい管理が求められる。
最近ではCGIに代わる技術としてPHPJavaサーブレットなどの技術があり、またRubyPythonなどの動的な言語で「Webフレームワーク」と呼ばれるシステムを使うことで、簡単にSNSのような高度なWebサービスを構築できるが、Perl/CGIはこうした技術の草分け的な存在であり、「Webサーバーの下でPerlスクリプトが動く」という技術は画期的で大流行した。その基本を知るためにCGIを勉強することは無駄ではない。逆に、PHPなどに対する理解が深まるだろう。僕も、最初に遊んだネットゲームは、Perl/CGIで書かれたブラウザゲーム(HTMLとボタンだけのシンプルなキャラクター育成・対戦ゲーム)だった。

Perlの強力なテキスト編集機能で、HTMLを出力する

Perlのテキスト編集機能は強力。正規表現が使えるほか、ヒアドキュメントを使うこともできる。
そんなPerlの強力な文字処理能力で、HTMLのタグやページも出力してやろう、というのがPerl/CGIの技術である。
実際のところ、HTMLではボタンやテキストボックスすら、ページの一部としてHTMLで書かれる。このため、Perl/CGIを使うことで、そうしたページそのものをPerlのprint関数で出力し、ページを自動で整形し、別に存在するデータを読み書きすることで、「リアルタイムに自動で作成する」ことができる。
同時に、GETやPOSTを用いることで、ユーザーからの投稿を取得し、そうしたデータを出力して保存できる。
Perl/CGIにはプロセスをその都度作成するためプロセスの作成・破棄のオーバーヘッドの問題があり、PHPなどのさらに高度な技術も存在する。どうしてもPerlで書きたい場合は、FastCGIと呼ばれる新しい技術がある。

掲示板の作り方

基本的に、
1.投稿された値を受けとる処理
2.ヘッダの表示
3.受け取ったデータをファイルに書き込む処理
4.投稿フォームの表示
5.記事の一覧表示(書き込んだファイルを読み出して表示する処理)
6.フッタの表示
という風にスクリプトを書けば良い。

データファイルの読み書き

Perl/CGIでは、rand()関数や変数を使うことで簡単に育成・バトルのようなゲームを作れますが、外部のファイルを全く使わずにゲームを作ってしまうと、実行するたびにキャラクターのステータスが初期値に戻ってしまいます。
こういう時は、データファイルを使って、外部の設定・データファイルに「その時の状態」を書き出すことで、連続したゲームプログラムを実現できます。
こういう時、便利なのが、文字列を分割するsplit関数と、文字列を連結するjoin関数です。これらを上手く使うことで、簡単にデータ形式を実現することができます。
たとえば、:で区切られたファイルを読み込むには、

$player = 'Schwarz';
@id = (1, 2, 3, 4);
@name = ('a', 'b', 'c', 'd');
@hp = (0, 0, 0, 0);
@atk = (0, 0, 0, 0);
@money = (0, 0, 0, 0);
open(FILE, "${player}.txt") or die "$!";
$i = 0;
foreach $line (<FILE>) {
    chomp($line);
    ($id[i], $name[i], $hp[i] $atk[i], $money[i]) = split(/:/, $line);
    $i++;
}
close(FILE);
@character1 = ($id[0], $name[0], $hp[0], $atk[0], $money[0]);
@character2 = ($id[1], $name[1], $hp[1], $atk[1], $money[1]);
@character3 = ($id[2], $name[2], $hp[2], $atk[2], $money[2]);
@character4 = ($id[3], $name[3], $hp[3], $atk[3], $money[3]);

とし、逆にファイルに書き出すには、

open(NEWFILE, "> ${player}.txt") or die "$!";
print NEWFILE join(':', @character1), "\n";
print NEWFILE join(':', @character2), "\n";
print NEWFILE join(':', @character3), "\n";
print NEWFILE join(':', @character4), "\n";
close(FILE);

のようにします。いささかデータ構造の設計上の問題は見受けられますが、@idや@nameは読み書きの時に一時的に格納する変数として使用し、通常は@character1などを通じてデータを操作します。

文字コードの設定とPerlのパス

CGIを作った時、文字コードをきちんと指定しないと出力されたHTMLの日本語部分が文字化けしてしまう。ソースファイルを記述した環境やエディタの設定に合わせて、「charset=Shift_JIS」や「charset=utf-8」を指定すること。HTMLの指示でもの部分を適切に設定すること。
また、Perl処理系のパスは、#!/usr/local/bin/perl(ソースからインストールした場合)や#!/usr/bin/perl(パッケージ管理システムからインストールした場合)を適切に設定すること。

パーミッション

LinuxなどのUNIX互換OSにおけるサーバーでは、パーミッション(読み込み・書き込み・実行の権限)を設定する仕組みになっていて、Perl/CGIで実行スクリプトを作っても、パーミッションが適切に設定されていないと実行できない(実行のための権限が必要)。
パーミッションの意味は、数値は読み込みを4、書き込みを2、実行を1として、これらを足した数値で権限を指定する。0の場合は何もできない。左からオーナー(所有者)、グループ(ファイルが属しているグループ)、その他(オーナー・グループ以外)を意味している。
実行されず読み取りだけを行うファイルは644、実行可能属性を付ける場合は755を設定するのが一般的。CGIスクリプトから書き換えられるファイル(データファイルなど)については666を設定する。所有者も間違って書き換えるのを防ぐために444や555を設定したり、自分しか読めないようにする場合は600を設定したり、グループの権限を無くして604を設定したりすることもできる。ディレクトリについては755を設定する。
Linuxマシンにじかにログインして変える場合や、SSH(リモートログインソフト)でリモートログインして変える場合は、以下のようにchmod(パーミッションの設定コマンド)でパーミッションに755を指定する。また、.htaccessファイルやHTMLファイル、画像ファイルなどは、644に設定する。

$ chmod 755 sample.cgi
$ chmod 644 image.gif

FTPクライアント(ファイル転送ソフト)でファイルを転送する場合は、UNIXコマンドが使えない代わり、FTPクライアントでファイルの属性を設定する。
WinSCPでは、「オプション→環境設定」を開いて、「転送」から「デフォルト」を選択して「編集」をクリックし、「アップロード時の設定」から「パーミッションの設定」にチェックを入れることで、ファイル転送全体のデフォルトのパーミッションの設定ができる。また、個別のファイルのパーミッションの設定は「ファイル→プロパティ」から行える(右クリック→プロパティでも良い)。全体を644、CGIスクリプトだけを755とするのが良いだろう。

単独テスト

サーバーに公開したCGIについては、./をつけてスクリプト名を実行する(PATHに含まれていなくても、相対パスで./sample.cgiとすれば今居るディレクトリの中にあるスクリプトを実行出来る)ことで、単独テストを行うことができる。

CGIスクリプトの入手とサーバーへの設置

ネットには、Perl/CGIPHPで作られたフリーなスクリプトを配布しているサイトがたくさんあります。たとえば掲示板であれば、「CGI スクリプト 掲示板」などで検索してください。
チャットや簡単な掲示スクリプトのほか、2ちゃんねる型のスレッドフロート型掲示板や、後述するFF BATTLEなどのブラウザゲームスクリプトなど、さまざまなスクリプトが配布されています。
これらのスクリプトの設置を行うには、レンタルサーバーを契約してアップロードを行います。このためには、Apacheの設定や、UNIXパーミッションの基本知識、それから文字コードの適切な設定についての知識が必要です。必要に応じて、FFFTPWinSCPのようなFTPファイル転送クライアントソフトウェアをインストールしましょう。テキストエディタも、Unicodeが扱えて、シンタックスハイライト(PerlPHPの文法に応じてキーワード色分けをしてくれる機能)があるものをインストールしましょう。初心者におすすめなのはサクラエディタです。EmacsライクなxyzzyAtomのような最先端のエディタもおすすめです。
実際にWebアプリケーションを運営するためには、常にリクエストに対してサービスを返すサーバーマシンを用意しなければなりませんが、無料ホームページスペースでは、HTMLだけをサポートしていて、Perl/CGIPHPは使えないことが多いです。また、容量も決まっていて、大規模な掲示板は運営できません。この場合、自宅サーバを作ることもできますが、スキルと管理コストが必要ですし、セキュリティやネットワーク負荷の問題もあり、現実的ではありません。思い切って、月1000円ぐらいのレンタルサーバーを購入しましょう。この時、PerlPHPだけではなく、SQLデータベースも使えるサーバーを選択すると、WordPressのような高度なシステムを使うことができます。掲示板だけではなく、MediaWikiのようなWikiシステムを利用したい場合も、PHP/SQLが使えれば動かせることが多いです。
ただし、不特定多数の利用する掲示板を運営する上で必要なのは、名誉棄損や誹謗中傷のような書き込みがあった時に、それを削除しなければならない、ということです。2ちゃんねるでは、運営者の西村ひろゆき氏が、裁判所に通いづめになるほどに、悪いことをたくさん書かれます。犯罪予告やストーカー行為、ハッキングや著作権違反のほう助のような罪もあります。それを覚悟して管理しなければなりません。
掲示板を運営したいのであれば、スクリプトをダウンロードしてサーバーにアップロードしなくても、したらばBBSのような「レンタル掲示板サイト」を利用することもできます。ホームページをレンタルするように、自分の掲示板サイトをレンタルして運営することができます。これは、個人のホームページのような場合では、手軽なため良いでしょう。
CGIによる掲示板を運営する上で僕が言えることは、古い書き込み全てを保持するよりも、何か月も前の書き込みは自動的に削除されていくような仕組みを作ることです。それによって、良い内容も悪い内容も自動的に消えていってくれます。また、SNSのように、アカウント制にして、悪いアカウントは凍結できる仕組みを作ることで、犯罪予告のような悪い書き込みの防止に繋がるかもしれません。Facebookは実名制を採用していますが、これは特に良い方法であると同時に、個人情報を集めすぎて逆に批判されるリスクもあります。Wikipediaのように不特定多数の特定の書き込みは最初からIPアドレスを表示するようにするというやり方もアリ。

昔はPerl/CGIが猛威を振るっていた

昔は、Web上の掲示板やチャットなど、ほとんどのCGIプログラムがPerlで書かれており、CGIと言えばPerl、Webアプリケーションと言えばPerlだった。PHPRubyのような後続の言語が現れて、JavaC#なども使うようになって、状況は変わってきたが、当時のPHPRubyは多くがPerlをとても参考にした言語だった。
Perl/CGIを今でも使っているサイトは多い。Perlスクリプトとして簡単にHTMLを吐くことができるし、C/C++よりも簡単で、コンパイルも必要ない。Apache 1系列とPerlは昔から事実上の標準だった。Webフレームワークがたくさん出て、もう昔の話となりつつあるが、それでも基本的な部分はPerlと変わっていない。