Pythonを用いたCGIスクリプティング入門
インタープリタ型のオブジェクト指向言語としてGuido van Rossum氏の開発したPythonは、イギリスのテレビ番組『空飛ぶモンティ・パイソン』にちなんだ名称が冠せられているが、その初回リリースは1991年と意外に古く、今では、Google、NASA、ForecastWatch.comなど多数の企業や組織にてスクリプティング言語としての用途に供されるようになっている。
Pythonの使用を開始する前の準備
このチュートリアルでは、Pythonについて最低限の使用経験のある読者を想定している。まったくの初心者という場合は、「Python Tutorial」や「Python Reference Manual」などPythonに関する優れた参考資料が多数オンライン公開されているので、事前にそちらを一読して頂きたい。
まず最初の確認事項として、開発作業に用いるシステムにPythonがインストールされている必要がある。Pythonのインストールおよびパス設定が既に済んでいれば、シェルプロンプトに続けて「python -V
」というコマンドを実行することによりバージョン番号(このチュートリアルで用いたものは2.5.1)が表示されるはずだ。Pythonがインストールされていない場合は、yumやapt-getなどのパッケージ管理ツールを用いて各自のリポジトリからPythonのダウンロードとインストールを行っておく必要がある。
手元のシステムにPythonがインストールされていれば次のステップとして、各自の利用するWebサーバの設定にてCGIスクリプティングが実行可能となっているかを確認する。なおこのチュートリアルの場合は、Apache Webサーバの使用を想定している。またrootないしsudoでのアクセス権限を有していないユーザが以下の設定変更を行う場合は、システム管理者によるサポートが必要となるはずだ。
次のステップとして/etc/httpd/conf/httpd.confを開き、サーバスクリプトの格納ディレクトリを指定している「#ScriptAlias: This controls which directories contain server scripts.
」で始まるテキストブロックを特定し、次のような設定が施されているかを確認する。
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" # # "/var/www/cgi-bin" should be changed to whatever your ScriptAliased # CGI directory exists, if you have that configured. # <Directory "/var/www/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory>
各自のhttpd.confファイルがここに引用した設定と完全に一致していないこともあるだろうが、心配することはない。現在ではCGIスクリプティングの許可を前提としたインストレーションが大部分を占めるようになっており、設定ファイルの中にはCGI関連の指定行がコメントアウトされているだけのものもあるからだ。そうした場合、ScriptAliasディレクティブの先頭が#という記号で始まっているはずなので、この記号を削除した上でhttpd.confファイルを保存し、「/etc/init.d/httpd restart
」によってApacheを再始動させる。
最初のサンプルスクリプト
まずはテキストエディタを用いてexample1.pyという名称のファイルを作成し、下記のコードを入力する。
#!/usr/bin/python print "Content-type: text/html" print print "<html>" print "<center>Hello, Linux.com!</center>" print "</html>"
このファイルについては保存先を/var/www/cgi-binとしておき(rootないしsudoのアクセス権限が必要)、更に「chmod 755 example1.py
」による実行パーミッションを設定しておく。
次にWebブラウザを起動し、http://yourtesthost.com/var/www/cgi-bin/example1.pyなど先のファイルにアクセスするためのURLを指定してブラウザでの読み込みを行う。ただしこの操作に関してはWebサーバ経由でファイルを転送させる必要があるので、File→Openメニューの選択によるファイルオープンをしてはいけない。以上の手順に問題がなければブラウザウィンドウの中央に“Hello, Linux.com!”という文字列が表示されるはずだが、表示されない場合はexample1.pyをダブルクリックしてここでのサンプルコードと食い違いがないかを確認して頂きたい。例えばこのコードでは、3行目にある一見すると単に空行を設けているだけのprint
行が重要な意味を有している。つまりWebサーバは"Content-type: text/html"
というエントリの次に空行を必要とするのであり、この空行がないと内部サーバエラーが生じてしまうのだ。
コードのシンタックスをチェックする1つの簡便な方法は./example1.py
というコマンドによってファイルを直接実行させることである。指定したファイル中のコードに問題がなければPythonによるファイルの実行結果として、プレインテキストにて対応するHTMLコードが出力されるはずだ。ただしこのテクニックはシンタックスのチェックには便利ではあるが、より複雑なCGIスクリプトに対するデバッグまで行えるというものではない。すべてのCGIスクリプトがコマンドラインから正しく実行できるものだとは限らないし、またコマンドラインからは正常に実行できたスクリプトであっても、Webサーバが呼び出した際にはクラッシュするというケースも存在するからである。
より高度なスクリプトを構築する場合、各自が用いているコード開発用のツールキットに若干の追加を行わなくてはならない。例えば次に解説するのも、そうした目的に基づくcgiおよびcgitbモジュールの使用法である。
フォーム表示を利用するサンプルスクリプト
標準的なPythonディストリビューションであれば、CGIアプリケーションの構築とデバッグに必要な拡張機能を提供するためのcgiおよびcgitbモジュールが付属しているはずだ。このうちcgiモジュールは各種のクラスを定義しているもので、このチュートリアルの場合はフォーム表示を行う2つ目のサンプルスクリプトにて、FieldStorageというクラスを利用することになる。同じくcgitbモジュールはデバッガとしての機能を有するもので、これが役立つのは少し長めのスクリプトを記述する場合であり、このチュートリアルの場合は3つ目のサンプルスクリプトをデバッグする際にこのモジュールを使用している。
次のサンプルスクリプトは、2つの質問を提示してその回答を集計するという簡単なアンケートを実施するものである。まずは1つ目のサンプルと同じ手順でexample2.pyという名前のファイルを作成し、その中に下記のコードをコピー&ペーストして/var/www/cgi-binに保存しておく。なおその際に「chmod 755 example2.py
」による実行パーミッションの設定を忘れてはいけない。
#!/usr/bin/python import cgi print "Content-type: text/html" print form = cgi.FieldStorage() laptops = form.getvalue('laptops','0') desktops = form.getvalue('desktops','0') print """ <html> <body> <form action='example2.py'> How many laptops do you own <input type='radio' checked name='laptops' value='0' />0 <input type='radio' name='laptops' value='1' />1 <input type='radio' name='laptops' value='2' />2 <p> How many desktops do you own <input type='radio' checked name='desktops' value='0' />0 <input type='radio' name='desktops' value='1' />1 <input type='radio' name='desktops' value='2' />2 <p> <input type='submit' /> <p> You own %d computers. </form> </body> </html>""" % (int(laptops)+int(desktops))
このexample2.pyの構造は1つ目のサンプルといくつかの点で異なっている。まず気づくのは、2行目にあるcgiモジュールのインポートおよび5行目にあるフォーム作成用のステートメントである。同様に6行目と7行目のFieldStorageクラスは、ここで作成するフォームからのデータ取得をするために使用している。example2.pyにおける残りの部分は通常のHTMLコードを記述するためのものだ。次の操作手順として、example2.pyの格納先がcgi-binディレクトリとなっていることを確認した後、このURLをWebブラウザに指定してexample2.pyを読み込ませると、ラップトップおよびデスクトップコンピュータをそれぞれ何台ずつ所有しているかを尋ねる2行形式のアンケートフォームが表示されるはずだ。そしてここで回答した数値については、合計が計算された上でフォーム下部に表示されるようになっている。回答する数値を変えてフォームの提出を何度か行い、正しい処理が行われているかを確かめて頂きたい。
cgitbを用いたデバッグ
こうしたコード入力後の動作試験に一発でパスするのは誰にとっても喜ばしい驚きであろうが、常にそうした幸運に恵まれるとは限らない。しかもコード中のミスを特定する上で、httpdの返してくる標準エラーメッセージは、たいていの場合において物の役に立たないものである。こうした意味不明なエラーメッセージに悩まされるか、それとも問題の根源を速やかに特定できるかの分かれ目となるのが、先に触れたcgitbなどのデバッガが利用できるかどうかなのだ。ここではcgitbの機能を確認する目的で、2つ目のサンプルスクリプトに意図的なエラーを混入させ、問題の発生源となっているコード部をcgitbを用いて特定してみよう。
まずはexample2.pyを開きファイルの最終行に移動する。この行には「(int(laptops) + int(desktops))
」というステートメントが記述されているが、ここにある+記号を/記号に変更し、「(int(laptops) / int(desktops))
」というステートメントに変更したファイルを保存しておく。こうした変更後のexample2.pyをURL指定によりWebブラウザに読み込むと、先に実行した場合と異なり空白ページが表示されるだけになっているはずだ。つまりここで仕掛けたエラーは、スクリプトの実行を妨げる一方でデバッグに利用可能な情報を何も出力させない性質のものなのである。
次に再度example2.pyを開き、ファイルの先頭部にあるimport cgi
というステートメントの直下に下記の2行を追加する。
import cgitb cgitb.enable()
この変更後のファイルを/var/www/cgi-binに保存してURL指定による読み込みを行うと、今度は単なる空白のWebページではなく、サンプルスクリプトの何処に問題があるかについての詳細なレポートが表示されるはずだ。この場合cgitbから表示されているのは「ZeroDivisionError: integer division or modulo by zero」というゼロ除算の発生を告げるメッセージなので、このスクリプトを再度正常に動作させるには、エラーの発生源である/記号を+記号に戻してexample2.pyを保存し直せばいいと判断できるのである。
とは言うものの、算術演算子の使い方に関する単発的なミスの特定などは高度なデバッグ機能を必要とするものでもないし、むしろ人間が自力でチェックした方が簡単に特定できそうなものである。しかしながら実際に用いるスクリプトはこうしたサンプルよりも遥かに長いコードとなるものであり、そうした長くて複雑なスクリプト中の何処かに存在するはずのエラー行という存在は、その1つを特定するだけでもかなりの長時間を要しかねないのだ。特にcgitbの使用は、タイプミスなどの識別に要する時間を大幅に節約してくれることになる。
更なる学習に向けて
スペースの都合もあるため、本稿では簡単なサンプルスクリプトを紹介するだけに止まり、CGIスクリプティングにおいてPythonがどれほど有用であるかを説明しきれなかったが、読者の学習意欲を刺激することはできたと思う。Pythonについてより深く学びたいという場合は、Magnus Lie Hetland氏の著した『Beginning Python: From Novice to Professional』や、O’Reillyから刊行されているMark Lutz氏の『Programming Python, Third Edition』が参考になるはずだ。
Bob Currierは、フロリダ州サラソータにあるMote Marine Laboratory社の主任データエンジニアとしてLinuxサーバファームを管理すると同時に、自動潜水艇用の運航制御コード開発に携わっており、そうした活動の傍ら、Linux.com、Network World、ZDnet.com、Smart Computingなど数多くの業界紙誌に100本を超える記事および書評や論評を寄稿している。