Perl - CGI编程

什么是CGI?

  • 通用网关接口或CGI是一组定义信息的标准在Web服务器和自定义脚本之间交换.

  • CGI规范目前由NCSA维护,NCSA定义CGI如下 :

  • 公共网关接口(CGI)是外部网关程序与HTTP服务器等信息服务器接口的标准.

  • 当前版本为CGI/1.1且CGI/1.2正在进行中.

网页浏览

为了理解CGI的概念,让我们看看当我们点击网页上可用的超链接来浏览特定的网页或网址时会发生什么.

  • 您的浏览器使用HTTP协议联系Web服务器,并要求提供URL,即网页文件名.

  • Web服务器将检查URL并查找文件名req uested.如果Web服务器找到该文件,则它会将文件发送回浏览器而不再执行任何操作,否则会发送一条错误消息,指出您已请求错误的文件.

  • Web浏览器从Web服务器获取响应,并显示收到的文件内容或未找到文件的错误消息.

但是,可以以这样的方式设置HTTP服务器,以便每当请求某个目录中的文件时不发回该文件;相反,它作为程序执行,无论该程序输出什么结果,都会将其发回给您的浏览器进行显示.这可以通过使用Web服务器中可用的特殊功能来完成,它被称为公共网关接口或CGI,并且由服务器执行以产生最终结果的此类程序称为CGI脚本.这些CGI程序可以是PERL脚本,Shell脚本,C或C ++程序等.

CGI架构图

CGI Architecture

Web服务器支持和配置

在继续CGI编程之前,请确保Web Server支持CGI功能,并配置为处理CGI程序. Web服务器要执行的所有CGI程序都保存在预先配置的目录中.该目录称为CGI目录,按照惯例,它被命名为/cgi-bin.按照惯例,Perl CGI文件将扩展为 .cgi .

第一个CGI程序

这是一个简单的链接链接到名为 hello.cgi 的CGI脚本.此文件已保存在/cgi-bin/目录中,并具有以下内容.在运行CGI程序之前,请确保使用 chmod 755 hello.cgi UNIX命令更改文件模式.

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

现在,如果你点击 hello.cgi 链接,那么请求转到在/cgi-bin中搜索hello.cgi的网络服务器目录,执行它和生成的任何结果,Web服务器将结果发送回Web浏览器,如下所示;

Hello Word! This is my first CGI program

这个hello.cgi脚本是一个简单的Perl脚本,它将输出写入STDOUT文件,即屏幕.有一个重要的额外功能可用于打印第一行内容类型:text/html \\\\\\\ .该行被发送回浏览器并指定要在浏览器屏幕上显示的内容类型.现在你必须具备CGI的基本概念,你可以使用Perl编写许多复杂的CGI程序.此脚本还可以与任何其他exertnal系统交互,以交换数据库,Web服务或任何其他复杂接口等信息.

了解HTTP标头

第一行 Content-type:text/html\r\\\
\r\ n
是HTTP标头的一部分,它被发送到浏览器,以便浏览器可以理解来自服务器端的传入内容.所有HTTP标头将采用以下形式 :

HTTP Field Name: Field Content

例如 :

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

还有其他一些重要的HTTP标头,你会经常在你的CGI编程中使用.

Sr.No.标题&说明
1

Content-type:String

定义要返回的内容格式的MIME字符串.示例是Content-type:text/html

2

过期:日期字符串

信息失效的日期.浏览器应该使用它来决定何时需要刷新页面.有效日期字符串的格式应为格林威治标准时间01年1月1日12:00:00.

3

Location: URL String

应该返回的网址而不是请求的URL.您可以使用此字段将请求重定向到任何其他位置.

4

Last-modified: String

上次修改文件的日期.

5

Content-length: String

返回数据的长度(以字节为单位).浏览器使用此值来报告文件的估计下载时间.

6

Set-Cookie:String

设置通过字符串传递的cookie

CGI环境变量

所有CGI程序将有权访问以下环境变量.这些变量在编写任何CGI程序时都起着重要作用.

Sr.No.变量Names&说明
1

CONTENT_TYPE

内容的数据类型.客户端将附加内容发送到服务器时使用.例如文件上传等.

2

CONTENT_LENGTH

查询信息的长度.它仅适用于POST请求

3

HTTP_COOKIE

以密钥和密钥形式返回设置的cookie价值对.

4

HTTP_USER_AGENT

User-Agent请求标头字段包含有关发起请求的用户代理的信息.它的Web浏览器名称.

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

服务器运行的软件的名称和版本.

这是一个小型CGI程序,用于列出Web服务器支持的所有CGI变量.点击此链接查看结果获取环境

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

提出"文件下载"对话框?

