Posted in ColdFusion | Posted on 02-08-2006 | 6,148 views
I just got this email this morning and had to share it:
I am converting from ASP to coldfusion but having troubles with code dealing with querystrings.I have the code:
<cfif parameterexists(URL.edit) AND URL.edit NEQ "">
<cfquery name="accountrecord" datasource="datasource">
SELECT *
FROM Admin
WHERE adID = #URL.edit#
</cfquery>Now I think coldfusion still tries to see if URL.Edit is defined for the sql statement although the if statement says only execute code if URL.edit value is present.
How do I fix this problem?
First off - welcome to the Light Side! I have some bad news for you. Now that you are leaving ASP you are going to need to find something else to do with your time once you start finishing your projects in a good tenth of the time it took you in ASP. (As you can see, I'm more than just a little bit biased towards ColdFusion. ;)
So - I had a hard time understanding the exact nature of your question. It sounds like you are saying the query is executing even when the url variable does not exist. While I have problems with your code (which I'll explain in a second), the logic at least seems right. Are you sure you aren't having some other problem?
That being said - let me pick apart your code a bit and point out some problems. First - forget about parameterExists(). You may have missed this in the docs, or seen it in use in other people's code, but it is deprecated. That just means you shouldn't use it. Instead, you want to use isDefined()*. Note that isDefined works a bit differently. Instead of:
parameterExists(name)
You use:
isDefined("name")
Notice the quotes? I'd rewrite your cfif like so:
Now another problem. I see you are using the value as a number in your query. You need to check and ensure that the value is a number. ColdFusion provides a function for that, isNumeric(). However, even that isn't enough. Don't forget the 3.14159 is also a number, but your database will be desiring a whole number. You can either check for that or simply round the number. That way if the number is changed by some unscrupulous user, it will still be ok for the query. ColdFusion provides a few functions that can get rid of anything after the decimal: round, fix, int, and ceiling. Any of these are fine.
Still with me? Notice how you use the variable inside your query? There is one more step you can do and that is to use cfqueryparam. This tag does a few things: One, it makes the query run a bit faster. Speed is always good. The best thing it does, however, is add one more layer of validation. It will double check to make sure your value really is the correct type. I'd check the docs for more information on the tag. Here is one more rewrite of your code.
Before I post the code though - please remember that there are many ways to skin the cat in ColdFusion. Consider this a suggestion. You don't have to write the code exactly as I have it.
2<cfquery name="accountrecord" datasource="datasource">
3SELECT *
4FROM Admin
5WHERE adID = <cfqueryparam cfsqltype="cf_sql_integer" value="#int(url.edit)#">
6</cfquery>
* So just a quick note. As I said - there are multiple ways of doing things in ColdFusion. While isDefined certainly works well enough to check for the existence of a variable, some people use structKeyExists instead. Now - I don't want to confuse you, so feel free to stop reading now. The basic idea is that all variable scopes in ColdFusion are structures. I'm not sure what the equivalent is in ASP, but I'm sure it has something similar. (Basically an array indexed by strings, not numbers.) Because all the scopes can be treated as a struct, you can change an isDefined("url.edit") to structKeyExists(url, "edit"). You will see some of my readers suggesting that instead of isDefined(). Myself - I'm slowly moving to that form as well, so now my code will sometimes use both methods.


We use lhp for our helpdesk and our maintenance department uses it for their workorders. Not perfect and certainly not what it was intended for but it sure beat me having to make one.
That said, we needed a couple of extra fields added to make it work for us along with a few other kludges.
Nice to have in LHP:
The name and email address of the person submitting the 'bug'. (not creationism but two fields with text in them)
The ability to send status change emails to the user that submitted the bug, remember that person more than likely will not be in user table.
Reports, bean counter type stuff, how many tickets closed, how many submitted, how many by location, blah blah
my ADD just kicked in so I'm out.
thanks what you do.
If you don't believe me, that's fine. Run a test where you run a loop 10,000 times for each one and see who comes out in front a majority of the time.
<cfset variables.start = gettickcount()>
<cfloop index="i" from="1" to="10000">
<cfset isdefined("url.testingthisout")>
</cfloop>
<cfset variables._isdefined = gettickcount() - variables.start>
<cfset variables.start = gettickcount()>
<cfloop index="i" from="1" to="10000">
<cfset StructKeyExists(url, "testingthisout")>
</cfloop>
<cfset variables._StructKeyExists = gettickcount() - variables.start>
<cfoutput><p>isdefined: #variables._isdefined# ms<br>StructKeyExists: #variables._StructKeyExists# ms<br></p></cfoutput>
Now grant it I will say one other thing. If you noticed the difference in performace between the two are minimal at best. That said, use which ever one you feel comfortable with. If you are having performace issues with your CF app, I would bet to say that using StructKeyExists isn't the reason and more likly it is a poorly designed database.
isdefined: 109 ms
StructKeyExists: 63 ms
further F5's gave me stuff closer to 30ms, with a few MS difference in favor of structKeyExists.
I started writing the explanation, but recalled a blog or post by Mike Nimer on the subject. I couoldn't find his, but I found one by Sean Corfield
http://corfield.org/blog/index.cfm/do/blog.entry/e...
The last comment said that isDefined was a security risk, so in my mind that would justify looking for an alternative.
But I don't think that it is.
I don't think there's a security risk with isDefined.
The only thing surprising about the following code is the very last line outputs your url variable if you call
www.MySite.com/mypage?SESSION.Username=Fred
But IF YOU HAD A SESION VARIABLE, it would output it correctly.
[cfdump var="#url#"]
[cfdump var="#Session#"]
[cfif isDefined("Session.Username")]
I'm getting hacked! Ack!
[/cfif]
[cfif StructKeyExists(url,"Session.UserName")]
Someone's trying to hack me!
[/cfif]
[cfoutput]#Session.UserName#[/cfoutput]
But just to reiterrate,
[cfif isDefined("Session.Username")]
is NOT a security risk if someone posts
www.MySite.com/mypage?SESSION.Username=Fred
<cfparam default="0" name="url.edit" type="numeric">
<cfif url.edit neq 0>
...
</cfif>
"If it's defined, then..." vs.
"If the struct key exists, then that means it's been defined..."
is wrong, if url.edit is undefined, an error will occur trying to evaluate the second part of the IF.
it should be
[cfif ISDEFINED("URL.EDIT")]
[cfif isNumeric(url.edit)]
...
[/cfif]
[/cfif]
T
Similarly with ORs - if the first condition is True, it doesn't evaluate the second condition (because if either is True the final result is True).
i just tested this on my new cf7 box, but it failes on my older cf6 box.
must be something new, i have tried this in the past and it has came back to haunt me. sorry for the premature post
regards
t
[Add Comment] [Subscribe to Comments]