An Example: Survey

Our Hello World example earlier might have given you a taste of how CGI scripts work, but it was too simple to be of much use. Here's a much more complex script that handles a Web-based survey. The script keeps track of all the survey for the data, handling the input from the current form and generating tables of results based on all the data submitted so far. Figure 16.4 shows our simple survey.

Figure 16.4. A simple Web survey.


After filling out the survey, the CGI script processes the input, adds it to the data already received, and generates a set of tables, shown in Figure 16.5.

Figure 16.5. The Web survey results


All the data from the survey is stored in a separate file on the Web server. You'll open, read, and write that data file as part of the CGI script to process the form.

The Form

Let's start with the HTML for the form, just to point out the values that you'll be working with in the CGI script. Listing 16.2 shows that HTML code:

Listing 16.2. survey.html
<html>
<head>
    <title>Quick Survey</title>
</head>
<body>
<h1>Please take our survey!</h1>
<form action="/cgi-bin/survey.pl">
<p><strong>Age: </strong><br />
<input type="radio" name="age" value="under18" />Under 18<br />
<input type="radio" name="age" value="18to34" />18-34<br />
<input type="radio" name="age" value="35to50" />35-50<br />
<input type="radio" name="age" value="50plus" />50+
</p>
<p><strong>Sex: </strong><br />
<input type="radio" name="sex" value="male" />Male<br />
<input type="radio" name="sex" value="female" />Female
</p>
<p><strong>Are you a Perl programmer? </strong><br />
<input type="radio" name="perl" value="yes">Yes<br />
<input type="radio" name="perl" value="no">No
<p><input type="submit" value="Submit my Results" /></p>
</form>
</body>
</html>
						

There are only a few important things to note about this HTML code. Here, instead of a text field like we had in the last example, we're using groups of radio buttons. Note that each group has the same name (for example, all four radio buttons in the age group are named “age”). This prevents more than one button from being selected at one time. It also means that when you get the input from your script, only one value from each group will appear. You'll have to test for the existence of each one to find out which one was selected.

The Script

The CGI script to process this form accomplishes four main things:

  • It opens and reads the survey data file into a hash.

  • It processes the input from the form, adding the new data to the old data.

  • It writes out the new data to the file again.

  • It generates HTML for the output, containing tables generated from the current survey data.

Listing 16.3 shows the code for our CGI script, called survey.pl.

Listing 16.3. The survey.pl Script
1:  #!/usr/local/bin/perl -w
2:  use strict;
3:  use CGI qw(:standard);
4:
5:  my $results = 'survey_results.txt';
6:  my %data = ();
7:  my $thing = '';
8:  my $val = 0;
9:
10: open(RESULTS, $results) or die "Can't open results file: $!";
11: while (<RESULTS>) {
12:     ($thing, $val) = split(' '),
13:     $data{$thing}  = $val;
14: }
15: close(RESULTS);
16:
17: # overall total
18: $data{total} ++;
19: # handle age
20: if (!param('age')) { $data{age_na} ++ }
21: else {
22:     if (param('age') eq 'under18') { $data{age_under18} ++; }
23:     elsif (param('age') eq '18to34') { $data{age_18to34} ++; }
24:     elsif (param('age') eq '35to50') { $data{age_35to50} ++; }
25:     elsif (param('age') eq '50plus') { $data{age_50plus} ++; }
26: }
27:
28: # handle sex
29: if (!param('sex')) { $data{sex_na} ++ }
30: else {
31:     if (param('sex') eq 'male') { $data{sex_m} ++; }
32:     elsif (param('sex') eq 'female') { $data{sex_f} ++; }
33: }
34:
35: # perl
36: if (!param('perl')) { $data{perl_na} ++ }
37: else {
38:     if (param('perl') eq 'yes') { $data{perl_y} ++; }
39:     elsif (param('perl') eq 'no') { $data{perl_n} ++; }
40: }
41:
42: open(RESULTS,">$results") or die "Can't write to results file: $!";
43: foreach $thing (keys %data) {
44:     print RESULTS "$thing $data{$thing} 
";
45: }
46: close(RESULTS);
47:
48: print header;
49: print start_html('Thank you'),
50: print <<EOF;
51: <h1>Thank you for filling out our survey!</h1>
52: <p>Our results so far:
53: <p>Sex:
54: <table border="1"><tr><th>Male</th><td>
55: EOF
56:
57: print &percent('sex_m'), "</td></tr>
";
58: print "<tr><th>Female</th><td>
";
59: print &percent('sex_f'), "</td></tr>
";
60: print "<tr><th>No Answer</th><td>
";
61: print &percent('sex_na'), "</td></tr>
";
62: print "</table>
";
63:
64: print "<p>Age:
";
65: print "<table border="1"><tr><th>Under 18</th><td>
";
66: print &percent('age_under18'), "</td></tr>
";
67: print "<tr><th>18 to 34</th><td>
";
68: print &percent('age_18to34'), "</td></tr>
";
69: print "<tr><th>35 to 50</th><td>
";
70: print &percent('age_35to50'), "</td></tr>
";
71: print "<tr><th>Over 50</th><td>
";
72: print &percent('age_50plus'), "</td></tr>
";
73: print "<tr><th>No Answer</th><td>
";
74: print &percent('age_na'), "</td></tr>
";
75: print "</table>
";
76: print "<p>Perl Programmer?
";
77: print "<table border="1"><tr><th>Yes</th><td>
";
78: print &percent('perl_y'), "</td></tr>
";
79: print "<tr><th>No</th><td>
";
80: print &percent('perl_n'), "</td></tr>
";
81: print "<tr><th>No Answer</th><td>
";
82: print &percent('perl_na'), "</td></tr>
";
83: print "</table>
";
84:
85: print end_html;
86:
87: sub percent {
88:     if (defined $data{$_[0]} ) {
89:         return sprintf("%.1f%%", $data{$_[0]}  / $data{total}  * 100);
90:     }
91:     else { return '0%'; }
92: }
						