有时您希望提供选项用户将单击一个链接,它将弹出一个"文件下载"对话框给用户,而不是显示实际内容.这很容易,并且将通过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和POST方法

当你需要通过时,你必须遇到很多情况从您的浏览器到Web服务器以及最终处理您的请求的CGI程序的一些信息.最常见的浏览器使用两种方法将此信息传递给Web服务器.这些方法是 GET 方法和 POST 方法.让我们逐个检查它们.

使用GET方法传递信息

GET方法发送附加到页面URL本身的编码用户信息.页面和编码信息由?分隔.字符如下 :

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

GET方法是将信息从浏览器传递到Web服务器的defualt方法,它产生一个长字符串出现在浏览器的"位置:"框中.如果您有密码或其他敏感信息要传递给服务器,则不应使用GET方法. GET方法有大小限制:请求字符串中只能传递1024个字符.

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

您可以通过简单地连接键和值对以及任何URL来传递信息,或者您可以使用HTML< FORM>使用GET方法传递信息的标签.

简单URL示例:获取方法

这是一个简单的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;

简单表单示例:GET方法

这是一个简单的示例,它使用HTML FORM传递两个值并提交按钮.我们将使用相同的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>

以下是上述表格编码的实际输出.现在您可以输入名字和姓氏,然后点击提交按钮查看结果.

使用POST方法传递信息

A将信息传递给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 FORM和提交按钮传递两个值.我们将使用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>

以下是上述表格编码的实际输出,您输入名字和姓氏,然后点击提交按钮查看结果.

将复选框数据传递给CGI程序

当需要选择多个选项时,将使用复选框.以下是带有两个复选框的表单的示例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>

此代码的结果为以下形式 :

下面是复选框.cgi 脚本来处理网页浏览器为单选按钮提供的输入.

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

将单选按钮数据传递给CGI程序

当只需要选择一个选项时,使用单选按钮.以下是带有两个单选按钮&减号的表单的示例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 脚本来处理网络浏览器为单选按钮提供的输入.

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

将文本区域数据传递给CGI程序

当多行文本必须传递给文本区域时,使用textarea元素CGI计划.以下是带有TEXTAREA框和减号的表单的示例HTML代码;

<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>

此代码的结果为以下形式 :

以下是 textarea.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;
}
$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;

将下拉框数据传递给CGI程序

当我们有多个选项可用时,会使用下拉框只会选择一两个.以下是带有一个下拉框的表单的示例HTML代码

<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>

此代码的结果为以下形式 :

以下是 dropdown.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{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;

在CGI中使用Cookie

HTTP协议是无状态协议.但对于商业网站,需要在不同页面之间维护会话信息.例如,一个用户注册在跨越许多页面的事务之后结束.但是如何在所有网页上维护用户的会话信息?

在许多情况下,使用cookie是记住和跟踪首选项,购买,佣金和其他所需信息的最有效方法.更好的访问者体验或网站统计信息.

工作原理

您的服务器以cookie的形式向访问者的浏览器发送一些数据.浏览器可以接受cookie.如果是,则将其作为纯文本记录存储在访问者的硬盘上.现在,当访问者到达您网站上的另一个页面时,该Cookie可供检索.检索后,您的服务器知道/记住存储的内容.

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

  • 过期 :  Cookie过期的日期.如果这是空白,则当访问者退出浏览器时,Cookie将过期.

  • : 您网站的域名.

  • 路径 : 设置cookie的目录或网页的路径.如果您想从任何目录或页面检索cookie,这可能是空白.

  • 安全 : 如果此字段包含单词"secure",则只能使用安全服务器检索cookie.如果此字段为空,则不存在此类限制.

  • 名称=值 :  Cookie以键和值对的形式设置和回顾.

设置Cookie

向浏览器发送cookie非常容易.这些cookie将与HTTP标头一起发送.假设您要将UserID和密码设置为cookie.所以它将按以下方式完成 :

#!/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.IT屋.com;\n";
print "Set-Cookie:Path = /perl;\n";
print "Content-type:text/html\r\n\r\n";
...........Rest of the HTML Content goes here....

这里我们用过设置Cookie HTTP标头以设置Cookie.可以选择设置Cookie属性,如Expires,Domain和Path.请务必注意在发送魔术行之前设置Cookie "Content-type:text/html\r\n\r\n .

检索Cookie

这很容易检索所有设置的cookie. Cookie存储在CGI环境变量HTTP_COOKIE中,它们将具有以下形式.

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";

如果在调用检索cookie脚本之前已经设置了cookie,则会产生以下结果.

User ID = XYZ
Password = XYZ123

CGI模块和库

您可以通过互联网找到许多内置模块,为您提供在CGI程序中使用的直接功能.以下是重要的一次.

  • CGI模块

  • Berkeley cgi-lib.pl