Let’s say you have an application requirement that uploads files to your web server and then lets your visitors either view or save them. They could be Documents, Spreadsheets, Photos, or anything else you can think of. However you want to be able to control who is able to access these files. How do you accomplish that with not allowing direct linking (ex. http://www.cfwebtools.com/files/xyz.docx)?
You can serve the files via a ColdFusion page. There are a few different methods to do this, and they really come down to MIME typing.
Option 1:
Allow the user to save or open any file.
<cfheader name="Content-Disposition" value="attachment; filename=""#getFileFromPath(filePath)#"""> <cfcontent file="#filePath#" type="application/octet-stream">
The cfheader of attachment and filename prompt the user to either save or externally open the document with the software and their computer. The client computer will determine which MIME type to use to associate with an application.
Option 2:
Allow the user to save or open only files with MIME types my server is aware of.
<cfset mimeType = getPageContext().getServletContext().getMimeType(filePath)> <cfif IsDefined("mimeType")> <cfheader name="Content-Disposition" value="attachment; filename=""#getFileFromPath(filePath)#"""> <cfcontent file="#filePath#" type="#mimeType#"> <cfelse> This type of file is not supported. </cfif>
Now – the MIME types supported are defined in your webserver, whether it’s IIS, Apache or other. Apache MIME types can be configured in the mime.types files in the httpd/conf directory. The getMimeTypes() method communicates with the web server and returns the associated MIME type for the file.
Now, be aware that there may be an issue with IIS communicating MIME types to ColdFusion on Windows 2K Server. I’ve had an application break using this method for additional types such as .docx extensions. I have not yet found a solution for it, and just use option #1 to work around it.
Option 3:
Allow the user to view supported types inside the browser such as MS Word documents and PDF files. If not supported in the browser, it will attempt to open the file externally.
<cfset mimeType = getPageContext().getServletContext().getMimeType(filePath)> <cfif IsDefined("mimeType")> <cfheader name="Content-Disposition" value="inline; filename=""#getFileFromPath(filePath)#"""> <cfcontent file="#filePath#" type="#mimeType#"> <cfelse> This type of file is not supported. </cfif>
You can also define the MIME type in the code by replacing the mimeType variable with the type such as “application/msword”.
Notice in the three examples I double up the quotes around the filename attribute in the cfheader tag. This resolves an issue that happens when you have spaces in the file name. Using no quotes will truncate the file name. Using double quotes will create an invalid tag. And using single quotes will just add single quotes to the file name. Therefore using doubled up (escaped) double quotes makes this work. Apparently in IE7 (and I’m assuming earlier versions) the spaces are converted into underscores (_). You could also use character codes (chr(34)) instead. Thanks to Ben Nadel for this solution.
These methods allow you to access any attached storage device on the server. Therefore you can save the files out of the web directory, making the file inaccessible without using your ColdFusion script. Imagine the possibilites like adding user authentication or IP restriction.
Additional resources:
Serving File Downloads with ColdFusion via Trunkful.com