Classic ASP code to download .CSV file - asp-classic

I have a website written in Classic ASP
One page creates a .CSV file from a SQL database and stores it in the root directory along with a "Click Here" link to download it to the users PC
It has been working fine for many years and is still working fine when downloading small files, but now it comes up with a "THIS PAGE CAN'T BE DISPLAYED" error when downloading a .csv file (in this example) of some 785 records
The code is pretty short as below with the one Private Sub that does the download
<%#Language="VBScript"%>
<%Reponse.Buffer = True%>
<%
On Error Resume Next
Dim strPath
strPath = CStr(Request.QueryString("File"))
'-- do some basic error checking for the QueryString
If strPath = "" Then
Response.Clear
Response.Write("No file specified.")
Response.End
ElseIf InStr(strPath, "..") > 0 Then
Response.Clear
Response.Write("Illegal folder location.")
Response.End
ElseIf Len(strPath) > 1024 Then
Response.Clear
Response.Write("Folder path too long.")
Response.End
Else
Call DownloadFile(strPath)
End If
Private Sub DownloadFile(file)
'--declare variables
Dim strAbsFile
Dim strFileExtension
Dim objFSO
Dim objFile
Dim objStream
'-- set absolute file location
strAbsFile = Server.MapPath(file)
'-- create FSO object to check if file exists and get properties
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
'-- check to see if the file exists
If objFSO.FileExists(strAbsFile) Then
Set objFile = objFSO.GetFile(strAbsFile)
'-- first clear the response, and then set the appropriate headers
Response.Clear
'-- the filename you give it will be the one that is shown
' to the users by default when they save
Response.AddHeader "Content-Disposition", "attachment; filename=" & objFile.Name
Response.AddHeader "Content-Length", objFile.Size
Response.ContentType = "application/octet-stream"
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
'-- set as binary
objStream.Type = 1
Response.CharSet = "UTF-8"
'-- load into the stream the file
objStream.LoadFromFile(strAbsFile)
'-- send the stream in the response
Response.BinaryWrite(objStream.Read)
objStream.Close
Set objStream = Nothing
Set objFile = Nothing
Else 'objFSO.FileExists(strAbsFile)
Response.Clear
Response.Write("No such file exists.")
End If
Set objFSO = Nothing
End Sub
%>
So something has changed in recent months
Ay advice much appreciated
Thanks in advance

Your IIS version and configuration might be needed to help but I know IIS6 introduced a 4MB limit to BinaryWrite. Try sending your file in chunks instead.
<% Response.Buffer = False %>
...
With Server.CreateObject("ADODB.Stream")
.Open
.Type = 1
.LoadFromFile strPath
' Send 256K chunks...
Const intChunkSize = 262144
Do While Response.IsClientConnected And (.Position < .Size)
Response.BinaryWrite .Read(intChunkSize)
Loop
.Close
End With

Related

ASP stream send a TXT file created on the fly

