Home » Tutorials » Cgi form |
In this tutorial you will learn how to write a Perl CGI form. If you have never done any Perl CGI programming before, we suggest you first look at the CGI Tutorial.
Firstly you need to ensure that you have access to a web server (that has Perl installed), that it has cgi enabled, and that you can put your Perl script into the cgi directory.
Like a standard Perl CGI script we use the CGI module to output the HTML:
#!/usr/bin/perl use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); my $q = new CGI; print $q->header; print $q->start_html(-title => 'A web form');
To begin a form, you can use the start_form method:
print $q->start_form;
Without any parameters, the HTML output is:
<form method="post" action="/cgi-bin/yourprogram.pl" enctype="application/x-www-form-urlencoded">
Using start_form, you can pass in parameters to define the form's properties and behaviour:
print $q->start_form( -name => 'main_form', -method => 'GET', -enctype => &CGI::URL_ENCODED, -onsubmit => 'return javascript:validation_function()', -action => '/where/your/form/gets/sent', # Defaults to # the current program );
The above code would produce the following HTML:
<form method="get" action="/where/your/form/gets/sent" enctype="application/x-www-form-urlencoded" onsubmit="return javascript:validation_function()" name="main_form">
When you end the form, you can use the end_form method:
print $q->end_form;
Form field methods are very similar to the standard html tag methods, but tend to require more parameters. The CGI module provides interfaces to more form fields than these, but these are the most common.
Text:
print $q->textfield( -name => 'text1', -value => 'default value', -size => 20, -maxlength => 30, );
You can add other parameters that would normally appear in a text field definition (with a '-' in front), such as -onchange, or -class. The above code produces HTML as follows:
<input type="text" name="text1" value="default value" size="20" maxlength="30" />
Textarea:
print $q->textarea( -name => 'textarea1', -value => 'default value', -cols => 60, -rows => 3, );
This produces the following HTML:
<textarea name="textarea1" rows="3" cols="60">default value </textarea>
Hidden:
Hidden fields are very useful in web forms:
print $q->hidden( -name => 'hidden1', -default => 'some value', );
This produces the following HTML:
<input type="hidden" name="hidden1" value="some value" />
Select:
Select lists are a little more complicated.
To create a simple select list, where all the values are the same as the displayed text, you can do the following:
my @values = ('value1', 'value2', 'value3'); print $q->popup_menu( -name => 'popup1', -values => \@values, -default => 'value2' );
This produces the following HTML:
<select name="popup1"> <option value="value1">value1</option> <option selected="selected" value="value2">value2</option> <option value="value3">value3</option> </select>
Or, if the select list is more complex, for example if the displayed text is to be different to the option values, or if you want to add attributes to the options:
my @values = ('value1', 'value2', 'value3'); my %labels = ( 'value1' => 'Choice 1', 'value2' => 'Choice 2', 'value3' => 'Choice 3', ); print $q->popup_menu( -name => 'popup1', -values => \@values, -default => 'value2', -labels => \%labels, -attributes => { 'value1' => { 'style' => 'color: red' } }, );
The HTML this produces is:
<select name="popup1"> <option style="color: red" value="value1">Choice 1</option> <option selected="selected" value="value2">Choice 2</option> <option value="value3">Choice 3</option> </select>
Or if you want to do the same, but only have one data structure storing the data (instead of both the @values array and the %labels hash):
my %labels = ( 'value1' => 'Choice 1', 'value2' => 'Choice 2', 'value3' => 'Choice 3', ); print $q->popup_menu( -name => 'popup1', -values => [keys %labels], -default => 'value2', -labels => \%labels, -attributes => {'value1' => {'style' => 'color: red'}}, );
Checkbox:
The following code will create a single checkbox field:
print $q->checkbox( -name => 'check2', -checked => 1, -value => 'two', -label => 'The number two', );
This produces the following HTML:
<input type="checkbox" name="check2" value="two" checked="checked" />The number two
The next code will create a group of checkboxes of the same name:
print $q->checkbox_group( -name => 'check1', -values => ['one', 'two', 'three', 'four'], -defaults => ['one', 'two'], -columns => 2, -rows => 2, );
You can affect the layout of the checkboxes by modifying the values of -columns and -rows.
The above code results in the following HTML:
<table> <tr> <td><input type="checkbox" name="check1" value="one" checked="checked" />one</td> <td><input type="checkbox" name="check1" value="three" />three</td> </tr> <tr> <td><input type="checkbox" name="check1" value="two" checked="checked" />two</td> <td><input type="checkbox" name="check1" value="four" />four</td> </tr> </table>
The table is the result of the -columns and -rows parameters.
Radio:
A radio button group is exactly the same as a checkbox group, except that there can only be one default value:
print $q->radio_group( -name => 'radio1', -values => ['one', 'two', 'three', 'four'], -default => 'one', -columns => 2, -rows => 2, );
The results in:
<table> <tr> <td><input type="radio" name="radio1" value="one" checked="checked" />one</td> <td><input type="radio" name="radio1" value="three" />three</td> </tr> <tr> <td><input type="radio" name="radio1" value="two" />two</td> <td><input type="radio" name="radio1" value="four" />four</td> </tr> </table>
Single radio buttons don't make much sense in a web form, so they are not addressed by the CGI module.
Submit:
A submit button is used to submit your data to the URL provided in the 'action' property of the form. Often in cgi scripts you leave the 'action' property blank, so that the form is submitted back to the same program. This means that you only have one file to maintain for a form.
You can output a submit button like this:
print $q->submit( -name => 'submit_form', -value => 'Click here!', -onsubmit => 'javascript: validate_form()', );
Button:
A standard button is very similar:
print $q->button( -name => 'submit_form', -value => 'Click here!', -onsubmit => 'javascript: validate_form()', );
Except that it will not submit the form (unless the javascript function does that).
When the form is submitted, the web server will run the CGI program specified in the ACTION parameter (or the same program if none is specified). This time, however, the CGI object has the values for all the form fields (or parameters specified in the URL).
You can access these values with the param() method:
my $text1_value = $q->param('text1');
Most fields return scalar values (e.g. a text field returns a single string), but some (for example, checkbox groups) can return many values. You can access these in the same way:
my @checked_boxes = $q->param('check1');
Or you can get all the parameters in a hash by using the Vars method:
my $all_params = $q->Vars; foreach my $param (keys %$all_params) { print "$param: " . $all_params->{$param} . "<BR>"; }
If you need all the parameter names, use the param method in array context:
my @param_names = $q->param();
To help you design your programs into nice readable web forms, we suggest the following architecture (pseudo code):
1. print http header # $q->header 2. print html_header_method # To make your pages look the same 3a. if there are no parameters output the form 3b. else if there is a key parameter # You may include a handle the results of the form # hidden 'mode' field # to make this easier 4. print end_html_method # May include a standard footer
Of course, you could make your program output many different forms and pages by adding more conditions:
1. print http header 2. print html_header_method 3a. if there are no parameters output the first form 3b. else if there is a key parameter (e.g. if ($q->param('mode') eq 'first_page') handle the results of the first form output the second form 3c. else if there is a key parameter (e.g. if ($q->param('mode') eq 'second_page') handle the results of the second form output the third form 3d. else if there is a key parameter (e.g. if ($q->param('mode') eq 'third_page') handle the results of the third form 4. print end_html_method # May include a standard footer
The following is an example of a questionnaire. The user fills in the form and submits it. The results are then displayed on the screen. Realistically, the results would probably be written to a database (using the DBI module, for example).
#!/usr/bin/perl use strict; use warnings; use CGI; use CGI::Carp qw(fatalsToBrowser); # Remove this in production my $q = new CGI; print $q->header(); # Output stylesheet, heading etc output_top($q); if ($q->param()) { # Parameters are defined, therefore the form has been submitted display_results($q); } else { # We're here for the first time, display the form output_form($q); } # Output footer and end html output_end($q); exit 0; #------------------------------------------------------------- # Outputs the start html tag, stylesheet and heading sub output_top { my ($q) = @_; print $q->start_html( -title => 'A Questionaire', -bgcolor => 'white', -style => { -code => ' /* Stylesheet code */ body { font-family: verdana, sans-serif; } h2 { color: darkblue; border-bottom: 1pt solid; width: 100%; } div { text-align: right; color: steelblue; border-top: darkblue 1pt solid; margin-top: 4pt; } th { text-align: right; padding: 2pt; vertical-align: top; } td { padding: 2pt; vertical-align: top; } /* End Stylesheet code */ ', }, ); print $q->h2("A Questionaire"); } # Outputs a footer line and end html tags sub output_end { my ($q) = @_; print $q->div("My Web Form"); print $q->end_html; } # Displays the results of the form sub display_results { my ($q) = @_; my $username = $q->param('user_name'); my $userage = $q->param('age'); my $usergender = $q->param('gender'); my @favourite_languages = sort $q->param('language'); my %sex = ('F' => 'girl', 'M' => 'boy'); print $q->h4("Hi $username"); print $q->p("You are a $sex{$usergender}, and you are $userage years old."); print $q->p("Your favourite languages are:"); print $q->table( {-border => 1, -cellpadding => 3}, $q->Tr($q->td(\@favourite_languages)), ); } # Outputs a web form sub output_form { my ($q) = @_; print $q->start_form( -name => 'main', -method => 'POST', ); print $q->start_table; print $q->Tr( $q->td('Name:'), $q->td( $q->textfield(-name => "user_name", -size => 50) ) ); print $q->Tr( $q->td('Age:'), $q->td( $q->radio_group( -name => 'age', -values => [ '0-12', '13-18', '18-30', '30-40', '40-50', '50-60', '60-70', '70+' ], -rows => 4, ) ) ); my %genders = ('F' => 'Female', 'M' => 'Male'); print $q->Tr( $q->td('Gender:'), $q->td( $q->popup_menu( -name => 'gender', -values => [keys %genders], -labels => \%genders, ) ) ); print $q->Tr( $q->td('Favourite Languages:'), $q->td( $q->checkbox_group( -name => 'language', -values => ['Perl', 'C', 'C++', 'C#', 'Java', 'VB', 'Python', 'Delphi'], -defaults => ['Perl'], -columns => 2, ) ) ); print $q->Tr( $q->td($q->submit(-value => 'Submit')), $q->td(' ') ); print $q->end_table; print $q->end_form; }
perldoc CGI