Difference between revisions of "ColdFusion Tips & Tricks"
(→Output CF Error details without CFDump) |
(→Create an Application.cfc file) |
||
Line 16: | Line 16: | ||
</cfcomponent> | </cfcomponent> | ||
</pre> | </pre> | ||
− | Setup ''' | + | Setup '''onRequest''' function in '''Application.cfc''' to include the '''Application.cfm''' file |
This step is only necessary if an Application.cfm file already exists in the root of the application. Below is what the Application.cfc file will look like after this addition: | This step is only necessary if an Application.cfm file already exists in the root of the application. Below is what the Application.cfc file will look like after this addition: | ||
Line 25: | Line 25: | ||
</cfscript> | </cfscript> | ||
− | <cffunction name=" | + | <cffunction name="onRequest" returnType="void"> |
− | <cfargument name=" | + | <cfargument name="targetPage" type="string" required="true" /> |
− | < | + | |
− | + | <!--- Include Application.cfm ---> | |
− | + | <cfinclude template="Application.cfm" /> | |
− | </ | + | |
+ | <!--- Include the requested page ---> | ||
+ | <cfinclude template="#ARGUMENTS.targetPage#" /> | ||
</cffunction> | </cffunction> | ||
</cfcomponent> | </cfcomponent> |
Revision as of 17:59, 18 April 2013
Contents
- 1 Converting Application.cfm to Application.cfm
- 2 CFHTTP Connection Failures over HTTPS
- 3 CFMAIL Multi-Part Emails
- 4 Per-Application ColdFusion Mappings
- 5 Per-Application Custom Tag Paths
- 6 Restart a ColdFusion Application
- 7 Scheduling Tasks in ColdFusion
- 8 Session Management - Handling Bots and Spiders
- 9 Session Management
- 10 Output CF Error details without CFDump
Converting Application.cfm to Application.cfm
Using an Application.cfc configuration file offers some advantages over the older style Application.cfm configuration files. Some of the main features that an Application.cfc file give you are "functions triggered by Application, Session, Request, and Error events" and "Application-Level Mappings and Custom Tag Paths".
There are only a few steps required to convert an application to use an Application.cfc file:
NOTE: You should ensure that you have a backup of any files before making changes to them.
Create an Application.cfc file
Below is an example Application.cfc file with the minimum requirements:
<cfcomponent> <cfscript> this.name = hash( getCurrentTemplatePath() ); // unique app name </cfscript> </cfcomponent>
Setup onRequest function in Application.cfc to include the Application.cfm file
This step is only necessary if an Application.cfm file already exists in the root of the application. Below is what the Application.cfc file will look like after this addition:
<cfcomponent> <cfscript> this.name = hash( getCurrentTemplatePath() ); // unique app name </cfscript> <cffunction name="onRequest" returnType="void"> <cfargument name="targetPage" type="string" required="true" /> <!--- Include Application.cfm ---> <cfinclude template="Application.cfm" /> <!--- Include the requested page ---> <cfinclude template="#ARGUMENTS.targetPage#" /> </cffunction> </cfcomponent>
Copy application settings from the cfapplication tag and remove the cfapplication tag
This step is only necessary if a cfapplication tag is used within the application. Each attribute of the cfapplication tag will need to be copied into the cfscript section at the top of the Application.cfc with the pattern [this.attributeName = "value";].
For example. The below cfapplication tag would be converted into our Application.cfc example as follows:
cfapplication tag:
<cfapplication name = "my_app_name" sessionManagement = "Yes" sessionTimeout = "#createTimeSpan(0,0,20,0)#" setClientCookies = "Yes">
Application.cfc:
<cfcomponent> <cfscript> this.name = "my_app_name"; // app name from old cfapplication tag this.sessionManagement = "Yes"; this.sessionTimeout = CreateTimeSpan(0,0,20,0); this.setClientCookies = "Yes"; </cfscript> <cffunction name="onRequestStart"> <cfargument name="requestname" required=true /> <cfscript> include "Application.cfm"; return true; </cfscript> </cffunction> </cfcomponent>
NOTE: Do not forget to remove the cfapplication tag after copying the settings into the Application.cfc file.
Now that the change is complete, this is a good time to test the application to ensure everything is working correctly with the new setup.
CFHTTP Connection Failures over HTTPS
If you try to use <cfhttp> to connect to a secure site (over HTTPS), you may receive the following error: "Connection Failure: Status code unavailable"
To fix this add the following code to your site's "Application.cfm" file (below the 'cfapplication' tag):
<!--- fix for HTTPS connection failures ---> <cfif NOT isDefined("Application.sslfix")> <cfset objSecurity = createObject("java", "java.security.Security") /> <cfset objSecurity.removeProvider("JsafeJCE") /> <cfset Application.sslfix = true /> </cfif>
If your site uses an "Application.cfc" file instead, then just place that code in the "'onApplicationStart()" method of that file. After making that adjustment you'll need to restart your ColdFusion application as shown here.
CFMAIL Multi-Part Emails
Sending emails with both Text and HTML parts helps reduce the chance of your messages getting caught by a mail server's spam filter. It also helps ensure your recipients can read the message regardless of the mail client being used. The easiest way to do this is to store your message in a variable using <cfsavecontent> then adding it to <cfmail> using <cfmailpart> as shown in the example below:
<!--- Store your message in a variable ---> <cfsavecontent variable="myemailcontent"> Hello, This is some plain text. <br /> <b>And this is some more text in HTML. It will appear in plain-text for anyone who views the Text part of this email, though.</b> </cfsavecontent> <!--- Function to strip HTML from message while preserving line breaks ---> <cffunction name= "textMessage" access= "public" returntype= "string" hint= "Converts an html email message into a nicely formatted with line breaks plain text message"> <cfargument name= "string" required= "true" type= "string"> <cfscript> var pattern = " <br>"; var CRLF = chr( 13) & chr( 10); var message = ReplaceNoCase(arguments.string, pattern, CRLF , "ALL"); pattern = "<[^>]*>"; </cfscript> <cfreturn REReplaceNoCase(message, pattern, "" , "ALL")> </cffunction> <!--- Now send the email. When adding the Text part, we'll use the textMessage() function we just created to strip out HTML tags. ---> <cfmail from="sender@domain.com" to="recipient@anotherdomain.com" subject="Multi-part Email with CFMAIL" type="html"> <cfmailpart type= "text/plain" charset= "utf-8">#textmessage(myemailcontent)#</cfmailpart> <cfmailpart type= "text/html" charset= "utf-8">#myemailcontent#</cfmailpart> </cfmail>
Reference: CFMAIL the right way
Per-Application ColdFusion Mappings
In ColdFusion 8 and above, it is possible to create per-application mappings through your site's Application.cfc file.
Once you have your Application.cfc created, you will insert the following line:
<cfset this.mappings["/test"]="d:\home\yourdomainname.com\wwwroot\test">
On your site though, you would change "/test" to the name of your mapping. IMPORTANT: You need to include the forward slash before the name of your mapping. Also, change "d:\home\yourdomainname.com\wwwroot\test" to the full physical path to the folder you wish to map. Note: The physical path to your FTP root is listed in the "Site Settings" of your control panel at wcp.hostek.com.
To call a template named "testing.cfm" in the "test" directory we just mapped, you would use this line:
<cfinclude template="/test/testing.cfm">
Per-Application Custom Tag Paths
Starting in ColdFusion 8, ColdFusion allows creation of Custom Tag Paths in each site's Application.cfc file. This allows you to create and manage your Custom Tag Paths without having to use CF Administrator (ie. submit a support ticket). The following steps will help you create a Custom Tag Path:
If you do not already have an Application.cfc file in your site's Web root, create one now. Place the following code in the Application.cfc file and save:
<cfcomponent> <cfset THIS.customtagpaths="d:\home\yourdomain.com\wwwroot\customtagfolder"> </cfcomponent>
In this case, you'd replace "yourdomain.com" with your domain name, and "customtagfolder" with the name of the folder you created for your custom tags.
Now you have successfully added your custom tag path. If you have multiple tag paths to add, try using the following code instead:
<cfcomponent> <cfset THIS.customtagpaths=ListAppend(THIS.customtagpaths, "d:\home\yourdomain.com\wwwroot\customtagfolder")> </cfcomponent>
Restart a ColdFusion Application
If you ever need to restart your site's ColdFusion application (to pick up a setting change, etc), you can do so via the ApplicationStop() function in ColdFusion 9+.
To use this you can create a file (ex: restart.cfm) containing the following code:
<cfset ApplicationStop() /> <cflocation url="index.cfm" addtoken="false" />
When you run the file containing that code your ColdFusion Application will be stopped (flushing your application scope), and when the browser is redirected to the index page the application will start again.
Scheduling Tasks in ColdFusion
On occasion shared ColdFusion hosting customers need to setup Scheduled Task to run files on a cycle.
This can be done with the following steps, making use of ColdFusion's <cfschedule> tag:
- Create a file locally using any text editor, save the file with the .CFM extension (example: setschedule_example.cfm).
- Copy and past in the code example below taken from ColdFusion's Documentation and save.
- Replace the data in the example note the following recommendations.
!- Name each file made for creating a schedule with the name of the task so you can reference the task later if needed. Specific naming will also make it more difficult for someone to randomly run the file.
!- If you need to schedule a job to run monthly on any date in the range 28-31, read about how ColdFusion will handle the scheduling in the ColdFuison8 documentation referenced below. - Working example, the code example below is a working tested solution for getting the weather for a specific zip code and the task to email the results.
Scheduled Task
<!-- This sets the initial task, if your just wanting to set the schedule --> <cfschedule action = "update" task = "Weather_Send" operation = "HTTPRequest" url = "http://test.hostek.net/weather_send.cfm" startDate = "7/6/09" startTime = "09:30 AM" interval = "3600" resolveURL = "Yes" requestTimeOut = "600"> <!-- This allows for the task created to be deleted, just uncomment and change the task name. --> <!-- cfschedule action = "delete" task = "Weather_Send"--> <!-- This allows for the task to be paused, just uncomment and change the task name. --> <!-- cfschedule action = "pause" task = "Weather_Send"--> <!-- This allows for the task resumed if paused, just uncomment and change the task name. --> <!-- cfschedule action = "resume" task = "Weather_Send"-->
Weather Collector
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>CF External Weather Checker</title> </head> <body> <cfset zip="12345"> <cfinvoke webservice="http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl" method="getCityWeatherByZIP" returnvariable="aWeatherReturn"> <cfinvokeargument name="ZIP" value="#zip#"/> </cfinvoke> <cfif aWeatherReturn.temperature EQ ""> <cfoutput> I cannot get the weather for #zip# external http connections must be DOWN.</cfoutput> <cfelse> <cfset message="The temperature for #zip# (Your city) is #aWeatherReturn.temperature# degrees."> </cfif> <cfif message NEQ ""> <cfmail from = "weather.server@test.com" to = "test@test.com" subject = "Weather checker"> #message# </cfmail> </cfif> </body> </html>
Session Management - Handling Bots and Spiders
Robots.txt File
First and foremost we suggest creating a robots.txt file in the web root of the domain to address two issues. First to control the rate at which the website is being crawled which can help prevent a bot/spider from creating a massive number of database connections at the same time. Second to prevent specific bots from crawling the website. We suggest the following defaults, however you might want to add or remove the user agents denied, and adjust the crawl rate but we suggest nothing lower than 3 seconds.
User-agent: * Crawl-delay: 10 User-agent: Baiduspider Disallow: / User-agent: Sosospider Disallow: /
Lower Session Timeouts for Bots and Spiders
Next we suggest setting your session timeout specifically lower for bots and spiders. These spiders and bots will crawl a page and when a session (ColdFusion) is created, it will persist during then entire page load. The page fully loaded allows the bot or spider to get the information from the Web page AND allows the session to expire quickly protecting ColdFusion from effects similar to a memory leak.
To do this, implement the appropriate solution for your site below:
If using Application.cfm
Place this code at the top of your Application.cfm file:<!--- This checks if a cookie is created, for bots this will return false and use the low session timeout ---> <cfif not structKeyExists(cookie, "cfid")> <cfset REQUEST.sessionTimeout = CreateTimeSpan(0,0,0,2) /> <cfelse> <cfset REQUEST.sessionTimeout = CreateTimeSpan(0,0,30,0) /> </cfif>Then use the REQUEST.sessionTimeout variable to specify the session timeout period in your cfapplication tag:
</cfif> <cfapplication name="myawesomeapp" sessionmanagement="Yes" sessiontimeout="#REQUEST.sessionTimeout#">
If using Application.cfc (tag-based)
If you primarily use cfml tags in your Application.cfc, you can set the Session Timeout like this:<!--- This checks if a cookie is created, for bots this will return false and use the low session timeout ---> <cfif StructKeyExists(cookie, "cfid")> <cfset this.sessiontimeout = CreateTimeSpan(0,0,30,0) /> <cfelse> <cfset this.sessiontimeout = CreateTimeSpan(0,0,0,2) /> </cfif>
If using Application.cfc (cfscript)
If instead, you're using cfscipt in your Application.cfc, you'll set the custom Session Timeout like this:<!--- This checks if a cookie is created, for bots this will return false and use the low session timeout ---> if (StructKeyExists(cookie, "cfid")){ this.sessionTimeout = createTimeSpan(0,0,30,0); } else { this.sessionTimeout = createTimeSpan(0,0,0,2); }
Reference: Session Management code examples for the Application.cfm
Session Management
How to verify Session Management is working
By default the Session Timeout is set to 20 minutes.
Here is a sample script to verify the ColdFusion Session variables and ColdFusion Session in general is working.
I'm sure there is an easier way to test this, but here is what I did. I created 2 pages. The first page sets the Session variables. The second page keeps adding to the counter and displaying the count, when the session started, and the current time.
This is handled differently based on whether you are using Application.cfm or Application.cfc, so be sure to note which one you are using. If using Application.cfm, you need to make sure your application.cfm file is set to handle session variables. To do this, make sure you have sessionmanagement="yes" like:
<cfapplication sessionmanagement="yes">
If using Application.cfc, you need to make sure your application.cfc is set to handle the sessions variables properly. Here is an example for that:
<cfcomponent> <cfset this.name = "myApplication"> <cfset this.Sessionmanagement = TRUE> </cfcomponent>
In the first page (ie, cfsessiontest.cfm) add this code:
<cfset SESSION.MyCount = 1> <cfset SESSION.StartTime = Now()> Current Count is: <cfoutput>#SESSION.MyCount#</cfoutput><BR /> Session Started at: <cfoutput>#SESSION.StartTime#</cfoutput><BR /> <A HREF="cfsessiontest2.cfm">Test Session</A>
Now create a new page named cfessiontest2.cfm and add this code:
<cfset SESSION.MyCount = #SESSION.MyCount# + 1> Current Count is: <cfoutput>#SESSION.MyCount#</cfoutput><BR /> The current time is <cfoutput>#Now()#</cfoutput> and the Session Started at: <cfoutput>#SESSION.StartTime#</cfoutput><BR /> <A HREF="cfsessiontest2.cfm">Test Session</A>
The first page will load the 2nd page and the 2nd page will keep loading itself when you click on the Test Session link.
Important: If you are on a Linux-based ColdFusion server, you MUST capitalize the 'A' in 'Application.cfm' or 'Application.cfc'. If you do not do this, ColdFusion will not recognize your 'Application.cfm' or 'Application.cfc' file.
Delete Session Cookies
On ColdFusion pages, you can use the following code to delete a users session cookies when he closes the browser:
<!---Kill user session if user closes browser---> <cfif IsDefined("Cookie.CFID") AND IsDefined("Cookie.CFTOKEN")> <cfset Variables.cfid_local = Cookie.CFID> <cfset Variables.cftoken_local = Cookie.CFTOKEN> <cfcookie name="CFID" value="#Variables.cfid_local#"> <cfcookie name="CFTOKEN" value="#Variables.cftoken_local#"> </cfif>
Adjusting Session Timeouts
Our ColdFusion servers have a default session timeout of two (2) hours. If you wish to adjust that, you can do so through your Application.cfm or Application.cfc files.
If using Application.cfm
This <cfapplication> tag specifies a custom session timeout of 3 hours and 30 minutes:<cfapplication name="myawesomeapp" sessionmanagement="Yes" sessiontimeout="#CreateTimeSpan(0,3,30,0)#">
If using Application.cfc (tag-based)
Use this code (adjusting the timespan as necessary) to set your custom session timeout:<cfset this.sessiontimeout = CreateTimeSpan(0,3,30,0) />
If using Application.cfc (cfscript)
Use this code (adjusting the timespan as necessary) to set your custom session timeout:this.sessionTimeout = createTimeSpan(0,3,30,0);
Output CF Error details without CFDump
It is common in an error handler that you want to output all of the error details to the screen, a file, or an email. Therefore, the cfdump tag is commonly used for this; and, while this works well in development, it is not always the best practice on a production site because of the performance of the cfdump tag due to its use of reflection (Runtime type introspection).
A better performing alternative is to output the information you want directly from the Error/Exception struct within a 'cfoutput' tag. This can be done by looking up the Error structure or the cfcatch structure in the ColdFusion docs to see what is available and what values you might want to output: Error: http://help.adobe.com/en_US/ColdFusi...2c24-7d29.html CFCatch: http://help.adobe.com/en_US/ColdFusi...2c24-7ec5.html
You can also use the following link to download an example CF custom tag that will give a similar error output as when using the cfdump tag on an error variable:
http://hostek.com/tutorials/ColdFusion/CF_OutputError.zip
Below is the custom tag's usage:
In the error handler specified in your 'cferror' tag:
<cf_OutputError Error="#Error#" />
The above code would replace:
<cfdump var="#Error#" />
Or, in a cfcatch block:
<cftry> ... <cfcatch> <cf_OutputCFCatch CFCatch="#CFCatch#" /> </cfcatch> </cftry>