CIS 24: CGI and Perl Programming for the Web

Class 8 (10/30) Lecture Notes

Topics

  1. Next Week's Midterm Exam
  2. Debugging Perl CGI Applications Checklist
  3. Modules & Pragmas
  4. Using the Perl CGI Module: CGI.pm
  5. Maintaining User "State"
  6. Lab

Return to CIS 24 home page


  1. Next Week's Midterm Exam
  2. The midterm will be a two hour test. Like the Quiz, it will be open note and open book. You will be asked to write two CGI scripts. To write the scripts successfully, you will need to know the programming techniques we discussed last week, and the ones we will discuss tonight. These techniques include:

    1. receiving and decoding data from an HTML form submission,
    2. putting the form data into a hash,
    3. performing input validation on the form data,
    4. displaying the form data in a dynamically created web page,
    5. maintaining user "state" in multiple form submissions (we'll learn this tonight).

    For the first script, you'll be given a sample form, and you'll need to do items 1-4 without the CGI.pm module. For the second script, you'll need to do items 1-5 with the CGI.pm module (we'll learn about CGI.pm tonight).

    Since the lecture notes have complete scripts for doing the above tasks, you won't have to write your scripts from scratch. The best strategy will be to start with the scripts from the lectures notes, and then modify and extend them as needed to meet the requirements of the exam questions.

    There will not be a lecture or lab after the midterm.

  3. Debugging Perl CGI Applications Checklist
  4. In last week's lab, the biggest challenge many of you faced was tracking down problems in your scripts. Here's a recap of debugging techniques, in the form of a checklist. Note that this checklist only applies to using Apache in Windows. Please come see me if you're using a UNIX system, as there are additional debugging techniques that apply to UNIX.

    1. Is your Web Server running? If it is, you will have a MS-DOS window running. The text in the window should indicate the Apache server is running. If it is not running, you can find "Start Apache" under Start | Programs | Apache Group.

    2. All of your HTML files should be saved in the directory htdocs under your Apache directory.

    3. All of your Perl scripts should be saved in the directory cgi-bin under your Apache directory.

    4. You should not browse the file system to use your HTML form. In order to have your form submission activate your Perl script, you need to view your HTML form through your web server. You can do this by typing the address http://localhost/your_filename.html into your browser's Location (or Address) window.

    5. Does the ACTION attribute of your FORM tag indicate the correct location of your Perl script? It should look something like this:
      <FORM METHOD="GET" ACTION="/cgi-bin/your_script.pl">

    6. Does your script have the correct shebang line? This is the very first line of your script. It's purpose is to tell the Apache web server that your script should be sent to the Perl interpreter, and it looks like this:
      #!perl

    7. Are there any syntax errors in your Perl script? You can check this by typing the following in an MS-DOS window:
      perl -c your_script.pl

    8. Is there a message in the web server's error log? To check this, note the exact time the "Server Error" page came up, and then use Notepad to open the file logs\error.log under your Apache directory. Scroll to the end of the file and look for error messages that were generated at the same time you saw the "Server Error" page. You will find the newest errors at the end of the file.

  5. Modules & Pragmas
    1. What are Perl modules?

      Perl comes with a built-in library of functions. For example, when you use the print function, you are calling a function that is available in the Perl function library. Often, when you're using Perl for a specific task - for example, retrieving data from a database, sending email, or processing HTML form submissions - you won't find functions in Perl that allow you to accomplish these tasks easily. We saw this last week in the code we wrote for processing forms submissions - we had to write several lines of complex code to accomplish this common task.

      Programmers have addressed the need for accomplishing commonly needed but complex tasks by creating and freely distributing Perl modules. For database interaction, there are the DBI and and DBD modules, for email there is the Net::SMTP module, for CGI programming there is the CGI module, and so on. There are currently about 3500 modules available for Perl, and at least 150 of the most popular ones come with the ActiveState version of Perl.

      When you use a Perl module, you make a special set of new functions available for use in your Perl script. By learning about Perl modules and making use of their functions, you can greatly simplify your programming efforts.

    2. How do I use a Perl module?

      Before you can use a module, it needs to be in the "lib" subdirectory of your Perl directory. If you look there with Windows Explorer, all the files you see that have a .pm file extension are Perl modules (also look in the subdirectories of "lib").

      To access the functions in a Perl module, you must invoke the module in your perl script with the use directive. The example below uses the Cwd module, which makes three new functions available in your script: cwd, getcwd, and fastgetcwd. This is a handy module to use if your script needs to know the current working directory. The system commands for this are different in Windows, UNIX, and Macintosh. The module knows how to implement the right calls for Cwd for the operating system you're using. This means that it's a good way to help provide portability of your code from one OS to another.

      #!perl
      use Cwd;
      $dir = fastgetcwd;
      print $dir;

      Some Perl modules allow you to specify directives indicating how you want to interact with the module. For example, with the CGI module, you can take direct advantage of its functions, or you can run it in an object-oriented programming mode. For this class, we're interested using its standard set of functions - we specify this by invoking the module with the ":standard" argument:

      use CGI qw(:standard);

      Note that ":standard" has a meaning that is specific to the CGI module - read the documentation on other modules to see if they have options such as this.

    3. Mistakes to Avoid When Using Modules

      • Don't use the full filename with the use directive. In the above example, the filename is Cwd.pm, but you leave out the .pm file extension when you invoke it.
      • Module names are case sensitive. If you try use cwd; you will not successfully invoke the Cwd module.
      • Some module names have double colons in them, for example File::Find - make sure you've spelled the module name correctly (this is actually the syntax to use when accessing a module within a file that contains more than one module - the "find" module is one of several modules in file.pm).
      • Make sure you have the module installed in your Perl "lib" directory, or one of its subdirectories, before you try to invoke it.

    4. How can I learn what a module can do, and where can I find more?

      As mentioned above, to see the modules that come with the ActiveState version of Perl, go into the "lib" subdirectory of the Perl directory on your computer and look for files with .pm file extensions.

      To see what a module can do, open an MS-DOS window and type perldoc module_name - for example:

      perldoc Cwd

      You can download and install more modules from the ActiveState web site by using the Perl Package Manager (PPM). This is a command-line utility that you can use to automatically download and install Perl modules. You can also use it to review your currently installed modules. Let's see more about at the ActiveState web site: http://www.activestate.com/Products/ActivePerl/docs/faq/ActivePerl-faq2.html

      You can find even more modules at the Web site for the Comprehensive Perl Archive Network (CPAN): www.cpan.org. You'll probably want to start with the The annotated module list (it's big!).

    5. What are Pragmas?

      Pragmas are invoked with the use directive, just like modules. However, instead of providing additional functions to your Perl script, pragmas alter how the Perl interpreter behaves. There are only 19 pragmas, and only a couple of them are commonly used: diagnostics and strict (you've probably noticed use strict; in the sample scripts in your book).

      diagnostics is used to provide more verbose error messages when a Perl script fails, and strict is used to enforce good coding practices. We'll talk about strict more in a later class.

  6. Using the Perl CGI Module: CGI.pm
  7. As we saw last week, the code we needed for processing form submissions was fairly complex. Since CGI programming is a common use of Perl, the CGI module has been created to simplify related programming tasks. Specifically, it was created by Lincoln Stein, and you can see all the documentation for CGI.pm at his web site.

    We can re-write our script from last week (for processing the submission from the birthday form) using the CGI module, like this:

    #!perl
    
    # Invoke the CGI module with ":standard" so that
    # we can use the module's standard set of functions.
    
    use CGI qw(:standard);
    
    # Check to see if the inputs are valid
    
    push (@errors, "your first name") unless (param('firstname') =~ /\w+/);
    push (@errors, "your last name") unless (param('lastname') =~ /\w+/);
    push (@errors, "a valid date for your birthday") unless (param('birthday') =~ m:^\d{1,2}/\d{1,2}/\d{1,2}$:);
    push (@errors, "a valid email address") unless (param('email') =~ /^\S+\@\S+\.\S+$/);
    
    # If there's any invalid data, print a page with the error messages, and exit the script.
    
    if (@errors) {
    	print header;
    	print
    		start_html('Input Error'),
    		h2('Input Error'),
    		p, "Please click your browser's <I>back</I> button and enter:";
    
    	print "<UL>";
    
    	foreach $error(@errors) {
    		print "<LI>$error\n";
    	}
    
    	print "</UL>";
    	print end_html;
    	exit;
    }
    
    # If there weren't any errors, we can print the response page.
    
    print header;
    print
    	start_html('Your name and birthday'),
    	h2('Your name and birthday'),
    	p, b('Your first name: '), param('firstname'),
    	p, b('Your last name: '), param('lastname'),
    	p, b('Your birthday: '), param('birthday'),
    	p, b('Your email address: '), param('email');
    
    print end_html;

  8. Maintaining User "State"
  9. It's sometimes necessary in CGI applications to have more than one form page in a row. Here's an example of one I created at a former job of mine: The Phoenix Product Finder. (Please do not submit the forms! This is a live application - just follow along with me in class).

    Applications like these need to "remember" what happens from one page to the next, so that when we reach the end, we haven't lost the information that was entered in the beginning.

    Let's do an example that's an extension of our "birthday" CGI application. First, add the following input field to the form in birthday.html

    <INPUT TYPE="hidden" NAME="page" VALUE="1">

    Here's the revised birthday.pl script:

    #!perl
    
    # Invoke the CGI module with ":standard" so that
    # we can use the module's standard set of functions.
    
    use CGI qw(:standard);
    
    # Check to see if the inputs are valid. First we need to
    # know which form submission is coming in. Check the 
    # HIDDEN input field "page" to see if this is from the
    # first form or the second form
    
    if (param('page') == 1) {
    	push (@errors, "your first name") unless (param('firstname') =~ /\w+/);
    	push (@errors, "your last name") unless (param('lastname') =~ /\w+/);
    	push (@errors, "a valid date for your birthday") unless (param('birthday') =~ m:^\d{1,2}/\d{1,2}/\d{1,2}$:);
    	push (@errors, "a valid email address") unless (param('email') =~ /^\S+\@\S+\.\S+$/);
    }
    
    else {
    	push (@errors, "your favorite color") unless (param('color') =~ /\w+/);
    }
    
    # If there's any invalid data, print a page with the error messages, and exit the script.
    
    if (@errors) {
    	print header;
    	print
    		start_html('Input Error'),
    		h2('Input Error'),
    		p, "Please click your browser's <I>back</I> button and enter:";
    
    	print "<UL>";
    
    	foreach $error(@errors) {
    		print "<LI>$error\n";
    	}
    
    	print "</UL>";
    	print end_html;
    	exit;
    }
    
    # If there weren't any errors, we can print the appropriate
    # response page.
    
    print header;
    
    if (param('page') == 1) {
    	print
    		start_html('Your name and birthday'),
    		h2('Your name and birthday'),
    		p, b('Your first name: '), param('firstname'),
    		p, b('Your last name: '), param('lastname'),
    		p, b('Your birthday: '), param('birthday'),
    		p, b('Your email address: '), param('email'),
    		start_form,
    		p, b('What is your favorite color? '), textfield('color'),
    		hidden(-name=>'firstname', -default=>param('firstname')),
    		hidden(-name=>'lastname', -default=>param('lastname')),
    		hidden(-name=>'birthday', -default=>param('birthday')),
    		hidden(-name=>'email', -default=>param('email')),
    		p, submit,
    		end_form;
    }
    
    else {
    	print
    		start_html('Your name, birthday, and favorite color'),
    		h2('Your name, birthday, and favorite color'),
    		p, b('Your first name: '), param('firstname'),
    		p, b('Your last name: '), param('lastname'),
    		p, b('Your birthday: '), param('birthday'),
    		p, b('Your email address: '), param('email'),
    		p, b('Your favorite color: '), param('color');
    }
    
    print end_html;

  10. Lab
    1. Modify the script in Section V above. In addition to having the second page ask for the user's favorite color, also have it ask for the user's zip code. Display the zip code entered by the user, along with the other form inputs, on the following page.

    2. Redo part C of your lab assignment from last week using CGI.pm. You can do this just as an exercise, or you can choose to do this and your remaining project work with CGI.pm. This will also be good preperation for the midterm.

    3. In preparing for next week's midterm exam, review last week's lecture notes and your lab work from last week. The exam will require you to do form processing with CGI.pm, and without CGI.pm - so knowing the methods covered in last week's class is important.

Return to CIS 24 home page