Python3-python-cgi-programming

提供:Dev Guides
移動先:案内検索

Python 3-CGIプログラミング

Common Gateway Interface(CGI)は、Webサーバーとカスタムスクリプト間で情報を交換する方法を定義する一連の標準です。 CGI仕様は現在、NCSAによって維持されています。

CGIとは何ですか?

  • Common Gateway Interface(CGI)は、HTTPサーバーなどの情報サーバーとインターフェイスする外部ゲートウェイプログラムの標準です。
  • 現在のバージョンはCGI/1.1で、CGI/1.2は進行中です。

ウェブブラウジング

CGIの概念を理解するために、ハイパーリンクをクリックして特定のWebページまたはURLを閲覧したときに何が起こるかを見てみましょう。

  • ブラウザはHTTP Webサーバーにアクセスし、URL、つまりファイル名を要求します。
  • WebサーバーはURLを解析し、ファイル名を探します。 そのファイルが見つかった場合、ブラウザに送り返します。それ以外の場合は、間違ったファイルを要求したことを示すエラーメッセージを送信します。 *WebブラウザはWebサーバーからの応答を受け取り、受信したファイルまたはエラーメッセージを表示します。

ただし、特定のディレクトリ内のファイルが要求されるたびに、そのファイルが送り返されないようにHTTPサーバーを設定することは可能です。代わりに、プログラムとして実行され、そのプログラム出力がブラウザに表示されるように送り返されます。 この機能はCommon Gateway InterfaceまたはCGIと呼ばれ、プログラムはCGIスクリプトと呼ばれます。 これらのCGIプログラムは、Pythonスクリプト、PERLスクリプト、シェルスクリプト、CまたはC ++プログラムなどです。

CGIアーキテクチャ図

CGIアーキテクチャ

Webサーバーのサポートと構成

CGIプログラミングを進める前に、WebサーバーがCGIをサポートし、CGIプログラムを処理するように構成されていることを確認してください。 HTTPサーバーによって実行されるすべてのCGIプログラムは、事前に構成されたディレクトリに保持されます。 このディレクトリはCGIディレクトリと呼ばれ、慣例により/var/www/cgi-binと名付けられます。 慣例により、CGIファイルの拡張子はasです。* cgi、ただし、ファイルをpython拡張子 *.py で保持することもできます。

デフォルトでは、Linuxサーバーは/var/wwwのcgi-binディレクトリー内のスクリプトのみを実行するように構成されています。 CGIスクリプトを実行する他のディレクトリを指定する場合は、httpd.confファイルの次の行をコメント化します-

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options ExecCGI
   Order allow,deny
   Allow from all
</Directory>

<Directory "/var/www/cgi-bin">
Options All
</Directory>

ここでは、Webサーバーが正常に稼働しており、PerlやShellなどの他のCGIプログラムを実行できることを前提としています。

最初のCGIプログラム

これは、link:/cgi-bin/hello.py [hello.py]というCGIスクリプトにリンクされた簡単なリンクです。 このファイルは/var/www/cgi-binディレクトリに保存され、次の内容が含まれています。 CGIプログラムを実行する前に、 chmod 755 hello.py UNIXコマンドを使用してファイルのモードを変更し、ファイルを実行可能にしてください。

#!/usr/bin/python

print ("Content-type:text/html\r\n\r\n")
print ('<html>')
print ('<head>')
print ('<title>Hello Word - First CGI Program</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word! This is my first CGI program</h2>')
print ('</body>')
print ('</html>')

-スクリプトの最初の行はPython実行可能ファイルへのパスでなければなりません。 Linuxでは#!/usr/bin/python3になります

ブラウザに次のURLを入力してください

http://localhost:8080/cgi-bin/hello.py
Hello Word! This is my first CGI program

このhello.pyスクリプトは単純なPythonスクリプトであり、出力をSTDOUTファイル、つまり画面に書き込みます。 印刷される最初の行である Content-type:text/html \ r \ n \ r \ n という重要で追加の機能が1つあります。 この行はブラウザに送り返され、ブラウザ画面に表示されるコンテンツタイプを指定します。

これまでに、CGIの基本概念を理解している必要があり、Pythonを使用して多くの複雑なCGIプログラムを作成できます。 このスクリプトは、他の外部システムとも対話して、RDBMSなどの情報を交換できます。

