Wednesday, September 18, 2013

CF10 expandPath() issue with IIS virtual directories

First of all, allow me to preface this post with the fact that I am not advocating the use of IIS virtual directories in lieu of ColdFusion mappings.  That is a separate legacy environment issue we're planning on addressing.

With that disclaimer out of the way, the issue that we were experiencing is with the expandPath() function not resolving properly for missing files/directories that use an IIS virtual directory as the mapping [i.e., expandPath("/myMapping/myMissingDirectory")].  This was a non-issue in ColdFusion 9.

This issue was present in ColdFusion 10 with ColdFusion mappings, but it apparently was fixed in the final build of ColdFusion 10 (I verified on my version which is running update 11).

The behavior that is happening is that if a file/directory in expandPath() does not exist CF is resolving the root mapping as starting at the root of your site directory (again, this is currently only an IIS VD issue).

For example, if you have a site directory of C:/inetpub/wwwroot/mySite and have an IIS virtual directory of myMapping that points to C:/inetpub/wwwroot/myMapping and you try to use expandPath() on a file/directory that does not exist then CF resolves the path as C:/inetpub/wwwroot/mySite/myMapping instead of C:/inetpub/wwwroot/myMapping as I would expect.

The fix for this is to use expandPath() on a directory you know will exist and append the rest of the path as in expandPath("/myMapping") & "/myMissingDirectory".

Since people should really be using ColdFusion mappings within CF code, I don't feel like a ticket should be created; but what do you all think?

Saturday, June 1, 2013

Introducing CodeChecker - a code review automation tool

Code review is an important part of any software development cycle.  It helps ensure to some degree the quality, coherency, and consistency of an application to the team's objectives.

When conducting code reviews, I much rather like to focus on the logic of the code and that it aligns to the direction our team is going rather than scanning line upon line for code that preferably should not be used such as output="true" in a cffunction or <cfif myVar IS 1>.

That is why I'd like to introduce CodeChecker! It is a code review automation tool that helps take away the tedious (and boring) aspects of reviewing code.  It has a UI to be ran from the browser, or you can call the CFCs directly in MXUnit.  All of the rules are defined as regular expressions, and it also integrates the popular QueryParamScanner and VarScoper components. My regex skills admittedly are not great, so anyone out there who would be willing to optimize them please contribute to the project on GitHub.  Below are some of the highlights.  More documentation can be found on the project's wiki.
  • Rule Categories
    • Security
    • Performance
    • Standards
    • Mainenance
  • Rules
    • Prohibit client scoped variables in a CFM page
    • File upload warnings to ensure they use the accept attribute and check for valid file extension and MIME type.
    • Prohibit nested cflock tags
    • Prohibit ParameterExists()
    • Prohibit IsDefined()
    • Prohibit Evaluate()
    • Prohibit DE()
    • Prohibit IIF()
    • Prohibit StructFind()
    • Prohibit DecrementValue()
    • Prohibit IncrementValue()
    • Use Len() instead of is "", is not "", etc.
    • Prohibit SetVariable()
    • Prohibit cfquery in a CFM page
    • Prohibit shared scope variables (form, application, url, session, cgi, client, request, cookie) in a CFC
    • Prohibit IS and GT for boolean tests
    • Prohibit IS/IS NOT when comparing numbers
    • Prohibit EQ/NEQ when comparing strings
    • Prohibit mathematical operations on strings
    • Prohibit the ampersand concatenator on numbers
    • Prohibit empty cfcatch blocks
    • Prohibit output=true in cfcomponent and cffunction
    • Require init method in CFCs
    • Require onMissingMethod method in CFCs
    • Require hints in cfcomponent, cffunction, and cfargument
    • Use ArrayNew() instead of ArrayNew(1)
    • Prohibit arguments-scoped datasource (since the datasource should be set on object instantiation)
    • Prohibit cfabort and abort()
    • Prohibit cfdump and writedump()
    • Prohibit cflog and writelog()
    • Prohibit console.log()
  • Third Party Plugins
Every team/developer has different needs and preferences, so feel free to remove any of the rules that you don't require.  As I mentioned above, feel free to contribute new rules and optimize the ones I've defined.  Also, any comments are welcome!

Special thanks/credit to Steve Bryant's CodeCop project for inspiring this.

Friday, April 5, 2013

UDF for converting a query string to a structure

Have you ever needed to work with url query string parameters? Working with a list is no fun, hence why I wrote the convertQueryStringToStruct UDF. This makes building search criteria displays much easier.

There is a great post by Mister Dai showing several scenarios. Credit to him for discovering the underlying solution!

Standard responses with Response.cfc

Standardizing responses is useful so you know what to expect when you make a service call. That is why I wrote Response.cfc (github repo link).

This response object by default returns a json packet so it can be easily manipulated by AJAX and remote API requests.  For non-AJAX/non-remote calls, I like to deserialize the json immediately after getting the response.

Properties of Response.cfc are below with sample use cases.

  • data (used to pass back context data)
  • errorCode (used to pass a unique code)
  • errorDetail (used for debugging)
  • errorMessage (used for generic messaging back to the user)
  • errors (each error to report back to the user)
  • statusCode (http status code for use by remote calls)
  • statusText (http status text for use by remote calls)
  • success (boolean flag for overall status of request)

Credit to Ben Nadel's Building An AJAX, jQuery, And ColdFusion Powered Application post for inspiring this.

Wednesday, July 25, 2012

Validate client-side with dataset property

There are many new and exciting things in HTML5, but one of the interesting shifts it has made in my programming is for client-side form validation using the new dataset property. This was also possible pre-HTML5 via the getAttribute() method.

The code below will first try to use the new dataset property. If that fails it will fallback to trying the getAttribute() method. This ensures that all browsers will behave the same regardless of their support for HTML5. And for good measure there is another fallback to a very generic message.

To take this a step further, you could use a dynamic programming language like ColdFusion to dynamically inject the message. You could even have it display a language-specific message (i.e., English, Spanish, etc.).

Thursday, July 12, 2012

t-sql get first item from list using substring and charindex

For those of us who have inherited non-normalized databases where lists are stored in a single column, it may be helpful to be able to get the first item in a list straight from your query. ColdFusion can do this by using ListFirst() once you return the query results, but I wanted to try to do the same in T-SQL. This would be useful if, for example, the first item in the list is the parent and the other items are children. The query below will help you identify the parent.

The first query which uses @InvalidList, will return 'Item1-Item2-Item3' because it does not match the list delimiter. The second query which uses @ValidList, will return 'Item1' only since it matched the list delimiter. The REPLACE is used to obviously strip the delimiter. Note the use of LTRIM and RTRIM to trim all spaces so our value is clean.

Searching on first character with CHARINDEX

Have you ever wanted to build an alphanumeric search allowing the user to click an individual letter or number range and then display the matching results? There are numerous ways to do this in multiple languages, but one way I found that works great is to just use CHARINDEX in T-SQL.

This query will return any record whose "table_name" begins with 'a', '1', 'm', or 's'. Obviously to match just on 'm', you would set @AlphaNumChars to 'm'. You could turn this into a stored procedure or keep it as an inline query. What other methods do you use? Let us know by leaving a comment.