Perl CGI Programming
Perl - CGI Programming (Historical Context & Modern Alternatives)
Section titled “Perl - CGI Programming (Historical Context & Modern Alternatives)”Important Note: CGI (Common Gateway Interface) is an older technology for web application development. While Perl was a dominant language for CGI scripting, modern Perl web development predominantly uses frameworks like Mojolicious, Dancer2, or Catalyst, which are built on the PSGI/Plack standard. These frameworks offer better performance, scalability, security, and development practices. This chapter covers CGI for historical understanding or very simple use cases.
What is CGI?
Section titled “What is CGI?”- CGI is a standard protocol that defines how web servers execute external programs (CGI scripts) to generate dynamic web content.
- When a web server receives a request for a CGI script, it executes the script and passes its output back to the client’s browser.
Web Browsing and CGI
Section titled “Web Browsing and CGI”Normally, when you request a static file (e.g., an HTML page or image):
- Your browser sends an HTTP request to the web server.
- The web server locates the file and sends its content back in an HTTP response.
- The browser displays the content.
With CGI:
- The browser requests a URL pointing to a CGI script.
- The web server recognizes it as a CGI script, executes it, and passes client information (like form data) to the script (often via environment variables and standard input).
- The CGI script processes the information and generates an HTTP response (headers and content, usually HTML) by printing to its standard output.
- The web server captures this output and sends it back to the browser.
Web Server Configuration for CGI
Section titled “Web Server Configuration for CGI”To run CGI scripts, your web server (e.g., Apache, Nginx) must be configured to support CGI. This usually involves:
- Designating a specific directory (often
/cgi-bin/or similar) where CGI scripts are stored. - Ensuring Perl scripts in this directory have execute permissions (e.g.,
chmod 755 script.cgi). - Configuring the server to treat files with a certain extension (e.g.,
.cgi,.pl) in that directory as executable CGI programs.
First CGI Program (using CGI.pm)
Section titled “First CGI Program (using CGI.pm)”The CGI.pm module simplifies many common CGI tasks, such as parsing input and generating HTML. While it was once a core module, it’s now typically installed from CPAN.
#!/usr/bin/perluse strict;use warnings;use CGI;
my $q = CGI->new; # Create a new CGI object
# Print the HTTP headerprint $q->header('text/html');
# Print the HTML contentprint $q->start_html('Hello World - First CGI Program');print $q->h1('Hello World! This is my first CGI program using CGI.pm');print $q->end_html;If this script (hello.cgi) is placed in a configured cgi-bin directory and accessed via a browser, it would output an HTML page with the ‘Hello World’ message.
HTTP Headers
Section titled “HTTP Headers”A CGI script must first output HTTP headers, followed by a blank line, then the actual content. The most important header is Content-Type, which tells the browser what kind of data to expect (e.g., text/html, application/json).
Manually printing headers (without CGI.pm):print "Content-Type: text/html\n\n"; # Note the double newlineCommon HTTP Headers for CGI:
| Header | Description |
|---|---|
Content-Type: type/subtype | MIME type of the content (e.g., text/html, image/png, application/json). |
Location: URL | Redirects the browser to a different URL (used with a 3xx status code). |
Set-Cookie: name=value; attributes | Sends a cookie to the browser. |
Content-Disposition: attachment; filename="file.ext" | Prompts the browser to download the content as a file. |
CGI Environment Variables
Section titled “CGI Environment Variables”The web server passes information to the CGI script via environment variables. CGI.pm often abstracts access to these, but understanding them is useful.
| Variable Name | Description |
|---|---|
REQUEST_METHOD | The HTTP method used (e.g., GET, POST). |
QUERY_STRING | URL-encoded data sent with a GET request (after the ?). |
CONTENT_LENGTH | Length of data sent with a POST request (read from STDIN). |
CONTENT_TYPE | MIME type of data sent with a POST request (e.g., application/x-www-form-urlencoded). |
REMOTE_ADDR | IP address of the client. |
HTTP_USER_AGENT | Browser/client identification string. |
SCRIPT_NAME | Path to the CGI script. |
SERVER_NAME | Hostname of the server. |
Example: Displaying Environment Variables (using CGI.pm)
#!/usr/bin/perluse strict;use warnings;use CGI;
my $q = CGI->new;
print $q->header('text/html');print $q->start_html('CGI Environment Variables');print $q->h1('CGI Environment Variables');
print $q->start_table({-border => 1});print $q->Tr($q->th(['Variable', 'Value']));
foreach my $key (sort keys %ENV) { print $q->Tr($q->td([$key, $ENV{$key}]));}print $q->end_table;print $q->end_html;GET and POST Methods
Section titled “GET and POST Methods”Browsers send data to web servers (and thus to CGI scripts) primarily using GET or POST methods.
GET Method
Section titled “GET Method”Data is appended to the URL as a query string (e.g., script.cgi?name=Alice&age=30). Accessible via $ENV{QUERY_STRING} or more easily with $q->param('name') using CGI.pm. Suitable for small amounts of non-sensitive data. Limited by URL length.
POST Method
Section titled “POST Method”Data is sent in the body of the HTTP request. Raw POST data is read from STDIN, with length given by $ENV{CONTENT_LENGTH}. CGI.pm handles this parsing transparently via $q->param('name'). Suitable for larger amounts of data or sensitive information.
Handling Form Data with CGI.pm
Section titled “Handling Form Data with CGI.pm”CGI.pm makes form handling easy, regardless of whether GET or POST is used.
HTML Form Example:
<form action="/cgi-bin/submit_form.cgi" method="POST"> First Name: <input type="text" name="first_name"><br> Last Name: <input type="text" name="last_name"><br> <input type="submit" value="Submit"></form>Perl CGI Script (submit_form.cgi):
#!/usr/bin/perluse strict;use warnings;use CGI;
my $q = CGI->new;
# Get form parametersmy $first_name = $q->param('first_name');my $last_name = $q->param('last_name');
print $q->header('text/html');print $q->start_html('Form Submission Result');print $q->h1('Submission Received');
if ($first_name && $last_name) { print $q->p("Hello, " . $q->escapeHTML($first_name) . " " . $q->escapeHTML($last_name) . "!");} else { print $q->p("Please provide both first and last names.");}
print $q->end_html;Note: escapeHTML() is crucial to prevent Cross-Site Scripting (XSS) vulnerabilities when displaying user-supplied data.
Handling Checkboxes, Radio Buttons, Textareas, Dropdowns
Section titled “Handling Checkboxes, Radio Buttons, Textareas, Dropdowns”CGI.pm’s param() method handles these input types correctly:
- Single value fields (text, radio, textarea, single-select dropdown):
$q->param('fieldname')returns a single value. - Multi-value fields (checkboxes with same name, multiple-select dropdown): In list context,
my @values = $q->param('fieldname')returns all selected values. In scalar context, it usually returns the first selected value.
Example (checkboxes):
HTML:<input type="checkbox" name="interests" value="music"> Music<input type="checkbox" name="interests" value="sports"> Sports
Perl:my @interests = $q->param('interests');if (@interests) { print $q->p("Your interests: " . $q->escapeHTML(join(', ', @interests)));} else { print $q->p("You selected no interests.");}Using Cookies in CGI
Section titled “Using Cookies in CGI”Cookies are small pieces of data stored by the browser, sent back to the server with subsequent requests. CGI.pm provides methods for setting and retrieving cookies.
Setting a Cookie:
#!/usr/bin/perluse strict;use warnings;use CGI;
my $q = CGI->new;
# Create a cookiemy $cookie = $q->cookie( -name => 'UserID', -value => 'XYZ123', -expires => '+30d', # Expires in 30 days -path => '/');
# Print header with the cookieprint $q->header(-cookie => $cookie, -type => 'text/html');print $q->start_html('Cookie Set');print $q->p('UserID cookie has been set.');print $q->end_html;Retrieving a Cookie:
#!/usr/bin/perluse strict;use warnings;use CGI;
my $q = CGI->new;
my $user_id = $q->cookie('UserID'); # Retrieve the cookie value
print $q->header('text/html');print $q->start_html('Cookie Retrieved');if (defined $user_id) { print $q->p("Retrieved UserID: " . $q->escapeHTML($user_id));} else { print $q->p('UserID cookie not found.');}print $q->end_html;File Uploads
Section titled “File Uploads”CGI.pm can also handle file uploads from forms with enctype="multipart/form-data".
HTML for file upload:<form method="POST" action="/cgi-bin/upload.cgi" enctype="multipart/form-data"> File: <input type="file" name="uploaded_file"> <input type="submit" value="Upload"></form>
Perl (`upload.cgi`):my $filename = $q->param('uploaded_file');if ($filename) { my $fh = $q->upload('uploaded_file'); # Filehandle to the uploaded temp file if ($fh) { # Process the file, e.g., save it # open(my $out_fh, '>', "/path/to/save/$filename") or die "Cannot save file: $!"; # binmode $out_fh; # while (my $bytes_read = read($fh, my $buffer, 4096)) { # print $out_fh $buffer; # } # close $out_fh; print $q->p("File '$filename' uploaded successfully (in theory)."); } else { print $q->p("Error getting upload handle for '$filename'."); }} else { print $q->p("No file was uploaded.");}Security Considerations
Section titled “Security Considerations”When writing CGI scripts (or any web application):
- Validate all input: Never trust data from the client.
- Escape output: Use functions like
CGI::escapeHTMLto prevent XSS when displaying user data. - Prevent SQL Injection: Use placeholders with DBI if interacting with databases.
- Taint Mode: Run Perl scripts with the
-Tflag (#!/usr/bin/perl -T) to enable taint checking, which helps identify insecure data flows. - Limit Permissions: Ensure CGI scripts run with minimal necessary permissions.
As mentioned, for new projects, using modern Perl web frameworks (Mojolicious, Dancer2, Catalyst) is strongly recommended over raw CGI scripting for better security, maintainability, and performance.