Python - CGI Programming: A Beginner's Guide
Hello there, future Python wizards! I'm thrilled to be your guide on this exciting journey into the world of CGI programming with Python. As someone who's been teaching computer science for years, I can tell you that CGI is like the secret sauce that makes your web applications come alive. So, let's roll up our sleeves and dive in!
What is CGI?
CGI stands for Common Gateway Interface. Now, I know that sounds like a mouthful, but think of it as a translator between your web server and your Python scripts. It's like having a friendly interpreter who helps your server and your code communicate seamlessly.
CGI allows us to create dynamic web pages that can respond to user input. Imagine a website that greets you by name or shows you personalized content - that's the magic of CGI at work!
Web Browsing
Before we get into the nitty-gritty of CGI, let's take a quick look at how web browsing works. When you type a URL into your browser, here's what happens:
- Your browser sends a request to the web server.
- The web server processes the request.
- The server sends back a response, usually in the form of an HTML page.
- Your browser renders this HTML, displaying the web page you see.
CGI comes into play when we want to generate dynamic content in step 3.
CGI Architecture Diagram
Here's a simple diagram to visualize how CGI fits into the web architecture:
+-------------+ HTTP Request +-------------+
| Browser | -----------------> | Web Server |
| | <----------------- | |
+-------------+ HTTP Response +-------------+
|
| CGI
v
+-------------+
| CGI Script |
| (Python) |
+-------------+
Web Server Support and Configuration
Most web servers support CGI, including Apache and Nginx. To use CGI with Python, you'll need to configure your server to execute Python scripts. This usually involves setting up a special directory for CGI scripts and telling the server to treat files in this directory as executable.
For example, in Apache, you might add something like this to your configuration:
<Directory /var/www/cgi-bin>
Options ExecCGI
AddHandler cgi-script .py
</Directory>
This tells Apache to execute .py files in the /var/www/cgi-bin directory as CGI scripts.
First CGI Program
Let's write our first CGI program! We'll start with the classic "Hello, World!" example. Create a file named hello.py
in your CGI directory:
#!/usr/bin/env python3
print("Content-Type: text/html")
print()
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>")
Let's break this down:
- The first line tells the server to use Python to execute this script.
-
Content-Type: text/html
is an HTTP header that tells the browser we're sending HTML. - The blank
print()
separates the headers from the body of the response. - The rest is just HTML that we're generating dynamically.
When you access this script through your web browser, you should see a page that says "Hello World! This is my first CGI program".
HTTP Header
In CGI programming, it's crucial to send the correct HTTP headers before your content. The most common header is Content-Type
, which tells the browser what kind of data you're sending. Here are some examples:
Content Type | Description |
---|---|
text/html | HTML content |
text/plain | Plain text |
image/jpeg | JPEG image |
application/json | JSON data |
Always remember to send the appropriate Content-Type header before your content!
CGI Environment Variables
CGI scripts have access to various environment variables that provide information about the request. Here's a script that displays some of these variables:
#!/usr/bin/env python3
import os
print("Content-Type: text/html")
print()
print("<html><body>")
print("<h2>Environment Variables:</h2>")
for param in os.environ.keys():
print("<b>%20s</b>: %s<br>" % (param, os.environ[param]))
print("</body></html>")
This script will show you all the environment variables available to your CGI script, including things like the user's browser type, the server name, and more.
GET and POST Methods
There are two main methods for sending data to a CGI script: GET and POST. Let's look at both:
GET Method
The GET method sends data as part of the URL. Here's a simple example:
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
name = form.getvalue('name', 'World')
print("<html><body>")
print(f"<h2>Hello, {name}!</h2>")
print("</body></html>")
You can access this script with a URL like http://yourserver.com/cgi-bin/hello.py?name=Alice
, and it will say "Hello, Alice!".
POST Method
The POST method sends data in the body of the HTTP request. It's typically used for forms. Here's an example:
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
name = form.getvalue('name', 'World')
email = form.getvalue('email', 'Not provided')
print("<html><body>")
print(f"<h2>Hello, {name}!</h2>")
print(f"<p>Your email is: {email}</p>")
print("</body></html>")
This script could be used with an HTML form that uses the POST method.
Handling Different Form Elements
CGI can handle various form elements. Let's look at a few examples:
Checkboxes
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
hobbies = form.getlist('hobby')
print("<html><body>")
print("<h2>Your hobbies:</h2>")
for hobby in hobbies:
print(f"<p>{hobby}</p>")
print("</body></html>")
Radio Buttons
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
gender = form.getvalue('gender', 'Not specified')
print("<html><body>")
print(f"<h2>Your gender: {gender}</h2>")
print("</body></html>")
Text Area
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
message = form.getvalue('message', 'No message provided')
print("<html><body>")
print("<h2>Your message:</h2>")
print(f"<p>{message}</p>")
print("</body></html>")
Drop Down Box
#!/usr/bin/env python3
import cgi
print("Content-Type: text/html")
print()
form = cgi.FieldStorage()
country = form.getvalue('country', 'Not selected')
print("<html><body>")
print(f"<h2>Your country: {country}</h2>")
print("</body></html>")
Using Cookies in CGI
Cookies are a way to store small pieces of data on the client-side. They're useful for remembering user preferences or maintaining session information. Here's how you can work with cookies in CGI:
Setting Cookies
#!/usr/bin/env python3
import cgi
from http import cookies
import datetime
# Create a cookie
c = cookies.SimpleCookie()
c['lastvisit'] = str(datetime.datetime.now())
c['lastvisit']['expires'] = 365 * 24 * 60 * 60 # expires in a year
print(c) # This prints the Set-Cookie header
print("Content-Type: text/html")
print()
print("<html><body>")
print("<h2>Cookie set!</h2>")
print("</body></html>")
Retrieving Cookies
#!/usr/bin/env python3
import os
from http import cookies
print("Content-Type: text/html")
print()
if 'HTTP_COOKIE' in os.environ:
cookie_string = os.environ.get('HTTP_COOKIE')
c = cookies.SimpleCookie()
c.load(cookie_string)
lastvisit = c.get('lastvisit')
if lastvisit:
print("<h2>Your last visit was:", lastvisit.value, "</h2>")
else:
print("<h2>This is your first visit!</h2>")
else:
print("<h2>This is your first visit!</h2>")
File Upload Example
Handling file uploads is a bit more complex, but here's a simple example:
#!/usr/bin/env python3
import cgi, os
import cgitb; cgitb.enable()
print("Content-Type: text/html")
print()
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("""\
<html>
<body>
<p>%s</p>
</body>
</html>
""" % message)
How To Raise a "File Download" Dialog Box?
To trigger a file download, you need to set the appropriate headers:
#!/usr/bin/env python3
import os
filename = "example.txt" # This would be your file name
filepath = "/path/to/your/file" # This would be the path to your file
print("Content-Type: application/octet-stream")
print(f"Content-Disposition: attachment; filename={filename}")
print() # Blank line, end of headers
# Now send the file content
with open(os.path.join(filepath, filename), 'rb') as f:
print(f.read())
This script sets the Content-Type to application/octet-stream
, which tells the browser to download the file rather than display it. The Content-Disposition header suggests a filename for the download.
And there you have it, folks! We've covered the basics of CGI programming with Python. Remember, practice makes perfect, so don't be afraid to experiment with these examples and create your own. Happy coding, and may your CGI scripts always run smoothly!
Credits: Image by storyset