Catching errors database errors in ColdFusion - coldfusion

I have a ColdFusion cfm file that communicates with a sql server database. Right now if something goes wrong with the database connection, it brings up an error page generated by ColdFusion. Is there a way I can catch the errors and display a message like, "Database server temporarily down, please come back later"?
Ted

You can use try/catch for an individual query - this will be the most granular approach.
<cftry>
<cfquery datasource="myDSN">BROKEN SQL</cfquery>
<cfcatch type="database">
<h1>Database Offline!</h1>
<p>Sorry, the database threw an error: #cfcatch.queryError#. Try again later.</p><cfabort>
</cfcatch>
</cftry>
You can also use the cferror tag for global exception handling (put this in Application.cfm):
<cferror
type="exception"
exception="database"
template="myFriendlyDatabaseErrorTemplate.cfm">
You can also use onError method within Application.cfc, which will also (like the cferror tag) catch all errors that occur during the request:
<cffunction name="onError" returnType="void">
<cfargument name="Exception" required=true/>
<cfargument name="EventName" type="String" required=true/>
<cfif arguments.Exception IS "database">
<cfinclude template="myFriendlyDatabaseErrorTemplate.cfm">
</cfif>
</cffunction>

Related

File Not Found in CF11 even though file exists

Well, I have been experiencing same error as discussed here:
Coldfusion 10 File Not Found Error
I am using Coldfusion 11 , developer edition on my Laptop , Windows 8.1 Pro (OS).
People have suggested two approaches over there to overcome this problem:
1) Setting Missing Template in CFAdmin
2) Setup onMissingTemplate function in Application.cfc
I am basically not sure with any of the approaches , however, I would like to go with the first approach. Could anyone tell me how should I set up missing template in CFadmin?
Why do you prefer letting the server handle the missing template? Myself, I like to handle it on a per-application basis. Some applications should never have links leading to non-existing files, others may operate on that as part of its core.
Straight from adobe's docs, you can use (I accidentally pulled this info from cf8 docs, but the link is to current docs and the result is largely the same.
<cffunction name="onMissingTemplate" returnType="boolean">
<cfargument type="string" name="targetPage" required=true/>
...
<cfreturn BooleanValue />
</cffunction>
For a few of my projects, I've written a CMS (Content-Management-System) that stores all the content in the database in fashion.
CMSPages
------------
PID PTitle PFile PContent
1 Home /index.cfm <b>Hey!</b> Welcome to our gollygizmo website.
And then I (my real code actually uses cfincludes rather than directly in the document. You can do it either way, but it was easiest for me to demonstrate with inline code).
<cffunction name="onMissingTemplate" returnType="boolean">
<cfargument type="string" name="targetPage" required=true/>
<cftry>
<cfquery name="FindPage">
select * from CMSPages
where pFile = <cfqueryparam cfsqltype="nvarchar" value="#Arguments.targetPage#">
</cfquery>
<cfif FindPage.recordcount eq 1>
<cfoutput query="FindPage">show page stuffs</cfoutput>
<cfreturn true>
<cfelse>
<!--- Page not found, log some stuff or email stuff
include cgi data so you know where the link came from --->
Hey, this page doesn't exist, sorry about that.
<cfreturn true>
</cfif>
<cfcatch>
<!--- Something went wrong, log/email error info and --->
<cfreturn false>
<!--- We return false here to pass it back to the default error handler, which can be a handler set in cfadmin. --->
</cfcatch>
</cftry>
</cffunction>
In such a scenario, it's probably beneficial to cache queries based on query name, you can do something like
<cfquery name="local.FindPage#hash(arguments.targetpage)#" cachedWithin="...">
...
</cfquery>
<cfset request.FindPage=local["Findpage#hash(arguments.targetpage)#"]>
So that the queries are cached by unique names, even though it's easily accesible in your document by a common name.
However, if you still prefer server-centric missing template handling, a simple search for cold fusion admin missing template will bring you here.
In the ColdFusion Administrator, click on "Settings" to view the "Server Settings" page
Specify the absolute path that ColdFusion will use to find your error handling template

Assign one error log file per application

