Forum Moderators: open

Message Too Old, No Replies

Dynamic Includes in ASP

Error Trapping Server.Execute?

         

rogerd

8:46 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



A site I'm working on has a large number of products, and, for various groups of products I'd like to insert some HTML when that page is called.

A true "dynamic include" isn't possible because SSI is processed before the ASP. I.e., a statement like,

<!-- #include file="<%= GroupName %>.asp" -->

simply won't work.

I've found that doing a Server.Execute will work, e.g.,

FileName = GroupName & ".asp"
Server.Execute(FileName)

will insert the appropriate file into the page.

This, however, errors out ungracefully if a file hasn't been set up for a particular group.

Is there a way to trap this kind of error, or is there a better way to do this?

txbakers

9:26 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



This is what I did and seemed to work. It only brought in the include for the appropriate action:

<% if (typ == "B") { %>
<!-- #include file="fin/billStudent.asp" -->
<% } else if (typ=="E") { %>
<!-- #include file="fin/enterBill.asp" -->
<% } else if (typ == "M") { %>
<!-- #include file="fin/misctrans.asp" -->
<% } else if (typ == "R") { %>
<!-- #include file="fin/recMoney.asp" -->
<% } else if (typ == "P") { %>
<!-- #include file="fin/payBill.asp" -->
<% } else if (typ == "D") { %>
<!-- #include file="fin/deposit.asp" -->
<% } %>
<% // end make transaction %>

GaryK

9:43 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



txbakers, that might work for Apache (which is what the syntax looks like it's for) but it won't work properly in VBScript which is what rogerd seems to be working in. By not working properly what I mean is it will only show the one include file that matches but since includes are processed before the VBScript every single asp file in the list gets executed!

For these sorts of purposes I have a general purpose function I call that uses the FileSystemObject to open and display the contents of the include file I want. Not exactly a true include but it works. Plus with error handling you can check for the existence of the include file and not include it if it doesn't exist thus avoiding any error messages being sent to the client. :)

txbakers

9:46 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



No, I'm on IIS.

When I view the source it only brings in the one include that is requested. I'm not sure if everything is processed, but if it is, it's not that big a deal.

The end result sent to the user is only the once include requested.

GaryK

9:52 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Wow, I've been using ASP/VBScript forever and I didn't know syntax like that was valid. I'll have to do some experimenting and see what's up. Maybe I will have found a better way than my way which always makes for a good day for me. ;)

defanjos

10:10 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



A way to do it, is to do the "if" statements on the include file itself, for example:

INCLUDE FILE (test.asp):

<%if group= "1" then %>
<p>1</p>
<%elseif group= "2" then %>
<p>2</p>
<%elseif group= "3" then %>
<p>3</p>
<%end if %>

PAGE:
<%
dim group
group="1"
'group can be set dynamically according to the DB call
%>
<html>
<head>
</head>
<body>
<!--#include file="test.asp" -->
</body>
</html>

Of course, "group" has to be set before the include file.

With this solution you only have one include file, and only the desired part of it will be included on the page.

GaryK

10:22 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



txbakers, I tried every variation on your code and could not get it to work. The double equal signs throw an error. So does the use of open and close curly brackets to take the place of "then" and "end if." On the bright side, I did learn you can use // for comments instead of the standard apostrophe.

defanjos, your solution seems very elegant. I'll play around with it later on after supper. The only drawback I can see is you could wind up with a huge test.asp file.

defanjos

10:55 pm on Dec 27, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The only drawback I can see is you could wind up with a huge test.asp file.

Very true, it works best with not too many groups.

If there are too many groups, probably getting the info from a DB will be the best bet.

webdevsf

11:00 pm on Dec 27, 2003 (gmt 0)

10+ Year Member



Put something like this:


on error resume next
Server.Execute NonExistentPage


if err = NonExistentPageErrorCode then response.write NonExistentPage & " does not exist"


on error goto 0

WDSF

uncle_bob

12:00 am on Dec 28, 2003 (gmt 0)

