Perl CGI Programming

From WikiOD

Perl CGI programming[edit | edit source]


What is CGI[edit | edit source]

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

CGI (Common Gateway Interface), a common gateway interface, is a program that runs on a server, such as an HTTP server, which provides an interface with the client's HTML page.


Web browsing[edit | edit source]

In order to better understand how CGI works, we can follow the process of clicking a link or URL on a web page:

  • 1. Use your browser to visit the URL and connect to the HTTP web server.
  • 2. After receiving the requested information, the web server will parse the URL and find whether the accessed file exists on the server. If there is, the content of the returned file will be returned, otherwise an error message will be returned.
  • 3. The browser receives information from the server and displays the received file or error message.

CGI programs can be Python scripts, PERL scripts, SHELL scripts, C or C++ programs, etc

Web server support and configuration[edit | edit source]

Before you do CGI programming, make sure that your web server supports CGI and has been configured with CGI handlers.

Apache supports CGI configuration:

Set up the CGI directory:

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

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

The extension of CGI files is .cgi, and Perl can also use the extension of .pl.

By default, the cgi-bin directory where the Linux server is configured and running is /var/www.

If you want to specify other directories to run 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 the Perl script file ending in .pl:

 AddHandler cgi-script .cgi .pl .py
The first CGI program[edit | edit source]

Below we create a test.cgi file, the code is as follows:

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

Then open http://localhost/cgi-bin/test.cgi through a browser,

The output content "Content-type:text/html\r\n\r\n" of the first line of the script is sent to the browser and informs the browser that the content type displayed is "text/html".


HTTP header[edit | edit source]

"Content-type: text/html" in the content of the test.cgi file is a part of the HTTP header, which will be sent to the browser to tell the browser the content type of the file.

The format of the HTTP header is as follows:

 HTTP field name: field content

E.g:

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

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

Head Describe
Content-type: The requested MIME information corresponding to the entity. For example: Content-type:text/html
Expires: Date Date and time when the response expires
Location: URL Used to redirect the recipient to a location other than the requested URL to complete the request or identify a new resource
Last-modified: Date The last modification time of the requested resource
Content-length: N Requested content length
Set-Cookie: String Set Http Cookie

CGI environment variables[edit | edit source]

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

Variable name Describe
CONTENT_TYPE The value of this environment variable indicates the MIME type of the information passed. At present, the environment variable CONTENT_TYPE is generally: application/x-www-form-urlencoded, which means that the data comes from an HTML form.
CONTENT_LENGTH If the server and CGI program information is transmitted in POST, this environment variable is the number of bytes of valid data that can be read from the standard input STDIN. This environment variable must be used when reading the input data.
HTTP_COOKIE COOKIE content in the client.
HTTP_USER_AGENT Provide client browser information including version number or other proprietary data.
PATH_INFO The value of this environment variable represents other path information immediately after the CGI program name. It often appears as a parameter of CGI programs.
QUERY_STRING If the server and CGI program information transfer method is GET, the value of this environment variable is even the information passed. This information is followed by the CGI program name, separated by a question mark'?' between the two.
REMOTE_ADDR The value of this environment variable is the IP address of the client who sent the request, such as 192.168.1.67 above. This value always exists. Moreover, it is the unique identifier that the Web client needs to provide to the Web server, and it can be used in the CGI program to distinguish different Web clients.
REMOTE_HOST The value of this environment variable contains the host name of the client that sent the CGI request. If the query you want is not supported, there is no need to define this environment variable.
REQUEST_METHOD Provides the method by which the script is called. For scripts using HTTP/1.0 protocol, only GET and POST are meaningful.
SCRIPT_FILENAME The full path of the CGI script
SCRIPT_NAME The name of the CGI script
SERVER_NAME This is the host name, alias or IP address of your WEB server.
SERVER_SOFTWARE The value of this environment variable contains the name and version number of the HTTP server calling the CGI program. For example, the above value is Apache/2.2.14 (Unix)

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

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

Download Document[edit | edit source]

If we want to download files through Perl CGI, we need to set different header information, as shown below:

 #!/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");
 }
----

Use GET method to transfer data[edit | edit source]

The GET method sends the encoded user information to the server. The data information is included in the URL of the request page, separated by "?" signs, as shown below:

 <code>http://www.test.com/cgi-bin/test.cgi?key1=value1&key2=value2</code>

Some other notes about GET requests:

  • GET requests can be cached
  • GET requests are kept in browser history
  • GET request can be bookmarked
  • GET requests should not be used when processing sensitive data
  • GET request has a length limit
  • GET requests should only be used to retrieve data
Simple url example: GET method[edit | edit source]

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

 /cgi-bin/test.cgi?name=Novice Tutorial&url=<code>http://www.phpxs.com</code>

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

 #!/usr/bin/perl
 
 local ($buffer, @pairs, $pair, $name, $value, %FORM);
 # Read text information
 $ENV{'REQUEST_METHOD'} =~ tr/az/AZ/;
 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>Novice Tutorial (phpxs.com)</title>';
 print "</head>";
 print "<body>";
 print "<code><h2>$name URL: $url</h2></code>";
 print "</body>";
 print "</html>";
 
 1;

Check the browser, the output result is as follows:

Simple form example: GET method[edit | edit source]

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

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

Use the POST method to pass data[edit | edit source]

