Tuesday, August 25, 2020

Python CGI Programming Tutorial



Hello dear readers! welcome back to another section of our tutorial on Python. In this tutorial post, we are going to be discussing about the CGI Programing in Python.

Common Gateway Interface (CGI), is a set of standards that defines how information is exchanged between  web server and a custom script. The CGI specifications are currently maintained by the NCSA.

What is CGI?

Common Gateway Interface (CGI) is a set of standards that defines how information is exchanged between web servers and custom script.

Current CGI version is CGI/2.18.

Web Browsing

To understand the basic concept of CGI, let us see what happens when we click on a hyperlink to browse a particular web page.

  • Your browser first contacts the web server and demands for the URL.
  • Web Server parses the URL and then looks for the file name. If it finds that file, then it sends it back to the web browser, otherwise it sends an error message indicating that the file you requested for could not be found.
  • The web browser takes a response from web server and it then displays either the received file or the error message.


However, it is possible to set up the HTTP server so that whenever a file in a particular directory is called, the file is not sent back to the web browser; instead it is to be executed as a program, and then whatever that program outputs is sent back for your web browser to display. This function is called the Common Gateway Interface or CGI and the programs are called the CGI scripts. These CGI programs can be a Python Script, C or C++ program, Shell Script, PERL Script, etc.

CGI Architecture Diagram


Web Server Support and Configuration

Before proceeding with CGI, make sure your Server supports CGI and it is configured to handle the CGI programs. All the CGI programs to be executed by the HTTP Server are stored in a pre-configured directory. This directory is called CGI Directory and by convention is named as /var/www/cgi-bin. By convention CGI files has extension as .cgi, but you may choose to keep your files with the Python extension .py as well.

By default Linux/Unix server is configured to run only the scripts in cgi-bin directory in /var/www. If you would love any other directory to run your CGI scripts, comment following lines in the httpd.conf file -

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

<Directory "/var/www/cgi-bin">
Options All
</Directory>

We assume you have your Server up and running successfully, and you are able to run any other CGI program like Shell or C++, etc.


First CGI Program

Following is a simple link, which is linked to a CGI script that is called hello.py. This file is kept inside the /var/www/cgi-bin directory and has the following content. Before running your CGI program, be sure to change the mode of file using chmod 755 hello.py command to make the file executable.

#!/usr/bin/python

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

Output

If you click on hello.py, it will produce the following result -

Hello World! This is my first CGI program

This hello.py script is a very simple Python script, which writes it's output on the STDOUT file, i.e. screen. There is one important and extra feature available which is the first line to be printed Content-type:text/html\r\n\r\n. This line is sent back to the browser and it specifies the content type that is to be displayed on the browser screen.

By now you must have understood the basic concept of CGI and can as well write plenty of complicated CGI programs using Python. This script can interact with any other external system as well for an exchange of information such as RDBMS.


HTTP Header

Line Content-type:text/html\r\n\r\n is part of the HTTP header sent to the web browser to understand it's content. All the HTTP header will be in the following form -

HTTP Field Name: Field Content

For Example
Content-type: text/html\r\n\r\n

There are few other important HTTP headers, which you will use regularly in your CGI Programming.

Sr.No.Header & Description
1
Content-type:
A MIME string defining the format of the file being returned. Example is Content-type:text/html
2
Expires: Date
The date the information becomes invalid. It is used by the browser to decide when a page needs to be refreshed. A valid date string is in the format 01 Jan 1998 12:00:00 GMT.
3
Location: URL
The URL that is returned instead of the URL requested. You can use this field to redirect a request to any file.
4
Last-modified: Date
The date of last modification of the resource.
5
Content-length: N
The length, in bytes, of the data being returned. The browser uses this value to report the estimated download time for a file.
6
Set-Cookie: String
Set the cookie passed through the string


CGI Environment Variables

CGI programs have access to the following environment variables. These variables play a vital role while writing CGI programs.

