Common Gateway Interface(CGI)是一个用来生成网页动态内容或者应用程序的标准方法。CGI在web服务器和web content生成程序之间提供一个接口。这个web content生成程序一般被称为CGI scripts或者简单点叫CGIs,通常由脚本语言写成,但是也能用任何的编程语言编写。
举个粟子,如果你想把一个数据库挂到网上,使得所有人都能查询它。基本上,你需要创建一个CGI程序,这个程序能够传送信息给数据库引擎,能够接收回查询结果。当web服务器执行这个CGI程序,并把从CGI中得到的查询结果写到web页面中传回给客户,也就使得查询完成。这也是为什么CGI叫gateway的原因。
CGI通常用来处理HTML中的<FORM>和<ISINDEX>元素。
Web服务器支持及配置
确保服务器支持CGI及已经配置CGI处理程序。
所有的服务器执行CGI程序都保存在一个预先配置的目录。这个目录被称为CGI目录,通常是cgi-bin。
CGI文件的扩展名为.cgi。
在httpd下可以配置httpd.conf文件如下:
-
1 <Directory"/var/www/cgi-bin"> 2 AllowOverrideNone 3 OptionsExecCGI 4 Order allow,deny 5 Allow from all 6 </Directory> 7 8 <Directory"/var/www/cgi-bin"> 9 OptionsAll 10 </Directory>
两种使用方法
通过表单间接调用:
-
1 <formmethod="POST"action="/cgi-bin/login"> 2 姓名:<input type="text"name="T1"size="20"><br> 3 身份证号码:<inputtype="text"name="T2"size="20"><br> 4 <inputtype="submit"value="提 交"name="B1"> 5 <inputtype="reset"value="重 写"name="B2"></p> 6 </form>
通过链接直接调用:
-
1 <body> 2 <a href="/cgi-bin/displaytime">显示服务器时间</a> 3 </body>
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地址。这个值总是存在的。而且它是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服务器的名称和版本号。 |
第一个CGI程序
-
1 #!/usr/bin/python 2 3 print("Content-type:text/html\r\n\r\n") 4 print("""<html> 5 <head> 6 <title>Hello Word - First CGI Program</title> 7 </head> 8 <body> 9 <h2>Hello Word! This is my first CGI program</h2> 10 </body> 11 </html>""")
在httpd中"/cgi-bin/"被等同于 "/var/www/cgi-bin/"。所以在调用的时候path可以直接写/cgi-bin/..
获取表单数据
index.html
-
1 <html> 2 <head> 3 <title>test</title> 4 </head> 5 <body> 6 <formaction="/cgi-bin/hello_get.py"method="get"> 7 First Name: <inputtype="text"name="first_name"> <br/> 8 9 Last Name: <inputtype="text"name="last_name"/> 10 <inputtype="submit"value="Submit"/> 11 </form> 12 </body> 13 </html>
当用户单击确认按钮时(这里是Submit),表单的内容会传送到另一个文件。表单的action属性定义了目的文件的文件名。由动作属性定义的这个文件通常会对接收到输入数据进行相关处理。
method通常指定的是http使用的method。所以这里是用http get hello_get.py,同时在URL后面加上查询字符串来给hello_get.py传递表单数据(这里分别是first_name及last_name)。
打开index.html如图:
点击Submit,浏览器立即跳转到hello_get.py(get方法),并附加查询字符串?first_name=L&last_name=C,并由hello_get.py来处理fisrt_name和last_name。
hello_get.py
-
1 #!/usr/bin/python 2 #-*- coding:utf-8 -*- 3 4 #CGI处理模块 5 import cgi,cgitb 6 7 form = cgi.FieldStorage() 8 9 first_name = form.getvalue(‘first_name‘) 10 last_name = form.getvalue(‘last_name‘) 11 12 13 print(‘Conten-type:text/html\r\n\r\n‘) 14 print("""<html> 15 <head> 16 <title>Hello - Second CGI Program</title> 17 </head> 18 <body> 19 <h2>Hello %s %s</h2> 20 </body> 21 </html>"""%(first_name,last_name))
即:http使用get方法向CGIs脚本传递数据,在URL的查询字符串中写入且用符号‘&‘分隔。
如果让http使用post方法,情况会有些不一样。改动index.html(仅改动form的属性method,改成post):
-
1 <html> 2 <head> 3 <title>test</title> 4 </head> 5 <body> 6 <formaction="/cgi-bin/hello_get.py"method="post"> 7 First Name: <inputtype="text"name="first_name"> <br/> 8 9 Last Name: <inputtype="text"name="last_name"/> 10 <inputtype="submit"value="Submit"/> 11 </form> 12 </body> 13 </html>
数据将以文本行的方式写在http头部后:
即:http使用post方法向CGIs脚本传递数据,在http请求正文中写入。以此,post向CGIs传输数据比get相对安全点。
上传文件
upload_file.html
-
1 <html> 2 <body> 3 <form enctype="multipart/form-data" 4 action="/cgi-bin/save_file.py" method="post"> 5 <p>File:<input type="file" name="filename"/></p> 6 <p><input type="submit" value="Upload"/></p> 7 </form> 8 </body> 9 </html>
save_file.py
-
1 #!/usr/bin/python 2 #-*- coding=utf-8 -*- 3 4 import cgi,os 5 import cgitb;cgitb.enable() 6 7 form = cgi.FieldStorage() 8 9 #获取文件名 10 fileitem = form[‘filename‘] 11 12 #检测文件是否上传 13 if fileitem.filename: 14 #设置文件路径 15 fn = os.path.basename(fileitem.filename.replace("\\","/")) 16 open(‘/tmp/‘+ fn,‘wb‘).write(fileitem.file.read()) 17 18 message =‘The file "‘+ fn +‘" was uploaded successfully‘ 19 20 else: 21 message =‘No file was uploaded‘ 22 23 print("""24 Content-Type: text/html\r\n\r\n 25 <html> 26 <body> 27 <p>%s</p> 28 </body> 29 </html> 30 """% message)
选择一个文件example.conf.json
文件数据被封装在请求正文。
参考资料
Wikipedia
http://web.archive.org/web/20100127191128/http://hoohoo.ncsa.illinois.edu/cgi/intro.html
http://www.w3cschool.cc/python/python-cgi.html
http://book.51cto.com/art/201108/282090.htm
http://www.w3school.com.cn/html/html_forms.asp
https://docs.python.org/3/library/cgi.html?highlight=cgi#module-cgi