利用服务器端的包含(ssi)语句(或者指令)能够做些什么呢?实际上不多,除非打算创建在web服务器上运行的可执行文件,并通过stdin和stdout函数访问isapi。这就意味能够用c、c++或其他语言(如delphi)等编写它们,但vb并不适合。此外,使用ssi指令能够做的事情可达到与在asp中实现同样好的效果。许多方法中,iis的ssi特性对使用这些特性的原有的web网站和web页面具有向下兼容性。 然而,可能有时会希望在站点上使用ssi而不是asp。在iis 5.0中,服务器端的包含指令能够比以前更加容易地集成到一个远程站点上的asp页,它们是有用的,特别是作为执行操作系统命令或原有的cgi应用程序的一种方式。后面将会非常详细地介绍可用的指令。 #include指令是这些指令之一,它已经与asp一起使用了一段时间了,同样也在ssi页中使用。事实上,这已经对那些不具备传统的web开发背景的asp开发人员带来了很多混乱。 4.2.1 不可思议的asp #include指令 在一个asp页中,可以使用#include指令把另一个文件的内容插入到当前的页面中: <!-- #include file=”/scripts/usefulbits.inc” --> 这条指令读取该文件的全部内容并插入到该页中,替代<!-- #include.. -->行。这是一种非常有用的插入html段落的技术,可反复使用。也常用该指令来插入代码段。例如,如果有一个包含几个脚本函数(或者只是单行脚本代码)的文件同时在几个页面中使用,则可以使用#include指令将其插入到需要它的每个页中。 通过把脚本和内容分开的方法,给页面提供了一个组成层次。这意味着如果对脚本进行了修改,在客户端再次打开该页面时,脚本的修改情况自动地反映到使用包含文件的每个页面中。包含文件也是一种插入服务器特定的信息的简单方法,所以把站点转移到另一个服务器不意味着必须编辑涉及原来服务器的所有页面(明显的例子是数据库连接字符串或指定一个完整的url或服务器名字的链接)。这可以极大地减少维护费用。 例如,可以把下面的内容作为一个包含文件,命名为connect.inc: <% strconnect = “server=myserver;database=mydb;driver={sql server};” _ & “uid=username;pwd=secretpassword” %> 然后可以在任何页中使用这个文件: <!-- #include file=”path_to_fileconnect.inc” --> <% … strtheconnectionstring = strconnect ‘from include file … %> 使用包含文件的另一种情况是有些内容需要按指定的时间间隔进行修改。例如,在wrox web deverloper站点上显示书目列表的网页,它包含了一个表,其中提供了所有的封面、书名和一些按钮,如图4-2所示: 这个表的html和文本保留在一个单独的文件中,该文件通过一条单独的#include语句包含在主页中。每次一本新书加入到该网页所基于的数据库中时,那个包含文本文件根据该数据库的情况重新创建,并作为一个文本文件写到磁盘上。 这个技术大大减少了在web服务器和数据库服务器上的工作量,对该站点的访问者实现较快地响应。 1. 包含文件和asp 在asp网页(即带有.asp文件扩展名的网页)中使用的#include指令不能像一条真正的ssi指令那样进行处理,它仅是一条asp能够识别并进行语法分析的特别指令。ssinc.dll直接用于执行ssi #include指令。然而这个由相应文件的内容替代#include指令的页面由asp解释。 这意味着asp对#include指令所进行的操作不实施控制。例如,可以试验以下代码: <% ‘this will *not* work strincludeurl = request.form(“filename”) %> … <!-- #include file=”<% = strincludeurl %>” --> ssinc.dll将查找名为<% = strincludeurl %>的文件,并且不可能找到,因此这段代码不会工作。 2. 包含文件的安全性 如果没有包含可执行脚本,在web服务器上的asp网页不能通过iis的web服务程序下载到一个客户端。但是,有人已经发现了偶然的安全性漏洞,比如著名的$data问题,所有在ntfs格式化的磁盘上保留web内容的web服务器都存在相应的问题。在iis 5.0中这个问题已经得到解决。 $data问题的出现是因为在windows ntfs驱动器上的所有文件都有一个缺省的“值”,即是该文件的内容,并且通过文件名加后缀“::$data”来指示。将其增加到一个asp网页的url的末尾将打乱iis中的脚本映射关系,且允许服务器不对其中包含的脚本进行处理而不载该页面。对iis 4.0和早期版本,有一个方法可以解决这个问题,或者可以只是增加几个映射来强制iis正常地执行该网页:即增加对“.asp::$data”和“.asa::$data”的映射,两者都指向asp.dll文件。 包含文件的扩展各一般是.inc或.txt。如果在站点上发现一个包含文件的路径和文件名,可通过把包含文件的url键入到浏览器的地址栏中,下载该包含文件,而不会把其作为asp网页的一部分来执行。为防止出现这样情况,特别是在文件包含有敏感信息(诸如一个数据库链接字符串)的情况下,可能希望包含文件的扩展名为.asp。在这种情况下,如果试图下载一个包含文件,它将首先被传送到asp,asp将执行该文件中的所有脚本代码,并只发送出结果。如在包含文件中定义的一个链接字符串如下: <% strconnect = “server=myserver;database=mydb;driver={sql server};” _ & “uid=username;pwd=secretpassword” response.write vbcrlf ‘output a carriage return character %> 客户端只能接受到单个回车符而不是脚本代码,因为该文件已经被asp在服务器上执行了。如果不包含回车符,浏览器将挂起并等待一个响应(这并不是我们的问题,因为我们确实不打算允许用户直接访问这个文件)。 iis 5.0和windows的访问控制列表 在iis 5.0中,microsoft已经改变了web服务器和操作系统访问服务器端包含文件的方法。 在iis早期版本中,当ssinc.dll载入一个虚拟url(即使用virtual = “filename”而不是file = “filename”)定位的一个包含文件时,将绕过windows本身的安全性检查并忽略该文件及所存储的目录上的任何安全性设置。现在,在iis 5.0中,运行当前asp或ssi页面的帐号必须与对该文件和目录在windows访问控制列表(acl)中设置的权限相一致。如果不一致,该ssi指令运行将失败。 4.2.2 服务器端包含指令概要 除了已经讨论过的#include语句以外,还有iis支持的五条服务器端包含指令(记住,除#include以外,这些语句不能在asp网页中执行)。这些服务器端包含指令及说明如表4-1所示: 表4-1 服务器端包含指令及说明 指 令 说 明 #include 把一个指定文件的内容插入到将被发送给客户端的响应流中并代替该指令。例如: <!-- #include file = “usefulbits.inc” --> 这条指令把名为usefulbits.inc文件的内容插入到响应中。这个文件可以由一个相对或全路径与文件名的组合描述,如file=”..scriptsmyscr.inc”。通过使用virtual属性,可使用一个虚拟的相对或绝对路径来描述它,例如: <!-- #include virtual=”/mysite/ussefulbits.inc” --> <!-- #include virtual=”../../thisbit/usefulbits.inc” --> #config 说明在其后的指令中将用于数据、时间和文件大小以及返回给客户端的一般性的ssi错误信息的文本的格式。例如: <!-- #config errmsg=”ssi processing error” --> 设置ssi错误信息内容为'ssi processing error'。 <!-- #config timefmt=”%a,%b %d %y %h:%m:%s” --> 设置由其后的ssi指令返回的日期和时间的格式。这个例子设置一个格式风格:saturday, august 14 1999 10:34:50。可以用于格式字符串的标志的列表在附录c中给出。 <!-- #config sizefmt=”bytes” --> 设置由其后的iis指令返回的文件大小的单位。这个例子设置单位为字节。对sizefmt可供选择的值是“abbrev”,指明计算值将千字节(kb)返回文件的大小 #echo 把一个http环境变量的值插入到发送给客户端的响应流中并替换该指令。例如: <!-- #echo var=”server_name” --> 写出正在执行指令到该网页的服务器的名字 #exec 执行一个程序或一个服务器外壳命令,例如: <!-- #exec cgi=”/scripts/myapp.exe?value1=this&value2=that --> 执行名为myapp.exe的cgi程序,允许传递查询字符串,程序在单独内存中执行。 <!-- #exec cmd=”cmd.exe/c iisreset/stop” --> 启动特定操作系统命令解释器(cmd.exe)并执行命令iisreset/stop。/c表示当命令结束时,命令解释器也结束。使用cmd要添加下列注册表项: hkey_local_machine/system/currentcontrolset/services/w3svc /parameters/ssienablecmddirective 设置值为1,并重启动www服务,就允许cmd标志用于#exec指令中。值为0,则禁止使用,并防止未验证的使用 #flastmod 把一个指定的文件上一次修改的日期和时间插入到发送给客户端的响应流中并代替该指令。 例如: <!-- #flastmod file=”default.asp” --> 像#include指令一样,也可以使用虚拟路径对该文件进行定义,如: virtual=”/mysite/usefulbits.inc” 或 virtual=”../thisbit/usefulbits.inc” #fsize 把一个指定的文件的大小插入到发送给客户端的响应流中并代替该指令。例如: <!-- #fsize file=”default.asp” --> 象#include指令一样,也可以使用虚拟路径对该文件进行定义,如: virtual=”/mysite/usefulbits.inc” 或 virtual=”../thisbit/usefulbits.inc” 1. iisreset实用程序 iisreset.exe是由iis 5.0提供的一个新的实用程序。作为一个命令行的实用程序,如果用于执行该实用程序的帐号具有管理员权限,它对于控制运行在本地或一个网络计算机上的internet联网服务器是非常有用的。它可用于以正确的顺序停止或启动所有的服务、显示服务的状态、重新引导服务器以及允许或禁止服务的管理。例如: iisreset /restart /timeout:30 /rebootonerror 这将以正确的顺序停止和重新启动所有internet服务。如果一种服务在指定的超时周期(30秒)内未能停止或重新启动,服务器将重新引导。可以用在cmd类型的#echo ssi指令中的一些开关,使该页面不能进行匿名访问并且要求用户提供在目标服务器上具有管理员权限的有效帐号的详细情况。这个实用程序的完整描述和可用的命令开关在附录c中。 2. net stop和net start命令 如果用来执行实用程序net.exe的帐号具有管理员权限,它可以用来管理服务器上运行的任何服务(即可以是本地的也可以是来自其他的一个计算机)。虽然不提倡把该程序用于internet服务(如www或ftp服务),但其停止和启动其他服务的功能是非常有用的。事实上,net命令同样可以用于一系列的其他网络相关命令。 语法是: net [start | stop] service_name 例如,可以用命令net stop cisvc和net start cisvc来停止和启动miscrosoft indexing service。可以用cmd类型的#echo ssi指令使该页面不能进行匿名访问并要求用户提供在目标服务器上的具有管理员权限的有效帐号的详细情况。稍后将看到一个这样的例子。 在windows 2000帮助文件中可以找到net命令的所有选项和开关的一个完整列表。从start菜单中选择help项,在help窗口的index页查找“netcommands”。 4.2.3 服务器端包含指令的例子 本节提供了一些示例页面,可以用来对各种服务器端包含语句进行实验。打开示例网页的子目录chapter04,显示“ssi directives and the asp server object”主页(即子目录chapter04中的default.asp),如图4-3所示: 本书的所有示例都可以从我们的web网站下载。读者将在示例的子目录chapter04中发现本章其余部分的所有示例页面。 1. 使用ssi/cgi处理指令 单击链接进入“server-side include and cgi statements”页面,这将打开ssi_cgi.stm页面。需要注意的是该页面的文件扩展名为.stm,表明这不是一个asp网页。该页面使用了前面已经讨论过的除#exec指令(稍后将看到)以外的所有ssi指令,且显示指令的使用方法和结果,如图4-4所示: (1)#include指令 该页的开始部分“include files with ssi”,显示名为intro.inc的另一个单独文件的内容。下面是该文件的全部内容: 注意我们必须使用html条目“<”和“>”来显示网页中的尖括号。如果不这样做,它们就不能被当作注解元素部分看待,并引起其中的指令被执行。 在主ssi_cgi.stm页面中,把这个文件插入到该页中的代码是很简单的: <!-- #include file=”intro.inc” --> (2)#config、#fsize和#flastmod指令 网页下一部分显示了与该页面在相同的目录中的文件default.asp的大小和最后被修改的时间。这里三次使用了#config指令: · 一次是设置ssi错误信息。 · 一次是设置日期和时间的格式。 · 一次是设置文件大小计算的格式。 使用#fsize和#fiastmod指令把值插入到该网页中: <p><div class="subhead">ssi statements</div> <!-- #config errmsg="ssi processing error" --> (sets error message in case of ssi error)<br> <!-- #config errmsg="ssi processing error" --><p> details of file 'default.asp':<br> <!-- #config sizefmt="bytes" --> (sets fsize to return size in bytes)<br> <!-- #config sizefmt="bytes" --> <!-- #fsize file="default.asp" --> returns: <b><!-- #fsize file="default.asp" --> bytes</b><br> <!-- #config timefmt="%a, %b %d %y %h:%m:%s" --> (sets format for date/time results)<br> <!-- #config timefmt="%a, %b %d %y %h:%m:%s" --> <!-- #flastmod file="default.asp" --> returns: <b><!-- #flastmod file="default.asp" --></b><p> (3)#echo 指令 该页的最后部分(在屏幕上只能看到一部分)显示可以使用#echo指令访问的所有http报头的内容。每一行的代码都是相同的,仅仅是var属性值有变化。附录g中给出了var属性的所有容许值的一个完整列表。 <div class="subhead">http variables</div> <!-- #echo var="auth_type" --> returns: <b><!-- #echo var="auth_type" --></b><br> <!-- #echo var="auth_password" --> returns: <b><!-- #echo var="auth_password" --></b><br> … etc … 2. 使用#exec指令 #exec指令与其他的ssi指令相比使用起来困难一些,正因为如此,将其独立地放到了另一个页面上。可以从“asp server object and ssi directives”主菜单上访问启动页面。 在该页面上,选择“using the #echo server-side include directive”链接。这个操作打开“the ssi #exec directive”页面,如图4-5所示: 这是一个asp网页ssi_exec.asp。两个按钮用来打开.stm页面,该页面执行其中使用#exec指令所描述的动作。 (1) 在服务器上运行这个示例 在ssi #exec指令示例能够在服务器上工作之前,必须对一些配置进行修改。首先,需要在web服务器的注册表中创建ssienablecmddirective项(类型dword),位置在下面的键名下: hkey_local_machinesystemcurrentcontrolsetservicesw3svcparameters 然后设置该值为1,如图4-6所示: 这样就允许#exec指令与cmd属性一起使用。 其次,必须对包含使用#exec指令的.stm文件的目录禁止匿名访问,客户端将被强制提供帐号的详细情况,该帐号应是一个具有管理员级权限帐号。这也是net命令正常工作的要求。 激活internet services manager应用程序,并选择包含使用#exec指令的.stm文件的目录(在示例中,这些文件是exec目录下的start_cisvc.stm和stop_cisvc.stm)。然后打开该目录的properties对话框。在directory security选项卡中单击anonymous access and authentication control区域中的edit按钮,打开 authentication methods对话框,如图4-7所示: 这个对话框不选中anonymous access复选框。如果不使用internet explorer访问该页面,打开basic authentication选项以允许非ie浏览器通过提交用户名/口令访问该页面。设置时,会出现一个有关安全的警告,单击yes。现在浏览器将被强制出示合适的帐号和身份证明,因为不能匿名访问该网页。 为了能看到启动和终止服务的结果,打开“services mmc插件”,终止indexing service,如图4-8所示: (2) 启动和终止indexing service 单击示例web网页上的按钮,启动microsoft indexing service。 这个服务的短名称为cisvc,它通常称为microsoft index server,名称中的“ci”字符,实际上代表“content indexer”。 出现提示时,输入在web服务器上的具有管理员权限的一个帐号的用户名和口令。当该页面(start_cisvc.stm)打开时,你将感觉到一定的延迟,这是因为#exec指令载入一个窗口命令解释器(cmd.exe)的实例,然后执行net start命令。一旦服务启动(或者如果已经在运行),将显示该页面的其余部分,如图4-9所示: 这个页面的代码十分简单。可以看到#exec指令带有cmd属性,它设置为“cmd.exe /c net start cisvc”。窗体包含有重新回到前一页面的submit按钮: <p>processing the ssi directive:</p> <p><b><!-- #exec cmd="cmd.exe /c net stop cisvc" --></b></p> <!-- #exec cmd="cmd.exe /c net stop cisvc" --> <form action="../ssi_exec.asp"> <input type="submit" name="cmdok" value=" "> return to the previous page<p> </form> 从前一页面可以打开其他的.stm网页,如stop_cisvc.stm用来再次终止该服务,不同之处仅在于使用了net stop命令而不是net start命令。 … <!-- #exec cmd=”cmd.exe /c net stop cisvc” --> …