HTTPヘッダ

Content-type:text/html \ r \ n \ r \ n は、コンテンツを理解するためにブラウザに送信されるHTTPヘッダーの一部です。 すべてのHTTPヘッダーは次の形式になります-

HTTP Field Name: Field Content

For Example
Content-type: text/html\r\n\r\n

CGIプログラミングで頻繁に使用する他の重要なHTTPヘッダーはほとんどありません。

Sr.No. Header & Description
1

Content-type:

返されるファイルの形式を定義するMIME文字列。 例はContent-type:text/htmlです

2

Expires: Date

情報が無効になる日付。 ブラウザがページを更新する必要がある時期を決定するために使用します。 有効な日付文字列の形式は、1998年1月1日12:00:00 GMTです。

3

Location: URL

要求されたURLの代わりに返されるURL。 このフィールドを使用して、リクエストを任意のファイルにリダイレクトできます。

4

Last-modified: Date

リソースの最終変更日。

5

Content-length: N

返されるデータの長さ(バイト単位)。 ブラウザはこの値を使用して、ファイルの推定ダウンロード時間を報告します。

6

Set-Cookie: String

_string_を介して渡されるCookieを設定します

CGI環境変数

すべてのCGIプログラムは、次の環境変数にアクセスできます。 これらの変数は、CGIプログラムの作成中に重要な役割を果たします。

Sr.No. Variable Name & Description
1

CONTENT_TYPE

コンテンツのデータ型。 クライアントが添付コンテンツをサーバーに送信するときに使用されます。 たとえば、ファイルのアップロード。

2

CONTENT_LENGTH

クエリ情報の長さ。 POSTリクエストでのみ使用できます。

3

HTTP_COOKIE

設定されたCookieをキーと値のペアの形式で返します。

4

HTTP_USER_AGENT

User-Agent request-headerフィールドには、リクエストを発信したユーザーエージェントに関する情報が含まれています。 Webブラウザーの名前です。

5

PATH_INFO

CGIスクリプトのパス。

6

QUERY_STRING

GETメソッド要求で送信されるURLエンコードされた情報。

7

REMOTE_ADDR

要求を行っているリモートホストのIPアドレス。 これは、ロギングまたは認証に役立ちます。

8

REMOTE_HOST

要求を行っているホストの完全修飾名。 この情報が利用できない場合、REMOTE_ADDRを使用してIRアドレスを取得できます。

9

REQUEST_METHOD

要求を行うために使用されるメソッド。 最も一般的なメソッドはGETおよびPOSTです。

10

SCRIPT_FILENAME

CGIスクリプトへのフルパス。

11

SCRIPT_NAME

CGIスクリプトの名前。

12

SERVER_NAME

サーバーのホスト名またはIPアドレス

13

SERVER_SOFTWARE

サーバーが実行しているソフトウェアの名前とバージョン。

すべてのCGI変数をリストする小さなCGIプログラムを次に示します。 このリンクをクリックして結果を確認してくださいhttp://www.finddevguides.com/cgi-bin/get_env.py[Get Environment]

#!/usr/bin/python

import os

print ("Content-type: text/html\r\n\r\n");
print ("<font size=+1>Environment</font><\br>");
for param in os.environ.keys():
   print ("<b>%20s</b>: %s<\br>" % (param, os.environ[param]))

GETおよびPOSTメソッド

ブラウザからWebサーバーに、そして最終的にはCGIプログラムに何らかの情報を渡す必要がある場合、多くの状況に遭遇したに違いありません。 ほとんどの場合、ブラウザはこの情報をWebサーバーに渡す2つの方法を使用します。 これらのメソッドは、GETメソッドとPOSTメソッドです。

GETメソッドを使用して情報を渡す

GETメソッドは、エンコードされたユーザー情報をページリクエストに追加して送信します。 ページとエンコードされた情報は、? 次のような文字-

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2
  • GETメソッドは、ブラウザからWebサーバーに情報を渡すデフォルトのメソッドであり、ブラウザのLocation:boxに表示される長い文字列を生成します。
  • サーバーに渡すパスワードまたはその他の機密情報がある場合は、GETメソッドを使用しないでください。
  • GETメソッドにはサイズ制限があります。リクエスト文字列で送信できるのは1024文字のみです。
  • GETメソッドはQUERY_STRINGヘッダーを使用して情報を送信し、QUERY_STRING環境変数を介してCGIプログラムでアクセスできます。

キーと値のペアをURLと一緒に連結するだけで情報を渡すことができます。または、GETメソッドを使用してHTML <FORM>タグを使用して情報を渡すことができます。

単純なURLの例:Getメソッド

これは、GETメソッドを使用してhello_get.pyプログラムに2つの値を渡す簡単なURLです。

/cgi-bin/hello_get.py?first_name=ZARA&last_name=ALI

以下は、Webブラウザからの入力を処理する hello_get.py スクリプトです。 私たちは cgi モジュールを使用します。これにより、渡された情報へのアクセスが非常に簡単になります-

#!/usr/bin/python

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print ("Content-type:text/html\r\n\r\n")
print ("<html>")
print ("<head>")
print ("<title>Hello - Second CGI Program</title>")
print ("</head>")
print ("<body>")
print ("<h2>Hello %s %s</h2>" % (first_name, last_name))
print ("</body>")
print ("</html>")

これは、次の結果を生成します-

Hello ZARA ALI

簡単なFORMの例:GETメソッド

この例では、HTML FORMと送信ボタンを使用して2つの値を渡します。 この入力を処理するために同じCGIスクリプトhello_get.pyを使用します。

<form action = "/cgi-bin/hello_get.py" method = "get">
   First Name: <input type = "text" name = "first_name">  <br/>

   Last Name: <input type = "text" name = "last_name"/>
   <input type = "submit" value = "Submit"/>
</form>

上記のフォームの実際の出力は次のとおりです。名と姓を入力し、送信ボタンをクリックして結果を確認します。

名前苗字:

POSTメソッドを使用して情報を渡す

CGIプログラムに情報を渡すより一般的に信頼できる方法は、POSTメソッドです。 これは、GETメソッドとまったく同じ方法で情報をパッケージ化しますが、?の後にテキスト文字列として送信する代わりに URLで別のメッセージとして送信します。 このメッセージは、標準入力の形式でCGIスクリプトに入力されます。

以下は、GETメソッドとPOSTメソッドを処理する同じhello_get.pyスクリプトです。

#!/usr/bin/python

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

HTMLフォームと送信ボタンを使用して2つの値を渡す上記と同じ例をもう一度見てみましょう。 この入力を処理するために同じCGIスクリプトhello_get.pyを使用します。

<form action = "/cgi-bin/hello_get.py" method = "post">
First Name: <input type = "text" name = "first_name"><br/>
Last Name: <input type = "text" name = "last_name"/>

<input type = "submit" value = "Submit"/>
</form>

上記のフォームの実際の出力は次のとおりです。 姓と名を入力し、送信ボタンをクリックして結果を確認します。

名前苗字:

チェックボックスデータをCGIプログラムに渡す

チェックボックスは、複数のオプションを選択する必要がある場合に使用されます。

ここに2つのチェックボックスを持つフォームのHTMLコードの例があります-

<form action = "/cgi-bin/checkbox.cgi" method = "POST" target = "_blank">
   <input type = "checkbox" name = "maths" value = "on"/> Maths
   <input type = "checkbox" name = "physics" value = "on"/> Physics
   <input type = "submit" value = "Select Subject"/>
</form>

このコードの結果は次の形式です-

数学物理学

以下は、Webブラウザからチェックボックスボタンに指定された入力を処理するためのcheckbox.cgiスクリプトです。

#!/usr/bin/python

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
if form.getvalue('maths'):
   math_flag = "ON"
else:
   math_flag = "OFF"

if form.getvalue('physics'):
   physics_flag = "ON"
else:
   physics_flag = "OFF"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Checkbox - Third CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> CheckBox Maths is : %s</h2>" % math_flag
print "<h2> CheckBox Physics is : %s</h2>" % physics_flag
print "</body>"
print "</html>"

ラジオボタンデータをCGIプログラムに渡す

オプションを1つだけ選択する必要がある場合は、ラジオボタンが使用されます。

これは、2つのラジオボタンがあるフォームのHTMLコードの例です-

