Form handling in Perl can be a very involved process. Below is a step-by-step for creating a simple feedback form. A visitor to your website fills this out and the information is emailed to you.

Create the web form

First we need to create a simple HTML form, to start with we'll keep the form simple by just asking for the users email address and comments. Here is our HTML form:

<html>
<head>
<title>Simple Feedback Form</title>
<style>label{display:block;}</style>
</head>
<body>

<form action="/cgi-bin/feedback_form.cgi" method="post">

<label>Email Address</label>
<input type="text" name="email_address" size="40">

<label>Your Feedback</label>
<textarea name="feedback" cols="50" rows="10"></textarea>

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

</form>

</body>
</html>

This form will send two parameters to our cgi script, email_address and feedback. Save this file as feedback_form.html and upload it to the web folder on your hosting.

Create the form script

We're going to use the CGI.pm Perl module to help make writing our cgi script easier. At the top of the script we start with the location of the perl interpretor, then we tell Perl we want to use the CGI.pm module and create a new cgi object:

#!/usr/bin/perl

use CGI;

my $cgi = new CGI;

The CGI.pm module is object-orientated, this means all of the CGI.pm functions and data are accessed through an instance of CGI.pm, in our script this instance is called $cgi.

Lets use our CGI object to retrieve the information from the form the user filled in. To access the form parameters we can use the CGI objects param function:

my $email_address = $cgi->param('email_address');
my $feedback = $cgi->param('feedback');

We store the form data in two local Perl variables, $email_address and $feedback.

Filtering user submitted data

Whenever you write a cgi script that receives data from an unknown source you should always filter the data to make sure it doesn't contain anything harmful. For example, if we don't filter the data in our form it would be quite easy for a Hacker to use our cgi script to send out spam to thousands of people. The golden rule is never trust any data you haven't created or don't control.

To filter our user data we're going to create two filter functions:

sub filter_email_header
{
  my $form_field = shift;
  $form_field = filter_form_data($form_field);
  $form_field  =~ s/[\0\n\r\|\!\/\<\>\^\$\%\*\&]+/ /g;

  return $form_field;
}

sub filter_form_data
{
  my $form_field = shift;
  $form_field  =~ s/From://gi;
  $form_field  =~ s/To://gi;
  $form_field  =~ s/BCC://gi;
  $form_field  =~ s/CC://gi;
  $form_field  =~ s/Subject://gi;
  $form_field  =~ s/Content-Type://gi;
  
  return $form_field;
}

The first filter function removes special characters which could be used to trick our script into sending spam and is applied to the $email_address data.The second filter function removes common email headers from the data the user submitted and can be applied to both $email_address and $feedback. We'll place the two functions at the bottom of our script.

Now we'll call the two filter functions to clean up our user submitted data:

$email_address  = filter_email_header($email_address);
$feedback = filter_form_data($feedback);

Emailing the feedback

Once we have the filtered data we need to email it back to you. Our web hosting servers run a local mail server (sendmail) that your cgi script can use to send email. To send the email our cgi script opens a communication channel to the sendmail program using the pipe (|) symbol. It then prints all the information necessary to send an email across that channel:

open ( MAIL, "| /usr/lib/sendmail -t" );
print MAIL "From: $email_address\n";
print MAIL "To: you\@domain.com\n";
print MAIL "Subject: Feedback Form Submission\n\n";
print MAIL "$feedback\n";
print MAIL "\n.\n";
close ( MAIL );

Make sure you set your email address on line 3, you'll need to escape the @ symbol by putting a backslash (\) before it because Perl uses the @ symbol to denote a special type of variable. The two newline characters (\n\n) at the end of line 4 are used to mark the end of the email headers ready for the content. The \n.\n on line 6 prints a dot (.) on its own line to tell sendmail that we've finished printing the message.

Thank the user for their feedback

Finally, when a user submits your form, let's show a page thanking them for their feedback:

print $cgi->header(-type => 'text/html');

print <<HTML_PAGE;
 <html>
<head>
<title>Thank You</title>
</head>
<body>
<h1>Thank You</h1>
<p>Thank you for your feedback.</p>
</body>
</html>
HTML_PAGE

The first thing we do is print back the HTTP header, using the CGI header function, to let the web browser know what type of content to expect. Then we print out the HTML page.

The final script

This example script shows a very basic way to get form contents emailed to you, it doesn't however have the refinements of a professional script, e.g. input validation. Below is the finished script. We've added some comments (lines beginning with #) to help make it clearer.

#!/usr/bin/perl

use CGI;

# Create a CGI.pm object
my $cgi = new CGI;

# Get the form data 
my $email_address = $cgi->param('email_address');
my $feedback = $cgi->param('feedback');

# Filter the form data
$email_address  = filter_email_header($email_address);
$feedback = filter_form_data($feedback);

# Email the form data
open ( MAIL, "| /usr/lib/sendmail -t" );
print MAIL "From: $email_address\n";
print MAIL "To: you\@domain.com\n";
print MAIL "Subject: Feedback Form Submission\n\n";
print MAIL "$feedback\n";
print MAIL "\n.\n";
close ( MAIL );

# Print the HTTP header
print $cgi->header(-type => 'text/html');

# Print the HTML thank you page
print <<HTML_PAGE;
 <html>
<head>
<title>Thank You</title>
</head>
<body>
<h1>Thank You</h1>
<p>Thank you for your feedback.</p>
</body>
</html>
HTML_PAGE

# Functions to filter the form data

sub filter_email_header
{
  my $form_field = shift;
  $form_field = filter_form_data($form_field);
  $form_field  =~ s/[\0\n\r\|\!\/\<\>\^\$\%\*\&]+/ /g;

  return $form_field ;
}

sub filter_form_data
{
  my $form_field = shift;
  $form_field  =~ s/From://gi;
  $form_field  =~ s/To://gi;
  $form_field  =~ s/BCC://gi;
  $form_field  =~ s/CC://gi;
  $form_field  =~ s/Subject://gi;
  $form_field  =~ s/Content-Type://gi;
  
  return $form_field ;
}

Save this script as feedback_form.cgi and upload it to the cgi-bin on your web hosting. Make sure you set the file permissions for the script to 755. Follow our How to change file permissions via FTP guide for instructions on how to do this.

Now you're ready to test your feedback form. Load your feedback form in your browser, http://www.domain.com/feedback_form.html, fill the form in and submit it. If everything works you should receive an email containing what you just entered in the form. If not, try checking out our Troubleshooting common Perl issues guide.

Need a hand? Search over a hundred step-by-step support guides