.
.
.
.
.
TOPページ(Alt+B)
.
ApacheでCGI

ApacheでCGIプログラムを実行するためには、

・CGIスクリプトの格納場所を設定しそこにCGI実行権を与える
・特定のファイル名拡張子をCGIスクリプトとして認識してもらうための設定を行う

の2つの方法があります。

httpd.confをメモ帳等で開いて、次の行を探します。

ScriptAlias /cgi-bin/ "C:/Apache/cgi-bin/"

<Directory "C:/Apache/cgi-bin">
   AllowOverride None
   Options None
   Order allow,deny
   Allow from all
</Directory>

ScriptAliasによって指定されたcgi-binディレクトリ(上記だと C:\Apache\cgi-bin )でCGIプログラムが実行できるように設定されています。つまり、デフォルトでは何もしなくてもこの C:\Apache\cgi-bin ディレクトリにスクリプトを置いてやればCGIプログラムは実行できます。CGIプログラムはサイト内のあちこちに分散させず、単独のディレクトリの下で管理していくのが基本ですから、この方法は優れた方法であるといえます。このように、ScriptAliasによって指定されたディレクトリにあるファイルはCGI実行可能なファイルとして扱われます。そのファイル名拡張子には.cgiの他、.pl、.dat、.exeなどが実行可能ファイルとして処理されます。

もう1つの方法はOptions指示子の引数としてExecCGIを指定し、明示的にCGIの実行を定義し、AddHandlerを使ってファイル名拡張子をcgi-scriptに関連付けます。これにはまず先ほどの

ScriptAlias /cgi-bin/ "C:/Apache/cgi-bin/"

の先頭に#を付けて無効にします。これはScriptAliasで指定されたディレクトリのすべてのファイルをファイルタイプに関係なく実行してしまうのを避けるためです。

CGIスクリプトを格納するディレクトリを決定し、Alias指示子で指定します。

Alias /cgi-bin/ "D:/home/http/cgi-bin/"

次に指定したディレクトリに<Directory>ブロックを追加し、CGIの実行権を付けます。

<Directory "D:/home/http/cgi-bin">
   Options ExecCGI
</Directory>

更に

#AddHandler cgi-script .cgi の先頭のコメントをはずし、有効にします。

これで D:\home\http\cgi-bin ディレクトリに格納したファイル名拡張子.cgiファイルのみ、CGIスクリプトとして処理されます。サンプルとして環境変数を出力する簡単なPerlスクリプトを表示してみましょう。 env.cgi.txt

ダウンロード後、env.cgiに名前を変更し、cgi-binディレクトリに置きます。ブラウザのURL入力欄に http://ホスト名/cgi-bin/env.cgi と入力します。うまく表示されましたか?

ApacheがCGIを処理する仕組みをみてみましょう。

CGIの処理はWebブラウザからHTTPを通じて情報を受け取った時点で開始されます。ブラウザから送られてくるリクエストはGETリクエストとPOSTリクエストが一般的です。

GET

GETリクエストは非常に単純なリクエストで、ユーザーがブラウザのURL欄にURL入力することで送られます。例えばhttp://www.abc.co.jp/と入力するとブラウザはサーバーに

GET /

というリクエストを送ります。GETリクエストを利用してCGIを実行する場合にはこのURLに含めた情報を送信することで可能となります。GETリクエストの場合、<FORM>タグでメソッドはGETを指定し

<form method="GET" action="http://www.abc.co.jp/found.cgi"></form>

更に<FORM>タグの中で<INPUT>タグを使ってテキストフィールド、チェックボックス他を定義します。

<input type="text" name="action" size="15px" value=""><input type="submit" value="送信">

