Simon & Matt's new Photoshop book is out now!

Photoshop CS3 Layers Bible book cover

Sharpen your Photoshop skills today!

PageKits.com Featured PageKits

Skin Deep (Blue) PageKit
Skin Deep (Blue) ($14.99)


Splash PageKit
Splash ($39.99)


See more! > >

 

How-To: Form validation with Perl and CGI

Level: Intermediate. Published on 12 June 2003 in Perl and CGI scripting

The most reliable way to make sure your users haven't filled in your forms wrongly is to use server-side form validation. This tutorial shows how you can do this with Perl and the CGI, and introduces the concept of subroutines along the way.

In this tutorial we're going to write a CGI script that checks whether a form has been filled out correctly. Along the way, you'll also learn about the concepts of reentrant forms and Perl subroutines. Read on!

Why use form validation?

Form validation prevents visitors to your site from accidentally sending you forms with missing or incorrect data. This can save you (and them) a lot of time and trouble!

It's possible to do form validation using JavaScript (see our Form validation with JavaScript how-to). JavaScript validation is nice and quick because there's no round-trip to the server; however Perl validation is more secure and reliable, because it will always work even if the browser has JavaScript disabled, or if the user has managed to "hack" the JavaScript validation.

Reentrant forms

If you've followed our Writing a simple form mailer how-to, you'll know how to write a simple Perl form handler that uses a static HTML page to display the form. In this tutorial, we're going to go one step better, and create our HTML form using the Perl script itself!

By doing this, we can re-display the form, along with any data entered by the user and an error message, if the user fills in the form incorrectly. This makes the form handling nice and friendly for the visitor.

This technique is often referred to as creating a reentrant form.

The form display subroutine

In order to create our reentrant form, we're going to write a subroutine to display the form.

Subroutines, like functions in JavaScript, give you an easy way to run a common function more than once in your script. Once you place your code within a subroutine block, you can run that code as often as you like, from anywhere in the script. What's more, you can pass parameters into the subroutine, and make it do different things depending on those parameters.