<form action = "/cgi-bin/radiobutton.py" method = "post" target = "_blank">
   <input type = "radio" name = "subject" value = "maths"/> Maths
   <input type = "radio" name = "subject" value = "physics"/> Physics
   <input type = "submit" value = "Select Subject"/>
</form>

このコードの結果は次の形式です-

数学物理学

以下は、ラジオボタンのWebブラウザーによって与えられた入力を処理するradiobutton.pyスクリプトです-

#!/usr/bin/python

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
if form.getvalue('subject'):
   subject = form.getvalue('subject')
else:
   subject = "Not set"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Radio - Fourth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

テキスト領域データをCGIプログラムに渡す

TEXTAREA要素は、複数行のテキストをCGIプログラムに渡す必要がある場合に使用されます。

以下は、TEXTAREAボックスを持つフォームのHTMLコードの例です-

<form action = "/cgi-bin/textarea.py" method = "post" target = "_blank">
   <textarea name = "textcontent" cols = "40" rows = "4">
      Type your text here...
   </textarea>
   <input type = "submit" value = "Submit"/>
</form>

このコードの結果は次の形式です-

以下は、Webブラウザによって与えられた入力を処理するtextarea.cgiスクリプトです-

#!/usr/bin/python

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
if form.getvalue('textcontent'):
   text_content = form.getvalue('textcontent')
else:
   text_content = "Not entered"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>";
print "<title>Text Area - Fifth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Entered Text Content is %s</h2>" % text_content
print "</body>"

ドロップダウンボックスデータをCGIプログラムに渡す

ドロップダウンボックスは、使用可能なオプションが多数あるが、1つまたは2つだけが選択される場合に使用されます。

これは、1つのドロップダウンボックスがあるフォームのHTMLコードの例です-

<form action = "/cgi-bin/dropdown.py" method = "post" target = "_blank">
   <select name = "dropdown">
      <option value = "Maths" selected>Maths</option>
      <option value = "Physics">Physics</option>
   </select>
   <input type = "submit" value = "Submit"/>
</form>

このコードの結果は次の形式です-

数学物理学

以下は、Webブラウザーからの入力を処理するdropdown.pyスクリプトです。

#!/usr/bin/python

# Import modules for CGI handling
import cgi, cgitb

# Create instance of FieldStorage
form = cgi.FieldStorage()

# Get data from fields
if form.getvalue('dropdown'):
   subject = form.getvalue('dropdown')
else:
   subject = "Not entered"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Dropdown Box - Sixth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

CGIでのCookieの使用

HTTPプロトコルはステートレスプロトコルです。 商用Webサイトの場合、異なるページ間でセッション情報を維持する必要があります。 たとえば、多くのページを完了すると、1人のユーザー登録が終了します。 すべてのWebページにわたってユーザーのセッション情報を維持する方法は?

多くの場合、Cookieの使用は、ユーザーの利便性やサイトの統計情報を改善するために必要な設定、購入、手数料、その他の情報を記憶および追跡する最も効率的な方法です。

使い方?

サーバーは、Cookieの形式で訪問者のブラウザにデータを送信します。 ブラウザはCookieを受け入れる場合があります。 存在する場合、訪問者のハードドライブにプレーンテキストレコードとして保存されます。 これで、訪問者がサイトの別のページに到達すると、Cookieを取得できます。 取得されると、サーバーは保存された内容を認識/記憶します。

クッキーは5つの可変長フィールドのプレーンテキストデータレコードです-

  • 有効期限-Cookieの有効期限が切れる日付。 これが空白の場合、訪問者がブラウザを終了すると、Cookieは期限切れになります。
  • ドメイン-サイトのドメイン名。
  • Path -Cookieを設定するディレクトリまたはWebページへのパス。 任意のディレクトリまたはページからCookieを取得する場合、これは空白になる場合があります。
  • Secure -このフィールドに「secure」という単語が含まれている場合、Cookieはセキュアサーバーでのみ取得できます。 このフィールドが空白の場合、そのような制限はありません。
  • 名前=値-Cookieはキーと値のペアの形式で設定および取得されます。

クッキーを設定する

クッキーをブラウザに送信するのは非常に簡単です。 これらのCookieは、HTTPヘッダーとともにコンテンツタイプフィールドに送信されます。 ユーザーIDとパスワードをCookieとして設定するとします。 クッキーの設定は次のように行われます-

