Easy Tutorial
❮ Ref Math Asin Python Os Tcsetpgrp ❯

Python CGI Programming


What is CGI

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

CGI (Common Gateway Interface), the Common Gateway Interface, is a program that runs on the server, such as an HTTP server, providing an interface to client HTML pages.


Web Browsing

To better understand how CGI works, let's look at the process of clicking a link or URL on a web page:

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


CGI Architecture Diagram


Web Server Support and Configuration

Before you start CGI programming, make sure your web server supports CGI and has been configured with CGI processing.

Apache supports CGI configuration:

Set up the CGI directory:

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

All HTTP servers execute CGI programs in a pre-configured directory. This directory is called the CGI directory and by convention, it is named /var/www/cgi-bin.

The extension for CGI files is .cgi, and Python can also use the .py extension.

By default, Linux servers are configured to run the cgi-bin directory at /var/www.

If you want to specify a different directory for running CGI scripts, you can modify the httpd.conf configuration file as follows:

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

Add the .py suffix in AddHandler so that we can access Python script files ending in .py:

AddHandler cgi-script .cgi .pl .py

First CGI Program

We use Python to create our first CGI program, named hello.py, located in the /var/www/cgi-bin directory, with the following content:

Example

#!/usr/bin/python3

print("Content-type:text/html")
print()                             # Empty line, to indicate the end of the header
print('<html>')
print('<head>')
print('<meta charset="utf-8">')
print('<title>Hello Word - My First CGI Program!</title>')
print('</head>')
print('<body>')
print('<h2>Hello Word! I am the first CGI program from tutorialpro.org</h2>')
print('</body>')
print('</html>')

After saving the file, modify hello.py, changing the file permissions to 755:

chmod 755 hello.py

The above program, when accessed in the browser, displays the following result:

This hello.py script is a simple Python script. The first line of output, "Content-type:text/html," is sent to the browser, informing it that the content type to be displayed is "text/html".

An empty line is printed to tell the server that the header information is over.


HTTP Header

The "Content-type:text/html" in the hello.py file is part of the HTTP header, which is sent to the browser to inform it of the content type of the file.

The format of the HTTP header is as follows:

HTTP Field Name: Field Content

For example:

Content-type: text/html

The following table describes commonly used information in the HTTP header in CGI programs:

Header Description
Content-type: MIME information corresponding to the entity requested. For example: Content-type:text/html
Expires: Date The date and time the response expires
Location: URL Used to redirect the recipient to a location other than the requested URL to complete the request or identify a new resource
Last-modified: Date The last modification time of the requested resource
Content-length: N The length of the requested content
Set-Cookie: String Sets an Http Cookie

CGI Environment Variables

All CGI programs receive the following environment variables, which play important roles in CGI programs:

Variable Name Description
CONTENT_TYPE The value of this environment variable indicates the MIME type of the information being passed. Currently, the CONTENT_TYPE environment variable is typically: application/x-www-form-urlencoded, indicating that the data comes from an HTML form.
CONTENT_LENGTH If the server communicates with the CGI program using the POST method, this environment variable indicates the number of bytes of valid data that can be read from the standard input STDIN. This environment variable must be used when reading input data.
HTTP_COOKIE The COOKIE content from the client machine.
HTTP_USER_AGENT Provides information about the client's browser, including version number or other proprietary data.
PATH_INFO The value of this environment variable represents additional path information following the CGI program name. It often appears as a parameter to the CGI program.
QUERY_STRING If the server communicates with the CGI program using the GET method, the value of this environment variable is the information being passed. This information follows the CGI program name, separated by a question mark '?'.
REMOTE_ADDR The value of this environment variable is the IP address of the client machine sending the request, such as 192.168.1.67. This value is always present and is the only identifier the Web client needs to provide to the Web server, which can be used in the CGI program to differentiate between different Web clients.
REMOTE_HOST The value of this environment variable contains the hostname of the client machine sending the CGI request. If reverse DNS lookup is not supported, this environment variable does not need to be defined.
REQUEST_METHOD Provides the method by which the script was called. For scripts using the HTTP/1.0 protocol, only GET and POST are meaningful.
SCRIPT_FILENAME The full path of the CGI script.
SCRIPT_NAME The name of the CGI script.
SERVER_NAME This is the hostname, 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 calling the CGI program. For example, the value above is Apache/2.2.14(Unix).

Below is a simple CGI script that outputs the CGI environment variables:

Example

#!/usr/bin/python3

import os

