Python3 CGI programming


What is CGI

CGI is currently maintained by NCSA, which defines CGI as follows:

CGI (Common Gateway Interface), a common gateway interface, is a program that runs on a server such as an HTTP server and provides an interface with a client HTML page.


Web browsing

To better understand how CGI works, we can click on a link or URL on a Web page:

  • 1. Use your browser to access the URL and connect to the HTTP web server.
  • 2, the Web server receives the request information will resolve the URL, and find out whether the accessed file exists on the server, if there is the contents of the return file, otherwise return the error message.
  • 3. The browser receives information from the server and displays the received files or error messages.

CGI programs can be Python scripts, PERL scripts, SHELL scripts, C or C?programs, etc.


CGI architecture diagram

Python3 CGI programming


Web server support and configuration

Before you program CGI, make sure that your web server supports CGI and that CGI handlers are configured.

Apache supports CGI configurations:

Set up the CGI directory:

ScriptAlias /cgi-bin/ /var/www/cgi-bin/

All HTTP server execution CGI programs are stored in a pre-configured directory. This directory is called the CGI directory, and as a rule, it is named /var/www/cgi-bin directory.

The extension of the CGI file is .cgi, and Python can also use .py the extension.

By default, the Linux server configuration runs in the cgi-bin directory /var/www.

If you want to specify other directories that run CGI scripts, you can modify the httpd.conf profile as follows:

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options +ExecCGI
   Order allow,deny
   Allow from all
</Directory>

Add the .py .py AddHandler so that we can access .py python script file at the end of the file:

AddHandler cgi-script .cgi .pl .py

The first CGI program

We created the first CGI program using Python, with the file name hello.py, in the /var/www/cgi-bin directory, as follows:

#!/usr/bin/python3
#coding=utf-8
print ('<html>')
print ('<head>')
print ('<meta charset="utf-8">')
print ('<title>Hello Word - 我的第一个 CGI 程序!</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word! 我的第一CGI程序</h2>')
print ('</body>')
print ('</html>')

After the file is saved, hello.py file is modified, and the permission to modify the file is 755:

chmod 755 hello.py 

The above programs display the following results in browser access:

Python3 CGI programming

This hello.py script is a simple Python script, the first line of the script output "Content-type:text/html" sent to the browser and told the browser to display the content type "text/html."

Print out an empty line to tell the server the end header information.


HTTP head

hello.py "Content-type:text/html" in the contents of the file is part of the HTTP header and is sent to the browser to tell the browser the type of content of the file.

The format of the HTTP header is as follows:

HTTP 字段名: 字段内容

For example:

Content-type: text/html

The following table describes the information that http heads are frequently used in CGI programs:

Head Describe
Content-type: The requested MIME information corresponding to the entity. For example: Content-type:text/html
Expires: Date The date and time the response expired
Location: URL Used to redirect the receiver to a location where the URL is not requested to complete the request or identify a new resource
Last-modified: Date The last time the resource was requested to be modified
Content-length: N The length of the requested content
Set-Cookie: String Set an Http cookie

CGI environment variables

All CGI programs receive the following environmental variables, which play an important role in CGI programs:

The name of the variable Describe
CONTENT_TYPE The value of this environment variable indicates the type of MIME of the information passed. Currently, environment variables CONTENT_TYPE generally: application/x-www-form-urlencoded, which says the data comes from HTML forms.
CONTENT_LENGTH If the server and CGI program information is passed in a POST, this environment variable is even the number of bytes of valid data that can be read from the standard input STDIN. This environment variable must be used when reading the data entered.
HTTP_COOKIE The contents of the COOKIE within the client.
HTTP_USER_AGENT Provides customer browser information that contains the number of versions or other proprietary data.
PATH_INFO The value of this environment variable represents other path information immediately after the CGI program name. It often appears as a parameter of a CGI program.
QUERY_STRING If the server and CGI program information is delivered in a GET way, the value of this environment variable even if the information is passed. T his information is followed by the CGI program name, with a question mark between the two.???" Separated.
REMOTE_ADDR The value of this environment variable is the IP address of the client sending the request, for example, 192.168.1.67 above. T his value is always present. And it is the unique identity that Web clients need to provide to Web servers, which can be used in CGI programs to distinguish between different Web clients.
REMOTE_HOST The value of this environment variable contains the host name of the client that sent the CGI request. If you do not support the query you want, you do not need to define this environment variable.
REQUEST_METHOD Provides the method to which the script is called. For scripts that use the HTTP/1.0 protocol, only GET and POST make sense.
SCRIPT_FILENAME The full path to the CGI script
SCRIPT_NAME The name of the CGI script
SERVER_NAME This is the host name, alias, or IP address of your WEB server.
SERVER_SOFTWARE The value of this environment variable contains the name and version number of the HTTP server that called the CGI program. For example, the above value is Apache/2.2.14 (Unix)