In our example, we're going to create a subroutine that displays the HTML form. We'll be calling this subroutine in two ways: firstly, when the blank form is first displayed to the visitor; and secondly, when we need to redisplay the form (including the visitor's data and any error message) in the event of the user sending us an incorrect form.

To do this, we need to pass any form field values that the user has sent us, and the error message, into the subroutine.

Our form will contain the following fields:

  • "Your Name" (text box)
  • "Your Sex" (radio button)
  • "Your Age" (drop-down list)

Here is our form display subroutine in full:


sub display_form
{
    my $error_message = shift;
    my $your_name = shift;
    my $your_sex = shift;
    my $your_age = shift;

    # Remove any potentially malicious HTML tags
    $your_name =~ s/<([^>]|\n)*>//g;

    # Build "selected" HTML for the "Your Sex" radio buttons
    my $your_sex_f_sel = $your_sex eq "f" ? " checked" : "";
    my $your_sex_m_sel = $your_sex eq "m" ? " checked" : "";

    # Build "selected" HTML for the "Your Age" drop-down list
    my $your_age_html = "";
    my @your_age_opts = ("Please select","Under 18","18-35","35-55","Over 55");

    foreach my $your_age_option ( @your_age_opts )
    {
        $your_age_html .= "<option value=\"$your_age_option\"";
        $your_age_html .= " selected" if ( $your_age_option eq $your_age );
        $your_age_html .= ">$your_age_option</option>";
    }

    # Display the form
    print <<END_HTML;
    <html>
    <head><title>Form Validation</title></head>
    <body>

    <form action="form_validation.cgi" method="post">
    <input type="hidden" name="submit" value="Submit">

    <p>$error_message</p>

    <p>Your Name:<br>
    <input type="text" name="your_name" value="$your_name">
    </p>

    <p>Your Sex:<br>
    <input type="radio" name="your_sex" value="f"$your_sex_f_sel>Female
    <input type="radio" name="your_sex" value="m"$your_sex_m_sel>Male
    </p>

    <p>Your Age:<br>
    <select name="your_age">$your_age_html</select>
    </p>

    <input type="submit" name="submit" value="Submit">

    </form>

    </body></html>
END_HTML

}

The first four lines use Perl's shift function to retrieve the parameters passed into it (if any). We then dynamically create and display the HTML for the form, pre-filling the form fields with any values that the user has already entered (passed via the parameters). The subroutine will also display any error message (again, passed as a parameter) at the top of the form.

Note that we're using a regular expression to filter the $your_name variable and remove any HTML tags before we display it in our form. This is a good idea as it will limit the risk of form hacking and cross-site-scripting attacks.

When writing real-world Web applications and scripts, always filter any data that the script receives from an untrusted source. This includes any data from form posts, GET variables in query strings, uploaded files and anything else that might have been created by someone, or something, you don't control.

The form contains a submit button called submit - our script can later use this field to determine if the form has been submitted yet or not. For backup, the same field is defined as a hidden field, in case the user just presses the Enter key rather than clicking on the "Submit" button.

The form validation subroutine

We'll now write the subroutine that checks the form fields entered by the user. If all the fields have been filled in correctly, we will return a success value (in this case, 1). If any fields are missing, we will call our reentrant form display subroutine above, passing in any fields that the user has entered, along with the error message, as parameters to the subroutine. We then return a failure value of 0.


sub validate_form
{
    my $your_name = $query->param("your_name");
    my $your_sex = $query->param("your_sex");
    my $your_age = $query->param("your_age");

    my $error_message = "";

    $error_message .= "Please enter your name<br/>" if ( !$your_name );
    $error_message .= "Please specify your sex<br/>" if ( !$your_sex );
    $error_message .= "Please specify your age<br/>" if
    ( $your_age eq "Please select" );

    if ( $error_message )
    {
        # Errors with the form - redisplay it and return failure
        display_form ( $error_message, $your_name, $your_sex, $your_age );
        return 0;
    }
    else
    {
        # Form OK - return success
        return 1;
    }
}

We've used Perl's string concatenation operator (.=) to append any error messages to the $error_message string. We can then test this string at the end of our checks to determine if it's empty or not. If it isn't empty, then we know there were errors, and we can redisplay the pre-filled form along with the error message, and return the failure code.

We can test if a form field is empty (i.e. the user hasn't entered anything) by using the not (!) operator. This returns a true value if the tested variable is empty. For example:


    $error_message .= "Please enter your name</br>" if ( !$your_name );

Putting it all together

We'll now write the rest of the script, including the decision-making logic. Here it is:


#!/usr/bin/perl

use CGI;

# Create the CGI object
my $query = new CGI;

# Output the HTTP header
print $query->header ( );

# Process form if submitted; otherwise display it
if ( $query->param("submit") )
{
    process_form ( );
}
else
{
    display_form ( );
}

sub process_form
{
    if ( validate_form ( ) )
    {
        print <<END_HTML;
        <html><head><title>Thank You</title></head>
        <body>
        Thank you - your form was submitted correctly!
        </body></html>
END_HTML
    }
}

This code just initialises the CGI query object, displays the HTTP header, and then calls either the process_form() subroutine or the display_form() subroutine, depending on whether the form has been submitted or not. (We test the value of the form field submit to determine if the form has been submitted - if the field is non-empty then the test returns true.)

The process_form() subroutine calls validate_form(), then simply displays a thank-you message if the form was filled in correctly. In a "real-world" application you would do all your actual form processing here (sending an email, adding a record to a database table, etc).

The finished script

You can view the whole script here, and see the script in action here. Try submitting the form without filling in all the fields, and see the results!

The end

That's the end of this article. We hope you found it useful. If you're still stuck and would like further help, check out our online Help Forums, where you can get assistance from members of Elated and other webmasters.

Also, don't forget the free ELATED Extra Newsletter, where you can get more great Web-building articles and tips sent straight to your inbox!

If you would like to offer us feedback on this or any of our articles, please contact us. Have fun!

Top of Page

Get our free newsletter!

  • Improve your Web skills
  • Exclusive tips and tricks
  • Free bonus Web template

Sign up now!

We won't give or sell your email address to anyone, and you can unsubscribe at any time. Privacy statement