Perl 简明教程

Perl - CGI Programming

What is CGI ?

  1. A Common Gateway Interface, or CGI, is a set of standards that defines how information is exchanged between the web server and a custom script.

  2. CGI 规范由 NCSA 维护,NCSA 对 CGI 的定义如下 −

  3. 通用网关接口 (CGI) 是外部网关程序与诸如 HTTP 服务器等信息服务器进行交互的标准。

  4. 当前版本为 CGI/1.1,CGI/1.2 正在进行中。

Web Browsing

To understand the concept of CGI, lets see what happens when we click a hyper link available on a web page to browse a particular web page or URL.

  1. Your browser contacts web server using HTTP protocol and demands for the URL, i.e., web page filename.

  2. Web Server will check the URL and will look for the filename requested. If web server finds that file then it sends the file back to the browser without any further execution otherwise sends an error message indicating that you have requested a wrong file.

  3. Web browser takes response from web server and displays either the received file content or an error message in case file is not found.

However, it is possible to set up HTTP server in such a way so that whenever a file in a certain directory is requested that file is not sent back; instead it is executed as a program, and whatever that program outputs as a result, that is sent back for your browser to display. This can be done by using a special functionality available in the web server and it is called Common Gateway Interface or CGI and such programs which are executed by the server to produce final result, are called CGI scripts. These CGI programs can be a PERL Script, Shell Script, C or C++ program, etc.

CGI Architecture Diagram

cgiarch

Web Server Support and Configuration

Before you proceed with CGI Programming, make sure that your Web Server supports CGI functionality and it is configured to handle CGI programs. All the CGI programs to be executed by the web server are kept in a pre-configured directory. This directory is called CGI directory and by convention it is named as /cgi-bin. By convention Perl CGI files will have extention as .cgi.

First CGI Program

Here is a simple link which is linked to a CGI script called hello.cgi. This file has been kept in /cgi-bin/ directory and it has the following content. Before running your CGI program, make sure you have change mode of file using chmod 755 hello.cgi UNIX command.

#!/usr/bin/perl

print "Content-type:text/html\r\n\r\n";
print '<html>';
print '<head>';
print '<title>Hello Word - First CGI Program</title>';
print '</head>';
print '<body>';
print '<h2>Hello Word! This is my first CGI program</h2>';
print '</body>';
print '</html>';

1;

Now if you click hello.cgi link then request goes to web server who search for hello.cgi in /cgi-bin directory, execute it and whatever result got generated, web server sends that result back to the web browser, which is as follows −

Hello Word! This is my first CGI program

This hello.cgi script is a simple Perl script which is writing its output on STDOUT file, i.e., screen. There is one important and extra feature available which is first line to be printed Content-type:text/html\r\n\r\n. This line is sent back to the browser and specifies the content type to be displayed on the browser screen. Now you must have undertood basic concept of CGI and you can write many complicated CGI programs using Perl. This script can interact with any other exertnal system also to exchange information such as a database, web services, or any other complex interfaces.

Understanding HTTP Header

The very first line Content-type:text/html\r\n\r\n is a part of HTTP header, which is sent to the browser so that browser can understand the incoming content from server side. All the HTTP header will be in the following form −

HTTP Field Name: Field Content

例如 −

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

有其他一些重要的 HTTP 头信息,您将在 CGI 编程中经常使用。

Sr.No.

Header & Description

1

Content-type: String A MIME string defining the format of the content being returned. Example is Content-type:text/html

2

Expires: Date String The date when the information becomes invalid. This should be used by the browser to decide when a page needs to be refreshed. A valid date string should be in the format 01 Jan 1998 12:00:00 GMT.

3

Location: URL String The URL that should be returned instead of the URL requested. You can use this filed to redirect a request to any other location.

4

Last-modified: String The date of last modification of the file.

5

Content-length: String The length, in bytes, of the data being returned. The browser uses this value to report the estimated download time for a file.

6

Set-Cookie: String Set the cookie passed through the string

CGI Environment Variables

所有 CGI 程序都将能够访问以下环境变量。这些变量在编写任何 CGI 程序时发挥着重要作用。

Sr.No.