Here's a simple CGI script that outputs CGI's environment variables:

#!/usr/bin/python3
#coding=utf-8
import os

print ("Content-type: text/html")
print ()
print ("<meta charset=\"utf-8\">")
print ("<b>环境变量</b><br>")
print ("<ul>")
for key in os.environ.keys():
    print ("<li><span style='color:green'>%30s </span> : %s </li>" % (key,os.environ[key]))
print ("</ul>")

Save the above points as test.py and modify the file permissions to 755, as follows:

Python3 CGI programming


GET and POST methods

The browser client passes information to the server in two ways, the GET method and the POST method.

Use the GET method to transfer data

The GET method sends encoded user information to the service side, and the data information is included on the URL of the request page to " ? number split, as follows:

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2
Some other comments about get requests:
  • GET requests can be cached
  • Get requests remain in the browser history
  • GET requests can be bookmarked
  • GET requests should not be used when processing sensitive data
  • Get requests have a length limit
  • GET requests should only be used to get data back

Simple url instance: GET method

Here's a simple URL that uses the GET method hello_get.py two parameters to the program:

/cgi-bin/test.py?name=W3Cschool教程&url=http://www.w3cschool.cn

Here's hello_get.py code for the file:

#!/usr/bin/python3
#coding=utf-8

# CGI处理模块
import cgi, cgitb 

# 创建 FieldStorage 的实例化
form = cgi.FieldStorage() 

# 获取数据
site_name = form.getvalue('name')
site_url  = form.getvalue('url')

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("<meta charset=\"utf-8\">")
print ("<title>W3Cschool教程 CGI 测试实例</title>")
print ("</head>")
print ("<body>")
print ("<h2>%s官网:%s</h2>" % (site_name, site_url))
print ("</body>")
print ("</html>")

After the file is saved, hello_get.py file is modified, and the permission to modify the file is 755:

chmod 755 hello_get.py 

The browser requests the output:

Python3 CGI programming

Simple form example: GET method

Here's an HTML form that uses the GET method to send two data to the server, and the submitted server script is also a hello_get.py file, hello_get.html the following code:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/hello_get.py" method="get">
站点名称: <input type="text" name="name">  <br />

站点 URL: <input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>

By default, the cgi-bin directory can only hold script files, and we store hello_get.html files in the test directory with 755 permissions to modify the files:

chmod 755 hello_get.html

The Gif demo looks like this:

Python3 CGI programming

Use the POST method to pass data

Using the POST method to pass data to the server is more secure and reliable, as sensitive information such as user passwords requires the use of POST to transfer data.

The following is also hello_get.py, which can also handle POST form data submitted by the browser:

#!/usr/bin/python3
#coding=utf-8

# CGI处理模块
import cgi, cgitb 

# 创建 FieldStorage 的实例化
form = cgi.FieldStorage() 

# 获取数据
site_name = form.getvalue('name')
site_url  = form.getvalue('url')

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("<meta charset=\"utf-8\">")
print ("<title>W3Cschool教程 CGI 测试实例</title>")
print ("</head>")
print ("<body>")
print ("<h2>%s官网:%s</h2>" % (site_name, site_url))
print ("</body>")
print ("</html>")

The following is how the form submits data to the server script via the POST method (method hello_get.py "post"):

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/hello_get.py" method="post">
站点名称: <input type="text" name="name">  <br />

站点 URL: <input type="text" name="url" />
<input type="submit" value="提交" />
</form>
</body>
</html>
</form>

The Gif demo looks like this:

Python3 CGI programming

Pass checkbox data through a CGI program

