LogoLogo
HomeAPIBlog
2.5.0
2.5.0
  • INTRODUCTION
    • Getting Started
      • Running Local Development servers
      • Beginner Tutorial: Hello World
      • Beginner Tutorial: Hello Database
      • Tutorial: CFWheels, AJAX, and You
    • Frameworks and CFWheels
    • Requirements
    • Manual Installation
    • Upgrading
    • Screencasts
  • Command Line Tools
    • CLI Commands
    • wheels - commands
    • wheels generate - commands
    • wheels dbmigrate - commands
    • wheels plugins - commands
  • Working with CFWheels
    • Conventions
    • Configuration and Defaults
    • Directory Structure
    • Switching Environments
    • Testing Your Application
    • Contributing to CFWheels
    • Documenting your Code
  • Handling Requests with Controllers
    • Request Handling
    • Rendering Content
    • Redirecting Users
    • Sending Files
    • Sending Email
    • Responding with Multiple Formats
    • Using the Flash
    • Using Filters
    • Verification
    • Event Handlers
    • Routing
    • URL Rewriting
      • Apache
      • IIS
      • Tomcat
      • Nginx
    • Obfuscating URLs
    • Caching
    • Nesting Controllers
    • CORS Requests
  • Displaying Views to Users
    • Pages
    • Partials
    • Linking Pages
    • Layouts
    • Form Helpers and Showing Errors
    • Displaying Links for Pagination
    • Date, Media, and Text Helpers
    • Creating Custom View Helpers
    • Localization
  • Database Interaction Through Models
    • Object Relational Mapping
    • Creating Records
    • Reading Records
    • Updating Records
    • Deleting Records
    • Column Statistics
    • Dynamic Finders
    • Getting Paginated Data
    • Associations
    • Nested Properties
    • Object Validation
    • Object Callbacks
    • Calculated Properties
    • Transactions
    • Dirty Records
    • Soft Delete
    • Automatic Time Stamps
    • Database Migrations
      • Migrations In Production
    • Using Multiple Data Sources
  • Plugins
    • Installing and Using Plugins
    • Developing Plugins
    • Publishing Plugins
  • External Links
    • Source Code
    • Issue Tracker
    • Sponsor Us
    • Community
Powered by GitBook
LogoLogo
On this page
  • Sending Files with the sendFile() Function
  • Sending Files via ram://
  • Securing Access to Files
  • Don't Open Any Holes with URL Parameters

Was this helpful?

Edit on GitHub
Export as PDF
  1. Handling Requests with Controllers

Sending Files

Use CFWheels to send files to your users securely and with better control of the user experience.

PreviousRedirecting UsersNextSending Email

Last updated 1 year ago

Was this helpful?

Sending files?! Is that really a necessary feature of CFWheels? Can't I just place the file on my web server and link to it? You are correct, there is absolutely no need to use CFWheels to send files. Your web server will do a fine job of sending out files to your users.

However, if you want a little more control over the way the user's browser handles the download or be able to secure access to your files then you might find the function useful.

Sending Files with the sendFile() Function

The convention in CFWheels is to place all files you want users to be able to download in the files folder.

Assuming you've placed a file named wheels_tutorial_20081028_J657D6HX.pdf in that folder, here is a quick example of how you can deliver that file to the user. Let's start with creating a link to the action that will handle the sending of the file first.

<p>
  #linkTo(text="Download Tutorial", action="sendTutorial")#
</p>

Now let's send the file to the user in the sendTutorial controller action. Just like the rendering functions in CFWheels, the function should be placed as the very last thing you do in your action code.

In this case, that's the only thing we are doing, but perhaps you want to track how many times the file is being downloaded, for example. In that case, the tracking code needs to be placed before the function.

Also, remember that the function replaces any rendering. You cannot send a file and render a page. (This will be quite obvious once you try this code because you'll see that the browser will give you a dialog box, and you won't actually leave the page that you're viewing at the time.)

Here's the sendTutorial action:

Example
function sendTutorial() {
    sendFile(file="wheels_tutorial_20081028_J657D6HX.pdf");
}

That's one ugly file name though, eh? Let's present it to the user in a nicer way by suggesting a different name to the browser:

Example
function sendTutorial() {
    sendFile(file="wheels_tutorial_20081028_J657D6HX.pdf", name="Tutorial.pdf");
}

Much better! :)

Here's an example:

Example

function sendTutorial() {
    sendFile(file="wheels_tutorial_20081028_J657D6HX.pdf", disposition="inline");
}

Sending Files via ram://

You can even send files which are stored in ram:// - this is particularly useful when you're dynamically creating files (such as PDF reports) which don't need to be written to the file system.

Example
// Create the PDF.
cfwheels = cfdocument(format='pdf') {
 writeOutput(Now());
}; 

// Write the file to RAM.
fileWrite("ram://cfwheels.pdf", cfwheels);

// Send it.
sendFile(file="ram://cfwheels.pdf");

Securing Access to Files

However, there is a security flaw here. Can you figure out what it is?

You may have guessed that the files folder is placed in your web root, so anyone can download files from it by typing http://www.domain.com/files/wheels_tutorial_20081028_J657D6HX.pdf in their browser. Although users would need to guess the file names to be able to access the files, we would still need something more robust as far as security goes.

There are two solutions to this.

The easiest one is to just lock down access to the folder using your web server. CFWheels won't be affected by it since it gets the file from the file system.

Example
function sendTutorial() {
    sendFile(file="../../tutorials/wheels_tutorial_20081028_J657D6HX.pdf");
}

This assumes you've moved the folder two levels up in your file system and into a folder named "tutorials".

Don't Open Any Holes with URL Parameters

By default, the function will try and force a download dialog box to be shown to the user. The purpose of this is to make it easy for the user to save the file to their computer. If you want the file to be shown inside the browser instead (when possible as decided by the browser in question), you can set the disposition argument to inline.

You can also specify what HTTP content type to use when delivering the file by using the type argument. Please refer to the API for the function for complete details.

Perhaps the main reason to use the function is that it gives you an easy way to secure access to your files. Maybe the tutorial file used in the above example is something the user paid for, and you only want for that user to be able to download it (and no one else). To accomplish this, you can just add some code to authenticate the user right before the call in your action.

If that is not an option, the other option is simply to move the files folder out of the web root, thus making it inaccessible. If you move the folder, you'll need to accommodate for this in your code by changing your calls to specify the path as well, like this:

A final note of warning: Be careful to not allow just any parameters from the URL to get passed through to the because then a user would be able to download any file from your server by playing around with the URL. Be wary of how you're using the params struct in this context!

sendFile()
sendFile()
sendFile()
sendFile()
sendFile()
sendFile()
sendFile()
sendFile()
sendFile()
sendFile()