Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Python CGI programming


May 10, 2021 Python2


Table of contents


Python 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

Python 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 .cgi, and Python can also use .py 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 suffix .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 used Python to create the first CGI program with the file name hellp.py, which is located in the /var/www/cgi-bin directory and is as follows, with permission to modify the file to 755:

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

print "Content-type:text/html\r\n\r\n"
print '<html>'
print '<head>'
print '<title>Hello Word - First CGI Program</title>'
print '</head>'
print '<body>'
print '<h2>Hello Word! This is my first CGI program</h2>'
print '</body>'
print '</html>'

The above programs display the following results in browser access:

Hello Word! This is my first CGI program

This hello.py script is a simple Python script, the first line of the script output "Content-type:text/html\r\n" sent to the browser and informed the browser that the content type displayed is "text/html".


HTTP head

hello.py "Content-type:text/html\n" in the contents of the file is part of the HTTP header, which is sent to the browser to tell the browser the content type 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 that is not a request URL 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 that sent 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 you can use 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/python
# -*- coding: UTF-8 -*-
# filename:test.py

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>"

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/hello_get.py?first_name=ZARA&last_name=ALI

Here's hello_get.py code for the file:

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

# CGI处理模块
import cgi, cgitb 

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

# 获取数据
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

The browser requests the output:

Hello ZARA ALI

Simple form example: GET method

The following is a form that uses the GET method to send two data to the server using the GET method, and the submitted server script is also hello_get.py file, code as follows:

<form action="/cgi-bin/hello_get.py" method="get">
First Name: <input type="text" name="first_name">  <br />

Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>

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:

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

# 引入 CGI 模块 
import cgi, cgitb 

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

# 获取表单数据
first_name = form.getvalue('first_name')
last_name  = form.getvalue('last_name')

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Hello - Second CGI Program</title>"
print "</head>"
print "<body>"
print "<h2>Hello %s %s</h2>" % (first_name, last_name)
print "</body>"
print "</html>"

The following is the form that submits data to the server hello_get.py the POST method:

<form action="/cgi-bin/hello_get.py" method="post">
First Name: <input type="text" name="first_name"><br />
Last Name: <input type="text" name="last_name" />

<input type="submit" value="Submit" />
</form>

Pass checkbox data through a CGI program

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

<form action="/cgi-bin/checkbox.cgi" method="POST" target="_blank">
<input type="checkbox" name="maths" value="on" /> Maths
<input type="checkbox" name="physics" value="on" /> Physics
<input type="submit" value="Select Subject" />
</form>

Here's the code .cgi checkbox file:

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

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

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

# 接收字段数据
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 "<html>"
print "<head>"
print "<title>Checkbox - Third CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> CheckBox Maths is : %s</h2>" % math_flag
print "<h2> CheckBox Physics is : %s</h2>" % physics_flag
print "</body>"
print "</html>"

Radio data is passed through a CGI program

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

<form action="/cgi-bin/radiobutton.py" method="post" target="_blank">
<input type="radio" name="subject" value="maths" /> Maths
<input type="radio" name="subject" value="physics" /> Physics
<input type="submit" value="Select Subject" />
</form>

radiobutton.py script code is as follows:

#coding=utf-8
#!/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:
   subject = "Not set"

print "Content-type:text/html\r\n\r\n"
print "<html>"
print "<head>"
print "<title>Radio - Fourth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

Textarea data is passed through a CGI program

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

<form action="/cgi-bin/textarea.py" method="post" target="_blank">
<textarea name="textcontent" cols="40" rows="4">
Type your text here...
</textarea>
<input type="submit" value="Submit" />
</form>

The textarea .cgi script code as follows:

#coding=utf-8
#!/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 "<html>"
print "<head>";
print "<title>Text Area - Fifth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Entered Text Content is %s</h2>" % text_content
print "</body>"

The pull-down data is passed through the CGI program

The HTML pull-down box code is as follows:

<form action="/cgi-bin/dropdown.py" method="post" target="_blank">
<select name="dropdown">
<option value="Maths" selected>Maths</option>
<option value="Physics">Physics</option>
</select>
<input type="submit" value="Submit"/>
</form>

dropdown.py script code looks like this:

#coding=utf-8
#!/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 "<html>"
print "<head>"
print "<title>Dropdown Box - Sixth CGI Program</title>"
print "</head>"
print "<body>"
print "<h2> Selected Subject is %s</h2>" % subject
print "</body>"
print "</html>"

Cookies are used in CGI

One of the great disadvantages of the http protocol is that it does not judge the user's identity, which is a great inconvenience to programmers.

The emergence of cookies makes up for this deficiency.

All cookies are the customer access script at the same time, through the customer's browser, the customer's hard disk to write record data, the next time the customer accesses the script to get back the data information, so as to achieve the function of identity identification, cookies are often used in password judgment.

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 set-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 used; "and", "" sign), which is used when there are multiple name values; n ame2=name2; n ame3=name3。
  • expires=date: the expiration date of the cookie, format: expires="Wdy, DD-Mon-YYYYY HH:MM:SS"
  • path-path: Set the path supported by the cookie, if the path is a path, then the cookie takes effect on all files and subdirectts in this directory, e.g.: path=/cgi-bin/" and if path is a file, the cookie means effective for that file, e.g. path="/cgi-bin/cookie.cgi"
  • domain-domain: Domain name in effect for cookies, e.g.: domain-"www.chinalb.com"
  • 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 HTTP_COOKIE environment 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 instances have UserID and Password set in the cookie:

<pre>
#coding=utf-8
#!/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.w3cschool.cn;\r\n"
print "Set-Cookie:Path=/perl;\n"
print "Content-type:text/html\r\n\r\n"
...........Rest of the HTML Content....

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. T his information is set before "Content-type:text/html\n\n?n".


Retrieve 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:

#coding=utf-8
#!/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

The output of the above script is as follows:

User ID = XYZ
Password = XYZ123

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:

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

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 = 'The file "' + fn + '" was uploaded successfully'
   
else:
   message = 'No file was uploaded'
   
print """\
Content-Type: text/html\n
<html>
<body>
   <p>%s</p>
</body>
</html>
""" % (message,)

If you're using Unix/Linux, you have to replace the file separator, just use the open() statement under window:

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

File download dialog box

If we need to provide the user with a file download link and pop up the file download dialog box after the user clicks on the link, we do so by setting up http header information, which is coded as follows:

#coding=utf-8
#!/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()