I'm not going to go through this script line by line because much of this is code you've seen in a similar form before (and a whole lot of it is just print statements). Here are some of the important parts to note, however.

The name of the survey data file is stored in the $results variable in line 10. Here, that file is assumed to be in the same directory as the CGI script itself; you'll need to set the pathname to the appropriate location for your script. That file consists of a set of data keys for each choice in the survey, as well as “na” keys for no answer. Each key has a value for the number of “votes” submitted. Lines 10 through 15 open and read that data file into the %data hash, closing it again immediately afterward.

Note

The results file—here, located in the same directory as the CGI script—must be writeable by the Web server. On Unix, that means the file must have the right permissions so that the user or group ID the Web server runs under (usually nobody) can write to it. On Windows that means your security must also be set accordingly. If you run into “can't write to results file” errors when you run this script under a Web server (that didn't happen when you ran it with regular Perl), check your file permissions.


Lines 17 through 41 process the input from the form in groups, corresponding to each group of radio buttons in the HTML file (age, sex, and perl). Note that for each group, you have to test to see if there was no answer (in which case, there won't be a key for that group in the param() array CGI.pm gives you). If there was a vote, we'll increment the value of that key in the data hash. We also keep track of the overall total (line 16), which we'll need to calculate the percentages for the final output.

After we're done processing the data, we can write out the new data file to that same file, one data key and value per line, separated by a space. The actual order of the keys doesn't matter because they'll just be re-read by the script again into a hash. A simple foreach loop in lines 44 and 45 will print the new values to the results file (which we reopened for writing in line 43).

The second half of the script prints the output to the survey so the user can get a response from the survey. Starting from line 49 we print the output starting with the header (line 49), the beginning of the HTML file (line 50), and some boilerplate HTML printed with a here document in lines 51 through 56.

Line 58 is where things start getting interesting. The rest of the HTML file consists of tables that show the current results of the survey. Much of the printing here involves the HTML code for the tables, but the final percentages are calculated using a help subroutine we defined called &percent(). The &percent() routine, defined in lines 89 through 94, generates a percent string based on the value it's given divided by the total number of responses. It also makes sure that the given data key actually has a value (if it's zero, it won't even appear in the %data hash). And, finally it formats the percentage with one decimal point and a percent sign using the sprintf function (note that because of the sprintf formatting codes, if you want to print an actual percent sign, you have to type it as %%).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.100.202