10+ Year Member



rogerd - what you are trying to do is one of the reasons we recently migrated our IIS/asp site to IIS/php . Dynamic includes in php are trivial.

For the server.execute(filename) method, why not just check the file exists first using the scripting.filesystemobject, rather than waiting for an error to occur.

webdevsf

12:04 am on Dec 28, 2003 (gmt 0)

10+ Year Member



The reason not to use the filesystemobject is that it is slow, a potential security violation, and its the type of problem that will only occur in .1% of the cases (if it is occurring more than that, you have other problems :) .

How is server.execute non-trivial?

uncle_bob

1:04 am on Dec 28, 2003 (gmt 0)

10+ Year Member



The problem we had with server.execute, is that it executes, rather than includes, so variables set in the outer asp are not available in the inner executed asp.
For a while we even had .stm's #including .asp's with parameters passed on the asp querystring. Not pretty.

txbakers

2:00 am on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



txbakers, I tried every variation on your code and could not get it to work. The double equal signs throw an error. So does the use of open and close curly brackets to take the place of "then" and "end if." On the bright side, I did learn you can use // for comments instead of the standard apostrophe.

I'm using JScript instead of VBScript for my coding.....

That's the syntax for that scripting language.

GaryK

3:41 am on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks for clearing that up for me. I've never actually used JScript with ASP even though I did know you can. :)

rogerd

4:47 am on Dec 28, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Sorry to be away from the discussion for a bit. The number of groups is high, say, 100+, so enumerating the choices isn't a great idea. The whole piece of third party software is written in ASP, so a PHP conversion isn't in the cards right now.

Checking the file first would be OK... I'll check out that possibility. A nonexistent file would be possible, as the site owner might add a new group but not the include file.

aspdaddy

3:56 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I have used code the same as txtbakers in asp/vbScript and it works fine - its the classic workaround for dynamic includes.

But, why dont you just stick with your original solution and provide a default error handling page:


if find( GroupName, Groups() )
FileName = GroupName & ".asp"
else
FileName = InvalidGroupErrorPage & ".asp?ID=" & GroupName
end if
Server.Execute(FileName)

rogerd

4:49 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Hmmm, aspdaddy, can I use the find function to check for the existence of a file? I know the Group exists (if the visitor is on this page), it's just that the include file might not have been created for that Group.

aspdaddy

5:05 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Sure you could write one, something like :
(not tested )

function find ( sName, folder)
for each file in folder
if file.name = sName
find=true
exit function
end if
next
find=false
end function

rogerd

5:54 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



I seem to have it working properly with filesystemobject - is this serious security issue?

GaryK

6:23 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



aspdaddy: Respectfully, why does he need to look thru 100+ files to find the one he wants?

Wouldn't the FileExists function in FSO be more efficient?

And then he could open the file as a TextStream and use the ReadAll function as the parameter for a Response.Write.

I do this all the time and my network admin tells me there are no serious security issues with this method and from his perspective it's a very efficient procedure.

He tells me the security issues with FSO exist mainly when you need to do something other than read files. In other words, something that would require Modify permissions on a file or folder so you can write to and/or delete the file.

I'd be happy to post the function I use if you want to see it.

aspdaddy

7:34 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



>Wouldn't the FileExists function in FSO be more efficient?

I dont know I have never tested it, maybe it just implements a search like I posted?

It was just a suggestion, I never said it was the best way.

GaryK

7:44 pm on Dec 28, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



>>I dont know I have never tested it, maybe it just implements a search like I posted?

It searches for the existence of the one file specified as a parameter to FileExists. :)

Here's the procedure I use. You'll probably want to encapsulate the paramFileName in a Server.MapPath function to get the full path to the file just once:

Public Sub DisplayIncludeFile(ByVal paramFileName)
Dim FSO 'As FileSystemObject
Dim IncFile 'As TextStream
Set FSO = Server.CreateObject("Scripting.FileSystemObject")
If FSO.FileExists(paramFileName) Then
Set IncFile = FSO.OpenTextFile(paramFileName, 1)
Response.Write IncFile.ReadAll
IncFile.Close
Set IncFile = Nothing
End If
Set FSO = Nothing
End Sub

