Solved

Developing cross version ColdFusion code

Posted on 2010-09-06
16
336 Views
Last Modified: 2013-12-16
Hi,

I need to write some ColdFusion code that can be used by our clients. They will be running different versions of ColdFusion.

As ColdFusion has evolved, they had added new features and extended the functionality of existing features.I need this code to work on as many versions of ColdFusion as possible, and take advantage of these extensions where possible.

For example, we are writing a hashing function. Previous to CF v7 (i.e. MX 6.1), there was only one hashing algorithm (MD5), and the hash() function only took 1 parameter (the data to be hashed). From v7 onwards, they added the ability to be able to specify the hashing algorithm.

(As a simple example of this - PLEASE DON'T QUESTION HOW I AM SOLVING THIS SPECIFIC CASE - THIS IS JUST A SIMPLE EXAMPLE THAT ILLUSTRATES MY QUESTION) I'd like to be able to write a general hashing function that will work in all versions of ColdFusion. I have written the function below:

<cfscript>
function CalculateHashDigest(inputString, hashMethod)
{
    switch (hashMethod)
    {
        case "MD5":
            // ColdFusion 6.1 MX and below
            if (SERVER.ColdFusion.ProductVersion LT 7)
            {                          
                hashDigest = Hash(inputString);
            }
            else
            {
                hashDigest = Hash(inputString, "MD5");
            }
            break;
        case "SHA1":
            // ColdFusion 6.1 MX and below - NOT SUPPORTED
            if (SERVER.ColdFusion.ProductVersion LT 7)
            {                          
                throw new Exception("SHA1 is only supported in ColdFusion v7 and above");
            }                          
            hashDigest = Hash(inputString, "SHA1");
        break;
    }

    return (hashDigest);
}
</cfscript>

This code is fine in CF v7 and above (it the pre-processor recognises both forms of the hash() function). It DOESN'T however work in CF MX 6.1, which doesn't recognise the extended hash() function with the additional parameters.

Is it possible to write code like this that - in C/C++, this would be done with #ifdef PreProcessor directives. Is there an equivalent in ColdFusion - where I can mark a block of code as out of bounds for the page complier?

Many thanks
0
Comment
Question by:irc-corp
16 Comments
 
LVL 16

Accepted Solution

by:
duncancumming earned 500 total points
Comment Utility
Could one solution be to have the various 'new' parts of code in external files, that you then cfinclude into your function as necessary?

e.g.

IF version GT 7
  <cfinclude hash.cfm>
ELSE
  hash(string)

0
 
LVL 24

Expert Comment

by:dgrafx
Comment Utility
first off - SERVER.ColdFusion.ProductVersion is NOT a numeric value!
So you can't say if less than or ???

Whenever I needed to perform logic based on what version, I first set an Application var for the version as follows
<cfset Application.CFProdVer=trim(listfirst(SERVER.ColdFusion.ProductVersion))>

then in your code logic I imagine you can do at least similar to what you have been doing except now use the new Application.CFProdVer in your code ...

keep in mind also that CF doesn't read code within IF blocks where the logic doesn't match (it only tests syntax validity like if you have a missing cfloop for ex).
so there was no need to try and duplicate a C ++ out of bounds thing - thats what the IF block does so to speak!!!
the problem you had was this statement
"if (SERVER.ColdFusion.ProductVersion LT 7)" - this will be FALSE every time so your else statement was called in both ver 7 and ver 6.1

good luck!
0
 

Author Comment

by:irc-corp
Comment Utility
Hi,

Syntax aside, using the IF blocks to "guard" against the CF going into the code block doesn't work (using CFSCRIPT at least), as the page pre-processor still parses the *entire* code block and throw exceptions based on things like too many parameters to a function.. This will happen BEFORE *any* logical flow has been through the code - so it is parsing purely based on language construct.

In CF MX 6.1 the hash() function only has 1 parameter, if you have ANY instances of code using this function with any more parameters (i.e. code targeting CF 7 - with the added "algorithm" param) - EVEN if it is within a "IF CF7" block (and so when executed will NEVER be touched by CF MX 6.1), CF 6.1 MX will *still* throw an exception, as it won't recognise the new CF 7 construct for the hash() function (too many params)

I think the cfinclude suggestion might be the way to go - will mean a re-structure of how I wanted to lay the code out, as I'll need to have separate files with version-specific functions in them (rather than single version-aware functions), but if it works, then at least it will have answered my question
0
 
LVL 24

Expert Comment

by:dgrafx
Comment Utility
with all due respect - didn't you even read what I posted?

read my first 2 sentences!!!

you seem as if you read the last paragraph and thats it!
btw - your statements here are NOT completely true - the ex i gave was designed to be a real quick ex and certainly not complete - i definately didn't plan on arguing that small point when it doesn't even matter - just read my post again!

IMPORTANT!
you need to understand that your code is forcing ALL Versions to the "else" leg of your if/else!!!
so with ver 7 its going to "else" and you think its working because ver 7 can understand whats in the else block!!!
and with ver 6 you are going to "else" also and throwing an error because 6 can't understand it!
you are then developing a whole theory around your previous post!

here is an ex
lets say you have a var named xxx
and its value is set to "hello world"
then you code
<cfif xxx lt 7>
your value is less than seven
<cfelse>
you value is NOT less than seven
</cfif>

this is exactly what you are doing now as SERVER.ColdFusion.ProductVersion is NOT a number either!!!
it is something like "7,0,0,12" or whatever - i don't have access to a ver 7 server to give it to you exactly.
0
 

Author Comment

by:irc-corp
Comment Utility
Hi,

I did read your first 2 sentences, and I had actually tried what you were suggesting. Have a look at this code (rewitten from CFSCRIPT to raw CF tags) - I have HARD CODED the version number to make the code simpler (and to side-step the red herring of how the version number was being determined):

<cfset Application.CFVersion=6>
<cfset szStringToHash="1234">
<cfset szAlgorithm="MD5">

<cfswitch expression="szAlgorithm">
    <cfcase value="MD5">
        <cfset szHashDigest=Hash(szStringToHash)>
    </cfcase>        
    <cfcase value="SHA1">
        <cfif Application.CFVersion EQ 6>
            <cfthrow type="any" message="SHA1 not supported in CF MX 6.1">
        <cfelse>
            <cfset szHashDigest=Hash(szStringToHash, "SHA1")>
        </cfif>
    </cfcase>        
</cfswitch>

<cfoutput>Hash Digest: #szHashDigest#</cfoutput>

This code DOES NOT WORK when run under CF 6.1 MX. The <cfif> tags DO NOT provide a suitable "guard" as the code (even before it is subjected to ANY logical flow) is being parsed for LANGUAGE VALIDITY and in CF 6.1 it IS FAILING because the hash() function (even though the code, when run, will ONLY ever be hit by CF 7) HAS TOO MANY PARAMETERS FOR CF 6.1! CF 6.1 DOES NOT UNDERSTAND the hash() function with any more than 1 parameter, therefore, It fails with the following error:

"The function takes 1 parameter"

Regards
0
 
LVL 24

Expert Comment

by:dgrafx
Comment Utility
ok - look
i'm not saying 6.1 understands it - I know nothing of 6.1 any longer - it's been years ...
but you are NOT using code like i suggested

what i am saying is that your logic is now faulty

to start with
its not a case if szAlgorithm is something or other
its a case if CFVersion is something or other

FIRST OFF : Do you have Application.CFVersion set to 6 (or 7)?

it can be really simple
<cfif Application.CFVersion lt 7>
      <cfset szHashDigest=Hash(szStringToHash)>
<cfelse>
      <cfset szHashDigest=Hash(szStringToHash, "SHA1")>
</cfif>

NOTE THAT EVERYTHING I SAY IS VALID ONLY IF YOU HAVE SET CFVERSION TO BE NUMERIC !!!
Remember that SERVER.ColdFusion.ProductVersion is NOT numeric!!!
0
 

Author Comment

by:irc-corp
Comment Utility
Hi,

You seem to be missing the *crucial* point I'm trying to make WRT this specific example

Have a look at the last code snippet I posted above - you seem to be quite fixated on the way that I have evaluated the version number, so I removed any reference to "SERVER.ColdFusion.ProductVersion" - the version variable I was using - Application.CFVersion was HARD CODED to 6 (when executed under CF 6.1 MX and set to 7 when run under CF 7), so based on your approach, the code should work as the execution flow will dictact that the "offending" (i.e. the CF 7+ code).

In this case, your approach will NEVER work when run under CF MX 6.1 as it includes a call to the Hash() function that CF 6.1 DOES NOT UNDERSTAND - THEREFORE CF 6.1 WILL THROW A PAGELEVEL EXCEPTION - EVEN BEFORE IT HAS TRIED TO EXECUTE A SINGLE LINE OF CODE! Your assertion that the logical flow during execution (in this case) is being UNDONE by the page preprocessor.

You approach WILL ONLY work if the structure of the code being executed CAN BE UNDERSTOOD (i.e. has the same structure) by ALL versions that are being targetted. This is NOT the case in this example (which is why I chose the Hash() function as my example) - the structure of the Hash() function HAS CHANGED BETWEEN THE VERSIONS, and so the code NEEDS to be able to cope with this (GRACEFULLY - with USEFUL error messages where necessary)

What you have suggested is defiinitely NOT what I would accept as Cross-Version code (code that WILL WORK regardless of the version of CF it is executed under - with any features not supported by that version giving USEFUL error messages)

I have *tried* your approach (using your "simple" example - with Applicatio.CFVersion being set CORRECTLY in each case) with both CF MX 6.1 and CF 7 and here are the results:

CF 7: WORKS!
CF MX 6.1: DOESN'T WORK

APPROACH DID NOT YIELD VERSION-AWARE CODE!
0
 

Author Comment

by:irc-corp
Comment Utility
.....
so based on your approach, the code should work as the execution flow will dictact that the "offending" (i.e. the CF 7+ code) will never get executed by CF MX 6.1 and so it will never cause it issues.
.....
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 24

Expert Comment

by:dgrafx
Comment Utility
what are you doing that this is breaking???
please post your entire code that relates to this.

if it is not working i gurarantee you are NOT doing the following as i suggested
<cfset cfversion=6>
<cfset inputstring="1234">

<cfif CFVersion lt 7>
      <cfset hashDigest = Hash(inputString)>
<cfelse>
      <cfset hashDigest = Hash(inputString, "MD5")>
</cfif>
HERE IS YOUR HASHDIGEST VALUE : #hashdigest#
How can this NOT work?
0
 

Author Comment

by:irc-corp
Comment Utility
Hi,

You can see how it is breaking from the attached screenshot.

The code that produced this error was the *exact* code you just posted - running under CF MX 6.1.

The execution flow of your code should mean that the Hash(p) function is the ONLY one executed, but this error is being thrown BEFORE any code execution is being done. This error is simply CF MX 6.1 complaining about presense of the Hash(p1,p2) statement - The fact that it will NEVER ACTAULLY EXECUTE that statement is neither here nor there - this is the page preprocessor throwing the error, and it doesn't care about Logical/Execution structure - it just cares that the code being passed into it is LEGAL and VALID.

Regards
CFError.jpg
0
 
LVL 24

Expert Comment

by:dgrafx
Comment Utility
thats the error you posted
i'd really love to see the exact code you are using
0
 

Author Comment

by:irc-corp
Comment Utility
Hi,

This is the exact code that I'm using - IT'S YOUR CODE - I just took it and ran it under a CF MX 6.1 install.

<cfset cfversion=6>
<cfset inputstring="1234">

<cfif CFVersion lt 7>
      <cfset hashDigest = Hash(inputString)>
<cfelse>
      <cfset hashDigest = Hash(inputString, "MD5")>
</cfif>
HERE IS YOUR HASHDIGEST VALUE : #hashdigest#

(I have attached a screenshot to show you)

Regards

CFCode.jpg
0
 
LVL 24

Expert Comment

by:dgrafx
Comment Utility
ok - I believe you and I apologize!

do it this way then

<cfif CFVersion lt 7>
      <cfset hashDigest = Hash(inputString)>
<cfelse>      
      <cfset inputString=inputString & ', "MD5"'>
      <cfset hashDigest = Hash(inputString)>
</cfif>

OR

<cfif CFVersion gte 7>
<cfset inputString=inputString & ', "MD5"'>
</cfif>

<cfset hashDigest = Hash(inputString)>


0
 

Author Comment

by:irc-corp
Comment Utility
Hi,

That doesn't work as it just sees the appended ', "MD5"' as part of the string to be hashed, rather than as another parameter (i.e. the algorithm):

e.g

when CFVersion = 6
Hash Digest = 81dc9bdb52d04dc20036dbd8313ed055 (which is just the MD5 of '1234')

when CFVersion = 7
Hash Digest = aa702aaa8b59854f1a406cdc695bdb9f (which is just the MD5 of '1234, "MD5"')

when CFVersion = 7 (and algorithm set to "SHA1")
Hash Digest = 79c25df8aca787a1ec3510e0fab4e659 (which is just the **MD5** of '1234, "SHA1"')

Regards
0
 

Author Comment

by:irc-corp
Comment Utility
I have solved this problem using <cfInclude> as the page preprocessor doesn't parse files specified in a cfinclude tag (until runtime when they are included)

I just put the version-specific functions into their own files and then include the correct file based on the version number:

<cfif SERVER.ColdFusion.ProductVersion LT 7>
    <cfinclude template="PaymentFormHelperCF61.cfm">
<cfelse>
    <cfinclude template="PaymentFormHelperCF7.cfm">
</cfif>

Interestingly, despite what was said in this thread, you CAN use the raw contents of the variable SERVER.ColdFusion.ProductVersion in a numeric comparision, as I'm guessing ColdFusion just does some kind of internal casting of the non-numeric version string to a numeric value
0
 
LVL 52

Expert Comment

by:_agx_
Comment Utility
>> you CAN use the raw contents of the variable SERVER.ColdFusion.ProductVersion
>> in a numeric comparision

Since CF is relatively typeless, you could always use strings with comparison operators like GT, LT, EQ.  The results are usually what you want, but sometimes do unexpected things.  Personally I prefer the safer approach. Extract the number, then compare.  Though either option should work with ProductVersion.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Hi. There are several upload tutorials using jquery and coldfusion. I found a very interesting one here Upload Your Files using Jquery & ColdFusion and Preview them (http://www.randhawaworld.com/) . I did keep the main js functions but made sever…
Recently while working on a project I got a very annoying cfdocument has no body error message. I had never seen this error before. So I checked the code. The code was pretty simple; it was Just showing me the cfdocumnt tag and inside that tag a …
The purpose of this video is to demonstrate how to manually back up a WordPress Database. This will be demonstrated using a Windows 8 PC. The Host used will be IPage.com Log into your Hosting account. IPage will be used for demonstration : Locat…
The purpose of this video is to demonstrate how to reset a WordPress password if you are locked out and cannot reset the password. A typical use would be if you cannot access the email to which WordPress would send the password recovery email to…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now