We have multiple applications running on the same server and default log files end up being a mess of everything, especially the Exception log for which the admin panel does not offer search capacities.
Is it at all possible to have Coldfusion log things pertaining to a given application (as defined by Application.cfm or .cfc) to a separate log?
If not, any alternative solutions to this issue?
I'd recommend application.cfc onError method to log uncaught errors in separate log file. Also this doc could be helpful: Handling errors in Application.cfc
Here's a basic example of using the onError function in application.cfc to log errors to an application-specific log file.
<cfcomponent output="false">
<cfset this.name = "myApp">
<cffunction name="onError">
<cfargument name="exception" required="true">
<cfargument name="eventName" type="string" required="true">
<cfset var myAppName = this.name>
<cfset var details = "">
<!--- You need to specify and check for the exception details you want to include in your log text --->
<cfif IsDefined( "exception.type" )>
<cfset details = "Type: #exception.type#. ">
</cfif>
<cfif IsDefined( "exception.message" )>
<cfset details = details & "Details: #exception.message#">
</cfif>
<cflog type="error" file="#myAppName#" text="#details#">
<!--- Specify how you want the error to be handled once it's been logged --->
<cfdump var="#exception#">
</cffunction>
</cfcomponent>
You need to specify which parts of the exception details you want to include in your log entry, bearing in mind that the keys of the exception struct will vary according to the type of error thrown. It's therefore best to check for their existence before adding them to the log text.
Official onError docs for ColdFusion MX7 (since your question's tagged with that version - which is also why I've used tags rather than cfscript in my example to be on the safe side).

Getting error that event handler not registered in Coldbox

I am getting the following error message. I have already created Uploads.cfc handler in handlers directory. Checked everything, can't find the solution.
Error Type: HandlerService.EventHandlerNotRegisteredException : [N/A]
Error Messages: The event: uploads is not valid registered event.
Here is the Uploads.cfc code:
<!--- Default Action --->
<cffunction name="index" returntype="string" output="false" hint="My main event">
<cfargument name="event">
<cfargument name="rc">
<cfargument name="prc">
<cfobject component="model.Uploader" name="fileUploader">
<cfset filesJson = fileUploader.Upload(rc.file)>
<cfreturn filesJson>
</cffunction>
Can you please suggest a solution?
You shouldn't have to restart the whole CF server. You just need to re-initialize ColdBox. Just add ?fwreint= or ?fwreint={password} to the URL. The password is set in ColdBox.cfc: "reinitpassword". You can also configure in ColdBox.cfc to not cache handlers in non-production environments.
If you're using ColdBox 3.6 or newer, you don't have to define event, rc and prc anymore.
<cffunction name="index" returntype="string" output="false" hint="My main event">
<cfobject component="model.Uploader" name="fileUploader">
<cfset filesJson = fileUploader.Upload(rc.file)>
<cfreturn filesJson>
</cffunction>
Secondly, you should use WireBox instead of creating objects on the fly as you're doing. And finally, don't define variables specific to a function into the variables scope of the handler CFC file. Prefix them with local to make sure that those variables are "function local": only available to the particular function that is using them.
<cffunction name="index" returntype="string" output="false" hint="My main event">
<cfset local.fileUploader = getModel("Uploader") >
<cfset local.filesJson = fileUploader.Upload(rc.file)>
<cfreturn local.filesJson>
</cffunction>
I have also encountered the same problem in the past. Try restart the ColdFusion Application Server.
iKnowKungFu misspelled ?fwreint= (missing i)
Should be ?fwreinit

How to display <cfreturn> output from a CFC being called from a form

