Dynamically including ASP File Improved

Dynamically Including ASP Files: Enhancements

ASP itself does not support dynamic file inclusion. Current dynamic inclusion is achieved by merging the included file into the main file using FSO before execution. Below, the traditional inclusion method (e.g., <--#include file="filename.asp">) is referred to as "traditional reference," while dynamic file inclusion implemented via functions is referred to as "dynamic reference."

A common implementation is as follows:

Function include(filename)
    Dim re, content, fso, f, aspStart, aspEnd
    set fso = CreateObject("Scripting.FileSystemObject")
    set f = fso.OpenTextFile(server.mappath(filename))
    content = f.ReadAll
    f.close
    set f = nothing
    set fso = nothing
    set re = new RegExp
    re.pattern = "^/s*="
    aspEnd = 1
    aspStart = inStr(aspEnd, content, "<%") + 2
    do while aspStart > aspEnd + 1
        Response.write Mid(content, aspEnd, aspStart - aspEnd - 2)
        aspEnd = inStr(aspStart, content, "%>") + 2
        Execute(re.replace(Mid(content, aspStart, aspEnd - aspStart - 2), "Response.Write "))
        aspStart = inStr(aspEnd, content, "<%") + 2
    loop
    Response.write Mid(content, aspEnd)
    set re = nothing
End Function

Usage example: include("youinc.asp")

The above example is cited from http://www.blueidea.com/tech/program/2003/101.asp.

However, this function fails when the included file itself contains other included files. Based on the above function, I have developed the following improved function, which can handle cases where the included file contains traditional inclusion files.

Function includeconvert(oRegExp, strFilename, strBlock)
    Dim incStart, incEnd, match, oMatches, str, code
    'Extract the filename from the include section using the same method as extracting ASP code, and output the rest as is.
    code = ""
    incEnd = 1
    incStart = InStr(incEnd, strBlock, "<--#") + 3
    oRegExp.pattern = "(\w+)=""([^""]+)""" 'Matches file="filename.ext" or virtual="virtualname.ext", capturing type and filename as two substrings.
    Set oMatches = oRegExp.Execute(Mid(strBlock, incStart, incEnd - incStart - 3))
    Set match = oMatches(0) 'When there is only one match, this retrieves it, avoiding the need for For Each match In oMatches ... Next.
    code = code & include(Mid(strFilename, 1, InStrRev(strFilename, "/")) & match.SubMatches(1))
    'Mid(filename, 1, InStrRev(filename, "/")) extracts the path from the referenced subfile name if it has a path, appending it to the traditionally referenced filename in the subfile to find the correct file path. This is because the file path for dynamic references is relative to the main file.
    'To get the second captured substring, use SubMatches(1).
    incStart = InStr(incEnd, strBlock, "<!--#include ") + 13
    Loop
    str = Mid(strBlock, incEnd)
    str = Replace(str, """", """"") 'Replace single double quotes with two double quotes.
    str = Replace(str, VbCr, "")
    str = Replace(str, VbLf, "")
    str = Replace(str, VbCrLf, "")
    code = code & VbCrLf & "Response.Write """ & str & """"
    includeconvert = code
End Function

Function include(filename)
    Dim re, content, fso, f, aspStart, aspEnd, code
    Set fso = CreateObject("scripting.FileSystemObject")
    Set f = fso.OpenTextFile(Server.MapPath(filename))
    content = f.ReadAll
    f.close
    Set f = nothing
    Set fso = nothing

    code = ""
    aspEnd = 1
    aspStart = InStr(aspEnd, content, "<%") + 2
    Set re = new RegExp
    Do While aspStart > aspEnd + 1
        'Traditional references <!--#include are definitely outside ASP code blocks, so convert them first.
        code = code & includeconvert(re, filename, Mid(content, aspEnd, aspStart - aspEnd - 2))
        aspEnd = InStr(aspStart, content, "%>") + 2
        re.pattern = "^/s*=" 'This regex replaces <% = str %> with the standard <%Response.Write str %>.
        'Add a newline before ASP blocks to avoid errors caused by multiple Response.Write statements on the same line.
        code = code & VbCrLf & re.replace(Mid(content, aspStart, aspEnd - aspStart - 2), "Response.Write ")
        aspStart = InStr(aspEnd, content, "<%") + 2
    Loop
    code = code & includeconvert(re, filename, Mid(content, aspEnd))
    Set re = nothing
    include = code
End Function

For convenience, the above function ultimately returns the entire ASP code with the included files integrated. To use it, you need to execute it with Execute(include("file.asp")).

The above function has been tested successfully when the included file and the main file are in the same path. Further error handling for cases where the included file and the main file are in different paths has not been implemented due to time constraints. Feedback and improvements are welcome.


Original link: https://www.snowpeak.fun/cn/article/detail/dynamically_including_asp_file_improved/