みなさんは、CGIという言葉を聞いたことがありますか?
CGIは、プログラムを使ってホームページを表示するための方式です。
有名なプログラム言語であるPythonを使ったり、PHP、Perl、Javaなどの様々な言語を使ったりして、CGIを作成できます。
あなたはいま、以下のような疑問が浮かんでいませんか?
・CGIを動かすためのサーバーが必要だそうですが、どういうこと?
・ユーザーが入力した内容をプログラムで利用するにはどうすればいいの?
・画像ファイルをアップロードして変換結果を表示してみたいけど、難しくない?
そんなあなたに向けて、試しにPythonでCGIスクリプトを書いてみることをおすすめする記事を書きました。
本記事を読む前に、Pythonがどんなプログラミング言語なのかをおさらいしておきたい人は次の記事を参考にしてください。
→ Pythonとは?特徴やできること、活用例をわかりやすく簡単に解説
なお、その他のPythonの記事についてはこちらにまとめています。
CGIとは
CGI(Common Gateway Interface)は、ホームページを表示するための方式の一つです。
CGIを理解する助けになるように、CGI以外の方式と比較してみました。
方式 | Webブラウザ(Webクライアント)によってURLが指定されたときの動作 |
---|---|
静的HTMLファイル方式 | URLに対応したHTMLファイルをWebブラウザに返す |
CGI方式、モジュール方式 | URLに対応したプログラムを実行し、実行結果をWebブラウザに返す。プログラムは、Pythonに限らずPHPやPerl、Javaで作成できます |
上記のとおり、CGI方式とモジュール方式はどちらもプログラムを使う方式ですが、サーバー側の設定の違いや、HTTPヘッダをどのプログラムが出力するかの違いなど、いくつかの違いがあります。
詳しくは、以下のサイトが参考になりますので、ぜひご覧ください。
参考:https://www.fumi.org/neta/201205sv.html
Pythonではなく、PHPのケースを説明していますが、考え方は同じです。
この記事では、PythonでCGIプログラムを作成し、CGI方式を利用するサイトを動作させる方法を説明します。
Pythonを準備しよう
PythonでCGIを使おうとしていますので、Pythonをインストールする必要があります。
この記事では、以下の記事で作成した環境を使いました。
CGIを使うだけならpillowは必要ありませんが、pillowで画像を変換するホームページを作成しましょう。
サーバーを準備しよう
CGIに対応したサーバーを用意します。
簡易的で簡単に試せるサーバーと、本格的で設定が大変なサーバーの2つを紹介します。
http.serverモジュール
簡易的で簡単に試せるサーバーです。
Python 3のhttp.serverモジュールを利用します。
※ちなみにPython 2の場合は、CGIHTTPServerモジュールを使いましょう。
まずは、作業用ディレクトリを作成して、そこに移動しましょう。
(1)「端末」を起動して、以下のコマンドを1行ずつ順番に入力します。
source activate pillow mkdir -p python/cgi-demo/ cd python/cgi-demo/
http.serverモジュールは、CGIプログラムが「CGIディレクトリ」に存在する場合のみプログラムの実行を許可する仕組みになっています。
「CGIディレクトリ」は、http.server.CGIHTTPRequestHandlerのcgi_directoriesで指定できます。
今回は、標準設定([‘/cgi-bin‘, ‘/htbin‘])のまま使いますので、cgi-binディレクトリを作成します。
(2)以下のコマンドを入力します。
mkdir cgi-bin
では、サーバーを起動しましょう。
(3)以下のコマンドを入力します。
python -m http.server --cgi
これでサーバーの準備は完了です。
Apache
本格的で設定が大変なサーバーとして、Apacheの設定を紹介しましょう。
(1)「端末」を起動して、以下のコマンドを入力します。
sudo apt install apache2
画面の指示に従って、Apacheをインストールしましょう。
(2)ブラウザを起動して「http://localhost/」にアクセスします。
Apacheが起動していれば、以下のように表示されます。
次に、CGIを有効にします。
(3)以下のコマンドを1行ずつ順番に入力します。
sudo ln -s /etc/apache2/mods-available/cgi.load /etc/apache2/mods-enabled/cgi.load sudo service apache2 restart
ちなみにApacheでは、ディレクトリごとにCGIプログラムの実行を許可する仕組みになっています。
標準では/usr/lib/cgi-binディレクトリで、CGIプログラムの実行が許可されています。
Hello, world!を表示してみよう
では、CGIプログラムを実行して、「Hello, world!」を表示してみましょう。
(1)以下のsample.cgiファイルを作成します。
http.serverモジュールを使う場合:
「python -m http.server –cgi」を実行したディレクトリの下にあるcgi-binディレクトリに、sample.cgiファイルを作成します。
Apacheを使う場合:
/usr/lib/cgi-binディレクトリに、sample.cgiファイルを作成します。
なお、/usr/lib/cgi-binディレクトリにファイルを作成するには、root権限が必要です。
sample.cgi:
#!/usr/bin/env python # -*- coding: utf-8 -*- import cgi import cgitb cgitb.enable() print("Content-Type: text/html") # HTML is following print("") # blank line, end of headers print("<TITLE>CGI script output</TITLE>") print("<H1>This is my first CGI script</H1>") print("Hello, world!")
実行権限を付与します。
(2)新しい「端末」を起動し、以下のコマンドを入力します。
http.serverモジュールを使う場合:
chmod +x python/cgi-demo/cgi-bin/sample.cgi
Apacheを使う場合:
sudo chmod +x /usr/lib/cgi-bin/sample.cgi
(3)ブラウザでsample.cgiにアクセスします。
http.serverモジュールを使う場合:
「http://localhost:8000/cgi-bin/sample.cgi」にアクセスします。
Apacheを使う場合:
「http://localhost/cgi-bin/sample.cgi」にアクセスします。
どちらの場合も、以下のようなページが表示されます。
Hello, world!が表示できましたね。
フォームを使って名前と住所を取得してみよう
次は、ユーザーがフォームに入力した内容を、プログラムで取得してみましょう。
わかりやすく、フォームに入力した内容を表示してみます。
(1)以下のform.htmlファイルを作成します。
http.serverモジュールを使う場合:
「python -m http.server –cgi」を実行したディレクトリに、form.htmlファイルを作成します。
Apacheを使う場合:
/var/www/htmlディレクトリに、form.htmlファイルを作成します。
なお、/var/www/htmlディレクトリにファイルを作成するには、root権限が必要です。
form.html:
<html> <head> <meta charset="utf-8"> <title>サンプルフォーム</title> </head> <body> <h1>cgi-bin/sample2.cgi</h2> <form action="cgi-bin/sample2.cgi" method="POST"> <p> ■ユーザー名<br/> <input type="text" name="name"><br/> </p> <p> ■住所<br/> <input type="text" name="addr"><br/> </p> <input type="submit" value="送信"> </form> </body> </html>
(2)以下のsample2.cgiファイルを作成します。
http.serverモジュールを使う場合:
「python -m http.server –cgi」を実行したディレクトリの下にあるcgi-binディレクトリに、sample2.cgiファイルを作成します。
Apacheを使う場合:
/usr/lib/cgi-binディレクトリに、sample2.cgiファイルを作成します。
なお、/usr/lib/cgi-binディレクトリにファイルを作成するには、root権限が必要です。
sample2.cgi:
#!/usr/bin/env python # -*- coding: utf-8 -*- import cgi import cgitb cgitb.enable() print("Content-Type: text/html; charset=utf-8") # HTML is following print("") # blank line, end of headers form = cgi.FieldStorage() if "name" not in form or "addr" not in form: print("<H1>Error</H1>") print("Please fill in the name and addr fields.") else: import html print("<H1>the name and addr fields</H1>") print("<p>name:", html.escape(form["name"].value), "</p>") print("<p>addr:", html.escape(form["addr"].value), "</p>")
form = cgi.FieldStorage()で、ユーザーが入力した内容をformに代入し、form[“name”].valueで値を取り出しています。
(3)ブラウザでform.htmlにアクセスします。
http.serverモジュールを使う場合:
「http://localhost:8000/form.html」にアクセスします。
Apacheを使う場合:
「http://localhost/form.html」にアクセスします。
どちらの場合も、以下のようなページが表示されます。
(4)ユーザー名と住所を入力して、「送信」をクリックします。
入力した名前と住所が表示されます。
ユーザーが入力したフォームから値を取得できました。
ファイルをアップロードしてみよう
最後は、ユーザーがアップロードした画像ファイルをpillowで加工して表示するプログラムです。
(1)以下のupload.htmlファイルを作成します。
http.serverモジュールを使う場合:
「python -m http.server –cgi」を実行したディレクトリに、upload.htmlファイルを作成します。
Apacheを使う場合:
/var/www/htmlディレクトリに、upload.htmlファイルを作成します。
なお、/var/www/htmlディレクトリにファイルを作成するには、root権限が必要です。
upload.html:
<html> <head> <meta http-equiv="Content-Type" content="text/html" charset="UTF-8" /> <title>アップロード</title> </head> <body> <h1>cgi-bin/sample3.cgi</h1> ■ファイル <form action="cgi-bin/sample3.cgi" method="POST" enctype="multipart/form-data"> <p><input type="file" name="imagefile"></p> <p><input type="submit"></p> </form> </body> </html>
(2)以下のsample3.cgiファイルを作成します。
http.serverモジュールを使う場合:
「python -m http.server –cgi」を実行したディレクトリの下にあるcgi-binディレクトリに、sample3.cgiファイルを作成します。
Apacheを使う場合:
/usr/lib/cgi-binディレクトリに、sample3.cgiファイルを作成します。
なお、/usr/lib/cgi-binディレクトリにファイルを作成するには、root権限が必要です。
sample3.cgi:
#!/usr/bin/env python # -*- coding: utf-8 -*- import cgi import cgitb cgitb.enable() print("Content-Type: text/html; charset=utf-8") # HTML is following print("") # blank line, end of headers form = cgi.FieldStorage() if "imagefile" in form: fileitem = form["imagefile"] if fileitem.file: # It's an uploaded file; count lines from PIL import Image image = Image.open(fileitem.file) image.save("org.png") image.convert("1").save("1_1-bit-pixels.png") image.convert("L").save("L_8-bit-grayscale.png") image.convert("P").save("P_8-bit-colors.png") print("<h1>オリジナル</h1>") print("<img src=\"../org.png\" width=\"350\">") print("<h1>画像モード変換後</h1>") print("<table>") print(" <tr><td>1_1-bit-pixels.png<br />") print(" <img src=\"../1_1-bit-pixels.png\" width=\"350\"></td>") print(" <td>L_8-bit-grayscale.png<br />") print(" <img src=\"../L_8-bit-grayscale.png\" width=\"350\"></td>") print(" <td>P_8-bit-colors.png<br />") print(" <img src=\"../P_8-bit-colors.png\" width=\"350\"></td></tr>")
form = cgi.FieldStorage()で、ユーザーがアップロードした内容をformに代入し、fileitem = form[“imagefile”]とfileitem.fileでファイルを取り出しています。
(3)ブラウザでupload.htmlにアクセスします。
http.serverモジュールを使う場合:
「http://localhost:8000/upload.html」にアクセスします。
Apacheを使う場合:
「http://localhost/upload.html」にアクセスします。
どちらの場合も、以下のようなページが表示されます。
(4)「参照」をクリックして、画像ファイルを選択し、「送信」をクリックします。
アップロードした画像と、pillowで変換した画像が表示されます。
まとめ
今回は、PythonでCGIを作成する方法を説明しました。
簡易的なサーバーのhttp.serverモジュールの利用方法と、本格的なサーバーのApacheの利用方法を説明しました。
サーバーの種類によって、設定も異なりますし、htmlファイルやcgiファイルを保存するディレクトリも異なりましたね。
次に、単純なプログラムを作って、文字列を表示するだけのCGIを作成しました。
また、ユーザーがフォームで入力した文字をプログラムで取得するCGIや、ユーザーがフォームからアップロードした画像データを加工するCGIも紹介しました。
ここまでできれば、あとはPythonで自由にアプリケーションを作成できるでしょう。
面白いモノができたら教えてくださいね!