A user recently asked me how I did the, "Your download will begin..." page at RIAForge. For an example, click the big download button at the Galleon project page. (Note it was updated this morning!)
First off - forcing a download is easy enough. You can use a cfheader/cfcontent combo like so:
<cfheader name="Content-disposition" value="attachment;filename=""#thefile#""">
<cfcontent file="#downloadpath#" type="application/unknown">
For RIAForge I used the unknown application type, but you can easily sniff the extension and use the proper mime type. (Something I need to do to RIAForge.) But how do I do this on a "Your download will begin..." type page? I simply link to a page and then add logic to either display the message or start the download. Here is the exact code RIAForge uses:
<cfset project = viewState.getValue("project")>
<cfset viewState.setValue("title", "#project.getName()# Download")>
<cfif not structKeyExists(url, "doit")>
<cfheader name="refresh" value="1; url=#viewstate.getValue("myself")#action.download&doit=true">
<cfoutput>
<p />
<div class="subhead">#viewState.getValue("title")#</div>
<div class="copy">
<p>
Your download will begin momentarily.
</p>
</div>
</cfoutput>
<cfelse>
<cfif project.getExternalDownload() neq "">
<cflocation url="#project.getExternalDownload()#" addToken="false">
<cfelse>
<cfset downloadpath = viewState.getValue("downloadpath")>
<cfset thefile = getFileFromPath(downloadpath)>
</cfif>
<cfheader name="Content-disposition" value="attachment;filename=""#thefile#""">
<cfcontent file="#downloadpath#" type="application/unknown">
</cfif>
I basically use a URL hook "doit" to determine if I'm showing the page or starting the download. Now you may ask - why in the heck do this anyway? Everyone say, Thank you IE! Along with the recent EOLAS issue, IE also changed how they handle what they consider to be automatic file downloads. If a page tries to download a file and you had not linked directly to the file, you will get a warning. If you tell IE to accept the download then it reloads the page. So if you were on a different page, you need to reclick the download link. Because I send the user to a page just for the download, it makes the process a bit less painless. They still have a reload, but they don't need to click on a download link.
One more quick note. This process was also helpful for RIAForge as it lets project owners point to external URLs for download information. With this download page I can handle updating the download stats for a project even when RIAForge doesn't actually host the zip.
Edited to fix an issue with files that have spaces in them. Thanks Rob Gonda.