Writing CGI Scripts in Python

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

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 ?
        Main()
      File "/cgi-bin/buggy.py", line 53, in Main
        Christmas()
    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:

    <img
    src="http://localhost/cgi-bin/count.py?\
    http://localhost/index.html">
    

    instead of:

    <img
    src="http://localhost/cgi-bin/count.py?
    _url=_http://localhost/index.html">?
    
  • 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_header()
 print_digits_values( counter )
 print_footer()
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 <).

______________________

Comments

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.

-Nobody

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState