Home > ColdFusion Tutorials > User Experience > Force File Download (Not Display In Browser)

Force File Download (Not Display In Browser)

Get the Code for this Tutorial
Comment on this Tutorial

Forcing File Downloads

Now, we know we can't force a user to accept a download, and we wouldn't want to anyways. But what I am refering to as a forced download here is forcing the download dialog box to display, rather then displaying the file in the browser.
If you link to a .jpg file and the user clicking on that link will see the image in the browser. But what if you want to promt the user to save the image to disk? We run into the same problem with other file types that a browser can handle on it's own or with plug ins. PDF's, words DOC, TXT files, etc.. Here's how to get that download dialog box open.

getFile.cfm
Make a new file. Let's call it getFile.cfm. This file will be calling the downloads for us.
Instead of linking to thisFile.txt like <a href="thisFile.txt">Download ThisFile.txt!</a> we will do it like <a href="getFile.cfm?file=thisFile.txt">Download ThisFile.txt!</a>

First get the full physical path to the file on the server drive.

<cfset fullPath = "c:\inetpub\mysite\">


Now let's make a list of mime types we are going to use. If you are using cffile to upload the files that will be downloaded, you should catch the cffile.contentType and cffile.contentSubType and save them with the filename you uploaded. Format the mime type properly like #cffile.contentType & "/" & cffile.contentSubType# and stick in the table with the other file info you store during upload. For this example I will hardcode a few mime types in, and look them up based on file extension.

<cfset mimeTypes = structNew()>
<cfset mimeTypes.doc   =   "application/msword">
<cfset mimeTypes.xls   =   "application/vnd.ms-excel">
<cfset mimeTypes.txt   =   "text/plain">


Add as many as you want.


Remember our filename is a url variable now, so get it from the url. We are going to check the extension of url.file against the structure of mime types we just made. If it is not in the list, use appliation/unknown as the mime type.

<cfif StructKeyExists(mimeTypes,listLast(url.file,"."))>
   <cfset thisMime = mimeTypes[listLast(url.file,".")]>
<cfelse>
   <cfset thisMime = "application/unknown">
</cfif>



This next part is part of the trick that makes this work. Use cfheader to change the http header information to make the file an attachment. This makes the download dialog open on the client side.
The filename=#url.file# part makes the file being downloaded have the correct name. If you leave this out, the download will by default be saved as getFile.cfm and we or the users don't want that.

<cfheader name="Content-disposition" value="attachment;filename=#replace(url.file," ","_","ALL")#">


Use cfcontent as usuall to finish of this script. Use the fullPath variable and the url.filename to make the file attribute in cfcontent

<cfcontent file="#fullPath & url.file#" type="#thisMime#" deletefile="No">


This is a basic example. The sweetest thing about using cfcontent to serve files is the fact that because you are calling the file by it's absolute path on the disk, you can put files BELOW the web root, where http has no access, and users can not download from unless you provide them a link to the file using the method we just went over. And, because it runs cfml before the download, you can do things like: check if the current url is your domain or not. If not, only diaply a thumbnail version of the image, even if the link is asking for the full size. Or serve a 'no hot linking' jpg instead of the requested one. Another thing I use it for is to run a few checks to make sure a logged on user has access ot the file they are trying to download. So even if they change the url param to ask for another file they can't download it.
____________

Back to the Top 

Tutorial Code

<!---{ set the full path to the files }--->
<cfset fullPath = "C:\Inetpub\mydomain\myfolder">

<!---{ make the mimeTypes struct }--->
<cfset mimeTypes = structNew()>
<!---{ populate the mimeTypes struct }--->
<cfset mimeTypes.doc   =   "application/msword">
<cfset mimeTypes.xls   =   "application/vnd.ms-excel">
<cfset mimeTypes.txt   =   "text/plain">

<!---{ see if the file extension passed via the url file is in our mimetype struct }--->
<cfif StructKeyExists(mimeTypes,listLast(url.file,"."))>
   <!---{ if it is, set it as the mimeType for cfcontent to use }--->
   <cfset thisMime = mimeTypes[listLast(url.file,".")]>
<cfelse>
   <cfset thisMime = "application/unknown">
</cfif>

<!---{ set the content-disposition and filename for the download in the http header}--->
<cfheader name="Content-disposition" value="attachment;filename=#replace(url.file," ","_","ALL")#">

<!---{ cfcontent gets the file and sends the http info }--->
<cfcontent file="#fullPath & url.file#" type="#thisMime#" deletefile="No">
Back to the Top 

Comments

Leave this field empty
No comments on this tutorial. Be the first to leave a comment by using the form above.

A lot-o-nothin STORE (Demo & Test Area - but feel free to purchase - it's all really for sale!)

Check Page Ranking