Sr.No.Variable Name & Description
1
CONTENT_TYPE
The data type of the content. Used when the client is sending attached content to the server. For example, file upload.
2
CONTENT_LENGTH
The length of the query information. It is available only for POST requests.
3
HTTP_COOKIE
Returns the set cookies in the form of key & value pair.
4
HTTP_USER_AGENT
The User-Agent request-header field contains information about the user agent originating the request. It is name of the web browser.
5
PATH_INFO
The path for the CGI script.
6
QUERY_STRING
The URL-encoded information that is sent with GET method request.
7
REMOTE_ADDR
The IP address of the remote host making the request. This is useful logging or for authentication.
8
REMOTE_HOST
The fully qualified name of the host making the request. If this information is not available, then REMOTE_ADDR can be used to get IR address.
9
REQUEST_METHOD
The method used to make the request. The most common methods are GET and POST.
10
SCRIPT_FILENAME
The full path to the CGI script.
11
SCRIPT_NAME
The name of the CGI script.
12
SERVER_NAME
The server's hostname or IP Address
13
SERVER_SOFTWARE
The name and version of the software the server is running.

Below is a small CGI program to list out all the CGI variables.

#!/usr/bin/python

import os

print "Content-type: text/html\r\n\r\n";
print "<font size=+1>Environment</font><\br>";
for param in os.environ.keys():
   print "<b>%20s</b>: %s<\br>" % (param, os.environ[param])



Get and Post Method

You must have come across a lot of circumstances where you need to pass some information from your browser to the server and ultimately to your CGI program. Most often, the browser uses two methods to pass this information to webserver. These methods are the POST and GET methods.

Passing Information using the GET Method

The GET method sends the encoded user information that is appended to the page request. The page and the encoded information are separated by the ? character as follows -

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

GET method is the default method to pass information from the web browser to server and it produces a long string that appears in your browser's Location:box. Never use GET method if you have password or other sensitive information to pass to the server.

GET method has size limitation: only 1024 characters can be sent in a request string. GET method sends information by making use of QUERY_STRING header and will be accessible in your CGI program via QUERY_STRING environment variable.

You can pass information by simply concatenating key and value pairs along with any URL or you can make use of the Html <form> tags to pass information using GET method.


Simple URL Example:GET Method

Following is a simple URL, which passes two values to hello_get.py program using GET method.

/cgi-bin/hello_get.py?first_name=PAUL&last_name=ALI

Following is a hello_get.py script to handle input that is given by the browser. We will be making use of the cgi module, which makes it very easy to access passed info -

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

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

# Get data from fields
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>"

Output

When the above code is executed, it will produce the following result -

Hello PAUL ALI

Simple Form Example:GET Method

This example passes two values by using the Html form and the submit button. We used the same CGI script hello_get.py to handle this input.

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

Output

The following below is the actual result of the above form, you enter the FIRST and LAST Name and then click on the submit button to see the result.

First Name:
Last Name:


Passing Information using the POST Method

A generally more reliable method of passing information to a CGI program is the POST method. This packages all the informations in exactly same way as GET method, but instead of sending it as a text string after a ? in the URL it sends the information as a separate message. This message come to the CGI script in the form of the standard Input.

Example

Below is the same hello_get.py script which handles GET as well as POST method.

#!/usr/bin/python

# Import modules for CGI handling 
import cgi, cgitb 

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

# Get data from fields
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>"

Let us now take again the same example as above which passes two values using the Html form and the submit button. We use the same CGI script hello_get.py to handle this input.

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

Output

The following below is the actual output of the above form. You enter FIRST and LAST Name and click on submit button to see the result -

First Name:
Last Name:


Passing Checkbox Data to CGI the Program

Checkboxes are used when more than one option is required to be selected.

Example

Following is a checkbox.cgi script to handle input given by the web browser for checkbox button.

#!/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('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>"

Following below is an example of a Html code for a form with two checkboxes -

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

Output

When the above code is executed, it will produce the following result -

Maths Physics

Passing Radio Button Data to the CGI Program

The radio buttons are used when only one option is required to be selected.

Example

The following is a radiobutton.py script for handling input given by the browser for radio button -

#!/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>"

Below is an example of Html code for a form with two radio buttons -

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

Output

When the above code is executed, it will produce the following result -

Maths Physics


Passing Text Area Data to the CGI Program

Text Area element is used when multiline text has to be passed to the CGI Program.

Example

Following below is a textarea.cgi script to handle input given by browser -

#!/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>"

Below is an example of Html code for a form with TEXTAREA box -

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

Output

When the above code is executed, it will produce the following result -


Passing Drop Down Box Data to the CGI Program