print("Content-type: text/html")
print()
print("&lt;meta charset=\"utf-8\">")
print("<b>Environment Variables</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 script as test.py and modify the file permissions to 755. The execution result is as follows:


GET and POST Methods

The browser client transmits information to the server through two methods, GET and POST.

Using GET Method to Transfer Data

The GET method sends encoded user information to the server, with the data information included in the URL of the request page, separated by a "?" character, as shown below:

http://www.test.com/cgi-bin/hello.py?key1=value1&key2=value2

Simple URL Example: GET Method

The following is a simple URL that sends two parameters to the hello_get.py program using the GET method:

/cgi-bin/test.py?name=tutorialpro.org&url=http://www.tutorialpro.org

The following is the code for the hello_get.py file:

Example

#!/usr/bin/python3

# CGI processing module
import cgi, cgitb 

# Create an instance of FieldStorage
form = cgi.FieldStorage() 

# Retrieve data
site_name = form.getvalue('name')
site_url  = form.getvalue('url')

print("Content-type:text/html")
print()
print("<html>")
print("<head>")
print ("&lt;meta charset=\"utf-8\">")
print ("<title>tutorialpro.org CGI Test Example</title>")
print ("</head>")
print ("<body>")
print ("<h2>%s Official Website: %s</h2>" % (site_name, site_url))
print ("</body>")
print ("</html>")

After saving the file, modify hello_get.py and change the file permissions to 755:

chmod 755 hello_get.py

Browser request output result:

Simple Form Example: GET Method

The following is an example of sending two pieces of data to the server using the GET method through an HTML form. The server script submitted is also the hello_get.py file. The hello_get.html code is as follows:

Example

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>tutorialpro.org(tutorialpro.org)</title>
</head>
<body>
<form action="/cgi-bin/hello_get.py" method="get">
Site Name: <input type="text" name="name">  <br />

Site URL: <input type="text" name="url" />
<input type="submit" value="Submit" />
</form>
</body>
</html>

By default, the cgi-bin directory can only store script files. We will store hello_get.html in the test directory and change the file permissions to 755:

chmod 755 hello_get.html

Gif demonstration is shown below:

Transmitting Data Using the POST Method

Using the POST method to transmit data to the server is more secure and reliable, especially for sensitive information such as user passwords.

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

Example

#!/usr/bin/python3

# CGI processing module
import cgi, cgitb 

# Create an instance of FieldStorage
form = cgi.FieldStorage() 

# Get data
site_name = form.getvalue('name')
site_url  = form.getvalue('url')

print ("Content-type:text/html")
print ()
print ("<html>")
print ("<head>")
print ("&lt;meta charset=\"utf-8\">")
print ("<title>tutorialpro.org CGI Test Example</title>")
print ("</head>")
print ("<body>")
print ("<h2>%s Official Website: %s</h2>" % (site_name, site_url))
print ("</body>")
print ("</html>")

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

Example

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>tutorialpro.org(tutorialpro.org)</title>
</head>
<body>
<form action="/cgi-bin/hello_get.py" method="post">
Site Name: <input type="text" name="name">  <br />

Site URL: <input type="text" name="url" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
</form>

Gif demonstration is shown below:

Passing Checkbox Data Through a CGI Program

A checkbox is used to submit one or multiple option data. The HTML code is as follows:

Example

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>tutorialpro.org(tutorialpro.org)</title>
</head>
<body>
<form action="/cgi-bin/checkbox.py" method="POST" target="_blank">

English:

<input type="checkbox" name="tutorialpro" value="on" /> tutorialpro.org <input type="checkbox" name="google" value="on" /> Google <input type="submit" value="Select Sites" /> </form> </body> </html>



Here is the code for the checkbox.py file:

## Example


!/usr/bin/python3

Import CGI processing module

import cgi, cgitb

Create an instance of FieldStorage

form = cgi.FieldStorage()

Receive field data

if form.getvalue('google'): google_flag = "Yes" else: google_flag = "No"

if form.getvalue('tutorialpro'): tutorialpro_flag = "Yes" else: tutorialpro_flag = "No"

print ("Content-type:text/html") print () print ("<html>") print ("<head>") print ("<meta charset=\"utf-8\">") print ("<title>tutorialpro.org CGI Test Example</title>") print ("</head>") print ("<body>") print ("<h2> tutorialpro.org selected: %s</h2>" % tutorialpro_flag) print ("<h2> Google selected: %s</h2>" % google_flag) print ("</body>") print ("</html>")



Modify checkbox.py permissions:


chmod 755 checkbox.py


Browser access GIF demonstration:

</head> <body> <form action="/cgi-bin/textarea.py" method="post" target="_blank"> <textarea name="textcontent" cols="40" rows="4"> Enter content here... </textarea> <input type="submit" value="Submit" /> </form> </body> </html>



textarea.py script code is as follows:

## Example


!/usr/bin/python3

Import CGI processing module

import cgi, cgitb

Create an instance of FieldStorage

form = cgi.FieldStorage()

Receive field data

if form.getvalue('textcontent'): text_content = form.getvalue('textcontent') else: text_content = "No content"

print ("Content-type:text/html") print () print ("<html>") print ("<head>") print ("<meta charset=\"utf-8\">") print ("<title>tutorialpro.org CGI Test Example</title>") print ("</head>") print ("<body>") print ("<h2> The content entered is: %s</h2>" % text_content) print ("</body>") print ("</html>")



Modify textarea.py permissions:


chmod 755 textarea.py


Browser access Gif demonstration:
Set-Cookie: name=name; expires=date; path=path; domain=domain; secure

- **name=name:** The value to be set for the cookie (name cannot use "**;**" and "**,**"), multiple name values are separated by "**;**", for example: **name1=name1; name2=name2; name3=name3**.

- **expires=date:** The expiration date of the cookie, format: expires="Wdy, DD-Mon-YYYY HH:MM:SS".

- **path=path:** The path for which the cookie is set. If path is a directory, the cookie is valid for all files and subdirectories in this directory, for example: path="/cgi-bin/". If path is a file, the cookie is only valid for this file, for example: path="/cgi-bin/cookie.cgi".

- **domain=domain:** The domain for which the cookie is valid, for example: domain="www.tutorialpro.org".

- **secure:** If this flag is given, the cookie can only be transmitted through an SSL protocol HTTPS server.

- The reception of cookies is achieved by setting the environment variable HTTP_COOKIE, which a CGI program can retrieve to obtain cookie information.

---

## Cookie Setting

Setting a cookie is very simple; the cookie is sent separately in the HTTP header. The following example sets the name and expires for a cookie:

## Example

```python
#!/usr/bin/python3

print('Set-Cookie: name="tutorialpro.org"; expires=Wed, 28 Aug 2016 18:30:00 GMT')
print('Content-Type: text/html')

print()
print("""
<html>
  <head>
    <meta charset="utf-8">
    <title>tutorialpro.org(tutorialpro.org)</title>
  </head>
  <body>
    <h1>Cookie set OK!</h1>
  </body>
</html>
""")

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

chmod 755 cookie_set.py

The above example uses the Set-Cookie header to set the Cookie information, with optional settings for other attributes such as the expiration time Expires, domain Domain, and path Path. These settings are made before the "Content-type:text/html".


Retrieving Cookie Information

Retrieving cookie information is also very simple. The cookie information is stored in the CGI environment variable HTTP_COOKIE in the following format:

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

The following is a simple CGI program to retrieve cookie information:

Example

#!/usr/bin/python3

# Import modules
import os
import http.cookies

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

print("""
<html>
<head>
<meta charset="utf-8">
<title>tutorialpro.org(tutorialpro.org)</title>
</head>
<body>
<h1>Reading cookie information</h1>
""")

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

    try:
        data = c['name'].value
        print("cookie data: " + data + "<br>")
    except KeyError:
        print("cookie not set or expired<br>")
print("""
</body>
</html>
""")

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

chmod 755 cookie_get.py

The above cookie setting demonstration is shown in the following GIF:

File Upload Example

To set up an HTML form for uploading files, you need to set the enctype attribute to multipart/form-data, as shown in the following code:

Example

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>tutorialpro.org(tutorialpro.org)</title>
</head>
<body>
  <form enctype="multipart/form-data" 
                    action="/cgi-bin/save_file.py" method="post">
    <p>Select file: <input type="file" name="filename" /></p>
    <p><input type="submit" value="Upload" /></p>
  </form>
</body>
</html>

The save_file.py script file code is as follows:

Example

#!/usr/bin/python3

import cgi, os
import cgitb; cgitb.enable()

form = cgi.FieldStorage()

# Get the file name
fileitem = form['filename']

# Check if the file was uploaded
if fileitem.filename:
  # Set the file path 
  fn = os.path.basename(fileitem.filename)
  open('/tmp/' + fn, 'wb').write(fileitem.file.read())

  message = 'File "' + fn + '" uploaded successfully'

else:
  message = 'No file was uploaded'

print ("""\
Content-Type: text/html\n
<html>
<head>
<meta charset="utf-8">
<title>tutorialpro.org(tutorialpro.org)</title>
</head>
<body>
  <p>%s</p>
</body>
</html>
""" % (message,))

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

chmod 755 save_file.py

The above cookie setting demonstration Gif is shown below:

If you are using a Unix/Linux system, you must replace the file separator. On Windows, you only need to use the open() statement:

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

File Download Dialog

First, create a foo.txt file in the current directory for the program to download.

File download is achieved by setting HTTP headers. The functional code is as follows:

Example

#!/usr/bin/python3

# HTTP Header
print ("Content-Disposition: attachment; filename=\"foo.txt\"")
print ()
# Open file
fo = open("foo.txt", "rb")

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

# Close file
fo.close()
❮ Ref Math Asin Python Os Tcsetpgrp ❯