views:

954

answers:

9

In the spirit of my other questions regarding "common programming mistakes ... to avoid"

What are some common programming mistakes for a ColdFusion programmer to avoid?

+3  A: 

Inappropriate use of #

SELECT *

Not scrubbing URL/form inputs

Debugging on in production environment (even if output is suppressed)

Al Everett
+20  A: 
  • set <cffile> upload path to a web accessible, CF-enabled directory!!!

  • isStruct() before isObject() in a series of <cfif>'s expecting isStruct only catches struct (cfc component returns True from isStruct() as well)

  • no HtmlEditFormat() when displaying user-generated content (XSS)

  • forgot to add output=false on CFC methods

  • not using <cfqueryparam> inside <cfquery>

  • not scoping not-so-evident variables like cfquery name or loop index in a method

  • use <cfform> when all they need is plain-vanilla HTML <form>

  • forgot to UrlEncodedFormat() user-defined URL

  • use <cffeed> without sanitizing the content

  • trust isDate() too much (any number would return true)

  • expect string comparison to be case-sensitive (IS and EQ operators are case-insensitive)

  • sending strings "yes" or "no" to SerializeJSON() without appending a whitespace to preserve the string (otherwise SerializeJSON() or DeserializeJSON() will translate them to "true" and "false")

  • not putting singletons services in application scope

  • blindly create as much CFCs as one wants like one would do in JAVA

  • putting complex value/object into a list (can't, list is just a string of comma-seperated values)

  • writing functions that takes array as an argument and modify that array expecting that array will be modified (array in CFML is passed by value)

  • blindly changes access="remote" on a method and expect it to work (when remote proxy is generally more appropriate)

  • use a lot of WriteOutput() in cfscript when CFML is more appropriate

  • blindly uses IsDefined() when StructKeyExists() can generally do it more efficiently

  • blindly uses Iif() and De() without knowing they're as nasty as Evaluate()

  • update some code in onApplicationStart() and not seeing the difference on refresh (restart the app!)

  • <cfloop> or '' outside of <cfquery> causing multiple new query connections to be opened. 99% of the time it's better to have multiple statements inside of one cfquery to perform multiple actions, or to UNION data together.

  • hardcoding absolute path when ExpandPath() is generally better

  • forgot to turn on Unicode support in DSN (Unicode becomes '????')

  • not upgrading to the latest JRE and Hotfixes

  • misusing Client scope and blow up Windows registry...

  • uses depreciated/obsolete functions/features (i.e. flash form aka flex 1.x alpha, cftable, Verity full-text search, etc...)

  • passing CFCATCH to a function as argument type Struct (CFCATCH behaves like a Struct, but it is not. Just pass it as type 'Any').

  • Not reading CFC Best Practices from ColdBox wiki.

  • buying in the mindset of .ASP(X) or .JSP or [insert web technology] are always better.. ;)

  • not use PrecisionEvaluate() and getting all sort of floating point rounding error especially when calculating money.

Henry
@Henry - this is quite a list my man! Thank you.
Andrew Siemer
still thinking what to add onto the list... :)
Henry
@Henry: Small typo - it's `HTMLEditFormat()`. (One reason for the commonness of XSS vulnerabilities is that the HTML escape functions names are so verbose everywhere: `htmlspecialchars()`, `Server.HTMLEncode()`, you name it. Usually I make a wrapper function for `HTMLEditFormat()` and call that `h()`, which is very convenient. Along with a wrapper for URLEncodedFormat called `u()`.)
Tomalak
Oh, and +1. Very nice compilation of things to get wrong in CF.
Tomalak
@Tomalak, fixed, thanks...
Henry
I still see this in legacy code: execute("form.counted#i#") instead of form['counted#i#'].
Ben Doom
hope you don't mind i added the spacing and edited some spelling, great list!
ethyreal
@ethyreal, why would I mind? :) Thank you for editing. I've also added 2 additional points on the post.
Henry
+1  A: 

SQL Injection Attacks. It seems like cfquery is just made to allow them. So you should use cfqueryparams.

JP Alioto
All better now?
JP Alioto
Can't stress strongly enough how good cfqueryparams are: cfqueryparam will stop sql injection - the sql server will never execute the value passed via cfqueryparam
Antony
+1  A: 

In Coldfusion, all variables are global by default, unless they are declared with the var keyword. (Somewhat similar to the situation in Javascript.)

So you either have to remember to var every variable used in a function, including things like names that are using in a cfquery name, or you can just use this trick:

<cffunction name="MyFunction">
    <cfset var Local = StructNew()>

    <!--- Now anything Local. is automatically local --->
    <cfset Local.x = 42>

    <!--- Including cfquery name="" --->
    <cfquery name="Local.Customers" datasource="some_datasource">
        SELECT C.ID, C.Name
        FROM Customers C
    </cfquery>
</cffunction>

There's nothing magic about the name Local, it's just convention. Although Coldfusion 9 will add an explict local scope, so if you use Local it will probably ease upgrading to CF9 when the time comes.

