Perl CGI Programming


What is CGI

CGI is currently maintained by NCSA. NCSA defines CGI as follows:

CGI (Common Gateway Interface), the general gateway interface, is a program that runs on a server such as an HTTP server and provides an interface to client HTML pages.


Web Browsing

To better understand how CGI works, we can start from the process of clicking a link or URL on a web page:

  • 1. Use your browser to access the URL and connect to the HTTP web server.
  • 2. After receiving the request, the web server parses the URL and checks whether the requested file exists on the server. If it exists, it returns the content of the file; otherwise, it returns an error message.
  • 3. The browser receives the information from the server and displays the received file or the error message.

CGI programs can be Python scripts, Perl scripts, Shell scripts, C or C++ programs, etc.


CGI Architecture Diagram

cgiarch


Web Server Support and Configuration

Before you start CGI programming, make sure your web server supports CGI and has the CGI handler configured.

Apache CGI Configuration:

Set up the CGI directory:

ScriptAlias /cgi-bin/ /var/www/cgi-bin/

All CGI programs executed by HTTP servers are stored in a preconfigured directory. This directory is called the CGI directory, and by convention it is named /var/www/cgi-bin.

CGI files have the extension .cgi. Perl can also use the .pl extension.

By default, Linux servers are configured with /var/www as the cgi-bin directory for running CGI scripts.

If you want to specify another directory for running CGI scripts, you can modify the httpd.conf configuration file as follows:

<Directory "/var/www/cgi-bin">
   AllowOverride None
   Options +ExecCGI
   Order allow,deny
   Allow from all
</Directory>

Add the .pl suffix to AddHandler so that we can access Perl script files ending with .pl:

AddHandler cgi-script .cgi .pl .py

First CGI Program

Below we create a test.cgi file with the following code:

test.cgi Code

#!/usr/bin/perl print "Content-type:text/html\r\n\r\n"; print '<html>'; print '<head>'; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print '</head>'; print '<body>'; print '<h2>Hello Word! </h2>'; print '<p>This is the first CGI program from Example Tutorial.</p>'; print '</body>'; print '</html>'; 1;

Then open http://localhost/cgi-bin/test.cgi in a browser, and the output is as follows:

The output 'Content-type:text/html\r\n\r\n' on the first line of the script is sent to the browser to inform the browser that the content type to display is 'text/html'.


HTTP Header

The 'Content-type:text/html' in the test.cgi file content is part of the HTTP header. It is sent to the browser to tell it the content type of the file.

The format of the HTTP header is as follows:

HTTP 字段名: 字段内容

For example:

Content-type:text/html\r\n\r\n

The following table describes the information frequently used in HTTP headers in CGI programs:

headDescription
Content-type: MIME information corresponding to the requested entity. For example: Content-type:text/html
Expires: Date The date and time at which the response expires
Location: URL Used to redirect the receiver to a location other than the requested URL to complete the request or identify a new resource
Last-modified: DateThe last modification time of the requested resource
Content-length: NThe content length of the request
Set-Cookie: String Set HTTP Cookie

CGI Environment Variables

All CGI programs receive the following environment variables, which play an important role in CGI programs:

Variable NameDescription
CONTENT_TYPEThe value of this environment variable indicates the MIME type of the transmitted information. Currently, the environment variable CONTENT_TYPE is generally: application/x-www-form-urlencoded, which indicates that the data comes from an HTML form.
CONTENT_LENGTHIf the transfer method between the server and the CGI program is POST, this environment variable is the number of valid data bytes that can be read from standard input STDIN. This environment variable must be used when reading the input data.
HTTP_COOKIEThe COOKIE content in the client.
HTTP_USER_AGENTProvides client browser information containing version numbers or other proprietary data.
PATH_INFOThe value of this environment variable represents other path information immediately following the CGI program name. It often appears as a parameter to the CGI program.
QUERY_STRINGIf the transfer method between the server and the CGI program is GET, the value of this environment variable is the transferred information. This information follows the CGI program name, separated by a question mark '?'.
REMOTE_ADDRThe value of this environment variable is the IP address of the client making the request, for example 192.168.1.67 above. This value is always present. It is also the unique identifier that a web client must provide to the web server, and it can be used in CGI programs to distinguish different web clients.
REMOTE_HOSTThe value of this environment variable contains the hostname of the client that sent the CGI request. If the server does not support the lookup you want, this environment variable need not be defined.
REQUEST_METHODProvides the method by which the script was called. For scripts using the HTTP/1.0 protocol, only GET and POST are meaningful.
SCRIPT_FILENAMEThe full path to the CGI script
SCRIPT_NAMEThe name of the CGI script
SERVER_NAMEThis is the hostname, alias, or IP address of your web server.
SERVER_SOFTWAREThe value of this environment variable contains the name and version number of the HTTP server that invoked the CGI program. For example, the value above is Apache/2.2.14(Unix).

The following is a simple CGI script that outputs CGI environment variables:

Example

#!/usr/bin/perl print "Content-type: text/html\n\n"; print '<meta charset="utf-8">'; print "<font size=+1>Environment variables:</font>\n"; foreach (sort keys %ENV) { print "<b>$_</b>: $ENV{$_}<br>\n"; } 1;

File Download

If we want to implement file download through Perl CGI, we need to set different header information, as follows:

Example

#!/usr/bin/perl # HTTP Header print "Content-Type:application/octet-stream; name=\"FileName\"\r\n"; print "Content-Disposition: attachment; filename=\"FileName\"\r\n\n"; # Actual File Content will go hear. open( FILE, "<FileName" ); while(read(FILE, $buffer, 100) ) { print("$buffer"); }

Using GET Method to Transfer Data

The GET method sends encoded user information to the server. The data is included in the URL of the requested page, separated by a '?' sign, as shown below:

http://www.test.com/cgi-bin/test.cgi?key1=value1&key2=value2
Some other notes about GET requests:
  • GET requests can be cached
  • GET requests remain in the browser history
  • GET requests can be bookmarked
  • GET requests should not be used when processing sensitive data
  • GET requests have a length limit
  • GET requests should only be used to retrieve data

Simple URL Example: GET Method

The following is a simple URL that sends two parameters to the test.cgi program using the GET method:

/cgi-bin/test.cgi?name=Example&url=http://www.example.com

The following is the code for the test.cgi file:

Example

#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read text information $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "GET") { $buffer = $ENV{'QUERY_STRING'}; } # Read name/value pair information @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $name = $FORM{name}; $url = $FORM{url}; print "Content-type:text/html\r\n\r\n"; print "<html>"; print "<head>"; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print "</head>"; print "<body>"; print "<h2>$nameURL:$url</h2>"; print "</body>"; print "</html>"; 1;

View in the browser, the output is as follows:

Simple Form Example: GET Method

The following is an HTML form that uses the GET method to send two data items to the server. The submitted server script is also the test.cgi file. The test.html code is as follows:

test.html File Code

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example Tutorial (example.com)</title> </head> <body> <form action="/cgi-bin/test.cgi" method="get">Site name:<input type="text" name="name"> <br />Site URL:<input type="text" name="url" /> <input type="submit" value="Submit" /> </form> </body> </html>

In the browser, the execution effect is as follows:


Using POST Method to Pass Data

Using the POST method to pass data to the server is safer and more reliable. Sensitive information such as user passwords needs to be transmitted using POST.

The following is also test.cgi; it can also handle POST form data submitted by the browser:

test.cgi Code

#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read text information $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Read name/value pair information @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $name = $FORM{name}; $url = $FORM{url}; print "Content-type:text/html\r\n\r\n"; print "<html>"; print "<head>"; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print "</head>"; print "<body>"; print "<h2>$nameURL:$url</h2>"; print "</body>"; print "</html>"; 1;

The following is an HTML form that uses the GET method to send two data items to the server. The submitted server script is also the test.cgi file. The test.html code is as follows:

test.html Code

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example Tutorial (example.com)</title> </head> <body> <form action="/cgi-bin/test.cgi" method="post">Site name:<input type="text" name="name"> <br />Site URL:<input type="text" name="url" /> <input type="submit" value="Submit" /> </form> </body> </html>

In the browser, the execution effect is as follows:

Passing Checkbox Data via CGI Program

Checkbox is used to submit one or more option data. The test.html code is as follows:

test.html Code

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example Tutorial (example.com)</title> </head> <body> <form action="/cgi-bin/test.cgi" method="POST" target="_blank"> <input type="checkbox" name="example" value="on" />Example Tutorial<input type="checkbox" name="google" value="on" /> Google <input type="submit" value="Select site" /> </form> </body> </html>

The following is the code of the test.cgi file:

test.cgi Code

#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read information $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Read name/value pair information @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } if( $FORM{example} ){ $example_flag ="ON"; }else{ $example_flag ="OFF"; } if( $FORM{google} ){ $google_flag ="ON"; }else{ $google_flag ="OFF"; } print "Content-type:text/html\r\n\r\n"; print "<html>"; print "<head>"; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print "</head>"; print "<body>"; print "<h2> Example Tutorial selected status :$example_flag</h2>"; print "<h2> Google selected status :$google_flag</h2>"; print "</body>"; print "</html>"; 1;

In the browser, the execution effect is as follows:


Passing Radio Data via CGI Program

Radio only sends one data item to the server. The test.html code is as follows:

test.html Code

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example Tutorial (example.com)</title> </head> <body> <form action="/cgi-bin/test.cgi" method="post" target="_blank"> <input type="radio" name="site" value="example" />Example Tutorial<input type="radio" name="site" value="google" /> Google <input type="submit" value="Submit" /> </form> </body> </html>

The test.cgi script code is as follows:

test.cgi Code