#!/usr/bin/python
print "Set-Cookie:UserID = XYZ;\r\n"
print "Set-Cookie:Password = XYZ123;\r\n"
print "Set-Cookie:Expires = Tuesday, 31-Dec-2007 23:12:40 GMT;\r\n"
print "Set-Cookie:Domain = www.finddevguides.com;\r\n"
print "Set-Cookie:Path =/perl;\n"
print "Content-type:text/html\r\n\r\n"
...........Rest of the HTML Content....

この例から、Cookieの設定方法を理解している必要があります。 Set-Cookie HTTPヘッダーを使用して、Cookieを設定します。

Expires、Domain、PathなどのCookie属性を設定することはオプションです。 マジックライン "Content-type:text/html \ r \ n \ r \ n を送信する前にCookieが設定されていることは注目に値します。

Cookieを取得する

設定されたすべてのCookieを取得するのは非常に簡単です。 クッキーはCGI環境変数HTTP_COOKIEに格納されており、次の形式になります-

key1 = value1;key2 = value2;key3 = value3....

Cookieを取得する方法の例を次に示します。

#!/usr/bin/python

# Import modules for CGI handling
from os import environ
import cgi, cgitb

if environ.has_key('HTTP_COOKIE'):
   for cookie in map(strip, split(environ['HTTP_COOKIE'], ';')):
      (key, value ) = split(cookie, '=');
      if key == "UserID":
         user_id = value

      if key == "Password":
         password = value

print "User ID  = %s" % user_id
print "Password = %s" % password

これにより、上記のスクリプトで設定されたCookieに対して次の結果が生成されます-

User ID = XYZ
Password = XYZ123

ファイルアップロードの例

ファイルをアップロードするには、HTMLフォームのenctype属性を multipart/form-data に設定する必要があります。 ファイルタイプの入力タグは、「参照」ボタンを作成します。

<html>
   <body>
      <form enctype = "multipart/form-data" action = "save_file.py" method = "post">
      <p>File: <input type = "file" name = "filename"/></p>
      <p><input type = "submit" value = "Upload"/></p>
      </form>
   </body>
</html>

このコードの結果は次の形式です-

ファイル:

上記の例は、サーバーにファイルをアップロードするユーザーを保存するために意図的に無効にされていますが、サーバーで上記のコードを試すことができます。

ファイルのアップロードを処理するスクリプト save_file.py を次に示します-

#!/usr/bin/python

import cgi, os
import cgitb; cgitb.enable()

form = cgi.FieldStorage()

# Get filename here.
fileitem = form['filename']

# Test if the file was uploaded
if fileitem.filename:
   # strip leading path from file name to avoid
   # directory traversal attacks
   fn = os.path.basename(fileitem.filename)
   open('/tmp/' + fn, 'wb').write(fileitem.file.read())

   message = 'The file "' + fn + '" was uploaded successfully'

else:
   message = 'No file was uploaded'

print """\
Content-Type: text/html\n
<html>
   <body>
      <p>%s</p>
   </body>
</html>
""" % (message,)

Unix/Linuxで上記のスクリプトを実行する場合、次のようにファイル区切り文字を置き換えるように注意する必要があります。そうしないと、Windowsマシンでopen()ステートメントの上で問題なく動作します。

fn = os.path.basename(fileitem.filename.replace("\\", "/" ))

「ファイルのダウンロード」ダイアログボックスを上げる方法は?

ユーザーがリンクをクリックすると、実際のコンテンツを表示する代わりに「ファイルのダウンロード」ダイアログボックスがポップアップするオプションを提供したい場合があります。 これは非常に簡単で、HTTPヘッダーを使用して実現できます。 このHTTPヘッダーは、前のセクションで説明したヘッダーとは異なります。

たとえば、特定のリンクから FileName ファイルをダウンロード可能にする場合、その構文は次のとおりです-

#!/usr/bin/python

# HTTP Header
print "Content-Type:application/octet-stream; name = \"FileName\"\r\n";
print "Content-Disposition: attachment; filename = \"FileName\"\r\n\n";

# Actual File Content will go here.
fo = open("foo.txt", "rb")

str = fo.read();
print str

# Close opend file
fo.close()

このチュートリアルをお楽しみください。 はいの場合は、link:/about/contact_us [お問い合わせ]からフィードバックを送ってください。