Note that the situation is a tad different for CFCs: In CFCs, the variables scope (the "default" scope) isn't global like it is for normal functions but rather exists per instance of your CFC. So while forgetting to use var is not quite as dangerous in a CFC as it is in a top-level function, the best practice is still to use var all the time.

Jason Creighton
"not quite as dangerous"? It is actually still quite dangerous since the code are not very thread-safe.
Henry
Well, yes, it's still evil and you should never do it, but the problems will be limited to that CFC, instead of potentially affecting any top-level function or .CFM page in your CF application.
Jason Creighton
A: 

Overuse of 'query of query'. That is, further filtering or sorting of query results using the cfquery tag.

This type of work is often done better by the database itself, particularly if the dataset is large.

AlexJReid
+2  A: 

Shamelessly stealing Henry's formatting...

  • it is faster and more accurate to check explicit boolean instead of implied; use <cfif query.recordCount GT 0> instead of <cfif query.recordCount>
  • do not use evaluate(), de(), or iif()... ever. there is always a way around these slow functions
  • understand structures, keys, values and how to access query and structure data using array notation. (this will usually get around your need for evaluate())
  • do not use pound signs unless you are outputting data or otherwise creating a string (don't do this: myFunction(arg = #myVar#) )
  • read and understand the difference between THIS and VARIABLES scope in a CFC
  • avoid extreme overuse of <cfsilent> when you probably need to use a <cfcontent reset="true"> just before you begin your output (before doctype, xml declaration, or <html>)
  • don't blindly drop ColdFusion values into an HTML script block (javascript) without using jsStringFormat()
  • if you are not using <CDATA> text in your XML, you may want to use xmlFormat() when creating an XML document
  • don't use Windows registry for Client scope data. Use the database.
  • if your IT architecture permits, use Session data instead of Client data.
  • use <cflock> correctly and consistently; shared data will leak in your Application.
  • if you are going to use Java objects, understand the Java error messages (for example, 'method cannot be found' may not mean the method does not exist at all, it means the method does not exist for the arguments you've supplied)
  • if you have to read large files, either use the new CF8 "File" functions or hand off the task to Java on CF6 & 7. <cffile> is inefficient for large files.
  • understand pass-by-reference and pass-by-value, and how those concepts work in CF; specifically when using functions to modify XML documents
  • as Henry stated, always use <cfqueryparam>; also ensure that you are using the correct CFSQLType parameter for your DBMS (for date, time, timestamp, etc)
  • don't chain together a series of <cfif> and <cfelseif> logic blocks, use <cfswitch> and <cfcase> if you have more than three conditions you need to handle
  • more of an architecture note: always do some sort of server side validation to catch the nasty data the wolf-shirt-wearing user may be passing you
  • last architecture note: let CF do your middle layer of data retrieval and display and let your webserver do webserver things like SEO URLs (I'm looking at you ColdCourse)
  • Douglas
    "don't chain together a series of <cfif> and <cfelseif> logic blocks, use <cfswitch> and <cfcase> if you have more than three conditions you need to handle" - That's a bit of a definite statement! I think cfif/cfelseif/cfelse statements are easier to read because there are less tags.
    Adrian Lynch
    A: 

    One of the biggest mistakes would be not using cfqueryparam

    Very bad:

    SELECT UserName
    FROM Customers
    WHERE CustomerID = #URL.custid#
    

    Very good:

    SELECT UserName
    FROM Customers
    WHERE CustomerID = <cfqueryparam value="#URL.custid#" cfsqltype="cf_sql_integer">`
    

    Making that mistake will cost you a website.

    jyoseph
    A: 

    Putting variables in the wrong scope; even if you don't blow up the registry or crash the server, it's easy to slowly drain performance from your application by bumping variables up to the highest scope in which you think you might need them, or to lose information because you stored it in one scope and tried to access them in a different scope.

    Using cfcatch without capturing and/or transmitting some information about the error so that it can be found and fixed. (It's difficult to find an error that doesn't tell you it occurred.)

    Using listcontains() when you want listfind(). Especially if the list contains numbers. listfind() matches only an entire item in a list; listcontains() matches part of an item. (Yes, we made this mistake once.)

    With administrator access:

    • Leaving the defaults for a data source set up on the server. "Least privileges" applies on the CF side as well; don't give it any more permissions than it specifically needs. (GRANT, ALTER, REVOKE, DROP ... you don't really want those checked.)
    • Not checking the boxes for retrieving all the contents from a CLOB/BLOB field when that's what you're expecting. (It was really interesting seeing that applied to a field in which we were storing PDFs.)
    Dave DuPlantis
    A: 

    Failing to prevent users from seeing coldfusion errors.

    Add a onError method to a top level Application.cfc to prevent users from seeing those all to detailed dump messages exposing your inner workings(and failings).

    <cffunction name="onError" returntype="void" output="true">
     <cfargument name="exception" type="any" required="true" />
     <cfargument name="eventname" type="string" required="true" />
    

    varscoper is also a great tool for automating the check for variable scoping omissions in components.

    http://varscoper.riaforge.org/

    np0x