Checkbox is used to submit one or more option data, and the HTML code is as follows:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/checkbox.py" method="POST" target="_blank">
<input type="checkbox" name="youj" value="on" /> W3Cschool教程
<input type="checkbox" name="google" value="on" /> Google
<input type="submit" value="选择站点" />
</form>
</body>
</html>

Here's checkbox.py code for the file:

#!/usr/bin/python3

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('google'):
   google_flag = "是"
else:
   google_flag = "否"

if form.getvalue('youj'):
   youj_flag = "是"
else:
   youj_flag = "否"

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("<meta charset=\"utf-8\">")
print ("<title>W3Cschool教程 CGI 测试实例</title>")
print ("</head>")
print ("<body>")
print ("<h2> W3Cschool教程是否选择了 : %s</h2>" % youj_flag)
print ("<h2> Google 是否选择了 : %s</h2>" % google_flag)
print ("</body>")
print ("</html>")

Modify checkbox.py permissions:

chmod 755 checkbox.py

Browser access gif demo:

Python3 CGI programming

Radio data is passed through a CGI program

Radio passes only one data to the server, and the HTML code looks like this:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/radiobutton.py" method="post" target="_blank">
<input type="radio" name="site" value="youj" /> W3Cschool教程
<input type="radio" name="site" value="google" /> Google
<input type="submit" value="提交" />
</form>
</body>
</html>

radiobutton.py script code is as follows:

#!/usr/bin/python3

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('site'):
   site = form.getvalue('site')
else:
   site = "提交数据为空"

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("<meta charset=\"utf-8\">")
print ("<title>W3Cschool教程 CGI 测试实例</title>")
print ("</head>")
print ("<body>")
print ("<h2> 选中的网站是 %s</h2>" % site)
print ("</body>")
print ("</html>")

Modify radiobutton.py permissions:

chmod 755 radiobutton.py

Browser access gif demo:

Python3 CGI programming

Textarea data is passed through a CGI program

Textarea passes multiple lines of data to the server, and the HTML code is as follows:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/textarea.py" method="post" target="_blank">
<textarea name="textcontent" cols="40" rows="4">
在这里输入内容...
</textarea>
<input type="submit" value="提交" />
</form>
</body>
</html>

textarea.py script code is as follows:

#!/usr/bin/python3

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('textcontent'):
   text_content = form.getvalue('textcontent')
else:
   text_content = "没有内容"

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("<meta charset=\"utf-8\">")
print ("<title>W3Cschool教程 CGI 测试实例</title>")
print ("</head>")
print ("<body>")
print ("<h2> 输入的内容是:%s</h2>" % text_content)
print ("</body>")
print ("</html>")

Modify textarea.py permissions:

chmod 755 textarea.py

Browser access gif demo:

Python3 CGI programming

The pull-down data is passed through the CGI program.

The HTML pull-down box code is as follows:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<form action="/cgi-bin/dropdown.py" method="post" target="_blank">
<select name="dropdown">
<option value="youj" selected>W3Cschool教程</option>
<option value="google">Google</option>
</select>
<input type="submit" value="提交"/>
</form>
</body>
</html>

dropdown.py script code looks like this:

#!/usr/bin/python3

# 引入 CGI 处理模块 
import cgi, cgitb 

# 创建 FieldStorage的实例 
form = cgi.FieldStorage() 

# 接收字段数据
if form.getvalue('dropdown'):
   dropdown_value = form.getvalue('dropdown')
else:
   dropdown_value = "没有内容"

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("<meta charset=\"utf-8\">")
print ("<title>W3Cschool教程 CGI 测试实例</title>")
print ("</head>")
print ("<body>")
print ("<h2> 选中的选项是:%s</h2>" % dropdown_value)
print ("</body>")
print ("</html>")

Modify dropdown.py permissions:

chmod 755 dropdown.py

Browser access gif demo:

Python3 CGI programming


Cookies are used in CGI

One of the great disadvantages of the http protocol is that the user's identity is not judged, which is a great inconvenience to the programmer, and the emergence of cookie functions to make up for this deficiency.

Cookies are when the customer accesses the script, through the customer's browser, writes the record data on the customer's hard drive, and when the customer accesses the script the next time the data information is taken back, thus achieving the function of identity identification, cookies are often used in identity verification.

The syntax of cookies

