Python - CGI編程:初學者指南

你好,未來的Python巫師們!我非常高興能成為你在這個令人興奮的CGI編程與Python結合的旅程中的嚮導。作為一個教了多年計算機科學的人,我告訴你,CGI就像是讓你的網頁應用程式活起來的秘密醬汁。所以,捲起袖子,我們一起深入探討吧!

Python - CGI Programming

什麼是CGI?

CGI代表公共網關接口。我知道這聽起來像是滿口胡言,但你可以把它看作是網頁伺服器和Python腳本之間的翻譯員。它就像是一個友好的口譯員,幫助你的伺服器和代碼無縫對接。

CGI使我們能夠創建動態網頁,能夠對用戶輸入做出反應。想像一個網站會根據你的名字來歡迎你,或者顯示個人化的內容 - 這就是CGI的魔法!

網頁瀏覽

在我們深入了解CGI之前,讓我們先簡單看看網頁瀏覽是如何工作的。當你在瀏覽器中輸入URL時,以下事情會發生:

  1. 你的瀏覽器向網頁伺服器發送請求。
  2. 網頁伺服器處理請求。
  3. 伺服器發送回應,通常是HTML頁面的形式。
  4. 你的瀏覽器渲染這個HTML,顯示你看到的網頁。

當我們想在第三步中生成動態內容時,CGI就派上用場了。

CGI架構圖

這裡有一個簡單的圖表,用來視覺化CGI如何在網頁架構中適用:

+-------------+    HTTP Request    +-------------+
|   瀏覽器   | -----------------> |  網頁伺服器 |
|             | <----------------- |             |
+-------------+    HTTP Response   +-------------+
|
| CGI
v
+-------------+
| CGI腳本  |
| (Python)    |
+-------------+

網頁伺服器支援與配置

大多數網頁伺服器支援CGI,包括Apache和Nginx。要使用CGI與Python,你需要配置你的伺服器以執行Python腳本。這通常涉及到設置一個特殊的目錄以存放CGI腳本,並告訴伺服器將此目錄中的文件視為可執行。

例如,在Apache中,你可能會在配置中添加如下內容:

<Directory /var/www/cgi-bin>
Options ExecCGI
AddHandler cgi-script .py
</Directory>

這會告訴Apache將/var/www/cgi-bin目錄中的.py文件作為CGI腳本執行。

第一個CGI程序

讓我們來寫第一個CGI程序吧!我們從經典的"Hello, World!"示例開始。在CGI目錄中創建一個名為hello.py的文件:

#!/usr/bin/env python3
print("Content-Type: text/html")
print()
print("<html>")
print("<head>")
print("<title>Hello World - 第一個CGI程序</title>")
print("</head>")
print("<body>")
print("<h2>Hello World! 這是我的第一個CGI程序</h2>")
print("</body>")
print("</html>")

讓我們來分解一下:

  1. 第一行告訴伺服器使用Python來執行這個腳本。
  2. Content-Type: text/html是一個HTTP標頭,告訴瀏覽器我們正在發送HTML。
  3. 空白的print()將標頭和響應的正文分開。
  4. 其餘的就是我們動態生成的HTML。

當你通過網頁瀏覽器訪問這個腳本時,你應該會看到一個顯示"Hello World! 這是我的第一個CGI程序"的頁面。

HTTP標頭

在CGI編程中, 在你的內容之前發送正確的HTTP標頭是至關重要的。 最常見的標頭是Content-Type,它告訴瀏覽器你正在發送什麼類型的數據。 以下是一些示例:

內容類型 描述
text/html HTML內容
text/plain 純文本
image/jpeg JPEG圖像
application/json JSON數據

永遠記得在內容之前發送適當的Content-Type標頭!

CGI環境變量

CGI腳本可以訪問各種環境變量,它們提供了有關請求的信息。 以下是一個顯示其中一些變量的腳本:

#!/usr/bin/env python3
import os

print("Content-Type: text/html")
print()
print("<html><body>")
print("<h2>環境變量:</h2>")
for param in os.environ.keys():
print(f"<b>%20s</b>: {os.environ[param]}<br>" % (param))
print("</body></html>")

這個腳本將顯示所有可用的環境變量,包括用戶的瀏覽器類型、伺服器名稱等。

GET和POST方法

有兩種主要的方法可以將數據發送到CGI腳本:GET和POST。我們來看看兩者:

GET方法

GET方法將數據作為URL的一部分發送。以下是一個簡單的例子:

#!/usr/bin/env python3
import cgi

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
name = form.getvalue('name', 'World')

print("<html><body>")
print(f"<h2>Hello, {name}!</h2>")
print("</body></html>")

