cgi.py
使用python编写cgi程序时,需要使用该模块;它还提供了一些调试脚本,以及处理文件上传请求的工具。
1 介绍
cgi脚本由http server(Apache httpd,nginx)调用,通常处理一些用户提交的信息。
CGI脚本的输出应该包括两部分,这两部分由空行分开。
第一部分说明返回内容的形式:
print "Content-Type: text/html" # HTML is following
print # blank line, end of headers
第二部分是返回的内容,一般为html;
print "<TITLE>CGI script output</TITLE>"
print "<H1>This is my first CGI script</H1>"
print "Hello, world!"
2 使用
2.1
模块引用
import cgi
import cgitb
cgitb.enable()
cgitb 会开启异常处理机制,可以在浏览器中看到错误的详细信息。如果不想在页面显示,也可以通过以下形式将其保存在指定文件中:
import cgitb
cgitb.enable(display=0, logdir="/path/to/logdir")
在开发cgi脚本时特别有用。可以在脚本测试完成后,再删除cgitb配置行。
2.2 表单数据
处理表单数据时,最好使用 FieldStorage 类。
form = cgi.FieldStorage()
if "name" not in form or "addr" not in form:
print "<H1>Error</H1>"
print "Please fill in the name and addr fields."
return
print "<p>name:", form["name"].value
print "<p>addr:", form["addr"].value
...further form processing here...
值为空的表单字段会被过滤掉,因此使用时需要判断是否存某字段,也可以使用FieldStorage(keep_blank_values=true)来保留这些空值的字段。
- 字段值可以通过value属性获得;
- 也可以通过getvalue()方法获得,getvalue()方法运行设置defalut value。
当提交的表单中,一个字段name对应多个value时, getvalue()将返回一个list。如果使用 form.getlist(),那么将始终返回一个list。
value = form.getlist("username")
usernames = ",".join(value)
表单:
<input type="checkbox" name="item" value="1" />
<input type="checkbox" name="item" value="2" />
cgi脚本可以这样写:
item = form.getvalue("item")
if isinstance(item, list):
# The user is requesting more than one item.
else:
# The user is requesting only one item.
如果以简单的形式处理:
user = form.getvalue("user").upper()
这种情况下,请求数据的格式一定不能出错,如果有的client在url的query字符串中也添加了一个 item=foo。那么cgi脚本就崩溃了,因为getvalue会返回一个列表。
这种通过判断的形式写的cgi脚本,逻辑判断太多,可读性不好。一个更方便的方法是使用 getfirst() 和 getlist()。
FieldStorage.getfirst(name [, defalut])
该方法只返回第一个值,当然第一值是否与期望值是否匹配,因浏览器而异。如果字段值为空时,也可以给定一个默认值。
FieldStorage.getlist(name)
该方法始终返回一个list,当值为空时,则返回空list。
import cgi
form = cgi.FieldStorage()
user = form.getfirst("user", "").upper() # This way it's safe.
for item in form.getlist("item"):
do_something(item)
这样的代码会显得更加优雅紧凑。
2.3 上传文件处理
如果字段为上传的文件名,那么通过value或者getvalue()访问该时将会以字符串的形式读取内存中的文件。一般情况下,应该先做判断,然后再读取。
fileitem = form["userfile"]
if fileitem.file:
# It's an uploaded file; count lines
linecount = 0
while 1:
line = fileitem.file.readline()
if not line: break
linecount = linecount + 1
通过Post提交的表单,同时又存在 query 字符串的形式,那么将同时包含 FieldStorage 和 MiniFieldStorage。
3 函数
cgi.parse()
cgi.parse_header()
cgi.test()
cgi.print_environ()
cgi.print_form()
cgi.print_directory()
cgi.print_environ_usage()
cgi.escape()
4 其他
对于任何需要cgi脚本读、写的文件,应该有足够的读(0644)写(0666)权限,出于安全考虑,HTTP server以 ‘nobody’用户执行脚本,没有任何特殊权限。
当需要加载自定义的 python 模块时,可以先在脚本中更改模块搜索路径。
import sys
sys.path.insert(0, "/usr/home/joe/lib/python")
sys.path.insert(0, "/usr/local/lib/python")
- 如果脚本有语法错误,Pyhotn解析器就不会去执行,HTTP Server将会发送未知错误到client。
#> python cgi-script.py
通过以上方式可以检测是否有语法错误。