Python3-CGIプログラミング

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

CGIとは何ですか?

  • Common Gateway Interface(CGI)は、外部ゲートウェイプログラムがHTTPサーバーなどの情報サーバーとインターフェイスするための標準です。

  • 現在のバージョンはCGI / 1.1であり、CGI /1.2は進行中です。

Webブラウジング

CGIの概念を理解するために、ハイパーリンクをクリックして特定のWebページまたはURLを参照するとどうなるかを見てみましょう。

  • ブラウザはHTTPWebサーバーに接続し、URL、つまりファイル名を要求します。

  • WebサーバーはURLを解析し、ファイル名を探します。そのファイルが見つかった場合はブラウザに送り返します。それ以外の場合は、間違ったファイルをリクエストしたことを示すエラーメッセージを送信します。

  • WebブラウザはWebサーバーから応答を受け取り、受信したファイルまたはエラーメッセージのいずれかを表示します。

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

CGIアーキテクチャ図

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

CGIプログラミングを続行する前に、WebサーバーがCGIをサポートし、CGIプログラムを処理するように構成されていることを確認してください。HTTPサーバーによって実行されるすべてのCGIプログラムは、事前設定されたディレクトリに保存されます。このディレクトリはCGIディレクトリと呼ばれ、慣例により/ var / www / cgi-binという名前が付けられています。慣例により、CGIファイルの拡張子はとしてです。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プログラム

これは、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>')

Note−スクリプトの最初の行は、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ファイル(画面)に書き込みます。印刷される最初の行である利用可能な1つの重要で追加の機能がありますContent-type:text/html\r\n\r\n。この行はブラウザに返送され、ブラウザ画面に表示されるコンテンツタイプを指定します。

これで、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ヘッダーは他にもいくつかあります。

シニア番号 ヘッダーと説明
1

Content-type:

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

2

Expires: Date

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

3

Location: URL

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

4

Last-modified: Date

リソースが最後に変更された日付。

5

Content-length: N

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

6

Set-Cookie: String

文字列を介して渡されるCookieを設定します

CGI環境変数

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

シニア番号 変数名と説明
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プログラムです。結果は表示するには、このリンクをクリックして環境を手に入れよう

#!/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プログラムに情報を渡す必要がある場合、多くの状況に遭遇したに違いありません。ほとんどの場合、ブラウザは2つの方法を使用し、2つはこの情報をWebサーバーに渡します。これらのメソッドは、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と連結するだけで情報を渡すか、HTML <FORM>タグを使用してGETメソッドを使用して情報を渡すことができます。

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

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

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

以下であり hello_get.pyWebブラウザからの入力を処理するスクリプト。使用します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メソッド

この例では、HTMLFORMと送信ボタンを使用して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>"

HTMLFORMと送信ボタンを使用して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を取得できるようになります。取得されると、サーバーは何が保存されたかを認識/記憶します。

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

  • Expires−Cookieの有効期限が切れる日付。これが空白の場合、訪問者がブラウザを終了するとCookieは期限切れになります。

  • Domain −サイトのドメイン名。

  • Path−Cookieを設定するディレクトリまたはWebページへのパス。任意のディレクトリまたはページからCookieを取得する場合は、これを空白にすることができます。

  • Secure−このフィールドに「セキュア」という単語が含まれている場合、Cookieはセキュアサーバーでのみ取得できます。このフィールドが空白の場合、そのような制限はありません。

  • Name = Value − Cookieは、キーと値のペアの形式で設定および取得されます。

クッキーの設定

ブラウザにCookieを送信するのは非常に簡単です。これらのCookieは、HTTPヘッダーとともにContent-typeフィールドに送信されます。ユーザー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.tutorialspoint.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 Cookieを設定するためのHTTPヘッダー。

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

クッキーの取得

設定されたすべての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()

このチュートリアルを楽しんでいただけたでしょうか。はいの場合は、フィードバックをお送りください。お問い合わせ