你可以通過URL如http://yourserver.com/cgi-bin/hello.py?name=Alice訪問此腳本,它將顯示"Hello, Alice!"。

POST方法

POST方法將數據作為HTTP請求的正文發送。它通常用於表單。以下是一個示例:

#!/usr/bin/env python3
import cgi

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
name = form.getvalue('name', 'World')
email = form.getvalue('email', 'Not provided')

print("<html><body>")
print(f"<h2>Hello, {name}!</h2>")
print(f"<p>你的郵箱是:{email}</p>")
print("</body></html>")

這個腳本可以與使用POST方法的HTML表單一起使用。

處理不同的表單元素

CGI可以處理各種表單元素。我們來看看一些例子:

勾選框

#!/usr/bin/env python3
import cgi

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
hobbies = form.getlist('hobby')

print("<html><body>")
print("<h2>你的愛好:</h2>")
for hobby in hobbies:
print(f"<p>{hobby}</p>")
print("</body></html>")

開關按鈕

#!/usr/bin/env python3
import cgi

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
gender = form.getvalue('gender', '未指定')

print("<html><body>")
print(f"<h2>你的性別:{gender}</h2>")
print("</body></html>")

文本區域

#!/usr/bin/env python3
import cgi

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
message = form.getvalue('message', '沒有提供信息')

print("<html><body>")
print("<h2>你的信息:</h2>")
print(f"<p>{message}</p>")
print("</body></html>")

下拉框

#!/usr/bin/env python3
import cgi

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()
country = form.getvalue('country', '未選擇')

print("<html><body>")
print(f"<h2>你的國家:{country}</h2>")
print("</body></html>")

在CGI中使用Cookies

Cookies是將小塊數據存儲在客戶端的一種方式。它們用於記憶用戶偏好或維護會話信息。以下是你如何在CGI中處理cookies的方法:

設置Cookies

#!/usr/bin/env python3
import cgi
from http import cookies
import datetime

# 創建一個cookie
c = cookies.SimpleCookie()
c['lastvisit'] = str(datetime.datetime.now())
c['lastvisit']['expires'] = 365 * 24 * 60 * 60  # 一年後過期

print(c)  # 這會打印出Set-Cookie標頭
print("Content-Type: text/html")
print()

print("<html><body>")
print("<h2>Cookie設置!</h2>")
print("</body></html>")

檢索Cookies

#!/usr/bin/env python3
import os
from http import cookies

print("Content-Type: text/html")
print()

if 'HTTP_COOKIE' in os.environ:
cookie_string = os.environ.get('HTTP_COOKIE')
c = cookies.SimpleCookie()
c.load(cookie_string)
lastvisit = c.get('lastvisit')
if lastvisit:
print(f"<h2>你的最後訪問是在:{lastvisit.value}</h2>")
else:
print("<h2>這是你第一次訪問!</h2>")
else:
print("<h2>這是你第一次訪問!</h2>")

文件上傳示例

處理文件上傳有點複雜,但以下是一個簡單的例子:

#!/usr/bin/env python3
import cgi, os
import cgitb; cgitb.enable()

print("Content-Type: text/html")
print()

form = cgi.FieldStorage()

# 在這裡獲取文件名。
fileitem = form['filename']

# 測試文件是否上傳
if fileitem.filename:
# 從文件名中刪除前面的路徑,避免目錄遍歷攻擊
fn = os.path.basename(fileitem.filename)
open('/tmp/' + fn, 'wb').write(fileitem.file.read())
message = f'文件"{fn}"上傳成功'
else:
message = '沒有文件被上傳'

print(f"""\
<html>
<body>
<p>{message}</p>
</body>
</html>
""")

如何引發“文件下載”對話框?

要觸發文件下載,你需要設置適當的標頭:

#!/usr/bin/env python3
import os

filename = "example.txt"  # 這將是你的文件名
filepath = "/path/to/your/file"  # 這將是文件的路徑

print("Content-Type: application/octet-stream")
print(f"Content-Disposition: attachment; filename={filename}")
print()  # 空行,標頭結束

# 現在發送文件內容
with open(os.path.join(filepath, filename), 'rb') as f:
print(f.read())

這個腳本設置了Content-Type為application/octet-stream,這告訴瀏覽器下載文件而不是顯示它。Content-Disposition標頭建議下載時的文件名。

以上就是CGI編程與Python的基础知识。請記住,熟練掌握需要多加練習,所以不要害怕實驗這些例子並創建自己的。祝編程愉快,願你的CGI腳本永遠運行平穩!

Credits: Image by storyset