CGI脚本工作原理
引言
新的网站设计人员在建立网站之后经常问到一个问题就是:“什么是CGI脚本,如何在我的网站上使用它?”或“如何在我的网站上创建交互式表单?”。
在本文中,我们将回答有关CGI脚本的问题,并演示如何创建自己的脚本。
在此过程中,您还将了解有关Web服务器的一些知识。让我们开始吧!
Web服务器
如Web服务器工作原理一文中所述,Web服务器相当简单。从根本上说,Web服务器只是从磁盘中检索出文件,并通过网络将其发送到发出请求的浏览器。假设您键入URL:http://www.bygpub.com/books/tg2rw/author.htm。Web服务器将会获得一个针对文件/books/tg2rw/author.htm的请求。查看下图,您可以了解服务器是如何解决该请求的:
|
在安装过程中,Web服务器已被告知c:My Documentswww是服务器的根目录。然后,该服务器会从根目录中找出/books/tg2rw/author.htm。当您请求URL http://www.bygpub.com/books/tg2rw/时,该服务器就会知道您正在查找该目录的默认文件。它会查找一些不同的文件名以试图找到默认文件:index.html、index.htm、default.html和default.htm。根据服务器的不同,它也可以查找其他文件名。因此,该服务器会将 http://www.bygpub.com/books/tg2rw/转换为 http://www.bygpub.com/books/tg2rw/index.htm并传送该文件。所有其他文件必须通过明确给出文件名来指定。
这就是所有Web服务器处理静态文件的方式。大多数Web服务器还可以通过称作通用网关接口(CGI)的机制处理动态文件。您已经在Web上的各种地方看到过CGI,只不过您当时可能对它并不了解。例如:
- 您可以在任何留言簿上通过HTML表单输入消息,当下一次查看此留言簿时,页面将会包含您输入的新条目。
- Network Solutions上的WHOIS表单允许您在表单上输入域名,返回的网页将根据输入的域名而有所不同。
- 任何搜索引擎都允许您在HTML表单上输入关键字,然后它将根据您输入的关键字动态创建页面。
所有这些动态页面使用的都是CGI。
CGI机制
在大多数Web服务器上,通过以下方式使CGI机制标准化。在服务器视为根目录的普通目录树中,可以创建一个名为cgi-bin的子目录。(可以在上一页的图示中查看此目录。)然后,服务器了解到不应只是读取和发送从特殊cgi-bin目录中请求的任何文件,而应执行它们。执行的程序的输出内容是它实际发送给请求该页的浏览器的内容。一般来说,可执行程序既可以是一个纯可执行程序(就像C编译器的输出),也可以是一个PERL脚本。PERL是一种用于CGI脚本的最流行的语言。
假设您在浏览器中键入URL:http://www.howstuffworks.com/cgi-bin/search.pl。由于服务器了解到search.pl位于cgi-bin目录中,因此它会执行search.pl(一个PERL脚本),并将执行的输出内容发送到浏览器。
您可以编写自己的脚本并试验CGI,前提是:
- 您了解某种编程语言,如C或PERL。
- 您对处理CGI脚本的Web服务器拥有访问权限。如果您已为用于承载您的网站的Web托管服务付费,则可以选择通过您的主机来访问CGI脚本。有关详细信息,请查看托管服务。如果您没有为用于承载您的网站的Web主机服务付费,则可以通过在家用计算机上安装Web服务器并学习如何使用它来进行试验。尽管第二种选择要稍微复杂一些,但您在此过程中肯定可以学到很多知识!
简单的CGI脚本
假定您对cgi-bin目录拥有访问权限(请参阅上一节),了解C编程语言或PERL,则可以使用CGI执行一系列有趣的试验。让我们从创建最简单的CGI脚本开始。
在网页基础知识一文中,我们研究了可能存在的最简单的HTML网页。这个网页的形式如下:
这个可能存在的最简单的CGI脚本在执行时,将会创建上述的简单的静态页面作为其输出。以下是用C语言编写此CGI程序的形式:
在Web服务器上,将此程序输入到文件simplest.c中,然后通过以下命令进行编译:
(有关如何编译C语言程序的详细信息,请参见C语言入门教程。)
将simplest.cgi放置在cgi-bin目录中,它就可以执行了。您现在就可以通过键入或单击此URL来尝试一下:http://www.howstuffworks.com/cgi-bin/simplest.cgi。您可以看到,该脚本所做的全部工作就是生成显示“Hello there!”的页面。唯一没有预料到的部分就是下面这行内容:
“Content-type:text/htmlnn”这行内容是一段特殊的文本,任何CGI脚本必须首先将它发送给浏览器。只要您记住这一点,就一切ok了。如果您忘记了这一点,则浏览器将拒绝输出脚本。
您可以在PERL中执行相同的操作。将下面这段PERL代码键入到一个名为simplest.pl的文件中:
将该文件放置到cgi-bin目录中。在UNIX计算机上,键入以下内容也许会有用:
这将告知UNIX该脚本是可执行的。您现在就可以通过键入或单击此URL来尝试一下:http://www.howstuffworks.com/cgi-bin/simplest.pl。
您现在已经了解了CGI脚本的基本概念。相当简单!实际上就是,执行一个程序,然后将程序的输出发送到调用脚本的浏览器。发送给stdout的正常输出就是发送给浏览器的输出。
不过,CGI脚本的重点在于创建动态内容——每次执行脚本时,输出应该是不同。毕竟,如果每次运行脚本时的输出都是相同的,您也可以使用静态页面。以下C语言程序演示了非常简单的动态内容:
使用一个文本编辑器,将此程序键入到一个名为count.c的文件中。通过键入以下命令对其进行编译:
创建另一个名为count.txt的文本文件,并在其中放入一个零。将counter.cgi和count.txt放置在cgi-bin目录中,即可以运行脚本。您现在就可以通过键入或单击此URL来尝试一下:http://www.howstuffworks.com/cgi-bin/count.cgi。您可以看到,脚本所做的全部工作就是生成一个显示“The current count is:X”的页面。运行一次脚本,其中的X就会递增一次。尝试将脚本运行几次,并注意观察页面内容的变化!
count.txt文件保留当前计数,同时小的incrementcount()函数使count.txt文件中的计数递增。此函数将打开count.txt文件、从中读取数字、递增数字并将其写回到文件中。实际上,此函数会尝试打开文件两次。这样做是为了防止两个用户试图同时访问该文件。这项技术并非万无一失,但对于这类简单情况还是有效的。如果在第二次尝试时无法打开文件,则将为调用者返回错误值-1。更加完善的程序将识别返回值-1,并会生成相应的错误提示。
gcc count.c -o count.cgi
#include
int incrementcount()
{
FILE *f;
int i;
f=fopen("count.txt", "r+");
if (!f)
{
sleep(1);
f=fopen("count.txt", "r+");
if (!f)
return -1;
}
fscanf(f, "%d", andi);
i++;
fseek(f,0,SEEK_SET);
fprintf(f, "%d", i);
fclose(f);
return i;
}
int main()
{
printf("Content-type:text/htmlnn");
printf("n");
printf("n");
printf("
The current count is:")
printf("%dn", incrementcount());
printf("n");
printf("n");
return 0;
}
chmod 755 simplest.pl
#! /usr/bin/perl
print andquot;Content-type:text/htmlnnandquot;;
print andquot;andlt;htmlandgt;andlt;bodyandgt;andlt;h1andgt;Hello World!andquot;;
print andquot;
nandquot;;
printf("Content-type:text/htmlnn");
gcc simplest.c -o simplest.cgi
#include
int main()
{
printf("Content-type:text/htmlnn");
printf("n");
printf("n");
printf("andlt;h1andgt;Hello there!andlt;/h1andgt;n");
printf("n");
printf("n");
return 0;
}
andlt;h1andgt;Hello there!andlt;/h1andgt;
HTML表单
我们已了解到CGI脚本的创建过程相当简单。Web服务器执行放置在cgi-bin目录中的任何可执行程序,并且可执行程序发送给 stdout的任何输出都将出现在调用该脚本的浏览器中。现在,我们需要找到一种用于将输入发送到脚本的方法。发送输入的一般方法是使用HTML表单。
表单在网络上随处可见。可以接受内容输入的任何页面都是表单。您可以在搜索引擎、留言簿、问卷等上面看到这些表单。您在HTML页上创建表单,并在表单的HTML标记中指定CGI脚本的名称,当用户单击表单上的Submit按钮时将调用该脚本。用户输入到表单中的值将会进行打包并发送到CGI脚本,这样脚本就可以随意使用这些值。
实际上,上述情况是很常见的,只是您可能没有意识到而已。例如,转到 http://www.lycos.com,在“Search for:”框中键入“test”一词并按“Go Get It!”按钮。结果页的 URL 类似于下面这样:
您会发现Lycos主页就是一个表单。Lycos在cgi-bin目录中有一个名为pursuit的脚本。表单会向此脚本发送五个参数:
- matchmode=and
- cat=lycos
- query=test
- x=10
- y=9
第三个参数正是我们输入的搜索字符串。其他四个参数也为脚本提供了一些信息。CGI脚本在Lycos数据库中查询“test”一词,然后返回结果。这就是任何搜索引擎的核心!
让我们创建一个简单的表单进行试验。创建一个名为simpleform.htm的文件,然后在其中输入以下 HTML:
可以单击此URL进行试验:http://www.howstuffworks.com/simpleform.htm。
您可以看到,HTML代码指定创建一个使用GET方法的表单,并将该方法发送给http://www.howstuffworks.com/cgi-bin/simpleform.cgi上的CGI脚本。该表单内包含一个文本输入区域以及标准的“Submit”和“Reset”按钮。
该表单引用的文件http://www.howstuffworks.com/cgi-bin/simpleform.cgi是一个C程序。它开始是作为一段C代码放置在名为simpleform.c的文件中:
使用以下命令对这段代码进行编译:
然后,将其放置在cgi-bin目录中。此程序只是收集表单发送的值并显示出来。例如,您可能会看到以下内容:
Name是表单中的文本输入字段的标识符(表单上的每个输入字段都应具有唯一的标识符),John+Smith是可能在表单上输入的典型姓名。请注意,“+”将替换空白字符。
通过本示例,您可以看出设置表单并将表单中的数据发送到CGI脚本中的基本过程是相当简单的。有几个细节需要注意:
- 表单上的每个输入字段应具有唯一的标识符。
- 表单需要使用GET或POST方法。使用GET方法的好处是,您可以在发送给脚本的URL中查看表单的值,从而使调试更简单。
- 由于对可以通过GET方法发送的字符数目存在一定的限制,因此对于大型表单,应优先使用POST方法。
- 使用GET方法发送的数据可以通过查看QUERY_STRING环境变量(通常使用 C 语言程序中的getenv函数和PERL中的$ENV工具读取)接收。使用POST方法发送的数据可以通过STDIN(使用C语言程序中的gets或PERL中的 ead)获取。
- 发送的数据会将所有字段串接在一个字符串中,并将替换许多字符,因此需要进行转换。例如,所有空白将替换为加号。
提到QUERY_STRING环境变量,有必要在此大致介绍一下环境变量。您可以在CGI 脚本中看到大量环境变量,其中包括:
- AUTH_TYPE
- CONTENT_LENGTH
- CONTENT_TYPE
- GATEWAY_INTERFACE
- HTTP_ACCEPT
- HTTP_USER_AGENT
- PATH_INFO
- PATH_TRANSLATED
- QUERY_STRING
- REMOTE_ADDR
- REMOTE_HOST
- REMOTE_IDENT
- REMOTE_USER
- REQUEST_METHOD
- SCRIPT_NAME
- SERVER_NAME
- SERVER_PORT
- SERVER_PROTOCOL
- SERVER_SOFTWARE
这些环境变量中隐藏了许多有用的信息,其中包括输入字符串的长度 (CONTENT_LENGTH)、使用的METHOD(GET 或 POST -- REQUEST_METHOD可让您清楚是在STDIN 中还是在QUERY_STRING中查找输入)、用户计算机的IP地址 (REMOTE_ADDR),等等。有关这些变量的完整说明,请参阅CGI环境变量。
The value entered was:Name=John+Smith
gcc simpleform.c -o simpleform.cgi
#include#include The value entered was:")int main() { printf("Content-type:text/htmlnn"); printf("n"); printf("n"); printf("
printf("%sn", getenv("QUERY_STRING"));
printf("n");
printf("n");
return 0;
}
A super-simple form
Enter Your Name:
http://www.lycos.com/cgi-bin/pursuit?matchmode=and andcat=lycosandquery
创建真实表单
一个真实的表单将包含各种输入区域,并需要在脚本中编写一些代码来撤消字符映射并分析出单个字符串。让我们先看看表单上的标准输入控件。这些控件包括:
- 单行文本输入
- 多行文本输入
- 选择列表
- 复选框
- 单选按钮
- 专用按钮 - 用于提交或清除表单
以下的一些示例演示了如何使用不同的控件标记:
单行编辑
“input”一词标识单行编辑区域。“name”字段为控件提供了一个用于 CGI 脚本的标识符,此标识符对于表单上的每个控件都应是唯一的。“size”字段指示表单上的输入区域的宽度(以字符为单位);“Maxlength”对输入区域内的最大字符数进行限制。“value”设置初始值。
Enter Name:
通常,输入区域的前面是一段静态文本,用于标识输入字段的用途。此处显示的是静态文本“Enter Name:”。
可以添加值“type=int”,以便将输入限制为整数值。默认情况下,值的类型为“text”,可接受任何字符。
多行编辑
多行编辑区域与输入区域类似。你可定义该控件的名称,并定义其在表单上的大小(以行和列为单位)。你在 标记之前输入的任何内容都将作为默认值出现在控件中。
复选框
复选框是类型设置为“checkbox”的特殊形式的输入区域。
如果选中复选框,则将返回值。
单选按钮
单选按钮与复选框类似,但它们可以组合在一起呈现:
Choose the search area:
Stocks Canadian Stocks Money Markets Mutual Funds
请注意,可以用 CHECKED 一词来标记默认的单选按钮。还请注意,同一组中的所有单选按钮的名称是相同的。
选择列表
选择列表使用户可以在许多选项中进行选择。选择列表的标记可让你在“size”字段中指定可见行的数目,并可让你指定所有选项的值。
Select an Option
MULTIPLE 一词将创建多选功能。
专用按钮
下列标记将创建两个专用按钮,一个按钮用于向服务器提交表单,另一个按钮用于重置表单:
示例:创建网页问卷
假设您要为某个网页创建一份简单的问卷。例如,您想要询问读者的姓名、性别、年龄和意见,然后在CGI脚本中进行处理。HTML表单可能存在于一个名为http://www.bowenwang.com.cn/survey.htm的文件中,形式如下:
BWW Survey Form
此表单引用的CGI脚本将接收四条不同的数据:提交表单的读者的姓名、年龄、性别和意见。脚本将对这四个值进行分析并处理所有字符转换。文件http://www.bowenwang.com.cn/survey.c用于创建脚本survey.cgi,其长度可能为100行。
关于CGI的一些知识
在这个关于CGI脚本的简明教程中,我们已了解到:
- CGI脚本是一个程序——通常为C语言程序或PERL脚本。
- 在大多数服务器上,CGI脚本位于一个名为cgi-bin的目录中。当浏览器请求脚本的URL时,将执行该脚本。
- 脚本发送给STDOUT的任何内容都将被发送给浏览器。首先发送字符串“Content-type: text/htmlnn”。然后,再发送其他内容;但是一般来说,将发送有效HTML文档的有效HTML标记。
- 通过创建HTML表单并使用其中的 ACTION指定脚本的URL,可将输入内容发送给脚本。
- 当脚本接收到表单中的数据后,需要分析出不同的字符串并转换所有修改过的字符。我们演示了一个可以执行这些任务的简单C语言程序。PERL的CGI库(参见下一页)使PERL脚本可以轻松转换。
评论
查看更多