Today we’re going to talk about an alternative function for deprecated CGI that will save you from pulling your hair out in frustration.
To kick things off: what is CGI? It stands for Common Gateway Interface, and it allows web servers to execute scripts on the server-side when a user submits data through a form or URL query parameters. However, as of Python 3.11, the cgi module has been deprecated in favor of using email’s MIME functionality instead (PEP 594).
But let’s say you have an old CGI script that still works perfectly fine and you don’t want to rewrite it from scratch just yet. Or maybe you prefer the simplicity of CGI over more complex frameworks like Flask or Django. Whatever your reason, we’ve got a solution for you!
Introducing `cgi.parse()` an alternative function that can handle query strings and form data in Python 3.x. This function is deprecated as well (PEP 594), but it still works just fine if you don’t mind using a third-party library or framework instead of the built-in email module.
Here’s how to use `cgi.parse()`:
# Import the necessary modules
import cgi, os
# Use the cgi module to parse the form data and store it in a dictionary
form = cgi.FieldStorage(environ=os.environ)
# Access the form data using dictionary syntax and store it in variables
name = form['name'].value # Retrieve the value of the 'name' field from the form data
email = form['email'].value # Retrieve the value of the 'email' field from the form data
message = form['message'].value # Retrieve the value of the 'message' field from the form data
# Print the appropriate headers for the browser to interpret the response as HTML
print("Content-Type: text/html")
print()
# Print a thank you message to the browser
print("<h1>Thank you for your message!</h1>")
In this example, we’re using `cgi.FieldStorage()` to parse the form data from the environment variables (which are set by the web server). We can then access each field as a dictionary key and retrieve its value using the `value` attribute.
But what if you want to handle multipart/form-data input instead? That’s where `cgi.parse_multipart()` comes in:
# Import necessary modules
import cgi, os # Import cgi and os modules for handling form data and operating system functions
from email import message_from_string # Import message_from_string function from email module
boundary = '---------------------------1234567890' # Set boundary for multipart/form-data input
# Read the entire request body and split it into chunks based on boundary lines
body = b'' # Initialize empty byte string for storing request body
while True: # Start a while loop
chunk = sys.stdin.buffer.read(1024) # Read 1024 bytes from standard input and store in chunk variable
if not chunk: break # If chunk is empty, break out of the loop
if b'\r\n' in chunk or b'\n\r' in chunk: # Check if chunk contains boundary lines
body += chunk[:chunk.index(b'\r\n')+2] # Add chunk to body up to the first boundary line
boundary_pos = chunk[chunk.index(b'\r\n')+2:].find(boundary) + 3 # Find the position of the next boundary line
if boundary_pos != -1: # If boundary line is found
yield message_from_string(''.join([body[:boundary_pos], chunk[boundary_pos:]])) # Yield a message from the body up to the boundary line and the chunk after the boundary line
body = b'' # Reset body to empty byte string
else:
body += chunk # If no boundary line is found, add chunk to body
# Access form data using dictionary syntax
message = next(body)['Content-Disposition'].split(";")[-1][2:-1] # Get the value of the 'Content-Disposition' field from the first message in the body
name, email, message = [x.strip() for x in message.split('&')] # Split the message into name, email, and message variables and remove any leading or trailing whitespace
# Print output to the browser
print("Content-Type: text/html") # Set content type to HTML
print() # Print an empty line to separate headers from body
print("<h1>Thank you for your message!</h1>") # Print a thank you message to the browser
In this example, we’re using `sys.stdin.buffer` to read the entire request body and split it into chunks based on boundary lines (which are set by the web server). We then use `email.message_from_string()` to convert each chunk into a message object that can be accessed as a dictionary key.
x! While we recommend using email’s MIME functionality instead, sometimes old habits die hard and this solution may come in handy. Just remember to use caution when handling user input and always sanitize your data before processing it further.