Question
· May 18, 2022

Downloading files from ZEN pages

Hi all

I have a Zen page which displays the contents of a table. One of the columns is a file path to a file on a local disk.

Is it possible, on a Zen page, to allow that file that described by the file path to be downloaded when a hyperlink is clicked on?

Cheers

Product version: IRIS 2021.1
$ZV: IRIS for Windows (x86-64) 2021.2.1 (Build 654U) Fri Mar 18 2022 06:09:35 EDT
Discussion (7)3
Log in or sign up to continue

If the file isn't accessible to link to directly, you may want to look into extending the %CSP.StreamServer class and linking to that. At a bare minimum, you'll want to override the OnPage and OnPreHTTP methods:

ClassMethod OnPage() As %Status
{
set myfile = ##class(%File).%New("/path/to/file")
do myfile.Open("S")
do myfile.OutputToDevice()
quit $$$OK
}

ClassMethod OnPreHTTP() As %Boolean [ Language = cache ]
{
do %response.SetHeader("Content-Disposition","attachment;filename=""filename""")
quit 1
}

Of course using your own file name and the path to the file. That's the local computer file path, not a URL. You also should set the content type appropriately using set %response.ContentType = "text/csv" or whatever the MIME type of the file is so that the browser can identify it correctly.

Unless you want to have to write another %CSP.StreamServer for every file, you'll have to pass the name of the filepath as an argument. So that would look more like:

ClassMethod OnPage() As %Status
{
set myfile = ##class(%File).%New(%request.Get("filepath"))
do myfile.Open("S")
do myfile.OutputToDevice()
quit $$$OK
}

ClassMethod OnPreHTTP() As %Boolean [ Language = cache ]
{
set filepath = %request.Get("filepath")
set %response.ContentType = "text/csv" //or whatever the appropriate MIME type is
do %response.SetHeader("Content-Disposition","attachment;filename="""_$P(filepath,"/",*)_"""")
quit 1
}

Then you could link to it as whatever the path to your stream server is with ?filepath=/path/to/file on the end.

If you take that approach, though, do some validation on the filepath and make sure it can ONLY go to the folder you want! Or, only pass the filename as a parameter to the page, and hard-code the folder in those methods.

Hi there! Thanks for taking the time to reply. I implemented the above code and was quickly able to download the file in question. However, the PDF files that is downloaded doesn't have the same size as the original - in fact all are 5Kb smaller, e.g.197Kb downloads to a 192Kb file, 241Kb to a 236Kb etc

I modified the OnPreHttp() method to set content length, but that had no effect.

/// Set the appropriate header for the file.
ClassMethod OnPreHTTP() As %Boolean
{
set filepath = %request.Get("filepath") set tFs=##class(%Stream.FileCharacter).%New()
set tFs.Filename=filepath set %response.ContentType = "application/pdf"
do %response.SetHeader("Content-Disposition","attachment;filename="""_$P(filepath,"\",*)_"""")
Do %response.SetHeader("Content-Length",tFs.Size)     Quit $$$OK
}
 

Do you have any ideas?