I have a web form which uses the action attribute to call a CFC like this:
<form action="mycfc.cfc?method=registeruser">
The CFC processes the data in the form and then I want it to return a variable telling the user if their form submission has been successful or not.
So within my CFC, I put this:
<cffunction name="registeruser" access="remote" hint="registers a new user" returnformat="JSON">
... PROCESSES FORM HERE THEN...
<cfset Msg = 'Success'>
<cfreturn Msg>
<cflocation url = "/registrationpage.cfm">
</cffunction>
How do I display the Msg variable in the registrationpage.cfm page? My output is set to JSON so I guess I have to DeSerialize but I have no idea how to actually reference/access this output from the method.
My whole answer is for educationnal purposes only and I strongly advise you to use an existing framework rather than reinventing the Wheels. Have a look at Picking a ColdFusion MVC Framework
You can store the value in the session scope. A lot of frameworks does it using a flash memory concept, which is a temporary memory (implemented as a struct) that destroys members when accessed.
Have a look at http://cfwheels.org/docs/1-1/chapter/using-the-flash it's quite straight forward to implement an API that does this.
Client code could look like (depending on your implementation):
<cfset session.flash.set('importantMsg', 'some important msg')>
<cflocation ...>
Then from the other page:
<cfif session.flash.has('importantMsg')>
<!--- The following line should also destroy the 'importantMsg' key --->
#session.flash.get('importantMsg')#
</cfif>
Here's an implementation example (not that the implementation is not thread-safe):
FlashMemory.cfc
<cfcomponent>
<cffunction name="init" returntype="FlashMemory">
<cfset variables.instance = {flash = {}}>
</cffunction>
<cffunction name="set" returntype="void">
<cfargument name="key" type="string" required="true">
<cfargument name="value" type="any" required="true">
<cfset variables.instance.flash[arguments.key] = arguments.value>
</cffunction>
<cffunction name="get" returntype="any">
<cfargument name="key" type="string" required="true">
<cfset var v = variables.instance.flash[arguments.key]>
<cfset structDelete(variables.instance.flash, arguments.key)>
<cfreturn v>
</cffunction>
<cffunction name="has" returntype="boolean">
<cfargument name="key" type="string" required="true">
<cfreturn structKeyExists(variables.instance.flash, arguments.key)>
</cffunction>
</cfcomponent>
onSessionStart
<cfset session.flash = new FlashMemory()>
Also please note that in your case, your remote CFC methods shouldn't return anything. You will use the flash memory to pass data around instead. That means when the method has finished it's work you can simply redirect the client.
You probably shouldn't use remote CFC methods in this particular case:
I have never really used remote CFC methods as stateful web services. The various advantages of remote CFC methods like their ability to spit out data in multiple data-interchange formats (JSON, WDDX...) is lost with your implementation.
You could simply do something like:
registration.cfm
<cfset errors = session.flash.get('registrationErrors')>
<cfif arrayLen(errors)>
<!--- Display errors --->
</cfif>
<form method="post" action="register.cfm">
...
</form>
register.cfm
<cfset registration = new Registration(argumentcollection = form)>
<cfset validator = new RegistrationValidator(registration)>
<cfif validator.validate()>
<cfset application.userService.register(registration)>
<!--- You can also redirect to a page that represents the correct state --->
<cflocation url="registered.cfm" addtoken="no">
<cfelse>
<!--- Store the errors collection in the flash memory --->
<cfset session.flash.set('registrationErrors', validator.errors())>
<!--- Redirect to the page the user came from --->
<cflocation url="#cgi.http_referer#" addtoken="no">
</cfif>
Take the cflocation tag out of your function. It will not execute anyway because it's after the cfreturn tag.
Also, post your form to a .cfm page, not the .cfc. From that .cfm page, do this:
<cfset MyObject = CreateObject(stuff for your cfc goes here)>
<cfset MessageFromFunction = MyObject.registeruser()>
<cfoutput>#MessageFromFunction</cfoutput.

ColdFusion = OnRequest Error

Looking through the logs, we're getting hundreds of the following
"Error","jrpp-185","08/21/12","10:05:43","PATH","www.domain.com
Agent:Mozilla/4.0 (compatible; Synapse)
Error: An exception occurred when invoking a event handler method from Application.cfc.
The method name is: onRequest.
They seem to be mostly search bots. The on place on APplication.cfc that I can see reference to the function is below
<cffunction name="onRequest" returnType="void">
<cfargument name="targetPage" type="String" required=true/>
<cfsetting enablecfoutputonly="yes" requesttimeout="20">
<cfparam name="url.refresh" default="0">
<cfset request.strMember = Duplicate(session.strMember)/>
<cfset request.tNow = GetTickCount()>
<cfif url.refresh EQ 0>
<cfset request.iCacheHr = 12/>
<cfelse>
<cfset request.iCacheHr = 0/>
</cfif>
<cflogin>
<cfif IsDefined("session.strMember.sRoles")>
<cfloginuser name="#session.strMember.sFirstName##session.strMember.sLastName#"
password="12345"
roles="#session.strMember.sRoles#"/>
</cfif>
</cflogin>
<cfinclude template="core/incl/SessionLogger.cfm">
<cfinclude template="core/incl/LinkTranslator.cfm">
<cfinclude template="core/incl/udf.cfm">
<cfinclude template="urlcheck.cfm"/>
<cfinclude template="#Arguments.targetPage#">
</cffunction>
From that, can anyone please advise on what's wrong and how to fix it? I'm fairly new to CF and this is making me pull out what little hair I have left
1) You use two different coding styles
<cfparam name="url.refresh" default="0">
<cfset request.strMember = Duplicate(session.strMember)/>
Invalid/left open XML tags in first line and valid (closed) XML tags in the second line.
Try to stick to one (preferably the last one).
2) You are using old way of checking variable being defined
IsDefined("session.strMember.sRoles")
read about newer (and better and faster)
StructKeyExists(session.strMember, "sRoles")
3) Most likely your code is calling
<cfloginuser ... >
at every page request
4) Make sure that paths for all includes are correct and they themselves don't have any errors.
Simplify your method until you stop getting an error and then investigate what exactly is causing it
Are the bots hitting a page that doesn't exist?
Maybe try changing the last line to:
<cfif fileExists(expandPath(Arguments.targetPage))>
<cfinclude template="#Arguments.targetPage#">
<cfelse>
<cfabort>
</cfif>
Maybe you could detect if they are a bot and server them something else? depends on how search friendly you want your site to be:
http://www.bennadel.com/blog/1083-ColdFusion-Session-Management-And-Spiders-Bots.htm