http://www.yiibai.com/python/python_cgi_programming.html
什麼是CGI ?
公共網關接口或CGI,Web服務器和一個自定義的腳本之間交換信息是是一組定義的標準..
CGI規範在由NCSA和NCSA定義的CGI保持如下:
公共網關接口或CGI,如HTTP服務器信息服務器的標準接口是外部網關方案.
當前版本CGI/1.1和CGI/1.2.
網頁瀏覽
理解CGI的概念,讓我們看看會發生什麼,當我們點擊一個超鏈接到瀏覽特定網頁或URL.
您的瀏覽器觸點的HTTP Web服務器,即需求的URL ie.文件名.
Web服務器解析URL,如果發現該文件,然後發送回瀏覽器,否則發送錯誤消息表明您已經請求一個錯誤的文件.
Web瀏覽器從Web服務器的響應,並顯示收到的文件或錯誤消息.
但是,它可能設立的HTTP服務器,因此,只要在某個目錄中的文件被請求文件送回,而是作爲一個程序執行,任何方案產出發送您的瀏覽器來顯示。這個函數被調用的通用網關接口或CGI程序稱爲CGI腳本。這些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文件中的下列行:
AllowOverride None Options ExecCGI Order allow,deny Allow from allOptions All
在這裏,我假設你有Web服務器,併成功運行,你可以運行任何其他CGI程序像Perl或shell等.
第一個CGI 程序
下面是一個簡單的鏈接,鏈接到CGI腳本名爲hello.py。此文件被保存在/var/www/cgi-bin目錄,它有以下內容。運行CGI程序之前,確保你有CHAGE模式使用 UNIX命令chmod命令 755 hello.py,使文件的可執行文件.
#!/usr/bin/python print "Content-type:text/html\r\n\r\n" print '' print '' print 'Hello Word - First CGI Program' print '' print '' print '
Hello Word! This is my first CGI program
' print '' print ''如果你點擊hello.py然後,這將產生以下輸出:
Hello Word! This is my first CGI program |
這個的hello.py腳本是一個簡單的Python腳本,這是寫在stdout文件,即它的輸出瀏覽器的屏幕。有一個重要的和額外的功能,這是第一行要打印的內容類型:文本/html\R\N\R\N。此行被髮送回瀏覽器,並指定內容類型的瀏覽器屏幕上顯示。現在,你必須理解CGI的基本概念,可以使用Python寫了許多複雜的CGI程序。這個腳本可以與任何其他擴展系統交換,如RDBMS的信息.
HTTP 頭
該行的內容類型:文本/html\R\N\R\n是理解的內容被髮送到瀏覽器的HTTP頭的一部分。所有的HTTP報頭,將在下列表格
HTTP Field Name: Field Content For Example Content-type: text/html\r\n\r\n
還有其他一些重要的HTTP頭,你會經常使用的CGI編程.
Header | Description |
---|---|
Content-type: | A MIME string defining the format of the file being returned. Example is Content-type:text/html |
Expires: Date | The date the information becomes invalid. This should be used by the browser to decide when a page needs to be refreshed. A valid date string should be in the format 01 Jan 1998 12:00:00 GMT. |
Location: URL | The URL that should be returned instead of the URL requested. You can use this filed to redirect a request to any file. |
Last-modified: Date | The date of last modification of the resource. |
Content-length: N | The length, in bytes, of the data being returned. The browser uses this value to report the estimated download time for a file. |
Set-Cookie: String | Set the cookie passed through the string |
CGI環境變量
所有的CGI程序,將有機會獲得以下環境變量。編寫任何CGI程序,這些變量發揮了重要作用.
Variable Name | Description |
CONTENT_TYPE | The data type of the content. Used when the client is sending attached content to the server. For example file upload etc. |
CONTENT_LENGTH | The length of the query information. It's available only for POST requests |
HTTP_COOKIE | Return the set cookies in the form of key & value pair. |
HTTP_USER_AGENT | The User-Agent request-header field contains information about the user agent originating the request. Its name of the web browser. |
PATH_INFO | The path for the CGI script. |
QUERY_STRING | The URL-encoded information that is sent with GET method request. |
REMOTE_ADDR | The IP address of the remote host making the request. This can be useful for logging or for authentication purpose. |
REMOTE_HOST | The fully qualified name of the host making the request. If this information is not available then REMOTE_ADDR can be used to get IR address. |
REQUEST_METHOD | The method used to make the request. The most common methods are GET and POST. |
SCRIPT_FILENAME | The full path to the CGI script. |
SCRIPT_NAME | The name of the CGI script. |
SERVER_NAME | The server's hostname or IP Address |
SERVER_SOFTWARE | The name and version of the software the server is running. |
這裏是小的CGI程序列出所有的CGI變量。
#!/usr/bin/python import os print "Content-type: text/html\r\n\r\n"; print "Environment<\br>"; for param in os.environ.keys(): print "%20s: %s<\br>" % (param,os.environ[param])
GET和POST 方法
你所遇到的許多情況下,當您需要從您的瀏覽器,Web服務器,並最終給你的CGI程序傳遞一些信息。最常用的瀏覽器使用兩種方法將此信息傳遞到Web服務器。這些方法是GET方法和POST方法.
使用GET方法傳遞信息:
GET方法發送編碼的用戶信息添加到頁面請求。分隔頁和編碼信息?字符作爲如下:
http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2
GET方法是defualt從瀏覽器向Web服務器的方法來傳遞信息,它會產生一個很長的字符串出現在瀏覽器的位置:框。切勿使用GET方法,如果你有密碼或其他敏感信息傳遞給服務器。 GET方法尺寸limtation:只有1024個字符,可以在請求字符串.
此信息通過使用QUERY_STRING的頭,將通過QUERY_STRING環境變量在你的CGI程序訪問
你可以通過簡單的連接鍵和值對非常久遠的任何URL的信息,或您可以使用HTML標籤來傳遞信息,使用GET方法.
簡單 URL 例子 : Get 方法
這裏是一個簡單的URL使用GET方法,這將通過兩個值hello_get.py方案.
下面是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 "" print "" print "Hello - Second CGI Program" print "" print "" print "
Hello %s %s
" % (first_name, last_name) print "" print ""This would generate following result:
Hello ZARA ALI |
簡單的FORM 例子:GET方法
下面是一個簡單的例子,通過這兩個值,使用HTML表單和提交按鈕。我們將使用相同的CGI腳本hello_get.py的處理此輸入.
First Name:Last Name:
這裏是上述形式的實際輸出,輸入第一個和最後一個名稱,然後點擊提交按鈕來查看結果.
First Name:
Last Name:
使用POST方法傳遞信息:
更可靠的信息傳遞給CGI程序的一般方法是POST方法。這包裝完全相同的方式爲GET方法的信息,而是它作爲一個文本字符串發送後?在URL中發送它作爲一個單獨的消息。此消息來自標準輸入的形式到CGI腳本.
下面是同hello_get.py腳本處理的GET以及POST方法.
#!/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 "" print "" print "Hello - Second CGI Program" print "" print "" print "
Hello %s %s
" % (first_name, last_name) print "" print ""讓我們再次看同以上相同的例子,其中通過兩個值,使用HTML表單和提交按鈕。我們將使用相同的CGI腳本hello_get.py的處理此輸入.
First Name:Last Name:
這裏是上述形式的實際輸出,輸入第一個和最後一個名稱,然後點擊提交按鈕來查看結果.
First Name:
Last Name:
傳遞複選框(checkbox)數據給CGI程序
複選框用於多個選項被選中時,.
這裏有兩個複選框的形式例如HTML代碼
Maths Physics
這段代碼的結果是下面的形式
Maths Physics下面是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 "" print "" print "Checkbox - Third CGI Program" print "" print "" print "
CheckBox Maths is : %s
" % math_flag print "CheckBox Physics is : %s
" % physics_flag print "" print ""單選按鈕數據傳遞給CGI程序
單選按鈕被選中時,只有一個選項是必需的.
這裏是兩個單選按鈕的形式例如HTML代碼:
MathsPhysics
這段代碼的結果是下面的形式
Maths Physics Physics下面是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:="" print="" "content-type:text="" html\r\n\r\n"="" ""="" "radio="" -="" fourth="" cgi="" program"="" "Selected Subject is %s" % subject print "" print ""="">
文本區域數據傳遞到CGI程序
TEXTAREA元素時使用多行文字要傳遞給CGI程序.
這裏是一個textarea框的形式例如HTML代碼:
Type your text here...
下面是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 "" print ""; print "Text Area - Fifth CGI Program" print "" print "" print "
Entered Text Content is %s
" % text_content print ""通過下拉框數據到CGI程序
下拉框是用來當我們有很多可供選擇,但只有一個或兩個將被選中.
這裏是一個下拉框的例子表單的HTML代碼
MathsPhysics
這段代碼的結果是下面的形式
下面是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 "" print "" print "Dropdown Box - Sixth CGI Program" print "" print "" print "
Selected Subject is %s
" % subject print "" print ""使用CGI中的Cookies
HTTP協議是無狀態的協議。但是,對於一個商業網站,它需要保持不同的頁面之間的會話信息。例如,一個用戶註冊完成後,許多網頁結束。但如何保持用戶會話信息的所有網頁.
在許多情況下,使用Cookie的記憶和跟蹤首選項,購買,佣金,其他更好的遊客體驗或網站統計所需的信息是最有效的方法.
它如何工作?
你的服務器發送一些數據到訪問者的瀏覽器Cookie的形式。瀏覽器可以接受的cookie。如果是這樣,它是作爲一個訪問者的硬盤驅動器上的純文本記錄存儲。現在,當遊客到達另一個網站上的網頁,cookie是用於檢索。一旦檢索,您的服務器知道/記得存儲.
Cookie是一個純文本的數據5可變長度字段記錄:
Expires : cookie將到期日期。如果是空白,訪問者退出瀏覽器時,cookie將到期.
Domain : 您的網站域名.
Path : 目錄或網頁設置cookie的路徑。這可能是空白的,如果你想從任何目錄或頁面的cookie檢索.
Secure : 目錄或網頁設置cookie的路徑。這可能是空白的,如果你想從任何目錄或頁面的cookie檢索.
Name=Value : Cookies是鍵和值對的形式設置和retrviewed.
設置Cookies
這是很容易發送到瀏覽器的cookies。這些cookie將被髮送HTTP頭之前的內容類型提交。假設你要設置用戶名和密碼的cookie。因此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.yiibai.com;\r\n" print "Set-Cookie:Path=/perl;\n" print "Content-type:text/html\r\n\r\n" ...........Rest of the HTML Content....
從這個例子中,你必須瞭解如何設置Cookie。我們使用設置CookieHTTP的頭設置Cookie.
在這裏,它是可選的設置Cookie的屬性,如過期,域和路徑。值得注意的是,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-數據。與該文件類型的輸入標記將創建一個“瀏覽”按鈕.
File:
這段代碼的結果是下面的形式:
注: 上面的例子已被禁用,故意人上傳的文件保存在我們的服務器上。但你可以嘗試上面的代碼與您的服務器.
這裏是處理文件上傳的的腳本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
%s
""" % (message,)Note:如果你是以上腳本運行在Unix / Linux,那麼你會採取如下替換文件分隔,否則您的Windows上述open()語句應該正常工作.
fn = os.path.basename(fileitem.filename.replace("\\", "/" ))
如何提高“文件下載”對話框 ?
有時你想給其中一個用戶點擊一個鏈接,它會彈出“文件下載”對話框的用戶,而不是顯示實際內容的選項。這是很容易的,將通過HTTP頭achived。
這個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()