I need to create and send a TXT file on the fly using classic asp. I know how to creates this file saving it into a directory and then send it using Server.CreateObject("ADODB.Stream") ... but what I wanted is to avoid saving it in the directory and just create and send on the fly.
In this case the TXT file is a list of records extracted from a MySql DB. One each line ...
strSQL = "SELECT * FROM mydb WHERE condition='ok';"
Set rs = my_conn.Execute(strSQL)
Response.Buffer = False
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 'adTypeBinary
objStream.Open
Response.ContentType = "application/x-unknown"
Response.Addheader "Content-Disposition", "attachment; filename=recordsfile.txt"
Response.BinaryWrite (dunno how to create a file with rs("field01") & " _ " & rs("field02") & vbnewline
objStream.Close
Set objStream = Nothing
Is it possible to do this ...meaning create a file in memory to strem/send ... orthere is no option but creating and saving it on disk before and send later ??
The following will work. Note: my example below assumes your recordset returns one field.
strSQL = "SELECT * FROM mydb WHERE condition='ok';"
Set rs = my_conn.Execute(strSQL)
if not rs.eof then
response.contentType = "application/octet-stream"
response.addHeader "Content-Disposition", "attachment; filename=recordsfile.txt"
do until rs.eof
response.write rs(0).value & vbcrlf
rs.movenext
loop
end if

How to a Hide Download Link

I created a protected area in my website, where only registered users can logon to download a restricted application (exe). But they can copy the download link and make it available on internet, so I am trying to find the simplest way to hide the download link (using ASP classic, if possible).
Here is what I got so far: http://forums.aspfree.com/code-bank-54/download-manager-downloading-files-secure-location-classic-asp-65239.html. But when using this download manager, the exe application unexplainably looses its digital signing :(
Please, can anyone give me some ideas? Maybe using PHP or Flash?
Thanks!
Here is the solution I found, using ASP classic:
<%
Option Explicit
Response.Buffer = True
If (not Session("Logged")) Then Response.End
Dim objFso
Dim objStream
Dim strFileName
Dim strFilePath
strFileName = "App.exe"
strFilePath = "d:\yoursitefolder\protectedfolder\"
Set objFso = Server.CreateObject("Scripting.FileSystemObject")
If objFso.FileExists(strFilePath & strFileName) Then
Response.AddHeader "Content-disposition", "filename=" & strFileName
Response.ContentType = "application/octet-stream"
Response.AddHeader "Pragma", "no-cache"
Response.AddHeader "Expires", "0"
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1
objStream.Open
objStream.LoadFromFile strFilePath & strFileName
Response.BinaryWrite(objStream.Read())
objStream.Close
Set objStream = Nothing
End If
Set objFso = Nothing
%>

close window when download finish-ASP

I have this function made to save a PDF file in the local disk.
How do I automatically close the window after the download completed with an alert/msg box stating that the window will close?
This doesn't work:
Response.Write ("<script>alert('Save Finished'); self.close();</script>")
TheCode:
Private Function SaveLocal1(ByRef cnCon, ByVal PDFFile)
Dim ObjStream
Dim ObjFileSys
Dim Size
Dim fpath
Dim bdata
'Response.Write("<script>alert('local');</script>")
fpath = "C:\1.pdf" 'path of the file in the local server
filename = "LocalSave.pdf" 'name to be saved
'Response.Write("<script>alert('file paths');</script>")
Set ObjStream = Server.CreateObject("ADODB.Stream")
ObjStream.Open
ObjStream.Type = 1
ObjStream.LoadFromFile fpath
'Response.Write("<script>alert('server.createobject');</script>")
Response.buffer = TRUE
Response.AddHeader "Content-Disposition","attachment;filename="& filename & ";"
Response.ContentType = "application/pdf"
Set ObjFileSys = CreateObject("Scripting.FileSystemObject")
Size = ObjFileSys.GetFile(fpath).Size
bdata = ObjStream.Read(Size)
Response.BinaryWrite(bdata) 'the file will be saved in the downloads folder
Response.Write("<script>alert('Save to local finish');</script>")
ObjStream.Close
Set ObjStream = Nothing
Response.Flush
Response.End
Response.Write ("<script>alert('Save Finished'); self.close();</script>")
End Function
I suppose there are could be 2 issue in your code.
2nd issue:
Response.End
Response.Write ("<script>alert('Save Finished'); self.close();</script>")
Response.End -- is last command. That is all. "Document" completed.
The End method causes the Web server to stop processing the script and
return the current result. The remaining contents of the file are not
processed.
Change order of following comand to
Response.Write ("<script>alert('Save Finished'); self.close();</script>")
Response.End
Use response.redirect and send this page to another page, use window.close on body onload

Error in downloaded pdf file - ASP classic

I'm creating a download manager, and everything seems to work. But the file that I get downloaded can not be opened. The file has the correct name and the extension .pdf - but my Mac says that the file cannot be opened (the file on the server works).
if request.querystring("downloadFile") <> "" then
strFilePath = Server.MapPath("/_customerFiles/"& session("URLmapping") &"/documents/"& request.querystring("downloadFile"))
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strFilePath) Then
Set objFile = objFSO.GetFile(strFilePath)
intFileSize = objFile.Size
Set objFile = Nothing
strFileName = request.querystring("filename")
strFileName = replace(request.querystring("downloadFile")," ","-")
Response.AddHeader "Content-Disposition","attachment; filename=" & strFileName
Response.ContentType = "application/octet-stream"
Response.AddHeader "Content-Length", intFileSize
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = 1 'adTypeBinary '
objStream.LoadFromFile strFilePath
Do While Not objStream.EOS And Response.IsClientConnected
Response.BinaryWrite objStream.Read(1024)
Response.Flush()
Loop
objStream.Close
Set objStream = Nothing
End if
Set objFSO = Nothing
end if
Have you considered that the output stream is having a Byte Order Mark (BOM) added (or maybe removed)? I would open both files in a hex editor and look for 3 bytes added at the start (and everything else moved along).
I know I'm late getting to this question, but I was just dealing with something similar and wanted share my observations to try to clear it up.
I have read (sorry I dont have a source) that the ADODB.Stream has to have its .Type specified prior to calling .Open
I also set the Stream .Mode property to 3 (meaning "open file for Reading") to prevent file access lock errors if multiple people try to access the file at the same time -- Also must be done before calling .Open
I have had varying success with Response.ContentType "application/octet-stream", and after some problems there, I changed mine to Response.ContentType "xxx/xxx". The browser will accept it as an unknown file type and then prompt the user to open it based on the registered program for that file extension.
Before you start adding Response Headers, you should call Response.Clear (just to be sure you're not sending extra markup)
After closing your FileSystemObject, you should call Response.End (again, just to be sure)
You needs to add the Response.Clear before Response.AddHeader and change the Response.ContentType, so the code is like below:
if request.querystring("downloadFile") <> "" then
strFilePath = Server.MapPath("/_customerFiles/"& session("URLmapping") &"/documents/"& request.querystring("downloadFile"))
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strFilePath) Then
Set objFile = objFSO.GetFile(strFilePath)
intFileSize = objFile.Size
Set objFile = Nothing
strFileName = request.querystring("filename")
strFileName = replace(request.querystring("downloadFile")," ","-")
Response.Clear
Response.AddHeader "Content-Disposition","attachment; filename=" & strFileName
Response.ContentType = "xxx/xxx"
Response.AddHeader "Content-Length", intFileSize
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Open
objStream.Type = 1 'adTypeBinary '
objStream.LoadFromFile strFilePath
Do While Not objStream.EOS And Response.IsClientConnected
Response.BinaryWrite objStream.Read(1024)
Response.Flush()
Loop
objStream.Close
Set objStream = Nothing
End if
Set objFSO = Nothing
End if

