File Path as Parameter

Re: http://www.experts-exchange.com/Web/Web_Languages/ASP/Q_20780828.html

Okay, I'm trying to pull this off - and believe it or not, I'm stumped.

I have download.asp that streams documents that users click on, and records the download in a db.

Problem: The documents are in a number of different folders, but the file location is hard coded into download.asp. From the previous Q, it seems that passing the location of the file as a parameter to download.asp is the best bet - but I can't figure out how to get it to function properly.

It also seems odd, because the links in the pages are of the type:
<a href="../download.asp?file=somefolder/anotherfolder/somedoc.doc">
So - doesn't that mean that the location of the file should be known, and can easily be inserted into download.asp on the fly?

download.asp is:
************

<%
response.buffer=true

Function downloadFile( strFile, strDownloadFilename, strPath )

     Dim strFilename,objStream,objFilesystem,objFilestream
     Dim intFileLength
     ' get path of specified file
     strFilename = Server.MapPath( strPath & strFile)
     ' clear the buffer
     Response.Buffer = True
     Response.Clear

     ' create stream
     Set objStream = Server.CreateObject("ADODB.Stream")
     objStream.Open

     ' set as binary
     objStream.Type = 1

     ' check the file exists
     Set objFilesystem = Server.CreateObject("Scripting.FileSystemObject")
     if not objFilesystem.FileExists(strFilename) then
          Response.Write("<h1>Error</h1>: " & strFilename & " does not exist<p>")
          Response.End
     end if

     ' get length of file
     Set objFilestream = objFilesystem.GetFile( strFilename )
     intFilelength = objFilestream.size
 
     objStream.LoadFromFile( strFilename )
     if err then
          Response.Write("<h1>Error: </h1>" & err.Description & "<p>")
          Response.End
     end if
     
     'format strFileName
     if Len( Trim(strDownloadFilename) ) > 0 then
          strDownloadFilename = Trim( strDownloadFilename )
     else
          strDownloadFilename = objFilestream.name
     end if

     ' send the headers to the users browser
     Response.AddHeader "Content-Disposition", "attachment; filename=" & strDownloadFilename
     Response.AddHeader "Content-Length", intFilelength
     Response.Charset = "UTF-8"
     Response.ContentType = "application/octet-stream"

     ' output the file to the browser
     Response.BinaryWrite objStream.Read
     Response.Flush

     ' tidy up
     objFilestream.Close
     Set objFilestream = Nothing
End Function


