読者です 読者をやめる 読者になる 読者になる

座敷牢日誌

都落ちした元SEがソフトウェアやネット関連のことを書いています

CGIが思ったよりも簡単だった

w3mは「file:///cgi-bin/xxxx.cgi」でcgiスクリプトを動かすことができる。なんか作れたら面白いよなあと思って、最近はCGIのことを調べることが多い。
昔はCGIで動かすことを想定したPerlのスクリプトを配布しているサイトがいっぱいあって、その頃はまだWebアプリケーションなんて言葉がなかったと思う。その頃自分はまだ高校生くらいで、同じようなスクリプトを拾ってきてローカルで動かしたり、カスタマイズして遊んでいた記憶がある。
当然、自分でもスクリプトを書いてみようとしたものだけど、正直Perlは難しかった。基本も知らずにいきなり掲示板のようなものを作ろうとすれば挫折するのは当然の帰結だ、と今は思うけど。
w3m用にCGIにトライしてみたところ、実は簡単だったんだなと思った。

CGIを動作させるための環境を用意する

ローカル内で動かしているApacheの設定ファイルを確認する必要がある。Ubuntudebianであれば、「/etc/apache2/sites-available」というディレクトリのなかにあって、有効な設定ファイルを開くと、次の記述がある。

	ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
	<Directory "/usr/lib/cgi-bin">
		AllowOverride None
		Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
		Order allow,deny
		Allow from all
	</Directory>

「/usr/lib/cgi-bin」にあるファイルをCGIスクリプトとする。「http://localhost/cgi-bin」でアクセスできるものとする、というのがこの設定の意味。だから、動かしたいスクリプトは「/usr/lib/cgi-bin」配下に置く。
僕はもともとあるdefaultをコピーしたものを有効にしていて、ドキュメントルートとcgi-binのディレクトリをホームディレクトリ配下に変えた。

  • ドキュメントルート「/var/www」 -> 「/home/username/var/www」
  • スクリプトのディレクトリ「/usr/lib/cgi-bin」 -> 「/home/username/lib/cgi-bin」

pythonでスクリプトを書いてみる

こんな感じのスクリプトを「~/lib/cgi-bin/test-01-py.cgi」に保存する。

#!/usr/bin/python
# coding: utf8

print u""" \
        Content-Type: text/html

        Hello world!
        """

そして実行権限を与えてやる。

$ chmod +x test-01-py.cgi

早速ブラウザで開いてみる。「http://localhost/cgi-bin/test-01-py.cgi」へアクセスする。

f:id:zashikiro:20120905030959p:plain

できた。

ここでのポイントはこれだけかなと。

  • 実行権限の付与
  • レスポンスヘッダを忘れないこと
  • レスポンスヘッダと出力内容の間に改行を2つ入れてやる

これらに誤りがあると、「500 Internal Server Error」がでる。ほんの少しだけハマった。

f:id:zashikiro:20120905031033p:plain

GETでフォームデータを扱ってみる

GETでフォーム入力のデータを扱ってみるテスト。次のスクリプトを「~/lib/cgi-bin/test-02-py.cgi」として保存し、実行権限を付与する。

#!/usr/bin/python
# coding: utf8

import os

# フォームを出力
print u"""\
        Content-Type: text/html

        <html>
        <body>
        <form method="GET" action="./test-02-py.cgi">
        <p>youre name:<input type="text" name="yourname" /></p>
        <p>address:<input type="text" name="address" /></p>
        <p><input type="submit" /></p>
        </form>
        """

# 環境変数 QUERY_STRING を表示
print "<pre style=\"color:red\">QUERY_STRING -> %s</pre>" % \
        os.getenv("QUERY_STRING")

print u""" \
        </body>
        </html>
        """

ブラウザで開いてみる。「http://localhost/cgi-bin/test-02-py.cgi」へアクセスし、フォームが出力されることを確認する。

f:id:zashikiro:20120905031042p:plain

フォームに値を入れて、フォームデータを送信。環境変数 QUERY_STRINGに値が入ることを確認する。

f:id:zashikiro:20120905031055p:plain

うーん、こんな簡単なんだっけ。

POSTメソッドでも試してみる

POSTメソッドで送信されたデータは環境変数・CONTENT_LENGTHの長さだけ、標準入力からとってくることになっている。
次のようなスクリプトを作って、「~/lib/cgi-bin/test-03-py.cgi」として保存する。

#!/usr/bin/python
# coding: utf8

import os
import sys

# フォームを出力
print u"""\
        Content-Type: text/html

        <html>
        <body>
        <form method="POST" action="./test-03-py.cgi">
        <p>youre name:<input type="text" name="yourname" /></p>
        <p>address:<input type="text" name="address" /></p>
        <p><input type="submit" /></p>
        </form>
        """

# 環境変数 CONTENT_LENGTH を出力
print "<pre style=\"color:red\">CONTENT_LENGTH => %s</pre>" % \
        os.getenv("CONTENT_LENGTH")

# 標準入力の内容を出力
print "<pre style=\"color:blue\">sys.stdin.read() => %s</pre>" % \
        sys.stdin.read()

print u""" \
        </body>
        </html>
        """

そして、フォームに値を入れて送信。

f:id:zashikiro:20120905031112p:plain

ちゃんと入力した値が入ってる。

フォームデータは標準モジュール「cgi」で扱える

ここまで環境変数と標準入力の内容を直接参照して、フォームデータのやりとりを試してみた。pythonには「cgi」という標準モジュールがあって、CGIスクリプトをもうちょい効率よく書けるようになっている。フォームデータの扱いについても、より安全に行えるメソッドがいくつもあるので、実際はそっちを使うべきだろう。

CGIは難しくないのだ

CGIは実行可能なファイルで、フォームデータを環境変数や標準入力を経由して取得し、それらをスクリプトのなかで扱ってやる、というだけだ。とりあえずpythonで試してみたが、C#(Mono)やbashスクリプトでも同じようなことができた。
まあ、今はapacheのモジュールとして動作させるほうが主流なので、CGIの知識が役立つ場面は少ないかもしれない。個人的にはCGIはハードルが高い、という長い間あった思い込みが解消できて、とりあえず満足。
既にいくつかw3m用のスクリプトを書いて動かしたりしている。用途もコードも恥ずかしいので晒す気はないけど。

広告を非表示にする