Writing CGI Scripts in Python

This article is neither a Python tutorial nor a CGI tutorial, but a “Python Presentation from a CGI perspective”.

Before putting your CGI scripts on-line, you should be sure that they're really clean, by testing them carefully, especially in near bounds or out of bounds conditions. A script that crashes in the middle of its job can cause large problems, like data inconsistency in a database application. You can eliminate most of the problems by running your script from the command line; then testing it from your HTTP daemon.

First, you have to remember that Python is an interpreted language. This means that several syntax errors will not be discovered until run time. You must be sure your script has been tested in every part of the control flow. You can do that by generating parameter sets that you will hardcode at the beginning of your script.

Then, be sure that incorrect input cannot lead to an incorrect behaviour of your script. Don't expect that all parameters received by your script will be meaningful. They can be corrupted during communication, or some hacker could try to obtain more data then normally allowed.

Listing 5 shows a different version of our Hello World script and demonstrates the following features:

  • Tuples: Tuples are arrays consisting of a number of values separated by commas. Ouput tuples are enclosed in parenthesis. The localtime() function returns a tuple which can be assigned in one variable (that becomes a tuple). Or as in this script, individual elements of the tuple can be assigned at one time to several variables.

  • The elif (“else if”) statement: Listing 5 has two syntax errors that are not detected when the interpreter loads the script, but will crash it when executed. It will crash at Christmas, because there is a call to a Christmas() function which has not been defined, and it will crash again at the New Year's Day, because in addition to “Happy New Year!”, it tries to print a “Max” variable which doesn't exist (due perhaps to a cut-and-paste from a script intended to wish someone happy birthday?). Here is what you'll find in the error_log file if the script is accessed on Christmas:

    Traceback (innermost last):
      File "/cgi-bin/buggy.py", line 59, in ?
      File "/cgi-bin/buggy.py", line 53, in Main
    NameError: Christmas

The fact that the script seems to execute normally (especially on New Year's Day, since everything that should have been printed is actually printed) can be a pitfall. The script has actually crashed!

Of course, in this script, crashing is not a big problem. But in an Intranet application, it could be very harmful. Imagine, for example, a script that displays a message saying it has updated your stock database, but has in fact crashed immediately after giving the message. The user thinks everything is going well, but the data have not been updated.

Let's get back to Listing 4. We've already seen that the generated xbm is not good; but maybe there are other problems. What happens if:

  • The script is called with:


    instead of:

  • The database file counters.gdbm does not exist?

  • The access count exceeds 9999?

I suggest you try these, and try your own solutions. For the last situation in the list—the access count exceeds 9999—there are several solutions; I suggest modifying the DIGITS value if the incremented value in the inc_counter() function has a length that exceeds DIGITS. How would you see the generated file if your web browser displays nothing? Maybe you could add the following code, replace the call to CGImain() with TSTmain() and run the script from the command line:

def TSTmain() :
 url = "http://localhost/test.html"
 counter = get_put_counter( url )
 print_digits_values( counter )
Form Handling

Listing 6 shows the HTML source for a form we are going to discuss for the remainder of this article. It allows the user to enter some values to perform a query on a database. The action parameter of the form should be adapted to your needs. For a real application, you should replace localhost by the fully qualified name of your host. The name of the script should also be adapted to call the right thing. Note that the HTML code defines a hidden field (TableName).

Let's start with a script that just echoes values entered by the user (see Listing 7). You'll see that, even if you leave the form empty, two parameters are displayed. The first one is (TableName), a hidden parameter in our form, and the second one is the value of the Submit button (which is also a field). Notice that:

  • CGI module imported by our scripts is used to parse the input sent by an HTML form. It works with GET and POST methods.

  • cgi.SvFormContentDict() builds a dictionary with:

        { field name ; field value }

couples corresponding to the data encoded by the user.

  • cgi.escape() is used to convert special characters into their HTML escape sequence (for example, < becomes <).



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Thanks for tutorial! I found a syntax error.

Anonymous's picture

Thanks for the tutorial. :)

There is a syntax error in listing 7, in the line "if len( fields ) = 0 :". You probably see it now, it should have been "==" and not "=" - we need the comparison operator, not the assignment operator.