#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read information $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Read name/value pair information @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $site = $FORM{site}; print "Content-type:text/html\r\n\r\n"; print "<html>"; print "<head>"; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print "</head>"; print "<body>"; print "<h2> Selected website$site</h2>"; print "</body>"; print "</html>"; 1;

In the browser, the execution effect is as follows:


Passing Textarea Data via CGI Program

Textarea sends multiple lines of data to the server. The test.html code is as follows:

test.html Code

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example Tutorial (example.com)</title> </head> <body> <form action="/cgi-bin/test.cgi" method="post" target="_blank"> <textarea name="textcontent" cols="40" rows="4">Enter content here...</textarea> <input type="submit" value="Submit" /> </form> </body> </html>

The test.cgi script code is as follows:

test.cgi Code

#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read information $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Read name/value pair information @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $text_content = $FORM{textcontent}; print "Content-type:text/html\r\n\r\n"; print "<html>"; print "<head>"; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print "</head>"; print "<body>"; print "<h2> The input text content is:$text_content</h2>"; print "</body>"; print "</html>"; 1;

In the browser, the execution effect is as follows:


Passing Dropdown Data via CGI Program

The HTML dropdown box code is as follows:

test.html Code

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Example Tutorial (example.com)</title> </head> <body> <form action="/cgi-bin/test.cgi" method="post" target="_blank"> <select name="dropdown"> <option value="example" selected>Example Tutorial</option> <option value="google">Google</option> </select> <input type="submit" value="Submit"/> </form> </body> </html>

The test.cgi script code is as follows:

test.cgi Code

#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read information $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Read name/value pair information @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } $site = $FORM{dropdown}; print "Content-type:text/html\r\n\r\n"; print "<html>"; print "<head>"; print '<meta charset="utf-8">'; print '<title>Example Tutorial (example.com)</title>'; print "</head>"; print "<body>"; print "<h2> The selected website is:$site</h2>"; print "</body>"; print "</html>"; 1;

In the browser, the execution effect is as follows:


Using Cookies in CGI

A major disadvantage of the HTTP protocol is that it does not judge user identity, which brings great inconvenience to programmers. The emergence of cookie functionality makes up for this shortcoming.

A cookie is when a client visits a script, and through the client's browser, record data is written to the client's hard disk. When the client accesses the script next time, the data information is retrieved, thereby achieving the function of identity determination. Cookies are commonly used in identity verification.

 

Cookie Syntax

HTTP cookies are sent through the HTTP header, which occurs before the file transfer. The syntax of the Set-Cookie header is as follows:

Set-cookie:name=name;expires=date;path=path;domain=domain;secure 
  • name=name:Need to set the cookie value (name cannot use ";",symbol), when there are multiple name values, use ";" to separate, for example:name1=name1;name2=name2;name3=name3。
  • expires=date:Cookie validity period, format: expires="Wdy,DD-Mon-YYYY HH:MM:SS"
  • path=path: Set the path supported by the cookie. If path is a path, the cookie takes effect for all files and subdirectories under this directory, for example: path="/cgi-bin/". If path is a file, the cookie only takes effect for this file, for example: path="/cgi-bin/cookie.cgi".
  • domain=domain:The domain name for which the cookie is valid, for example: domain="www.example.com"
  • secure:If this flag is given, it means the cookie can only be transmitted through an HTTPS server using the SSL protocol.
  • Cookie reception is implemented by setting the environment variable HTTP_COOKIE. CGI programs can retrieve cookie information by querying this variable.

Setting Cookies

Setting cookies is very simple; cookies are sent separately in the HTTP header. The following example sets UserID, Password, and expires in the cookie:

Example

#!/usr/bin/perl print "Set-Cookie:UserID=XYZ;\n"; print "Set-Cookie:Password=XYZ123;\n"; print "Set-Cookie:Expires=Tuesday, 31-Dec-2017 23:12:40 GMT";\n"; print "Set-Cookie:Domain=www.example.com;\n"; print "Set-Cookie:Path=/perl;\n"; print "Content-type:text/html\r\n\r\n"; ...........other HTML content

Retrieving Cookies

The cookie information retrieval page is very simple. Cookie information is stored in the CGI environment variable HTTP_COOKIE, in the following format:

Example

#!/usr/bin/perl $rcvd_cookies = $ENV{'HTTP_COOKIE'}; @cookies = split /;/, $rcvd_cookies; foreach $cookie ( @cookies ){ ($key, $val) = split(/=/, $cookie); # splits on the first =. $key =~ s/^\s+//; $val =~ s/^\s+//; $key =~ s/\s+$//; $val =~ s/\s+$//; if( $key eq "UserID" ){ $user_id = $val; }elsif($key eq "Password"){ $password = $val; } } print "User ID = $user_id\n"; print "Password = $password\n";

The output result of the above example is:

User ID = XYZ
Password = XYZ123

CGI Module

Perl provides many built-in CGI modules, the following two are commonly used:

Other Extensions