{"__v":2,"_id":"550979a0aa9bd525001a0658","category":{"__v":16,"_id":"550974cc368a56170041475b","project":"55070e814bb83b2500ec9404","version":"550974cb368a561700414757","pages":["55097808ad1f0523008ecbca","550979624c7c3f2300aabf01","5509797daa9bd525001a0656","550979a0aa9bd525001a0658","550979ba4c7c3f2300aabf03","550979e6dd77250d007369f2","55097a02dd77250d007369f4","55097a0fad1f0523008ecbce","55097a1baa9bd525001a065a","55097a212dd6a11900e6e7b0","55097a28ad1f0523008ecbd0","55097a304c7c3f2300aabf05","55097a3add77250d007369f6","55097a402dd6a11900e6e7b2","55097a6fdd77250d007369f8","55097a77ad1f0523008ecbd2"],"reference":false,"createdAt":"2015-03-18T11:08:22.079Z","from_sync":false,"order":3,"slug":"handling-requests-with-controllers","title":"Handling Requests with Controllers"},"project":"55070e814bb83b2500ec9404","user":"55070d24d30b3f190011b941","version":{"__v":1,"_id":"550974cb368a561700414757","forked_from":"55070e814bb83b2500ec9407","project":"55070e814bb83b2500ec9404","createdAt":"2015-03-18T12:51:23.709Z","releaseDate":"2015-03-18T12:51:23.709Z","categories":["550974cc368a561700414758","550974cc368a561700414759","550974cc368a56170041475a","550974cc368a56170041475b","550974cc368a56170041475c","550974cc368a56170041475d","550974cc368a56170041475e"],"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.4.0","version":"1.4"},"updates":[],"createdAt":"2015-03-18T13:12:00.190Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"order":3,"body":"Sending files?! Is that really a necessary feature of Wheels? Can't I just place\nthe file on my web server and link to it? You are correct, there is absolutely\nno need to use Wheels to send files. Your web server will do a fine job of\nsending out files to your users.\n\nHowever, if you want a little more control over the way the user's browser\nhandles the download or be able to secure access to your files then you might\nfind the [sendFile()][1] function useful.\n\n## Sending Files With the [sendFile()][1] Function\n\nThe convention in Wheels is to place all files you want users to be able to\ndownload in the `files` folder.\n\nAssuming you've placed a file named `wheels_tutorial_20081028_J657D6HX.pdf` in\nthat folder, here is a quick example of how you can deliver that file to the\nuser. Let's start with creating a link to the action that will handle the\nsending of the file first.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#linkTo(text=\\\"Download Tutorial\\\", action=\\\"sendTutorial\\\")#\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nNow let's send the file to the user in the `sendTutorial` controller action.\nJust like the rendering functions in Wheels, the [sendFile()][1] function should\nbe placed as the very last thing you do in your action code.\n\nIn this case, that's the only thing we are doing, but perhaps you want to track\nhow many times the file is being downloaded, for example. In that case, the\ntracking code needs to be placed *before* the [sendFile()][1] function.\n\nAlso, remember that the [sendFile()][1] function replaces any rendering. You\ncannot send a file *and* render a page. (This will be quite obvious once you try\nthis code because you'll see that the browser will give you a dialog box, and\nyou won't actually leave the page that you're viewing at the time.)\n\nHere's the `sendTutorial` action:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cffunction name=\\\"sendTutorial\\\">\\n    <cfset sendFile(file=\\\"wheels_tutorial_20081028_J657D6HX.pdf\\\")>\\n</cffunction>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nThat's one ugly file name though, eh? Let's present it to the user in a nicer\nway by suggesting a different name to the browser:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cffunction name=\\\"sendTutorial\\\">\\n    <cfset sendFile(file=\\\"wheels_tutorial_20081028_J657D6HX.pdf\\\", name=\\\"Tutorial.pdf\\\")>\\n</cffunction>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nMuch better! :)\n\nBy default, the [sendFile()][1] function will try and force a download dialog\nbox to be shown to the user. The purpose of this is to make it easy for the user\nto save the file to their computer. If you want the file to be shown inside the\nbrowser instead (when possible as decided by the browser in question), you can\nset the `disposition` argument to `inline`.\n\nHere's an example:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cffunction name=\\\"sendTutorial\\\">\\n    <cfset sendFile(file=\\\"wheels_tutorial_20081028_J657D6HX.pdf\\\", disposition=\\\"inline\\\")>\\n</cffunction>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nYou can also specify what HTTP content type to use when delivering the file by\nusing the `type` argument. Please refer to the API for the [sendFile()][1]\nfunction for complete details.\n\n## Securing Access to Files\n\nPerhaps the main reason to use the [sendFile()][1] function is that it gives you\nan easy way to secure access to your files. Maybe the tutorial file used in the\nabove example is something the user paid for, and you only want for that user to\nbe able to download it (and no one else). To accomplish this, you can just add\nsome code to authenticate the user right before the [sendFile()][1] call in your\naction.\n\nHowever, there is a security flaw here. Can you figure out what it is?\n\nYou may have guessed that the files folder is placed in your web root, so anyone\ncan download files from it by typing\n`http://www.domain.com/files/wheels_tutorial_20081028_J657D6HX.pdf` in their\nbrowser. Although users would need to guess the file names to be able to access\nthe files, we would still need something more robust as far as security goes.\n\nThere are two solutions to this.\n\nThe easiest one is to just lock down access to the folder using your web server.\nWheels won't be affected by it since it gets the file from the file system.\n\nIf that is not an option, the other option is simply to move the files folder\nout of the web root, thus making it inaccessible. If you move the folder, you'll\nneed to accommodate for this in your code by changing your [sendFile()][1] calls\nto specify the path as well, like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cffunction name=\\\"sendTutorial\\\">\\n    <cfset sendFile(file=\\\"../../tutorials/wheels_tutorial_20081028_J657D6HX.pdf\\\")>\\n</cffunction>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nThis assumes you've moved the folder two levels up in your file system and into\na folder named tutorials.\n\n## Don't Open Any Holes with URL Parameters\n\n**A final note of warning:** Be careful to not allow just any parameters from\nthe URL to get passed through to the [sendFile()][1] because then a user would\nbe able to download any file from your server by playing around with the URL.\nBe wary of how you're using the `params` struct in this context!\n\n[1]: doc:sendfile","excerpt":"Use Wheels to send files to your users securely and with better control of the user experience.","slug":"sending-files","type":"basic","title":"Sending Files"}

Sending Files

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

Sending files?! Is that really a necessary feature of Wheels? 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 Wheels 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 [sendFile()][1] function useful. ## Sending Files With the [sendFile()][1] Function The convention in Wheels 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. [block:code] { "codes": [ { "code": "#linkTo(text=\"Download Tutorial\", action=\"sendTutorial\")#", "language": "text" } ] } [/block] Now let's send the file to the user in the `sendTutorial` controller action. Just like the rendering functions in Wheels, the [sendFile()][1] 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 [sendFile()][1] function. Also, remember that the [sendFile()][1] 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: [block:code] { "codes": [ { "code": "<cffunction name=\"sendTutorial\">\n <cfset sendFile(file=\"wheels_tutorial_20081028_J657D6HX.pdf\")>\n</cffunction>", "language": "text" } ] } [/block] 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: [block:code] { "codes": [ { "code": "<cffunction name=\"sendTutorial\">\n <cfset sendFile(file=\"wheels_tutorial_20081028_J657D6HX.pdf\", name=\"Tutorial.pdf\")>\n</cffunction>", "language": "text" } ] } [/block] Much better! :) By default, the [sendFile()][1] 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`. Here's an example: [block:code] { "codes": [ { "code": "<cffunction name=\"sendTutorial\">\n <cfset sendFile(file=\"wheels_tutorial_20081028_J657D6HX.pdf\", disposition=\"inline\")>\n</cffunction>", "language": "text" } ] } [/block] 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 [sendFile()][1] function for complete details. ## Securing Access to Files Perhaps the main reason to use the [sendFile()][1] 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 [sendFile()][1] call in your action. 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. Wheels won't be affected by it since it gets the file from the file system. 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 [sendFile()][1] calls to specify the path as well, like this: [block:code] { "codes": [ { "code": "<cffunction name=\"sendTutorial\">\n <cfset sendFile(file=\"../../tutorials/wheels_tutorial_20081028_J657D6HX.pdf\")>\n</cffunction>", "language": "text" } ] } [/block] 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 **A final note of warning:** Be careful to not allow just any parameters from the URL to get passed through to the [sendFile()][1] 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! [1]: doc:sendfile