Having not worked with coldfusion before I was asked to look into some strange intermittent bugs in a coldfusion application.
After reading about scopes I believe the problem is because none of the variables in my cfc functions are using the var
keyword, and the same variable name is used in various functions. So as I understand it the variables are scoped at page level and different threads calling these functions will be overwriting the variable causing the "strange" problems.
My question is what is the proper way to do this?
<cfset var listCount = 0>
<cfquery name="qGetElementsByType" dbtype="query" maxrows="#arguments.num_to_return#">
SELECT elementId,
title, PIhtml, Rerhtml,
text, url, image, Rank, isPoll, pollId, subjectId
FROM arguments.element_query
WHERE <cfloop list="#arguments.element_type_id#" index="lcv">
<cfif listCount GT 0>
OR
</cfif>
subjectid = #lcv#
<cfset listCount = listCount + 1>
</cfloop>
</cfquery>
Does var
need to be added each time the listCount variable is set, or just on the initial declaration?
(I hope this answer isn't too long-winded. I didn't think the existing answers gave sufficient information, but hopefully haven't gone too far the other way...)
In CF, there are assorted scopes which variables can be placed in (application,session,url,cgi,etc).
Some of these require explicit declaration to be used (e.g. session variables must always be scoped), others can be automatically accessed when reading a variable (e.g. form and url variables can be read by using an unscoped variable) - there is an order of precedence here which determines which scopes are checked for an unscoped variable.
The bottom scope in this ordering is the variables
scope, which is a scope which applies for the entire current page/object instance.
When setting a new variable, if unscoped, it is created in the variables
scope. Since this is a global scope, it can be accessed from both different instances of the same function, as well as difference functions, which causes the issues of which you're aware.
To prevent a variable going into the global variables scope you must place it in the function's local
scope. (Technically you can place it in the function's arguments
scope, but this will likely confuse people.)
In earlier versions of CF, there was no way to explicitly access the local scope - you needed to use the var
keyword in order to create the variable inside the local scope - and once created it will always take precedence (both for reading and writing) over the variables scope.
With CF9, the local
scope is now a "proper" scope and can be accessed explicitly, so instead of using <cfset var x = 0 />
you can write <cfset local.x = 0 />
- the main benefit of this is when you are creating a variable where the var
keyword cannot be used, e.g. <cfquery name="local.qGetElementsByType" ...>
and <cfloop index="local.lcv"...>
You still only need to apply the local scope when first creating each variable, to prevent it going into the variables scope - subsequent reads/updates can be unscoped if you prefer, just as they would be when doing the var scope.
(Although there are other potential scope-related issues with unscoped variables, such as inside of a <cfloop query="queryname">
block, and because of this some people will argue you should always scope all variables no matter what.)
In summary, to make the code you show safe, you need to scope:
qGetElementsByType
from the cfquery taglvc
from the cfloop tagSince these variables are not created with cfset, scoping is most easily done by prefixing the names with local.
Since you have already var
scoped the listCount variable, you don't need to do it again in the same function - you can optionally use <cfset local.listCount = local.listCount + 1>
(or indeed <cfset local.listCount++ >
) but again this is a matter of preference and not needed to protect against leaking into the variables scope.
(side note: Ideally, you should use the cfqueryparam tag around #lcv#
to protect against SQL injection - even though this is a query of query this might still be an issue, and it's always better to play it safe on security.)
Of course, that's just this function - you'll also need to fix other functions - and an easy way to do that is to use the varscoper tool to scan your entire codebase and identify variables that need scoping.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With