Variables Names & Description

1

CONTENT_TYPE The data type of the content. Used when the client is sending attached content to the server. For example file upload, etc.

2

CONTENT_LENGTH The length of the query information. It’s available only for POST requests

3

HTTP_COOKIE 以键 & 值对的形式返回设置的 cookie。

4

HTTP_USER_AGENT The User-Agent request-header field contains information about the user agent originating the request. Its name of the web browser.

5

PATH_INFO CGI 脚本的路径。

6

QUERY_STRING 随 GET 方法请求而发送的 URL 编码信息。

7

REMOTE_ADDR 发出请求的远程主机的 IP 地址。这对于记录或认证目的非常有用。

8

REMOTE_HOST 发出请求的主机的完全限定域名。如果此信息不可用,则可以使用 REMOTE_ADDR 获取 IR 地址。

9

REQUEST_METHOD 用于发出请求的方法。最常见的方法是 GET 和 POST。

10

SCRIPT_FILENAME CGI 脚本的完整路径。

11

SCRIPT_NAME CGI 脚本的名称。

12

SERVER_NAME 服务器的主机名或 IP 地址。

13

SERVER_SOFTWARE 服务器正在运行的软件的名称和版本。

这里是列出 Web 服务器支持的所有 CGI 变量的小型 CGI 程序。单击此链接 Get Environment 查看结果

#!/usr/bin/perl

print "Content-type: text/html\n\n";
print "<font size=+1>Environment</font>\n";
foreach (sort keys %ENV) {
   print "<b>$_</b>: $ENV{$_}<br>\n";
}

1;

Raise a "File Download" Dialog Box?

有时,您希望提供一个选项,用户单击该选项将看到一个“文件下载”对话框,而不是显示实际内容。这非常简单,通过 HTTP 头可以实现。

此 HTTP 头与前面部分中提到的头不同。例如,如果您想让某个 FileName 文件可从给定链接下载,则其语法如下:

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

GET and POST Methods

您肯定遇到过许多情况,您需要将某些信息从浏览器传递到 Web 服务器,最终传递到处理您请求的 CGI 程序中。浏览器最常使用两种方法将此信息传递到 Web 服务器上。这两种方法是 GET 方法和 POST 方法。让我们逐一了解它们。

Passing Information using GET Method

GET 方法将编码的用户信息追加到页面 URL 本身。该页面和编码信息由 ? 字符分隔,如下所示:

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

GET 方法是将信息从浏览器传递到 Web 服务器的默认方法,它会生成一个长字符串,显示在浏览器的 Location: 框中。如果您有密码或其他要传递给服务器的敏感信息,则绝不应使用 GET 方法。GET 方法有大小限制:请求字符串中仅能传递 1024 个字符。

此信息使用 QUERY_STRING 头传递,并可通过 QUERY_STRING 环境变量在你的 CGI 程序中访问,可以在你的 CGI 程序中解析和使用。

您可以简单地将键值对与任何 URL 连接起来传递信息,也可以使用 HTML <FORM> 标记使用 GET 方法传递信息。

Simple URL Example: Get Method

下面是一个简单的 URL,它将两个值传递给 hello_get.cgi 程序,并使用 GET 方法。

下面是 hello_get.cgi 脚本,用于处理 Web 浏览器给出的输入。

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/;
if ($ENV{'REQUEST_METHOD'} eq "GET") {
   $buffer = $ENV{'QUERY_STRING'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex($1))/eg;
   $FORM{$name} = $value;
}
$first_name = $FORM{first_name};
$last_name  = $FORM{last_name};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print "<title>Hello - Second CGI Program</title>";
print "</head>";
print "<body>";
print "<h2>Hello $first_name $last_name - Second CGI Program</h2>";
print "</body>";
print "</html>";

1;

Simple FORM Example: GET Method

下面是一个简单的示例,它使用 HTML 表单和提交按钮传递两个值。我们将使用相同的 CGI 脚本 hello_get.cgi 来处理此输入。

<FORM action = "/cgi-bin/hello_get.cgi" method = "GET">
First Name: <input type = "text" name = "first_name">  <br>

Last Name: <input type = "text" name = "last_name">
<input type = "submit" value = "Submit">
</FORM>

这是上面表单代码的实际输出。现在,您可以输入名字和姓氏,然后单击提交按钮以查看结果。

Passing Information using POST Method

向 CGI 程序传递信息的更可靠的方法是 POST 方法。这会打包信息的方式与 GET 方法完全相同,但不是在 URL 中在 ? 后面以文本字符串的形式发送,而是作为 HTTP 头的一部分以单独消息的形式发送。Web 服务器会通过标准输入的形式提供此消息给 CGI 脚本。

下面是经过修改的 hello_post.cgi 脚本,用于处理 Web 浏览器给出的输入。此脚本将处理 GET 和 POST 方法。

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$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'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex($1))/eg;
   $FORM{$name} = $value;
}
$first_name = $FORM{first_name};
$last_name  = $FORM{last_name};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print "<title>Hello - Second CGI Program</title>";
print "</head>";
print "<body>";
print "<h2>Hello $first_name $last_name - Second CGI Program</h2>";
print "</body>";
print "</html>";

1;

让我们再次举上面的例子,使用 HTML 表单和提交按钮传递两个值。我们将使用 CGI 脚本 hello_post.cgi 来处理此输入。

<FORM action = "/cgi-bin/hello_post.cgi" method = "POST">
First Name: <input type = "text" name = "first_name">  <br>

Last Name: <input type = "text" name = "last_name">

<input type = "submit" value = "Submit">
</FORM>

这是上面表单代码的实际输出。您可以输入名字和姓氏,然后单击提交按钮以查看结果。

Passing Checkbox Data to CGI Program

当需要选择多个选项时,会使用复选框。以下是带两个复选框的表单的 HTML 代码示例。

<form action = "/cgi-bin/checkbox.cgi" method = "POST" target = "_blank">
<input type = "checkbox" name = "maths" value = "on"> Maths
<input type = "checkbox" name = "physics" value = "on"> Physics
<input type = "submit" value = "Select Subject">
</form>

这段代码的结果是以下表单−

下面是 checkbox.cgi 脚本,用于处理 Web 浏览器给出的单选按钮输入。

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$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'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex($1))/eg;
   $FORM{$name} = $value;
}
if( $FORM{maths} ) {
   $maths_flag ="ON";
} else {
   $maths_flag ="OFF";
}
if( $FORM{physics} ) {
   $physics_flag ="ON";
} else {
   $physics_flag ="OFF";
}

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print "<title>Checkbox - Third CGI Program</title>";
print "</head>";
print "<body>";
print "<h2> CheckBox Maths is : $maths_flag</h2>";
print "<h2> CheckBox Physics is : $physics_flag</h2>";
print "</body>";
print "</html>";

1;

Passing Radio Button Data to CGI Program

只有在需要选择一个选项时才使用单选按钮。以下是带两个单选按钮的表单的 HTML 代码示例:

<form action = "/cgi-bin/radiobutton.cgi" method = "POST" target = "_blank">
<input type = "radio" name = "subject" value = "maths"> Maths
<input type = "radio" name = "subject" value = "physics"> Physics
<input type = "submit" value = "Select Subject">
</form>

这段代码的结果是以下表单−

下面是 radiobutton.cgi 脚本,用于处理 Web 浏览器给出的单选按钮输入。

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$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'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex($1))/eg;
   $FORM{$name} = $value;
}
$subject = $FORM{subject};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print "<title>Radio - Fourth CGI Program</title>";
print "</head>";
print "<body>";
print "<h2> Selected Subject is $subject</h2>";
print "</body>";
print "</html>";

1;

Passing Text Area Data to CGI Program

A textarea element is used when multiline text has to be passed to the CGI Program. Here is an example HTML code for a form with a TEXTAREA box −

<form action = "/cgi-bin/textarea.cgi" method = "POST" target = "_blank">
<textarea name = "textcontent" cols = 40 rows = 4>
Type your text here...
</textarea>
<input type = "submit" value = "Submit">
</form>

这段代码的结果是以下表单−

Below is the textarea.cgi script to handle input given by the web browser.

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$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'};
}
# Split information into name/value pairs
@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 "<title>Text Area - Fifth CGI Program</title>";
print "</head>";
print "<body>";
print "<h2> Entered Text Content is $text_content</h2>";
print "</body>";
print "</html>";

1;

Passing Drop Down Box Data to CGI Program

A drop down box is used when we have many options available but only one or two will be selected. Here is example HTML code for a form with one drop down box

<form action = "/cgi-bin/dropdown.cgi" method = "POST" target = "_blank">
<select name = "dropdown">
<option value = "Maths" selected>Maths</option>
<option value = "Physics">Physics</option>
</select>
<input type = "submit" value = "Submit">
</form>

这段代码的结果是以下表单−

Below is the dropdown.cgi script to handle input given by web browser.

#!/usr/bin/perl

local ($buffer, @pairs, $pair, $name, $value, %FORM);
# Read in text
$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'};
}
# Split information into name/value pairs
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
   ($name, $value) = split(/=/, $pair);
   $value =~ tr/+/ /;
   $value =~ s/%(..)/pack("C", hex($1))/eg;
   $FORM{$name} = $value;
}
$subject = $FORM{dropdown};

print "Content-type:text/html\r\n\r\n";
print "<html>";
print "<head>";
print "<title>Dropdown Box - Sixth CGI Program</title>";
print "</head>";
print "<body>";
print "<h2> Selected Subject is $subject</h2>";
print "</body>";
print "</html>";

1;

Using Cookies in CGI

HTTP protocol is a stateless protocol. But for a commercial website it is required to maintain session information among different pages. For example one user registration ends after transactions which spans through many pages. But how to maintain user’s session information across all the web pages?

在许多情况下,使用 cookie 是记忆和跟踪偏好、购买、佣金和其他信息最有效的方法,而这些信息对于提升访问者体验或网站统计至关重要。

How It Works

您的服务器会以 Cookie 的形式向访客的浏览器发送一些数据。浏览器可能会接受 Cookie。如果接受,它将作为纯文本记录存储在访客硬盘上。现在,当访客到达您站点上的另一个页面时,可以检索 Cookie。检索后,您的服务器知道/记住存储的内容。

Cookie 是纯文本数据记录,包含 5 个可变长度字段:

  1. Expires − cookie 的过期日期。如果留空,则 cookie 将在访问者退出浏览器时过期。

  2. Domain − 您网站的域名。

  3. Path − 设置 cookie 的目录或网页的路径。如果您希望从任何目录或页面检索 cookie,则可以留空。

  4. Secure - 如果此字段包含单词“secure”,则只能通过安全服务器来检索 cookie。如果此字段为空,则不存在此类限制。

  5. Name = Value − Cookies are set and retrviewed in the form of key and value pairs.

Setting up Cookies

It is very easy to send cookies to browser. These cookies will be sent along with the HTTP Header. Assuming you want to set UserID and Password as cookies. So it will be done as follows −

#!/usr/bin/perl

print "Set-Cookie:UserID = XYZ;\n";
print "Set-Cookie:Password = XYZ123;\n";
print "Set-Cookie:Expires = Tuesday, 31-Dec-2007 23:12:40 GMT";\n";
print "Set-Cookie:Domain = www.tutorialspoint.com;\n";
print "Set-Cookie:Path = /perl;\n";
print "Content-type:text/html\r\n\r\n";
...........Rest of the HTML Content goes here....

Here we used Set-Cookie HTTP header to set cookies. It is optional to set cookies attributes like Expires, Domain, and Path. It is important to note that cookies are set before sending magic line "Content-type:text/html\r\n\r\n.

Retrieving Cookies

It is very easy to retrieve all the set cookies. Cookies are stored in CGI environment variable HTTP_COOKIE and they will have following form.

key1 = value1;key2 = value2;key3 = value3....

以下是有关如何检索 cookie 的示例。

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

This will produce the following result, provided above cookies have been set before calling retrieval cookies script.

User ID = XYZ
Password = XYZ123

CGI Modules and Libraries

You will find many built-in modules over the internet which provides you direct functions to use in your CGI program. Following are the important once.