【Python 3.6】Linux+AnacondaでCGIを動かそう

みなさんは、CGIという言葉を聞いたことがありますか?

CGIは、プログラムを使ってホームページを表示するための方式です。

有名なプログラム言語であるPythonを使ったり、PHPPerlJavaなどの様々な言語を使ったりして、CGIを作成できます。

あなたはいま、以下のような疑問が浮かんでいませんか?

・CGIってなに?
・CGIを動かすためのサーバーが必要だそうですが、どういうこと?
・ユーザーが入力した内容をプログラムで利用するにはどうすればいいの?
・画像ファイルをアップロードして変換結果を表示してみたいけど、難しくない?

そんなあなたに向けて、試しにPythonでCGIスクリプトを書いてみることをおすすめする記事を書きました。

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をインストールする必要があります。

この記事では、以下の記事で作成した環境を使いました。

Pythonの画像処理ライブラリpillowの使い方をわかりやすく解説!
更新日 : 2019年5月8日

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.CGIHTTPRequestHandlercgi_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で自由にアプリケーションを作成できるでしょう。

面白いモノができたら教えてくださいね!

書いた人

侍テック編集部

侍エンジニア塾は「人生を変えるプログラミング学習」をコンセンプトに、過去多くのフリーランスエンジニアを輩出したプログラミングスクールです。侍テック編集部では技術系コンテンツを中心に有用な情報を発信していきます。
サービスページはこちら
ツイッターはこちら
フェイスブックはこちら

あなたの目的に合わせた
SAMURAI ENGINEERの運営サービス

SAMURAI ENGINEER Pro

未経験でも挫折しないプログラミングスクール

詳細はこちら

SAMURAI ENGINEER Plus

日本最大級のサブスク型オンラインITスクール

詳細はこちら

SAMURAI ENGINEER Freelance

「一人で稼げる」スキルを身につける

詳細はこちら