例えば、検索CGI  ”found.cgi”  があるとすると、この状態では http://www.abc.co.jp/found.cgi?Apache+CGI というリクエストが送られます。つまり?の後の文字列がユーザーによって要求された値となり、このリクエストに対しApacheはHTTPリクエストのメソッド(GET)を環境変数REQUEST_METHODに格納し、クライアントによって入力されたデータはQUERY_STRINGに格納されます。その後CGIプログラムが実行され、その結果を標準出力STDOUTに出力します。ApacheはSTDOUTを読み取り解析しブラウザに表示します。ただこのGETには情報量の制限がある(255文字)ため大量のデータを送る必要がある時には次のPOSTリクエストを利用します。

POST

POSTリクエストの場合の<FORM>タグのメソッド指定はPOSTとなり

<form method="POST" action="http://www.abc.co.jp/found.cgi"></form>

更にGET同様<FORM>タグの中で<INPUT>タグを使ってテキストフィールド、チェックボックス他を定義します。

このフォームの情報を送信する際にはブラウザはサーバーに対してPOSTリクエストを送信し、指定されたACTIONを実行するよう要求します。送信されたデータは環境変数QUERY_STRINGには格納されずCGIプログラムの標準入力STDINに送られます。

GETとPOSTについてはこのくらいにして本題に戻ります。WebブラウザからHTTPを通じて受け取った情報を解析した結果、外部プログラム(Perlインタプリタ等)を必要とするものについては、まず外部プログラムが存在するかどうかを確認し、存在すればその外部プログラムを呼び出し、処理を行い、その結果を返します。

掲示板を例にとると、

  1. 掲示板に書き込む
  2. 書き込み処理のためにはPerlインタプリタの助けが必要
  3. Perlインタプリタを呼び出す
  4. Perlインタプリタが書き込み処理を行う
  5. 書き込んだ結果をHTMLに返す

という流れになります。

CGIはサーバーに負荷がかかるということをよく耳にしますが、この一連の流れの中でもっともCPUに高い負荷をかけるのはCGIプログラムの処理そのものではなく、実は外部プログラムの呼び出し(Perlインタプリタの呼び出し)作業です。これは現在インターネットサーバーとして標準のUNIXシステムではプロセスが新しい子プロセスを生成する際に元の親プロセスのメモリ空間やファイルハンドル等をすべてコピーするためで、この問題は現在ではかなり改善されているとはいえ、まだまだ大きな処理能力を必要とします。特に頻繁にこの作業を行う必要があるチャットプログラムの使用をホームページ容量提供元が嫌がるもの分かりますね。

Apacheとmod_perl

mod_perlはActivePerlなどと同様Perlインタプリタの1つですが、上記の問題を改善すべくApacheにPerlインタープリタを組み込んでしまおう、というものです。つまりApacheにPerlインタープリタを組み込んでしまえば(モジュール化してしまえば)CGIを使わずに済み、WebサーバーのパフォーマンスをUPさせることができるわけです。入手時はhttp://perl.apache.org/からApache1.xxにはmod_perl 1.0を、Apache2.xxにはmod_perl 2.0を選択します。mod_perlをApacheに組み込む方法としては2種類あり、Apacheをソースコードからコンパイルし静的にリンクする方法と、mod_perlをDSO(Dynamic Shared Object)モジュールとしてLoadModule指示子で動的にリンクする方法です。Windows版Apacheにおいても最初の静的にリンクされた状態でコンパイルされたバイナリを入手することが可能です。

UNIX版Apacheにmod_perlを組み込む例

# tar zxvf apache_1.3.27.tar.gz
# tar xzvf mod_perl-1.0-current.tar.gz

# cd mod_perl-1.28
# perl Makefile.PL \
APACHE_SRC=../apache_1.3.27/src \
PREP_HTTPD=1 \
DO_HTTPD=1 \
USE_APACI=1 \
EVERYTHING=1

# make
# make install

# cd ../apache_1.3.27
# ./configure --activate-module=src/modules/perl/libperl.a

# make
# make install

mod_perlを組み込んだApache環境では、Apache::RegistryApache::PerlRunという2つのモジュール用命令を利用することができます。