The http cookie is sent via the http header, which predations the transmission of the file, and the syntax of the head s et-cookie is as follows:

Set-cookie:name=name;expires=date;path=path;domain=domain;secure 
  • name-name: the value of the cookie needs to be set (name cannot be ; "and" , "number" when there are multiple name values used " ; " Separation, e.g. name1=name1; n ame2=name2; n ame3=name3
  • expires=date: the expiration date of the cookie, format: expires="Wdy, DD-Mon-YYYYY HH:MM:SS"
  • path:set the path supported by the cookie, if path is a path, then the cookie takes effect on all files and subdirectts in this directory, e.g.: path="/cgi-bin/", if path is a file, then cookie means that the file is in effect, e.g. path=/cgi-bin/cookie.cgi"
  • domain-domain: Domain name in effect for cookies, e.g.: domain-www.w3cschool.cn"
  • Secure: If this flag is given, the cookie can only be passed through the https server of the SSL protocol.
  • The receipt of a cookie is achieved by setting HTTP_COOKIE variable, which the CGI program can retrieve to obtain cookie information.

Cookie settings

Cookies are set up very simply and are sent separately at the http header. The following examples set name and expires in the cookie:

#!/usr/bin/python3
# 
print ('Content-Type: text/html')
print ('Set-Cookie: name="W3Cschool教程";expires=Wed, 28 Aug 2016 18:30:00 GMT')
print ()
print ("""
<html>
  <head>
    <meta charset="utf-8">
    <title>W3Cschool教程(w3cschool.cn)</title>
  </head>
    <body>
        <h1>Cookie set OK!</h1>
    </body>
</html>
""")

Save the above code to cookie_set.py and modify the cookie_set.py permissions:

chmod 755 cookie_set.py

The above example uses set-cookie header information to set cookie information, and other properties of cookies, such as Expiration Time Expires, Domain Domain, Path Path, can be selected. This information is set before "Content-type:text/html".


Retrieving cookie information

The cookie information retrieval page is very simple and the cookie information is stored in CGI's environment HTTP_COOKIE, in the following format:

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

Here's a simple CGI program for retrieving cookie information:

#!/usr/bin/python3

# 导入模块
import os
import Cookie

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

print ("""
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
<h1>读取cookie信息</h1>
""")

if 'HTTP_COOKIE' in os.environ:
    cookie_string=os.environ.get('HTTP_COOKIE')
    c=Cookie.SimpleCookie()
    c.load(cookie_string)

    try:
        data=c['name'].value
        print ("cookie data: "+data+"<br>")
    except KeyError:
        print ("cookie 没有设置或者已过去<br>")
print ("""
</body>
</html>
""")

Save the above code to cookie_get.py and modify the cookie_get.py permissions:

chmod 755 cookie_get.py

The above cookies set the color Gif as follows:

Python3 CGI programming

File upload instance

HTML Settings The form for uploading files needs to set the enctype property to multipart/form-data, as follows:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
 <form enctype="multipart/form-data" 
                     action="/cgi-bin/save_file.py" method="post">
   <p>选中文件: <input type="file" name="filename" /></p>
   <p><input type="submit" value="上传" /></p>
   </form>
</body>
</html>

save_file.py script file code is as follows:

#!/usr/bin/python3

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 = '文件 "' + fn + '" 上传成功'
   
else:
   message = '文件没有上传'
   
print ("""\
Content-Type: text/html\n
<html>
<head>
<meta charset="utf-8">
<title>W3Cschool教程(w3cschool.cn)</title>
</head>
<body>
   <p>%s</p>
</body>
</html>
""" % (message,))

Save the above code to save_file.py and modify the save_file.py permissions:

chmod 755 save_file.py

The above cookies set the color Gif as follows:

Python3 CGI programming

If you're using a Unix/Linux system, you have to replace the file separator, and you only need to use the open() statement under window:

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

File download dialog box

Let's start by creating a foo .txt in the current directory for the download of the program.

File downloads are implemented by setting up HTTP header information with the following functional code:

#!/usr/bin/python3

# HTTP 头部
print ("Content-Disposition: attachment; filename=\"foo.txt\"")
print ()
# 打开文件
fo = open("foo.txt", "rb")

str = fo.read();
print (str)

# 关闭文件
fo.close()