Python CGI編程

來源:互聯網
上載者:User

什麼是CGI

CGI 目前由NCSA維護,NCSA定義CGI如下:

CGI(Common Gateway Interface),通用閘道介面,它是一段程式,運行在伺服器上如:HTTP伺服器,提供同用戶端HTML頁面的介面。

網頁瀏覽

為了更好的瞭解CGI是如何工作的,我們可以從在網頁上點擊一個連結或URL的流程:

1、使用你的瀏覽器訪問URL並串連到HTTP 網頁伺服器。

2、Web伺服器接收到請求資訊後會解析URL,並尋找訪問的檔案在伺服器上是否存在,如果存在返迴文件的內容,否則返回錯誤資訊。

3、瀏覽器從伺服器上接收資訊,並顯示接收的檔案或者錯誤資訊。

CGI程式可以是Python指令碼,PERL指令碼,SHELL指令碼,C或者C++程式等。

CGI架構圖

Web伺服器支援及配置

在你進行CGI編程前,確保您的Web伺服器支援CGI及已經配置了CGI的處理常式。

所有的HTTP伺服器執行CGI程式都儲存在一個預先配置的目錄。這個目錄被稱為CGI目錄,並按照慣例,它被命名為/var/www/cgi-bin目錄。

CGI檔案的副檔名為.cgi,python也可以使用.py副檔名。

預設情況下,Linux伺服器配置啟動並執行cgi-bin目錄中為/var/www。

如果你想指定其他運行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>

第一個CGI程式

我們使用Python建立第一個CGI程式,檔案名稱為hellp.py,檔案位於/var/www/cgi-bin目錄中,內容如下,修改檔案的許可權為755:

#!/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>'

以上程式在瀏覽器訪問顯示結果如下:

Hello Word! This is my first CGI program

這個的hello.py指令碼是一個簡單的Python指令碼,指令碼第一的輸出內容"Content-type:text/html\r\n\r\n"發送到瀏覽器並告知瀏覽器顯示的內容類型為"text/html"。

HTTP頭部

hello.py檔案內容中的" Content-type:text/html\r\n\r\n"即為HTTP頭部的一部分,它會發送給瀏覽器告訴瀏覽器檔案的內容類型。

HTTP頭部的格式如下:

HTTP 欄位名: 欄位內容

例如

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

以下表格介紹了CGI程式中HTTP頭部經常使用的資訊:

描述

Content-type: 請求的與實體對應的MIME資訊。例如: Content-type:text/html

Expires: Date 響應到期的日期和時間

Location: URL 用來重新導向接收方到非請求URL的位置來完成請求或標識新的資源

Last-modified: Date 請求資源的最後修改時間

Content-length: N 請求的內容長度

Set-Cookie: String 設定Http Cookie

CGI環境變數

所有的CGI程式都接收以下的環境變數,這些變數在CGI程式中發揮了重要的作用:

變數名

描述

CONTENT_TYPE 這個環境變數的值指示所傳遞來的資訊的MIME類型。目前,環境變數CONTENT_TYPE一般都是:application/x-www-form-urlencoded,他表示資料來自於HTML表單。

CONTENT_LENGTH 如果伺服器與CGI程式資訊的傳遞方式是POST,這個環境變數即使從標準輸入STDIN中可以讀到的有效資料的位元組數。這個環境變數在讀取所輸入的資料時必須使用。

HTTP_COOKIE 客戶機內的 COOKIE 內容。

HTTP_USER_AGENT 提供包含了版本數或其他專有資料的客戶瀏覽器資訊。

PATH_INFO 這個環境變數的值表示緊接在CGI程式名之後的其他路徑資訊。它常常作為CGI程式的參數出現。

QUERY_STRING 如果伺服器與CGI程式資訊的傳遞方式是GET,這個環境變數的值即使所傳遞的資訊。這個資訊經跟在CGI程式名的後面,兩者中間用一個問號'?'分隔。

REMOTE_ADDR 這個環境變數的值是發送請求的客戶機的IP地址,例如上面的192.168.1.67。這個值總是存在的。而且它是Web客戶機需要提供給Web伺服器的唯一標識,可以在CGI程式中用它來區分不同的Web客戶機。

REMOTE_HOST 這個環境變數的值包含發送CGI請求的客戶機的主機名稱。如果不支援你想查詢,則無需定義此環境變數。

REQUEST_METHOD 提供指令碼被調用的方法。對於使用 HTTP/1.0 協議的指令碼,僅 GET 和 POST 有意義。

SCRIPT_FILENAME CGI指令碼的完整路徑

SCRIPT_NAME CGI指令碼的的名稱

SERVER_NAME 這是你的 WEB 伺服器的主機名稱、別名或IP地址。

SERVER_SOFTWARE 這個環境變數的值包含了調用CGI程式的HTTP伺服器的名稱和版本號碼。例如,上面的值為Apache/2.2.14(Unix)

以下是一個簡單的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方法

瀏覽器用戶端通過兩種方法向伺服器傳遞資訊,這兩種方法就是 GET 方法和 POST 方法。