How to download the files using vbscript in classic asp

I am working on Classic Asp with VBScript. I am trying to display list of files from a directory with download option. like,
When i click on the download link the corresponding file need to be download for that i have used the following code like,
<html>
<head>
<title> My First ASP Page </title>
</head>
<body>
<%
Dim fso
Dim ObjFolder
Dim ObjOutFile
Dim ObjFiles
Dim ObjFile
'Creating File System Object
Set fso = CreateObject("Scripting.FileSystemObject")
'Getting the Folder Object
Set ObjFolder = fso.GetFolder("F:\karthik")
'Creating an Output File to write the File Names
Set ObjOutFile = fso.CreateTextFile("F:\WindowsFiles.txt")
'Getting the list of Files
Set ObjFiles = ObjFolder.Files
'Writing Name and Path of each File to Output File
Response.Write("<table cellpadding=""4"" cellspacing=""5"" >")
For Each ObjFile In ObjFiles
Response.Write("<tr><td>"&ObjFile.Name & String(50 - Len(ObjFile.Name), " ")&"</td><td>Download</td></tr>")
Next
Response.Write("</table>")
ObjOutFile.Close
%><br>
<script language="vbscript" type="text/vbscript">
Sub HTTPDownload( myURL, myPath )
' Standard housekeeping
Dim i, objFile, objFSO, objHTTP, strFile, strMsg
Const ForReading = 1, ForWriting = 2, ForAppending = 8
' Create a File System Object
Set objFSO = CreateObject( "Scripting.FileSystemObject" )
' Check if the specified target file or folder exists,
' and build the fully qualified path of the target file
If objFSO.FolderExists( myPath ) Then
strFile = objFSO.BuildPath( myPath, Mid( myURL, InStrRev( myURL, "/" ) + 1 ) )
ElseIf objFSO.FolderExists( Left( myPath, InStrRev( myPath, "\" ) - 1 ) ) Then
strFile = myPath
Else
WScript.Echo "ERROR: Target folder not found."
Exit Sub
End If
' Create or open the target file
Set objFile = objFSO.OpenTextFile( strFile, ForWriting, True )
' Create an HTTP object
Set objHTTP = CreateObject( "WinHttp.WinHttpRequest.5.1" )
' Download the specified URL
objHTTP.Open "GET", myURL, False
objHTTP.Send
' Write the downloaded byte stream to the target file
For i = 1 To LenB( objHTTP.ResponseBody )
objFile.Write Chr( AscB( MidB( objHTTP.ResponseBody, i, 1 ) ) )
Next
' Close the target file
objFile.Close( )
End Sub
</script>
</body>
</html>
It seems you are trying to do this on the server-side using client-side scripting. Here is a better solution that uses server-side ASP to send the file. You will need to split your code over two pages.
Your current script should be replaced with this:
<html>
<head>
<title> My First ASP Page </title>
</head>
<body>
<% Dim fso
Dim ObjFolder
Dim ObjOutFile
Dim ObjFiles
Dim ObjFile
'Creating File System Object
Set fso = CreateObject("Scripting.FileSystemObject")
'Getting the Folder Object
Set ObjFolder = fso.GetFolder("F:\karthik")
'Getting the list of Files
Set ObjFiles = ObjFolder.Files
'Writing Name and Path of each File to Output File
Response.Write("<table cellpadding=""4"" cellspacing=""5"" >")
For Each ObjFile In ObjFiles
Response.Write("<tr><td>"&ObjFile.Name & String(50 - Len(ObjFile.Name), " ")&"</td><td>Download</td></tr>")
Next
Response.Write("</table>")
%><br>
</body>
</html>
Then you need to create another script which I have called download.asp which handles the download:
<%
Dim objConn, strFile
Dim intCampaignRecipientID
strFile = Request.QueryString("file")
If strFile <> "" Then
Response.Buffer = False
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 'adTypeBinary
objStream.Open
objStream.LoadFromFile("F:\karthik\" & strFile)
Response.ContentType = "application/x-unknown"
Response.Addheader "Content-Disposition", "attachment; filename=" & strFile
Response.BinaryWrite objStream.Read
objStream.Close
Set objStream = Nothing
End If
%>
I like this solution, but users can see the downloads in the history, or modify the querystring. This solution can be modified for POST usage this way:
in the page code modify the link:
FileName`
and further down
<form id="frm2dl" action="download.asp" method="post"><input type="hidden" id="file2dl" name="file2dl" value="" /></form>
then in your javascript file get the filename:
function getfile(obj) {
var f=obj.innerText;
$("#frm2dl #file2dl").val(f);
$("#frm2dl").submit();
}
alternately you could use a file ID then in the download.asp have a lookup function from ID to filename.
Then in the download.asp use request.form("file2dl") instead of request.querystring.
UPDATE:
Also, depending on server version you might get the 4MB limit (I have to work with Microsoft-IIS/7.5 on intranet). Therefore for large files the code will not work. Here is my improved version:
Dim strFileName, strFilePath, objFSO, objStream, objFile, intFileSize
Const lChkSize = 524288 ' 500KB - server typical limit is 4MB
'If session("loggedIn") = True Then ' insert your logon validation code here. bypassed for testing
strFileName = request.form("file2dl")
strFilename = Replace(strFilename,"..","") ' prevent parent path navigation - also ensure uploaded files do not contain this sequence
strFilename = Replace(strFilename,"/","") ' prevent path navigation
strFilename = Replace(strFilename,"\","") ' filenames should already be cleaned by a previous process
strFilePath = server.MapPath("/insert your URL absolute sources filepath here/" & strFilename)
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strFilePath) Then
Set objFile = objFSO.GetFile(strFilePath)
intFileSize = objFile.Size
Set objFile = Nothing
Response.AddHeader "Content-Disposition","attachment; filename=" & strFileName
Response.ContentType = "application/x-msdownload"
Response.AddHeader "Content-Length", intFileSize
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 'adTypeBinary
objStream.Open
objStream.LoadFromFile strFilePath
Do While Not objStream.EOS And Response.IsClientConnected
Response.BinaryWrite objStream.Read(lChkSize)
Response.Flush()
Loop
objStream.Close
Set objStream = Nothing
Else
Response.write "Error finding file: " & request.form("file2dl")
End if
Set objFSO = Nothing
'End If

Resources