浅析Apache中SSI和CGI的设定方法
时间:2006-09-05 来源:cnscn2008
由于Apache具有相当高的可移植性,它支持超过30种操作系统,包括Unix、Windows 及Darwin等系统,所以目前在网络上已注册的网域里大部份是使用Apache网页服务器。目前ApacheSoftware Foundation 正致力于发展现在已进入alpha测试阶段的Apache2.0。在这里,我和大家探讨如何修改服务器选项让服务器能提供简单的动态网页内容,也就是支持 CGI程序及 Server-Side Include(SSI)程序。
1、准备工作
首先,我假设你已经安装好Apache而且你的Apache能提供静态网页供浏览。Apache的安装会自动附上静态的HTML测试页,也就是说如果能看到那测试页,就代表你的Apache能正常运作了。基本安装下的Apache仅能提供静态的HTML网页。然而,你可以通过使用模块(modules)来提升它的功能。在原始的设定下,Apache的编译会包含mod_include 及 moc_cgi 这两个模块。你可以在bin子目录下执行./httpd -l来查看你的Apache是否装有这两个模块。执行的输出会是一长串Apache现在安装的所有模块。如果mod_include及moc_cgi 这两个模块不在清单里,你必须重新编译服务器。重新编译时,确定依照如何含括 mod_include、moc_cgi 模块的说明。此外你还必需有提供实时网页的Server-Side Includes(相关资料网址:http://www.oreilly.com/catalog/apache/excerpt/ch10.html)。有了 server-side includes (SSI)支持,你就能制作出实时的动态网页。接下来,我先从服务器的SSI支持设定开始,然后进入CGI的编写。
2、Apache的设定
首先你必须先找到Apache这个设定文件。Apache的原始安装目录在 Unix下是/usr/local/apache,在Windows下则是 c:\Program Files\Apache。接着在conf子目录下你会找到httpd.conf 文件。这就是Apache的设定档。这个设定文件是个纯文字文件,所以你可以使用一般的文字编辑器,如vi或Notepad 等,来编辑。首先要注意的是在这个设定档里有些行的起始文字是#符号,这表示这行的文字全为批注。适当地在你的设定档内做批注是个好习惯,因为那帮你记得你曾做了哪些设定以及为什么。
3、执行 SSI 程序
开启设定文件并寻找以下这些文字:
#
# To use server-parsedHTMLfiles
#
#AddType text/html .shtml
#AddHandler server-parsed .shtml
删除AddType及AddHandler这两行指令前的#符号。AddType指令会要求服务器在传回任何附属档名为.shtml的网页时,以 text或HTML做为传回文件的内容格式。AddHandler 则是用来指示服务器将文件内容送交给mod_include 处理。之后,mod_include 就会判断该如何响应这样的文件。接下来,寻找以下文字:
;
在这行文字及对应的; 间会有一行选项行(options line)。原始的设定是:
Options Indexes FollowSymLinks MultiViews
在这行尾端加上Includes ,结果看起来会是这样:
Options Indexes FollowSymLinks MultiViews Includes
这是要求Apache在htdocs子目录里执行 server-side includes 程序。为了让这些修改生效,我们必须重新启动服务器。在 Unix 下重新激活,执行"kill -HUP `cat /usr/local/apache/logs/httpd.pid`"。在 Windows 下,执行"Apache-k restart"。现在我们来试试刚才的设定结果。在/usr/local/apache/htdocs 目录里新增一个文件 test.shtml。这个文件必须要包含以下程序代码:
[an error occurred while processing this directive]; The file hello.txt is [an error occurred while processing this directive]; long and it was last modified on [an error occurred while processing this directive];
这段 SSI 程序会去读取一个称为 hello.txt 文件,并将该文件的大小以及最近一次的修改日期输出到网页上。显然的,我们还必须在 htdocs 目录下新增这个hello.txt 文件。在我的hello.txt 文件里只有一行文字:HOW ARE YOU!。完成新增这些文件后,打开你惯用的浏览器并开启http://localhost/test.shtml网页。如果你服务器的安装并不是通过root用户,你可能必须改为开启http://localhost:8080/test.shtml。之后将得到如下结果:
HOW ARE YOU! The file hello.txt is 1k bytes long and it was last modified on Wednesday, 02-Aug-2000 20:18:28 PDT
另外一种可以激活支持SSI程序的方法称为XbitHack设定(相关资料网址:http://www.apache.org/docs/mod/mod_include.html#xbithack )。这个方法的由来是当你将文本文件的使用者可执行位(user-executable bit)设为可执行状态后,Apache会将那些文件视为 SSI 程序文件。
要激活这样的功能必须将以下指令(directive)放在所有目录的 .htaccess 文件里:XbitHack status on (or full) status 的值可以设为on 、off 或是full。on 的设定会强制服务器将所有使用者可执行的文件视为SSI项。Off则使服务器完全忽略使用者可执行的设定状态。若是设定为Full,服务器会视所有使用者可执行档为SSI项,同时也会检查组可执行(group-executable bit)。如果组可执行项设定为可执行时,传回header的last modified time的值就会被设定为该文件最近一次被修改的时间。这样的设定可以让客户端的浏览器及代理服务器(proxy)进行缓存(caching)。不过在使用这样的功能时必须要小心。例如说,如果你的网页有提供轮替式广告看板你就不会想要设定群组可执行位为开启的状态,因为那么做会让第一个下载的广告被快取起来,导致使用者再也看不到其它页的广告。
4、执行CGI程序
在Apache原始安装里,cgi-bin子目录下附有两组CGI程序,test-cgi 以及printenv,只不过这两组程序有潜在的安全漏洞。但是由于我们只是要做设定测试,并且我们不会将这样的原始安装设定直接放在主运行服务器(live server),所以我们还是会激活其中一组CGI程序,看看Apache当初是如何被设定来执行这组程序。最后我们会自己撰写一支简单的CGI程序。
首先,要确定这组程序是能执行的。进入cgi-bin子目录,确定程序文件被设定为使用者(服务器执行时使用者)可执行以及使用组(服务器执行时使用组)可执行。对 Windows系统来说,这一步应该是非必要的。接着,对服务器要求这样的内容:
http://localhost:8080/cgi-bin/test-cgi
注意:只有在通过非root使用者进行服务器安装的情况下才需要指定8080端口(port)。这支Apache内建的test-cgi程序会列出 CGI程序会存取的变量值。激活CGI支持是设定在httpd.conf设定文件内的ScriptAlias 指令区段。这个指令区段的原始设定值是:
ScriptAlias /cgi-bin/ "/usr/local/apache/cgi-bin/"
这行指令是告诉Apache如果要求的网页路径是以cgi-bin为起始,这些文件可在/usr/local/apache/cgi-bin/ 目录下找得到。这行指令同时也告诉Apache要在这个目录下执行文件。在下面我准备了一个会输出"How are you!"的简单CGI程序。我将它命名为 how.sh。
#!/bin/sh
echo "Content-type: text/html"
echo
echo "How are you!"
修改这个文件的权限使其成为可执行文件并且向你的服务器提出以下的要求:
http://localhost:8080/cgi-bin/how.sh
虽然这组CGI是采用shell script来编写,其实它可以用任何适用于该系统的语言来撰写。至于关于CGI程序的撰写如果有机会我会和大家作更深入的探讨。
结论:
Apache支持的所有SSI 指令可以在Apachedocumentation 里找到,Apache所有的功能都可以通过设定文件(config file)进行调试。在这里我所介绍的仅只是设定文件相关知识的皮毛。设定文件的原始设定有着非常详尽的说明文件,而且每一个系统版本都附有核心模块及标准模块的说明文件,如果你花些时间在这些文件里摸索,你会找到任何你想要的功能。
(http://www.fanqiang.com)
====================================================================
本文针对服务器端包含(Server Side Includes),通常简称为SSI,讨论如何配置服务器以允许SSI,并介绍一些对现有HTML页面增加动态内容的基本SSI技术。
本文后部将讨论用SSI做一些应该算比较高级的事情,比如SSI指令中的条件语句。
什么是SSI?
SSI (Server Side Includes)是HTML页面中的指令,在页面被提供时由服务器进行运算,以对现有HTML页面增加动态生成的内容,而无须通过CGI程序提供其整个页面,或者使用其他动态技术。
对什么时候用SSI,而什么时候用某些程序生成整个页面的权衡,取决于页面中有多少内容是静态,有多少内容需要在每次页面被提供时重新计算。SSI是一种增加小段信息的好方法,诸如当前时间。如果你的页面大部分是在被提供时生成的,那就要另找方案了。
配置服务器以允许SSI
要使服务器允许SSI,必须在httpd.conf文件或.htaccess文件中有如下配置:
Options +Includes
告诉服务器以允许解析文件中的SSI指令。注意,在多数配置中,多个Options指令会互相覆盖,所以,可能必须对需要SSI的特定目录使用Options,以确保位于最后并起作用。
并不是所有文件中的SSI指令都会被解析,所以,必须告诉Apache应该解析哪些文件。有两种方法,使Apache解析带有特定文件后缀的任何文件,比如.shtml, 配置如下:
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
这种方法的缺点之一是,为了使文件名有.shtml后缀从而执行其中的指令,可能需要改变加入SSI指令的现有的文件,以及所有指向此页面的连接。
另一种方法是,使用XBitHack指令:
XBitHack on
XBitHack告诉Apache解析有执行权限的文件中的SSI指令。如此,只要用chmod使文件变成可执行的,就可以对现有的页面增加SSI指令。
chmod +x pagename.html
这里简要说明一点:偶然会有人向你推荐,无须用带.shtml的文件名,使Apache解析所有.html文件的SSI就可以了。那些人可能没听说过XBitHack。要知道,这样做会使Apache在发送文件到客户端之前通读此文件,即使其中并没有任何SSI指令,从而对速度有不小影响,所以这并不是好办法。
当然,在Windows上,没有对应的执行权限可以设置,但还是应该谨慎选择。
按缺省配置,Apache不会为SSI页面发送最后修改日期或者内容长度的HTTP头,因为这些值对动态页面来说难以计算。这样会阻止页面被缓冲,导致客户端性能有能够感觉到的下降。有两种解决方法:
- 使用XBitHack Full配置。它告诉Apache判断最后修改日期时,只查看被请求的文件本身的日期,而忽略其中包含的任何文件的修改日期。
- 使用mod_expires提供的指令为文件设置一个明确的过期时间,并告诉浏览器和代理这个文件可以被缓冲。
基本SSI指令
SSI指令有如下语法:
<!--#element attribute=value attribute=value ... -->
其格式很象HTML的注释,因此如果没有正确配置SSI,它会被浏览器忽略,但在HTML代码中仍然可见。而如果正确配置了SSI,则此指令会被其结果替代。
其中的元素可以有许多,我们会在下一个版本的文档中讨论其中的大多数,而在这里,仅举几个SSI的例子。
今天的日期
<!--#echo var="DATE_LOCAL" -->
echo元素仅仅是反馈一个变量的值。标准变量有许多,其中包含对CGI程序有效的所有的环境变量。另外,你也可以用set元素定义你的专用变量。
如果你不喜欢日期的这种打印格式,可以用config元素的timefmt属性,改变其格式。
<!--#config timefmt="%A %B %d, %Y" -->
Today is <!--#echo var="DATE_LOCAL" -->
文件的修改日期
This document last modified <!--#flastmod file="index.html" -->
这个元素也是使用timefmt的格式配置。
包含一个CGI程序的输出
这是SSI的很常见的一个用途-包含一个CGI程序的输出,比如人人喜欢的``点击计数器''。
<!--#include virtual="/cgi-bin/counter.pl" -->
附加的例子
以下是一些对HTML文档使用SSI的特殊例子。
文档是什么时候被修改的?
此前,我们提到过可以用SSI通知用户文档是什么时候被修改的,但是其具体实施方法却基本上是个问题。以下代码,放在HTML文档中,会在页面中产生一个时间戳,当然,首先,你必须按上述方法使SSI有效。
<!--#config timefmt="%A %B %d, %Y" -->
This file last modified <!--#flastmod file="ssi.shtml" -->
不用说,你应该用你实际引用的文件名来替换ssi.shtml,所以,如果你想简单地在任何文件中粘贴一段通用代码以达到这个目的,这个方法就并不方便,如此,就会用到LAST_MODIFIED变量:
<!--#config timefmt="%D" -->
This file last modified <!--#echo var="LAST_MODIFIED" -->
有关timefmt格式的细节,可以到搜索站点查找strftime,其语法是相同的。
包含一个标准注脚
如果你管理一个拥有许多页面的站点,你会发现对所有页面做改动是很痛苦的,尤其是在试图对所有页面维持某种标准观感的时候。
使用包含一个页眉和/或注脚的方法,可以减轻修改的负担。你只要制作一个注脚文件,并用includeSSI命令包含到每个页面,即可。include元素能按file属性或者virtual属性判断应该包含的文件。file属性是一个相对于当前目录的文件路径,即不能是一个绝对文件路径(以/开头)。virtual属性可能更有用,它是一个相对于被提供文档的URL,可以以/开头,但必须与被提供文档在同一个服务器。
<!--#include virtual="/footer.html" -->
SSI指令和注脚文件相结合使用是很有用的,比如在注脚文件中使用LAST_MODIFIED指令。SSI指令可以出现在包含文件中,而include可以嵌套,即一个包含文件可以包含另一个。
其他的设置
config除了能设置时间格式,还有两种用途。
当SSI指令发生错误时,会产生如下消息:
[an error occurred while processing this directive]
为了改变消息的形式,可以使用config元素的errmsg属性:
<!--#config errmsg="[It appears that you don't know how to use SSI]" -->
当然,最终用户永远也不会看到这个消息,因为在网站投入运行之前你已经把这些问题都解决了(是吗?)。
还可以使用config的sizefmt属性设置返回的文件大小的格式,或者是以字节为单位,或者是以Kb或Mb为单位的简写。
执行命令
我期望未来几个月内能再写一篇小型CGI程序使用SSI的文章,而这里,仅介绍exec的使用。SSI确实可以利用shell(/bin/sh,精确地说,还可以是Win32中的DOS shell)来执行命令。下例产生一个目录列表:
<pre>
<!--#exec cmd="ls" -->
</pre>
在Windows中:
<pre>
<!--#exec cmd="dir" -->
</pre>
你可能会发现,在Windows中这个指令的结果有些奇怪,dir的输出中包含有字串``<dir>'',它会使浏览器产生混淆。
注意,这个功能是极度危险的,因为它会执行任何包含在exec标记中的命令。如果用户有可能修改你的网页内容,比如“留言本”,那么你一定要关闭这个功能。在Options指令中加上IncludesNOEXEC参数,以关闭exec功能,同时又保留SSI。
高级SSI技术
除了分离内容,Apache SSI还可以设置用以比较和条件表达式的变量。
警告
本文中讨论的大多数功能仅在Apache 1.2及更新版本中有效。如果你运行的不是Apache 1.2及更新版本,请立刻或者尽快升级,现在就动手,我们会等你弄好了再继续往下讲。
设置变量
使用set指令可以设置变量以备后用,其语法是:
<!--#set var="name" value="Rich" -->
除了设置文字变量以外,还可以设置其他任何变量,比如环境变量和此前提到过的一些变量(如LAST_MODIFIED),作为你的专用变量。在变量名前面缀以$,表示它是一个变量,而不是一个文字性字串。
<!--#set var="modified" value="$LAST_MODIFIED" -->
在文字性字串中使用$,必须使用转义符号\
<!--#set var="cost" value="\$100" -->
最后,如果要在较长的字串中,可以用花括号把变量名括起来,以免变量名与其他字符之间冲突而产生混淆(要对这种情况举例说明有点难度,但还是希望你能领会)。
<!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" -->
条件表达式
有了变量,就可以设置和比较它们的值以表示条件,SSI也因此成为一种简洁的编程语言。mod_include提供了if, elif, else和endif等结构以构造条件语句,从而对一个实在的页面高效地生成多个逻辑的页面。
条件的结构如下:
<!--#if expr="test_condition" -->
<!--#elif expr="test_condition" -->
<!--#else -->
<!--#endif -->
test_condition可以是任何逻辑比较 - 可以是一个值和另一个值比较,也可以是测试一个特定的值是否为“真”(一个给定的字串如果非空则为真)。完整的比较操作符列表,见mod_include。以下是可能会用到的一些例子。
在配置文件中,可以这样设置:
BrowserMatchNoCase macintosh Mac
BrowserMatchNoCase MSIE InternetExplorer
如果客户端在Macintosh上运行Internet Explorer,则上例设置环境变量``Mac'' 和``InternetExplorer''为真。
然后,在允许SSI的文档中,可以这样设置:
<!--#if expr="${Mac} && ${InternetExplorer}" -->
Apologetic text goes here
<!--#else -->
Cool JavaScript code goes here
<!--#endif -->
我一点也不反对在Mac上运行IE - 只是上个星期我花了好几个小时试图在Mac上的IE中使用JavaScript,而它在其他地方都能正常运作,以上只是一个临时的妥协方案。
任何其他变量(或者是你定义的,或者是标准的环境变量)都可以用于条件语句。利用Apache的SetEnvIf以及其他相关指令设置环境变量,此功能可以很好地实现动态页面而无须借助于CGI。
总结
SSI固然不能替代CGI或者其他动态页面技术,但它是在页面中插入众多小型的动态片段的优秀方法,而无须大量额外的操作。