Interesting question, Doug. I'll try my best to answer it. First off, I think you make a mistake when you say that 'elegant' handling of the error is impossible with cfqueryparam. It certainly isn't. In fact, one could simply take your code examples and merge them:Hey Ray, do you think sometime you could discuss using cfqueryparam versus the need to have "elegant" ways of handling bad data? It seems like a better solution would be to redirect the user back to a default page than to have a page crash because of bad data or a hacking attempt.
I guess my point is: isn't this code:
<cfif isNumeric(url.this)> <cfquery name="theQuery" datasource="ds"> SELECT this, that FROM theTable WHERE this = url.this </cfquery> <cfelse> <cflocation url="/SomePlaceSafe.cfm"> </cfif>
more elegant than this code:
<cfquery name="theQuery" datasource="#ds#"> SELECT this, that FROM theTable WHERE this = <cfqueryparam value="url.this" cfsqltype="cf_sql_integer" /> </cfquery>I've seen you complain about this before in your Twitter feed, so I figured you had an opinion about it. (And for the sake of argument let's ignore claims that cfqueryparam actually improves performance with certain databases.)
2 <cfquery
3 name="theQuery" datasource="#ds#">
4 SELECT this, that FROM theTable WHERE this =
5 <cfqueryparam value="#url.this#" cfsqltype="cf_sql_integer" />
6 </cfquery>
7 <cfelse>
8 <cflocation
9 url="/SomePlaceSafe.cfm">
10 </cfif>
Comment 1 written by Jeff Bouley on 10 July 2009, at 7:10 AM
I am a huge proponent of cfqueryparam only in this scenario. I believe the best approach here is to try catch the query and either bubble or handle accordingly with the cflocation. I wrap all 3rd party calls; db, file, com, etc with try catch as they are ultimately outside the the cf engine and can produce unexpected results (for instance if the db is down or unstable).
It is also much less code and validation is really an after thought. I believe the input (text box in html or flex) should be validated client side before ever going to the server as well.
Hope this code comes out in the comment:
<cftry>
<cfquery name="theQuery" datasource="#ds#">
SELECT this,
that
FROM theTable
WHERE this = <cfqueryparam value="#url.this#" cfsqltype="cf_sql_integer" />
</cfquery>
<cfcatch type="database">
<!--- Either bubble with cferror and pass on to global handler, i.e. onError in app.cfc
or just place your cflocation in the catch (used in this example --->
<cflocation url="/SomePlaceSafe.cfm">
</cfcatch>
</cftry>
Comment 2 written by Raymond Camden on 10 July 2009, at 7:24 AM
Comment 3 written by Jim Priest on 10 July 2009, at 7:59 AM
And hopefully everyone is using the jQuery validation plugin :)
Comment 4 written by Dan Vega on 10 July 2009, at 8:04 AM
1.) populate my object with data
2.) validate
3.) if object has errors display them
else save
Comment 5 written by Joel Cox on 10 July 2009, at 8:11 AM
Comment 6 written by Jay Greer on 10 July 2009, at 8:16 AM
Jim, if you're subscribing to this post, what's the "jQuery validation plugin"..?
Comment 7 written by Dan Vega on 10 July 2009, at 8:18 AM
Comment 8 written by Jim Priest on 10 July 2009, at 8:33 AM
Check out Jorn's plugin here: http://bassistance.de/jquery-plugins/jquery-plugin...
Comment 9 written by JC on 10 July 2009, at 8:55 AM
Comment 10 written by Joel Cox on 10 July 2009, at 8:59 AM
Oh, absolutely. If the exception message gives details about the database system, table names, column names, etc, this is valuable information for further attacks.
Comment 11 written by Raymond Camden on 10 July 2009, at 10:10 AM
Comment 12 written by Mary Jo on 10 July 2009, at 12:30 PM
Comment 13 written by Dave Crawford on 10 July 2009, at 12:57 PM
Defense in depth should be the order of the day. A nice looking default error message is good, but preventing information leakage is better. User input is pure evil until you prove otherwise.
Comment 14 written by Andy Sandefer on 10 July 2009, at 4:04 PM
My approach has changed quite a bit and I find myself often using cfajaxproxy along with front end javascript validation a lot more than serverside error handling techniques. I'm consistent in using cfqueryparam on the back end but trapping crap data up front and stopping the process before the submit even happens is really working out for me.
It is a lot of extra work but using cfajaxproxy to check for primary key violations in instances where the user names a key is helpful (subsidiary tables that employ meaningful user defined codes rather than manufactured primary key values to make records unique). For instance, nobody wants a unit of measure code named 2, they want lbs or units.
Just my opinion.
Comment 15 written by Doug on 11 July 2009, at 1:34 PM
Thanks for the tips Ray! (And I've gotta put my fear aside and start dabbling in ModelGlue. Time to read your next blog post...)
Comment 16 written by martin on 11 July 2009, at 4:49 PM
Take a look here: http://www.martinfowler.com/bliki/AnemicDomainMode...
Comment 17 written by martin on 11 July 2009, at 4:52 PM
Comment 18 written by Jeff Bouley on 12 July 2009, at 10:28 AM
Though, I'm concerned about some of the responses here. Who says the db throws a native error in my scenario @Dave Crawford? It never gets to the db if the cfqueryparam fails.
As for custom error handling that is a given. I eluded to bubble to a global handler; CF 101 or app dev in general, never show or present native errors to the user. I usually roll my own error handler .cfc which handles the error per the given process (make the error as pretty as you like here) i.e. Send an email, custom log with cflog, etc.
There you can present a more intelligent response to the user so that customer support can do their job effectively. This kind of information may go as far as including template, line number, and query name info. Alot of flexibility here or just cflocation afterward per Doug's initial example.
As for the validation discussion, whether you incorporate that client or server side is personal choice. I don't like taxing the server if I can do it client side (remember the old cfform js trick?). This goes years back, but I would have the server gen the js for me and switch back to html form. Many advances with jQuery here agreeed... I have worked on projects where it is done both client and server. I personally have no issue with implementing in the Bean per @Martin's response.
Comment 19 written by Jeff Bouley on 12 July 2009, at 10:30 AM
Comment 20 written by Rob Barthle on 14 July 2009, at 3:49 PM
Ultimately I don't want to rely on CFQUERYPARAM to catch data type failures, it's the last line of defense for me. I'll cover every variable in a query, but I'm more interested in the performance boosts CFQUERYPARAM provides. The added security is an extra benefit to me, since I should have covered the security needs beforehand.
Comment 21 written by Doug on 15 July 2009, at 8:04 AM
[Add Comment] [Subscribe to Comments]