・Apache::Registry・・・・・Perlで作成したモジュールを実行する際に1度だけモジュールがコンパイルされ、メモリに常駐する。
・Apache::PerlRun・・・・・Perlで作成したモジュールが呼び出されるたびにコンパイルされる。

PerlRunではモジュールが呼び出されるたびにコンパイルされますが、Perlを外部プログラムとして呼び出すわけではないのでCGIの時と比較して遅くなるなどということはないでしょう。
mod_perlを利用するためのhttpd.confの記述方法としては

PerlHandler Apache::Registry
PerlSendHeader On

などと指定してやります。PerlSendHeader Onと指定することにより、従来のCGIスクリプトを若干のコードの書き換えでApacheモジュールとして利用することができます。この記述が無い場合にはPerlで作成したCGIスクリプトの最初に「HTTP/1.0 200 OK」といった記述が必要になります。

mod_perlを利用することにより、大幅なパフォーマンスUPが期待できますが、問題点もあります。それはメモリを大量に消費することです。モジュールの種類が増えれば増えるほど、プロセスに必要なメモリ領域はどんどん大きくなっていきます。また、CGIプログラムにバグがあった場合、最悪の場合サーバーシステムのダウンということも起こりえます。特にマルチプロセスで動作するWindowsの場合には、即サーバーのダウンという危険を伴うことになり兼ねません。また、セキュリティの面においてもsuEXECを使った外部プログラムのユーザーIDに各ユーザーのユーザーIDをセットするといったようなことは出来なくなるため(一般ユーザーが作成したモジュールもApacheのユーザー権限で実行されるため)、危険性を伴います。そこで現実的には、通常のCGIプログラムは外部プログラムの呼び出しによって処理し、テストされた完成度の高いCGIプログラムのみモジュールとして利用する、といった方法が正しい使い方となります。具体的には、

Alias /cgi-bin/ "D:/home/http/cgi-bin/" #通常のCGIスクリプトを置くディレクトリ

<Directory "D:/home/http/cgi-bin">
   Options ExecCGI
   AddHandler cgi-script .cgi
   Allow from all
</Directory>

Alias /perl/ "D:/home/http/perl/"          #モジュールとして常駐されるCGIスクリプトを置くディレクトリ

<Directory "D:/home/http/perl">
  SetHandler perl-script
  PerlHandler Apache::Registry   #mod_perlをRegistry命令で実行する
  PerlInitHandler Apache::StatINC #userequireで読み込んでいるモジュールを変更した場合にはその変更を反映させる
  Options ExecCGI
  PerlSendHeader On                   #HTTP応答ヘッダを出力する
  Allow from all
</Directory>
PerlFreshRestart On

という具合に、使い分けるという手があります。以下は筆者が実際に利用しているDSOモードでのmod_perlの指定方法です。

# use mod_perl
<IfModule mod_perl.c>

<Files *.xcg>
SetHandler perl-script
PerlHandler Apache::Registry
PerlInitHandler Apache::StatINC
Options ExecCGI
PerlSendHeader On
</Files>
Perlrequire /var/www/cgi-bin/startup.pl
PerlFreshRestart On

<Files *.pl>
SetHandler perl-script
PerlHandler Apache::PerlRun
Options ExecCGI
PerlSendHeader On
</Files>

</IfModule>

Apacheでmod_perlを有効にするための起動ファイル、startup.plには

use strict;
use Apache::Registry();
use Apache::Status();
return 1

と入れています。

ここではスクリプトの拡張子によってRegistryモードとPerlRunモードを使い分けています。つまり拡張子を.xcgとした場合にはRegistryモードで、.plとした場合はPerlRunモードで、そして.cgiとした場合は通常のCGIプログラムとして動作します。

TOPページ(Alt+B)

CopyRight (C) 2000-2013 by T.Shiraishi All right reserved 無断転載禁止/リンクフリー