Creating a Multiple Choice quiz System, Part 3
Before we get to work coding, let's figure out how all of this works. We invoke edit-quiz.pl in a number of different ways, using both GET (i.e., entering its URL in a browser window or clicking on a hyperlink within a page of HTML) and POST (i.e., when we click on a submit button at the bottom of an HTML form).
If edit-quiz.pl is invoked using GET without any arguments, we are asked which quiz we wish to create or edit. Entering the name of the quiz file and pressing Return submits it to the program, which then receives this argument—again using GET--in the query string.
The query string, for those of you relatively new to CGI programming, is the term for anything following the question mark in a URL. It allows the passing of simple arguments to a CGI program without having to use POST, a more complicated and sophisticated protocol for passing information. Thus, if someone invokes the program:
http://www.fictional.edu/cgi-bin/program.pl
the query string is null, because there is no argument. But if someone invokes the CGI program:
http://www.fictional.edu/cgi-bin/program.pl?foobarthe argument is foobar. If we are using CGI.pm, a Perl module for writing CGI programs (available from CPAN at http://www.perl.com/CPAN), we can theoretically retrieve the contents of the query string using the query_string method, as in:
my $query = new CGI; my $query_string = $query->query_string;For reasons that I don't completely understand, the query_string method returns the query string with a prepended keywords=, as if the query string had been submitted to our CGI program in an HTML form element named keywords. While this can sometimes come in handy, for the most part, I find it a surprising quirk in an otherwise excellent package.
If CGI.pm is going to treat the query string as a parameter named keywords, we have to retrieve its value in the same way as we would other parameters, namely:
my $query = new CGI;
my $query_string = $query->param("keywords");
which might seem a bit odd at first, but you get used to it.
We determine whether our program was invoked via GET or POST using the method request_method within CGI.pm. In other words, we can do the following:
my $query = new CGI; my $request_method = $query-7gt;request_method;
At this point, the variable $request_method contains either the string GET or POST, depending on how the program was invoked. The main difference between these two invocation methods is how arguments are passed to the program: GET sends all of the variable values in the query string, while POST sends them via stdin, the file handle associated with standard input. Luckily, CGI.pm frees us from having to deal with these methods and invisibly hands us the parameters regardless of their source.
In any event, if our program is invoked with any value in the query string, we print out an HTML form containing the contents of the quiz file with that name or a blank HTML form allowing the user to create a quiz of that name. You can see that program in Listing 1.
There are several things to note in this program. First of all, we need to tell the program the maximum number of questions that each quiz can contain. We do this by setting a global variable, $MAX_QUESTIONS, at the top of the program. Either very short or very long quizzes can be allowed for by changing this variable.
Also, notice how we manage to create a page of HTML that invokes our program with an argument in the query string. We use the <ISINDEX> tag, which has been all but forgotten on the Web, mostly because it creates an ugly text box whose instructions are difficult or impossible to change and rarely relevant to the subject at hand. Nevertheless, <ISINDEX> comes in handy if you want to provide a program with a mechanism to feed a user-defined argument to itself.
In addition, we create a new instance of QuizQuestions based on the name of the quiz that we received from the user in the query string. Once the instance of QuizQuestions is created, we instruct it to load its contents from disk. Of course, if this is a new quiz, then there is nothing to load, and this is noted in the error message returned by the loadFile method. We don't care if there was an error opening the file—if the quiz file exists, the contents are displayed in the HTML form, but if it does not exist, it is treated as a new quiz.
Of course, it is not a good idea to ignore error messages altogether. But the error messages returned by the loadFile method are fairly primitive, indicating whether the file was successfully loaded. Better error messages might distinguish between an inability to find the file in question, a quiz file that exists but cannot be read and a quiz file containing errors. But for now, this is all we've got, so we will have to live with it.
We insert the current value of each HTML form element by placing the value inside a variable. One of the nice things about Perl is that uninitialized variables default to the empty string (""). This means that if we have not set a particular question or answer, things don't crash. Rather, since we get the empty string back from the variable, we can stick the variable into the form element's value attribute, thus resetting the form element's value.
We use a bit of cleverness to indicate which element of the selection list (which is used to indicate the correct answer) should be selected by default. Here is the code:
my $letter = "";
foreach $letter
("a","b","c","d")
{
print "<option ";
print "selected " if ($letter eq $correct);
print "$letter>$letter\n";
}
print "</select>\n";
In this code, we simply iterate through all four possible correct answers, inserting the word selected inside of the <option> tag where it is appropriate.
As you can see, it is not difficult to create a program that displays the contents of a quiz file. If we want to create an editor, we need to write the second half of the program, namely the part that takes the submitted form contents and saves them to disk. Luckily, the way we have organized our HTML form makes this fairly trouble-free.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- Designing Electronics with Linux
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Dynamic DNS—an Object Lesson in Problem Solving
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- Build a Skype Server for Your Home Phone System
- Validate an E-Mail Address with PHP, the Right Way
- A Topic for Discussion - Open Source Feature-Richness?
- Why Python?
- Tech Tip: Really Simple HTTP Server with Python
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




1 hour 39 min ago
1 hour 47 min ago
4 hours 2 min ago
6 hours 32 min ago
16 hours 35 min ago
21 hours 2 min ago
1 day 37 min ago
1 day 1 hour ago
1 day 3 hours ago
1 day 3 hours ago