rogerd

1:38 am on Dec 29, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



This is the code I ended up with - seems to work:

set fso = createobject("scripting.filesystemobject")
if fso.FileExists (server.mappath(FileName)) then
Server.Execute(FileName)
End If

Thanks for the input, everyone!

GaryK

2:07 am on Dec 29, 2003 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



You forgot to Set FSO = Nothing when you're done with it. ;)

rogerd

2:42 am on Dec 29, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



Thanks, GaryK.

ClickMagazine

7:37 pm on Dec 29, 2003 (gmt 0)

10+ Year Member



I use SSI with a Case Select all the time. A HUGE portion of my site revolves around them.

The only issue with a SSI is ALL the include files must exist! So if I reference one, I make sure I have a blank page there or I leave it out of the statement. IF statements also work.

(VB Script and IIS)
Select Case Num
Case 1
<!-- Include file One -->
Case 2
<!-- Include file Two -->
Case Else
<!-- Include file Default -->
End Select

You don't need to use the Server.Execute

rogerd

8:00 pm on Dec 29, 2003 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



CM, I think the Case method is fine for small numbers of options with small files. For a large number of cases, though, the code would get unmanageable and the preloading of all include files (even though only one is used) would be onerous.

Also, the case solution takes the "dynamic" aspect out of the code as a new case must be coded manually. The FSO solution allows a new Group to be added to the database and the page will automatically load the correct file (or skip it if the file isn't there).

The case approach is simple & elegant, though, for small option sets.

tjoekbezoer

8:34 pm on Dec 30, 2003 (gmt 0)



I have written a function that enables you to dynamically include .asp files, just like in php.

The function is somewhat long because it filters out the <% and %>, and all possible sorts of comment tags (//, ' and the Rem function)

For me this works brilliantly, because the limitation of Server.Transfer and Server.Execute is that you cannot use objects and variables from the executed file in the parent file. With this function you can.

Here it is:


'--------------------------------------------------------------------------
'INCLUDE
'Dynamically includes and executes strFile. If strFile is not
'found, it will return and error and stop parsing the page.
'--------------------------------------------------------------------------
Sub Include(strFile)
Dim objRegExp
Dim objFSO

Set objRegExp = new RegExp
With objRegExp
.Global = True
.MultiLine = True
.IgnoreCase = True
End With

Set objFSO = Server.CreateObject("Scripting.FileSystemObject")

If objFSO.FileExists(Server.MapPath(strFile)) Then
// Include file is found, start preparing the execution
// Open the file for reading, and read the contents
Set objFile = objFSO.OpenTextFile(Server.MapPath(strFile), 1)
strSource = objFile.ReadAll

// Filter out comment- and ASP tags cos they return errors
strSource = Replace(strSource, Chr(60)&Chr(37), "")
strSource = Replace(strSource, Chr(37)&Chr(62), "")
objRegExp.Pattern = "^[ \t]*(//¦\')[\s\S]*?$"
strSource = objRegExp.Replace(strSource, "")

// Execute the code
On Error Resume Next
Execute strSource

// If an error occurs, detect it here and stop parsing after displaying error.
If Err.Number>0 Then
Response.Write "---FATAL ERROR: while trying to execute <b>" & strFile & "</b>---<br>"
Response.Write "---Error description: " & Err.Description & "<br>"
Response.Write "---Error Source: " & Err.Source & "<hr>"
Response.Write "<b>Script Source</b><br>"
Response.Write Replace(Replace(Server.HTMLEncode(strSource), Chr(10), "<br>"), Chr(9), "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;")
Response.End
End If

On Error GoTo 0
Else
// Include file is not found, abort.
Response.Write "--- <b>FATAL:</b> Include file <b>" & strFile & "</b> is not found ---<br>"
Response.End
End If
End Sub