fileName = server.mappath(request("file"))
tempFile=split(filename,"\")
' lets shorten the url of the file that goes in the db
dbFileName = tempFile(ubound(tempFile))

set conn=Server.CreateObject("ADODB.Connection")
set rs=Server.CreateObject("ADODB.Recordset")
conn.open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & server.mappath("/_private/data/tracking.mdb")
rs.open "SELECT * FROM tracking WHERE download='  ' ",conn,2,2
rs.Addnew
rs("download")=dbFileName
rs("username")=session("fname") & " " & session("lname")
realdatetime= dateadd("h",-5,Now)
rs("date")=realdatetime
rs.update
rs.Close()
conn.Close()
set rs=nothing
set conn=nothing

Call downloadFile( Replace( dbFileName ,"/","\"),dbFileName,"somefolder/anotherfolder/" )
%>

************

Notice the line directly above, it has the path hardcoded. What's the best way to get around this - even if I create a separate download.asp for each folder so I can hard code it, I'm still left with the problem that the documents are another folder down - meaning there's over 50 of them:

somefolder1/anotherfolder1/- there are many docs, pdf's, ppt's, xls's etc in this folder
somefolder1/anotherfolder2/- there are many docs, pdf's, ppt's, xls's etc in this folder
somefolder1/anotherfolder3/- there are many docs, pdf's, ppt's, xls's etc in this folder
somefolder1/anotherfolder4/- there are many docs, pdf's, ppt's, xls's etc in this folder

somefolder2/anotherfolder1/- there are many docs, pdf's, ppt's, xls's etc in this folder
somefolder2/anotherfolder2/- there are many docs, pdf's, ppt's, xls's etc in this folder
somefolder2/anotherfolder3/- there are many docs, pdf's, ppt's, xls's etc in this folder
somefolder2/anotherfolder4/- there are many docs, pdf's, ppt's, xls's etc in this folder

etc...

Any ideas?
LVL 31
seanpowellAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Göran AnderssonCommented:
This code picks out just the file name from the parameter passed to the page:

fileName = server.mappath(request("file"))
tempFile=split(filename,"\")
' lets shorten the url of the file that goes in the db
dbFileName = tempFile(ubound(tempFile))

Do this instead, and you have the path also:

fileName = server.mappath(request("file"))
lngPos=InStrRev(fileName,"\")
dbFileName=Mid(fileName,lngPos+1)
strPath=Left(fileName,lngPos-1)

Now you can use it when getting the file:

Call downloadFile(dbFileName,dbFileName,strPath)
seanpowellAuthor Commented:
I'm getting this when I make that change:

Server.MapPath() error 'ASP 0172 : 80004005'
Invalid Path
/manual/download.asp, line 9
The Path parameter for the MapPath method must be a virtual path. A physical path was used.
ap_sajithCommented:
You could define constants and declare the file path in download.asp
eg:
suploadpath="C:/webroot/upload/docs"

sdownloadpath=suploadpath & strPath

Cheers!!
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

seanpowellAuthor Commented:
I don't follow you there...
ap_sajithCommented:
Define the root download folder as a constant..say c:\downloads is your download folder.

get the folder name and file path from the query string.

eg:\doc\temp.pdf

Now you can get the actual file path by combining the two ..

eg:: c:\downloads\doc\temp.pdf

and use the following function..

Function downloadFile( strFile, strDownloadFilename, strPath )

    Dim strFilename,objStream,objFilesystem,objFilestream
    Dim intFileLength
    ' get path of specified file
    strFilename = strPath
     ' clear the buffer
    Response.Buffer = True
    Response.Clear

    ' create stream
    Set objStream = Server.CreateObject("ADODB.Stream")
    objStream.Open

    ' set as binary
    objStream.Type = 1

    ' check the file exists
    Set objFilesystem = Server.CreateObject("Scripting.FileSystemObject")
    if not objFilesystem.FileExists(strFilename) then
         Response.Write("<h1>Error</h1>: " & strFilename & " does not exist<p>")
         Response.End
    end if

    ' get length of file
    Set objFilestream = objFilesystem.GetFile( strFilename )
    intFilelength = objFilestream.size

     objStream.LoadFromFile( strFilename )
    if err then
         Response.Write("<h1>Error: </h1>" & err.Description & "<p>")
         Response.End
    end if
   
     'format strFileName
    if Len( Trim(strDownloadFilename) ) > 0 then
         strDownloadFilename = Trim( strDownloadFilename )
    else
         strDownloadFilename = objFilestream.name
    end if

    ' send the headers to the users browser
    Response.AddHeader "Content-Disposition", "attachment; filename=" & strDownloadFilename
    Response.AddHeader "Content-Length", intFilelength
    Response.Charset = "UTF-8"
    Response.ContentType = "application/octet-stream"

    ' output the file to the browser
    Response.BinaryWrite objStream.Read
    Response.Flush

    ' tidy up
    objFilestream.Close
    Set objFilestream = Nothing
End Function


fileName = server.mappath(request("file"))
tempFile=split(filename,"\")
' lets shorten the url of the file that goes in the db
dbFileName = tempFile(ubound(tempFile))

set conn=Server.CreateObject("ADODB.Connection")
set rs=Server.CreateObject("ADODB.Recordset")
conn.open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & server.mappath("/_private/data/tracking.mdb")
rs.open "SELECT * FROM tracking WHERE download='  ' ",conn,2,2
rs.Addnew
rs("download")=dbFileName
rs("username")=session("fname") & " " & session("lname")
realdatetime= dateadd("h",-5,Now)
rs("date")=realdatetime
rs.update
rs.Close()
conn.Close()
set rs=nothing
set conn=nothing

CONST sDownload Path="C:\Downloads\"
' ** Use this if you are not passing the folder name along the querystring **
'strFolderPath="somefolder/anotherfolder/"  
strFullPath=sDownload & strFolderPath & request.querystring("file")
Call downloadFile( Replace( dbFileName ,"/","\"),dbFileName,strFullPath )


Cheers!!
ap_sajithCommented:
CONST sDownload Path="C:\Downloads\"

Should be

CONST sDownload="C:\Downloads\"

Cheers!!

seanpowellAuthor Commented:
Sorry - I may be missing something:

CONST sDownload="C:\Downloads\"
' ** Use this if you are not passing the folder name along the querystring **
'strFolderPath="somefolder/anotherfolder/"  
strFullPath=sDownload & strFolderPath & request.querystring("file")
Call downloadFile( Replace( dbFileName ,"/","\"),dbFileName,strFullPath )

The only constants in the folder locations in the site are:

http://domain.com/folder/

So I would write your code like:
CONST sDownload="http://domain.com/folder/"

This:
'strFolderPath="somefolder/anotherfolder/"

if you look at my example above, could be:

'strFolderPath="somefolder1/anotherfolder1/"
'strFolderPath="somefolder2/anotherfolder5/"
'strFolderPath="somefolder3/anotherfolder23/"

etc.


So how would this work?
ap_sajithCommented:
>>http://domain.com/folder/
<%=server.mappath("folder")%> should give you your root downloads folder.

so,
CONST sDownload="http://domain.com/folder/" becomes..

CONST sDownload=server.mappath("folder")

This should get you the root folder. Now since you are passing the subfolder path along the query string,

your full file path would be..

strfullpath=sDownload & request.querystring("file")

Cheers!!
seanpowellAuthor Commented:
I think I follow you - however I get:

Microsoft VBScript compilation error '800a0415'

Expected literal constant

/manual/download_new.asp, line 80

CONST sDownload=server.mappath("manual")
----------------------------------------^

Do I need this somewhere:
<%=server.mappath("manual")%>
Göran AnderssonCommented:
That's right. The function uses a virtual path.

Change this:
strFilename = Server.MapPath( strPath & strFile)
to
strFilename = strPath & "\" & strFile
seanpowellAuthor Commented:
Actually I originally had this:
strFilename = Server.MapPath( strPath & strFile)

ap_sajith changed it to:
strFilename = strPath

So now I need to change it to:
strFilename = strPath & "\" & strFile

I'll give it a try...
seanpowellAuthor Commented:
No change...
ap_sajithCommented:
change CONST sDownload=server.mappath("manual")
to
dim sDownload
sDownload=server.mappath("manual")

cheers!!
seanpowellAuthor Commented:
That just gives me a blank page when I click onthe word Doc link...
seanpowellAuthor Commented:
Here is the adjusted download.asp page incorporating all the modifications from above:


<%
response.buffer=true

Function downloadFile( strFile, strDownloadFilename, strPath )

    Dim strFilename,objStream,objFilesystem,objFilestream
    Dim intFileLength
    ' get path of specified file
    strFilename = strPath & "\" & strFile
     ' clear the buffer
    Response.Buffer = True
    Response.Clear

    ' create stream
    Set objStream = Server.CreateObject("ADODB.Stream")
    objStream.Open

    ' set as binary
    objStream.Type = 1

    ' check the file exists
    Set objFilesystem = Server.CreateObject("Scripting.FileSystemObject")
    if not objFilesystem.FileExists(strFilename) then
         Response.Write("<h1>Error</h1>: " & strFilename & " does not exist<p>")
         Response.End
    end if

    ' get length of file
    Set objFilestream = objFilesystem.GetFile( strFilename )
    intFilelength = objFilestream.size

     objStream.LoadFromFile( strFilename )
    if err then
         Response.Write("<h1>Error: </h1>" & err.Description & "<p>")
         Response.End
    end if
   
     'format strFileName
    if Len( Trim(strDownloadFilename) ) > 0 then
         strDownloadFilename = Trim( strDownloadFilename )
    else
         strDownloadFilename = objFilestream.name
    end if

    ' send the headers to the users browser
    Response.AddHeader "Content-Disposition", "attachment; filename=" & strDownloadFilename
    Response.AddHeader "Content-Length", intFilelength
    Response.Charset = "UTF-8"
    Response.ContentType = "application/octet-stream"

    ' output the file to the browser
    Response.BinaryWrite objStream.Read
    Response.Flush

    ' tidy up
    objFilestream.Close
    Set objFilestream = Nothing
End Function


fileName = server.mappath(request("file"))
tempFile=split(filename,"\")
dbFileName = tempFile(ubound(tempFile))

set conn=Server.CreateObject("ADODB.Connection")
set rs=Server.CreateObject("ADODB.Recordset")
conn.open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & server.mappath("/_private/data/tracking.mdb")
rs.open "SELECT * FROM tracking WHERE download='  ' ",conn,2,2
rs.Addnew
rs("download")=dbFileName
rs("username")=session("fname") & " " & session("lname")
realdatetime= dateadd("h",-5,Now)
rs("date")=realdatetime
rs.update
rs.Close()
conn.Close()
set rs=nothing
set conn=nothing

dim sDownload
sDownload=server.mappath("manual")
strfullpath=sDownload & request.querystring("file")

%>
ap_sajithCommented:
Try this..

<%
response.buffer=true

Function downloadFile( strFile, strDownloadFilename, strPath )

    Dim strFilename,objStream,objFilesystem,objFilestream
    Dim intFileLength
    ' get path of specified file
    strFilename = strPath & "\" & strFile
     ' clear the buffer
    Response.Buffer = True
    Response.Clear

    ' create stream
    Set objStream = Server.CreateObject("ADODB.Stream")
    objStream.Open

    ' set as binary
    objStream.Type = 1

    ' check the file exists
    Set objFilesystem = Server.CreateObject("Scripting.FileSystemObject")
    if not objFilesystem.FileExists(strFilename) then
         Response.Write("<h1>Error</h1>: " & strDownloadFileName & " does not exist<p>") ' ** DO NOT SHOW THE FULL PATH **
         Response.End
    end if

    ' get length of file
    Set objFilestream = objFilesystem.GetFile( strFilename )
    intFilelength = objFilestream.size

     objStream.LoadFromFile( strFilename )
    if err then
         Response.Write("<h1>Error: </h1>" & err.Description & "<p>")
         Response.End
    end if
   
     'format strFileName
    if Len( Trim(strDownloadFilename) ) > 0 then
         strDownloadFilename = Trim( strDownloadFilename )
    else
         strDownloadFilename = objFilestream.name
    end if

    ' send the headers to the users browser
    Response.AddHeader "Content-Disposition", "attachment; filename=" & strDownloadFilename
    Response.AddHeader "Content-Length", intFilelength
    Response.Charset = "UTF-8"
    Response.ContentType = "application/octet-stream"

    ' output the file to the browser
    Response.BinaryWrite objStream.Read
    Response.Flush

    ' tidy up
    objFilestream.Close
    Set objFilestream = Nothing
End Function


fileName = strDownloadFileName

set conn=Server.CreateObject("ADODB.Connection")
set rs=Server.CreateObject("ADODB.Recordset")
conn.open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & server.mappath("/_private/data/tracking.mdb")
rs.open "SELECT * FROM tracking WHERE download='  ' ",conn,2,2
rs.Addnew
rs("download")=dbFileName
rs("username")=session("fname") & " " & session("lname")
realdatetime= dateadd("h",-5,Now)
rs("date")=realdatetime
rs.update
rs.Close()
conn.Close()
set rs=nothing
set conn=nothing

dim sDownload
strfullpath=server.mappath("manual")
sfile=Request.Querystring("file")
CALL downloadFile(sfile, mid(sfile,instrrev(str,"\")+1), strfullpath )
'SAMPLE STRINGS WOULD BE: strFile-"docs\folder2\test.doc" , strDownloadFilename-"test.doc",strPath-"C:\webroot\manual"
%>

Cheers!!
fritz_the_blankCommented:
I am coming to this late, but it seems to me the issue here is how to get the file name and the path from the request object. Then those two values could be passed to the function. How about something like this:

<HTML>
<HEAD>
<META NAME="GENERATOR" Content="Microsoft Visual Studio 6.0">
<TITLE></TITLE>
<SCRIPT LANGUAGE=vbscript>
sub findFileAndPath()
      'request.querystring("file") yields somefolder/anotherfolder/somedoc.doc
      strParameter = "somefolder/anotherfolder/somedoc.doc"
      strFile =  Right(strParameter,Len(strParameter)-instrrev(strParameter,"/"))
      strPath = Left(strParameter, Len(strParameter) - Len(strFile) )
      msgbox "Path: " & strPath & vbTab & "File: " & strFile
end sub
</SCRIPT>
</HEAD>
<BODY onLoad=findFileAndPath>
</BODY>
</HTML>


If this yields the necessary parameters, then we could do something like:


strParameter = request.querystring("file")
strFile =  Right(strParameter,Len(strParameter)-instrrev(strParameter,"/"))
strPath = Left(strParameter, Len(strParameter) - Len(strFile) )

Call downloadFile( strFile,strFile,strPath)


We should check to make sure, however, that the strPath isn't missing or adding an extra / somewhere.

Fritz the Blank

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
seanpowellAuthor Commented:
You nailed it Fritz.
seanpowellAuthor Commented:
This is perfect:

strParameter = request.querystring("file")
strFile =  Right(strParameter,Len(strParameter)-instrrev(strParameter,"/"))
strPath = Left(strParameter, Len(strParameter) - Len(strFile) )

Call downloadFile( strFile,strFile,strPath)

The links are now coded as:
<a href="../download.asp?file=somefolder/somefolder/somedoc.doc

What's written to the db is:
somedoc.doc

It would be nice if I had the other 2 "somefolder" names in the db along with the file - but it's not a deal breaker...
fritz_the_blankCommented:
just do this:

rs("download")=request.("file")


FtB
seanpowellAuthor Commented:
:-(

Microsoft VBScript compilation error '800a03f2'

Expected identifier

/manual/download.asp, line 69

rs("download")=request.("file")
-----------------------^
seanpowellAuthor Commented:
I think its
rs("download")=request("file")
seanpowellAuthor Commented:
Yes, that did it.
I think I read somewhere that knowing when to remove a period automatically advances you to ASP "Wizard" level.
seanpowellAuthor Commented:
Thanks FtB

I've posted two other Q's for GreenGhost and ap_sajith. I hope that's okay... I really appreciate all your help and time.

Sean
fritz_the_blankCommented:
Glad to have helped!

I see you posted points for GG and APS at:

http://www.experts-exchange.com/Web/Web_Languages/ASP/Q_20783497.html

http://www.experts-exchange.com/Web/Web_Languages/ASP/Q_20783499.html

Always a swell thing to do--I know that's what I always do.

FtB
MRSONNYCommented:
why are the download limited to 20Mb
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
ASP

From novice to tech pro — start learning today.