It is safer and more reliable to use the POST method to transmit data to the server. For example, some sensitive information such as user passwords need to use POST to transmit data.

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

 #!/usr/bin/perl
 
 local ($buffer, @pairs, $pair, $name, $value, %FORM);
 # Read text information
 $ENV{'REQUEST_METHOD'} =~ tr/az/AZ/;
 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>Novice Tutorial (phpxs.com)</title>';
 print "</head>";
 print "<body>";
 print "<code><h2>$name URL: $url</h2></code>";
 print "</body>";
 print "</html>";
 
 1;

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

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Novice Tutorial (phpxs.com)</title>
 </head>
 <body>
 <form action="/cgi-bin/test.cgi" method="post">
 Site name: <code><input type="text" name="name"></code> <code><br /></code>
 
 Site URL: <input type="text" name="url" />
 <input type="submit" value="Submit" />
 </form>
 </body>
 </html>
Pass checkbox data through CGI program[edit | edit source]

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

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Novice Tutorial (phpxs.com)</title>
 </head>
 <body>
 <form action="/cgi-bin/test.cgi" method="POST" target="_blank">
 <input type="checkbox" name="runoob" value="on" /> Novice 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:

 #!/usr/bin/perl
 
 local ($buffer, @pairs, $pair, $name, $value, %FORM);
 # Read information
 $ENV{'REQUEST_METHOD'} =~ tr/az/AZ/;
 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{runoob} ){
    $runoob_flag ="ON";
 }else{
    $runoob_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>Novice Tutorial (phpxs.com)</title>';
 print "</head>";
 print "<body>";
 print "<code><h2> The selected state of the rookie tutorial: $runoob_flag</h2></code>";
 print "<code><h2> Google selection status: $google_flag</h2></code>";
 print "</body>";
 print "</html>";
 
 1;
----

Pass Radio data through CGI program[edit | edit source]

Radio only transmits one piece of data to the server, the test.html code is as follows:

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Novice Tutorial (phpxs.com)</title>
 </head>
 <body>
 <form action="/cgi-bin/test.cgi" method="post" target="_blank">
 <input type="radio" name="site" value="runoob" /> Novice 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:

 #!/usr/bin/perl
 
 local ($buffer, @pairs, $pair, $name, $value, %FORM);
 # Read information
 $ENV{'REQUEST_METHOD'} =~ tr/az/AZ/;
 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>Novice Tutorial (phpxs.com)</title>';
 print "</head>";
 print "<body>";
 print "<code><h2> Selected website $site</h2></code>";
 print "</body>";
 print "</html>";
 
 1;
----

Pass Text area data through CGI program[edit | edit source]

Text area sends multiple rows of data to the server, the test.html code is as follows:

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <title>Novice Tutorial (phpxs.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:

 #!/usr/bin/perl
 
 local ($buffer, @pairs, $pair, $name, $value, %FORM);
 # Read information
 $ENV{'REQUEST_METHOD'} =~ tr/az/AZ/;
 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>Novice Tutorial (phpxs.com)</title>';
 print "</head>";
 print "<body>";
 print "<code><h2>The input text content is: $text_content</h2></code>";
 print "</body>";
 print "</html>";
 
 1;
----

Pass drop-down data through CGI program[edit | edit source]

The HTML drop-down box code is as follows:

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

The test. cgi script code is as follows:

 #!/usr/bin/perl
 
 local ($buffer, @pairs, $pair, $name, $value, %FORM);
 # Read information
 $ENV{'REQUEST_METHOD'} =~ tr/az/AZ/;
 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>Novice Tutorial (phpxs.com)</title>';
 print "</head>";
 print "<body>";
 print "<code><h2>The selected website is: $site</h2></code>";
 print "</body>";
 print "</html>";
 
 1;
----

Use of cookies in CGI[edit | edit source]

A big disadvantage of the http protocol is that it does not judge the user's identity, which brings great inconvenience to the programmer, and the emergence of the cookie function makes up for this deficiency.

Cookie is to write record data on the client's hard disk through the client's browser while the client accesses the script, and retrieve the data information when the client accesses the script next time, so as to achieve the function of identity discrimination. Cookies are often used in identity verification.

 

The syntax of cookies[edit | edit source]

The sending of http cookie is realized through the http header, which is earlier than the transmission of the file. The syntax of the header set-cookie is as follows:

 Set-cookie:name=name;expires=date;path=path;domain=domain;secure
  • name=name: The value of the cookie needs to be set (name cannot use " ; " and " , " signs). When there are multiple name values, use " ; " to separate, for example: name1=name1;name2=name2;name3=name3 .
  • expires=date: the expiration date of the cookie, 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 will take effect on all files and subdirectories in this directory, for example: path="/cgi-bin/", if the path is a file, then the cookie Refers to the effect of this file, for example: path="/cgi-bin/cookie.cgi".
  • domain=domain: The domain name that is valid for the cookie, for example: domain="www.phpxs.com"
  • secure: If this flag is given, it means that the cookie can only be transmitted through the https server of the SSL protocol.
  • The cookie reception is achieved by setting the environment variable HTTP_COOKIE, and the CGI program can retrieve the cookie information by retrieving this variable.

Cookie settings[edit | edit source]

The setting of the cookie is very simple, the cookie will be sent separately in the http header. The following example sets UserID, Password, and expires in the cookie:

 #!/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.phpxs.com;\n";
 print "Set-Cookie:Path=/perl;\n";
 print "Content-type:text/html\r\n\r\n";
 ...........Other HTML content
Find cookies[edit | edit source]

The cookie information retrieval page is very simple. The cookie information is stored in the CGI environment variable HTTP_COOKIE, and the storage format is as follows:

 #!/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 of the above example is:
 User ID = XYZ
 Password = XYZ123
----

CGI module[edit | edit source]

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

  • CGI module
  • Berkeley cgi-lib.pl