使用GET方法傳輸資料

GET方法發送編碼後的使用者資訊到服務端,資料資訊包含在請求頁面的URL上,以"?"號分割, 如下所示:

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2

有關 GET 請求的其他一些注釋:

GET 請求可被緩衝

GET 請求保留在瀏覽器記錄中

GET 請求可被收藏為書籤

GET 請求不應在處理敏感性資料時使用

GET 請求有長度限制

GET 請求只應當用於取回資料

簡單的url執行個體:GET方法

以下是一個簡單的URL,使用GET方法向hello_get.py程式發送兩個參數:

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

以下為hello_get.py檔案的代碼:

#!/usr/bin/python

# CGI處理模組

import cgi, cgitb

# 建立 FieldStorage 的執行個體化

form = cgi.FieldStorage()

# 擷取資料

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

簡單的表單一實例:GET方法

以下是一個通過HTML的表單使用GET方法向伺服器發送兩個資料,提交的伺服器指令碼同樣是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方法傳遞資料

使用POST方法向伺服器傳遞資料是更安全可靠的,像一些敏感資訊如使用者密碼等需要使用POST傳輸資料。

以下同樣是hello_get.py ,它也可以處理瀏覽器提交的POST表單資料:

#!/usr/bin/python

# 引入 CGI 模組

import cgi, cgitb

# 建立 FieldStorage 執行個體

form = cgi.FieldStorage()

# 擷取表單資料

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>"

以下為表單通過POST方法向伺服器指令碼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程式傳遞checkbox資料

checkbox用於提交一個或者多個選項資料,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>

以下為 checkbox.cgi 檔案的代碼:

#!/usr/bin/python

# 引入 CGI 處理模組

import cgi, cgitb

# 建立 FieldStorage的執行個體

form = cgi.FieldStorage()

# 接收欄位資料

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程式傳遞Radio資料

Radio只向伺服器傳遞一個資料,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>

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 資料

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>

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程式傳遞下拉資料

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>

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協議一個很大的缺點就是不作使用者身份的判斷,這樣給編程人員帶來很大的不便,

而cookie功能的出現彌補了這個缺憾。

所有cookie就是在客戶訪問指令碼的同時,通過客戶的瀏覽器,在客戶硬碟上寫入紀錄資料 ,當下次客戶訪問指令碼時取回資料資訊,從而達到身份判別的功能,cookie常用在密碼判斷中 。

 

cookie的文法

http cookie的發送是通過http頭部來實現的,他早於檔案的傳遞,頭部set-cookie的文法如下:

Set-cookie:name=name;expires=date;path=path;domain=domain;secure

name=name: 需要設定cookie的值(name不能使用";"和","號),有多個name值時用";"分隔例如:name1=name1;name2=name2;name3=name3。

expires=date: cookie的有效期間限,格式: expires="Wdy,DD-Mon-YYYY HH:MM:SS"

path=path: 設定cookie支援的路徑,如果path是一個路徑,則cookie對這個目錄下的所有檔案及子目錄生效,例如: path="/cgi-bin/",如果path是一個檔案,則cookie指對這個檔案生效,例如:path="/cgi-bin /cookie.cgi"。

domain=domain: 對cookie生效的網域名稱,例如:domain="www.chinalb.com"

secure: 如果給出此標誌,表示cookie只能通過SSL協議的https伺服器來傳遞。

cookie的接收是通過設定環境變數HTTP_COOKIE來實現的,CGI程式可以通過檢索該變數擷取cookie資訊。

Cookie設定

Cookie的設定非常簡單,cookie會在http頭部單獨發送。以下執行個體在cookie中設定了UserID 和 Password:

<pre>

#!/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.ziqiangxuetang.com;\r\n"

print "Set-Cookie:Path=/perl;\n"

print "Content-type:text/html\r\n\r\n"

...........Rest of the HTML Content....

以上執行個體使用了 Set-Cookie 頭資訊來設定Cookie資訊,可選項中設定了Cookie的其他屬性,如到期時間Expires,網域名稱Domain,路徑Path。這些資訊設定在 "Content-type:text/html\r\n\r\n"之前。

檢索Cookie資訊

Cookie資訊檢索頁非常簡單,Cookie資訊儲存在CGI的環境變數HTTP_COOKIE中,儲存格式如下:

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

以下是一個簡單的CGI檢索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

以上指令碼輸出結果如下:

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()

# 擷取檔案名稱

fileitem = form['filename']

# 檢測檔案是否上傳

if fileitem.filename:

# 設定檔案路徑

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,你必須替換檔案分隔字元,在window下只需要使用open()語句即可:

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

檔案下載對話方塊

如果我們需要為使用者提供檔案下載連結,並在使用者點選連結後彈出檔案下載對話方塊,我們通過設定HTTP頭資訊來實現這些功能,功能代碼如下:

#!/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 hear.

fo = open("foo.txt", "rb")

str = fo.read();

print str

# Close opend file

fo.close()

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.