Drop Down Box is used when we have many options available but only one or two will be selected.

Example

Following is a dropdown.py script to handle input given by the web browser -

#!/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>"

Below is an example of Html code for a form with one drop down box -

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

Output

When the above code is executed, it will produce the following result -




Using Cookies in CGI
The Http protocol is a stateless protocol. For a commercial site, it is important to maintain session information among various pages. Now the question is how can we then maintain the user's session information across all web pages?

In many situations, using cookies is the most efficient method to remember and track preferences, commissions, purchases, and any other information that is needed for better visitor experience.

How it Works?
Your server sends some data to the visitor's browser in form of a cookie. The browser may accept the cookie. If it does, it is stored as a plain text record on the visitor's harddrive. Now when the visitor enters another page on your site, the cookie is available for retrieval. Once its retrieved, your web server knows/remembers what is stored.

Cookies are plain text data records of 5 variable-length fields -

  • Expires - The date that the cookie is going to expire. If this is empty, the cookie is going to expire as soon as the visitor quits the browser.
  • Domain - The domain name of your site.
  • Path - The path to the web page that sets the cookie. This may be blank if you want to retrieve the cookie from any page.
  • Secure - If this field holds the word "secure", the cookie may only be retrieved from a secured server, if this field is blank, no such restrictions exist.
  • Name=Value - Cookies are set and retrieved in the form of key & value pairs.


Setting up Cookies
It is very easy to send cookies to the browser. These cookies are sent with HTTP Header before to Content-type field. Suppose you want to set UserId and Password as cookies. Setting up the cookie is done as follows -

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

From the above example, you must have understood how to set cookies. We use Set-Cookie HTTP Header to set cookies.

It is optional to set the cookies attributes like Expires, Domain, and Path. It is notable that cookies are set before sending the magic line "Content-type:text/html\r\n\r\n.

Retrieving Cookies
It is very simple to retrieve all the set cookies. Cookies are stored in CGI environment variable called HTTP_COOKIE and they will have the following form -

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

Example
The following is an example of how to retrieve cookies.

#!/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

Output
When the above code is executed, it will produce the following result -

User ID = XYZ
Password = XYZ123


File Upload Example
To be able to upload a file, the Html form must have the enctype attribute set to multipart/form-data. The input tag with file type creates a "Browse" button.

<html>
<body>
   <form enctype = "multipart/form-data" 
                     action = "save_file.py" method = "post">
   <p>File: <input type = "file" name = "filename" /></p>
   <p><input type = "submit" value = "Upload" /></p>
   </form>
</body>
</html>

Output
When the above code is executed, it will produce the following result -



   
File:

The above example have been disabled intentionally in order for people not to upload files on our sever, but you can try the above code out with your server.

Following is the save_file.py script to handle file upload -

#!/usr/bin/python

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

form = cgi.FieldStorage()

# Get filename here.
fileitem = form['filename']

# Test if the file was uploaded
if fileitem.filename:
   # strip leading path from file name to avoid 
   # directory traversal attacks
   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 run the above script on a Linux operating system, then you need to take care of replacing file separator as follows, or else on your windows machine the above open() statement should work fine.

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

How to Raise a "File Download" Dialogue Box?
Sometimes, it is desired that you want to give an option where your site user can click a link and it will pop up a "File Download" dialogue box instead of displaying actual content. This is very easy and can be achieved through HTTP header. This HTTP header is a bit different from the one that was mentioned in the previous section of this guide.

Example
If you want to make a FileName file downloadable from a given link, then its syntax is as follows -

#!/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 here.
fo = open("foo.txt", "rb")

str = fo.read();
print str

# Close opend file
fo.close()


Alright guys! This is where we are rounding up for this tutorial post. In our next tutorial, we are going to be discussing about the Python MySQL Database Access.

Feel free to ask your questions where necessary and i will attend to them as soon as possible. If this tutorial was helpful to you, you can use the share button to share this tutorial.

Follow us on our various social media platforms to stay updated with our latest tutorials. You can also subscribe to our newsletter in order to get our tutorials delivered directly to your emails.

Thanks for reading and bye for now.
Share:

0 comments:

Post a Comment

Hello dear readers! Please kindly try your best to make sure your comments comply with our comment policy guidelines. You can visit our comment policy page to view these guidelines which are clearly stated. Thank you.