a query string into a structure - coldfusion

I am using taffy and am passing an unknown query string to a function. I do not know the query string values passed in advance, so I am trying to use that in the function but it is not working. Please point me to right direction.
Here is my code:
<cffunction name="qrystringToStruct" returntype="any">
<cfargument name="myStruct" default="#structNew()#" type="struct">
<cfargument name="str" required="true" default="">
<cfscript>
for(i=1; i LTE listLen(arguments.str,'&');i=i+1) {
structInsert(myStruct, i, listGetAt(arguments.str,i,'&'));
}
</cfscript>
<cfreturn myStruct>
</cffunction>
<cffunction name="getCourseById" taffy:verb="get" taffy:docs:hide>
<cfargument name="structurl" type="any" default="" />
<cfdump var="#structurl#">
<cfdump var="#qrystringToStruct(structurl)#" abort>
<cfset var local = {} />
This is how I am calling the url:
http://localhost:9002/taffy/index.cfm//coursesMethods?credits=3&coursetitle=power
but all I am getting is [empty string]

Let me just preface this by saying I've never used Taffy. However with that said, I don't think it's relevant to the problem specified in your posted question. There are a few things in your code that's puzzling to me.
Your call qrystringToStruct(structurl) passes one parameter but your function definition has two parameters.
Why would you declare myStruct as a parameter and then <cfreturn myStruct> in your qrystringToStruct function definition? It makes no sense.
You say you pass the full url to http://localhost:9002/taffy/index.cfm//coursesMethods?credits=3&coursetitle=power? Why not just pass the querystring portion using cgi.QUERY_STRING?
Anyhow, I think you're overcomplicating this and you don't need a custom function to parse out your querystring. All you need is one line of code.
<cfset qryString = listToArray(cgi.QUERY_STRING, "&")>
You can test it out here here.

Related

Convert Special Characters to HTML - ColdFusion

I need to convert a lot of special characters to their html format and I am trying to do this with a function that is using ReplaceList but something is wrong with the function or the values I am passing to it.
This is the function
<cffunction name="HtmlUnEditFormat" access="public" returntype="string" output="no" displayname="HtmlUnEditFormat" hint="Undo escaped characters">
<cfargument name="str" type="string" required="Yes" />
<cfscript>
var lEntities = "&##xE7;,&##xF4;,&##xE2;,Î,Ç,È,Ó,Ê,&OElig,Â,«,»,À,É,≤,ý,χ,∑,′,ÿ,∼,β,⌈,ñ,ß,„,´,·,–,ς,®,†,⊕,õ,η,⌉,ó,­,>,φ,∠,‏,α,∩,↓,υ,ℑ,³,ρ,é,¹,<,¢,¸,π,⊃,÷,ƒ,¿,ê, ,∅,∀, ,γ,¡,ø,¬,à,ð,ℵ,º,ψ,⊗,δ,ö,°,≅,ª,‹,♣,â,ò,ï,♦,æ,∧,◊,è,¾,&,⊄,ν,“,∈,ç,ˆ,©,á,§,—,ë,κ,∉,⌊,≥,ì,↔,∗,ô,∞,¦,∫,¯,½,¤,≈,λ,⁄,‘,…,œ,£,♥,−,ã,ε,∇,∃,ä,μ,¼, ,≡,•,←,«,‾,∨,€,µ,≠,∪,å,ι,í,⊥,¶,→,»,û,ο,‚,ϑ,∋,∂,”,℘,‰,²,σ,⋅,š,¥,ξ,±,ℜ,þ,〉,ù,√,‍,∴,↑,×, ,θ,⌋,⊂,⊇,ü,’,ζ,™,î,ϖ,‌,〈,˜,ú,¨,∝,ϒ,ω,↵,τ,⊆,›,∏,",‎,♠";
var lEntitiesChars = "ç,ô,â,Î,Ç,È,Ó,Ê,Œ,Â,«,»,À,É,?,ý,?,?,?,Ÿ,?,?,?,ñ,ß,„,´,·,–,?,®,‡,?,õ,?,?,ó,­,>,?,?,?,?,?,?,?,?,³,?,é,¹,<,¢,¸,?,?,÷,ƒ,¿,ê,?,?,?,?,?,¡,ø,¬,à,ð,?,º,?,?,?,ö,°,?,ª,‹,?,â,ò,ï,?,æ,?,?,è,¾,&,?,?,“,?,ç,ˆ,©,á,§,—,ë,?,?,?,?,ì,?,?,ô,?,¦,?,¯,½,¤,?,?,?,‘,…,œ,£,?,?,ã,?,?,?,ä,?,¼, ,?,•,?,«,?,?,€,µ,?,?,å,?,í,?,¶,?,»,û,?,‚,?,?,?,”,?,‰,²,?,?,š,¥,?,±,?,þ,?,ù,?,?,?,?,×,?,?,?,?,?,ü,’,?,™,î,?,?,?,˜,ú,¨,?,?,?,?,?,?,›,?,"",?,?";
</cfscript>
<cfreturn ReplaceList(arguments.str, lEntities, lEntitiesChars) />
</cffunction>
This is how I am calling it:
<cfoutput>
<cfloop query="local.q" startrow="2">
#HtmlUnEditFormat(consultServiceType)# <br />
</cfloop>
</cfoutput>
These are the strings I am passing to it:
Security?
Security Guard®
Alarm System©
Private Investigator;
I am not getting any errors back (I had a cftry in the function before) and the strings come back the same
EDIT:
I've tried using #FindNoCase('©',consultServiceType)# and is returning 0 so I guess something is wrong with the string I am passing in?
You're using CF11, did you try EncodeForHTML() ?
The accepted answer is the better approach (don't reinvent the wheel), but your function isn't working because you have lEntities and lEntitiesChars mixed up.
<cffunction name="HtmlUnEditFormat" access="public" returntype="string" output="no" displayname="HtmlUnEditFormat" hint="Undo escaped characters">
<cfargument name="str" type="string" required="Yes" />
<cfscript>
var lEntities = "&##xE7;,&##xF4;,&##xE2;,Î,Ç,È,Ó,Ê,&OElig,Â,«,»,À,É,≤,ý,χ,∑,′,ÿ,∼,β,⌈,ñ,ß,„,´,·,–,ς,®,†,⊕,õ,η,⌉,ó,­,>,φ,∠,‏,α,∩,↓,υ,ℑ,³,ρ,é,¹,<,¢,¸,π,⊃,÷,ƒ,¿,ê, ,∅,∀, ,γ,¡,ø,¬,à,ð,ℵ,º,ψ,⊗,δ,ö,°,≅,ª,‹,♣,â,ò,ï,♦,æ,∧,◊,è,¾,&,⊄,ν,“,∈,ç,ˆ,©,á,§,—,ë,κ,∉,⌊,≥,ì,↔,∗,ô,∞,¦,∫,¯,½,¤,≈,λ,⁄,‘,…,œ,£,♥,−,ã,ε,∇,∃,ä,μ,¼, ,≡,•,←,«,‾,∨,€,µ,≠,∪,å,ι,í,⊥,¶,→,»,û,ο,‚,ϑ,∋,∂,”,℘,‰,²,σ,⋅,š,¥,ξ,±,ℜ,þ,〉,ù,√,‍,∴,↑,×, ,θ,⌋,⊂,⊇,ü,’,ζ,™,î,ϖ,‌,〈,˜,ú,¨,∝,ϒ,ω,↵,τ,⊆,›,∏,",‎,♠";
var lEntitiesChars = "ç,ô,â,Î,Ç,È,Ó,Ê,Œ,Â,«,»,À,É,?,ý,?,?,?,Ÿ,?,?,?,ñ,ß,„,´,·,–,?,®,‡,?,õ,?,?,ó,­,>,?,?,?,?,?,?,?,?,³,?,é,¹,<,¢,¸,?,?,÷,ƒ,¿,ê,?,?,?,?,?,¡,ø,¬,à,ð,?,º,?,?,?,ö,°,?,ª,‹,?,â,ò,ï,?,æ,?,?,è,¾,&,?,?,“,?,ç,ˆ,©,á,§,—,ë,?,?,?,?,ì,?,?,ô,?,¦,?,¯,½,¤,?,?,?,‘,…,œ,£,?,?,ã,?,?,?,ä,?,¼, ,?,•,?,«,?,?,€,µ,?,?,å,?,í,?,¶,?,»,û,?,‚,?,?,?,”,?,‰,²,?,?,š,¥,?,±,?,þ,?,ù,?,?,?,?,×,?,?,?,?,?,ü,’,?,™,î,?,?,?,˜,ú,¨,?,?,?,?,?,?,›,?,"",?,?";
</cfscript>
<cfreturn ReplaceList(arguments.str, lEntitiesChars, lEntities) />
</cffunction>
<cfoutput>#htmluneditformat("Company?")#</cfoutput>
Further, #ReplaceList()# in both ACF and Railo/Lucee recurse through the list, which means the order of the lists matter. With the fix I suggest, ? becomes &le;. A fix to this would be to move & and the code for it to the beginning of each list.
Consider this simple piece of code
<cfoutput>#replacelist("abc","a,b","b,c")#</cfoutput>
You would probably expect the output to be "bcc", but that's not how ReplaceList works, it works something more like this
<cfset sx = "abc">
<cfset listf = "a,b">
<cfset listr = "b,c">
<cfloop from="1" to="#listlen(listf)#" index="i">
<cfset sx = replace(sx,listgetat(listf,i),listgetat(listr,i),"ALL")>
<!--- iteration one replaces a with b to make bbc --->
<!--- iteration two replaces b with c to make ccc --->
</cfloop>
I'm not suggesting that someone use this code when CF has the built in functionality, I'm merely explaining why it doesn't work and a pitfall of ReplaceList().

Coldfusion and unscoped variables

I am currently checking all my functions and components for unscoped variables. I am using a tool called varscoper4 to check all functions. Given the following code varscoper tells me that the variable "input" at line 4 in unscoped. Is this true and do i need to scope the argument variable if I alter it?
<cfoutput>#testit(1)#</cfoutput>
<cffunction name="testit">
<cfargument name="input">
<Cfset input = 3>
<cfreturn input>
</cffunction>
FYI if I do not alter the argument variable input in the function varscoper4 does not report any unscoped variables.
<cfoutput>#testit(1)#</cfoutput>
<cffunction name="testit">
<cfargument name="input">
<Cfset var output = 3 + input>
<cfreturn output>
</cffunction>
In your fist code block, input is "unscoped" but CF interprets it as arguments scope. CF will always try to find your unscoped variables by looking through a priority order. You can find more information on that here: http://www.learncfinaweek.com/week1/Scopes/
You can also view for yourself what that looks like by dumping the different scopes and seeing the output.
<cfoutput>#testit(1)#</cfoutput>
<cffunction name="testit">
<cfargument name="input">
<cfset input = 3>
<cfdump var="#variables#" label="variables">
<cfdump var="#arguments#" label="arguments">
<cfdump var="#local#" label="local">
<cfreturn input>
</cffunction>
I would strongly encourage you to take the output of your varscoper tool as a guide to where you should explicitly scope your variables. In that case, your first block of code would look like this. This is for clarity and certainty in your code.
<cfoutput>#testit(1)#</cfoutput>
<cffunction name="testit">
<cfargument name="input">
<cfset arguments.input = 3>
<cfdump var="#variables#" label="variables">
<cfdump var="#arguments#" label="arguments">
<cfdump var="#local#" label="local">
<cfreturn arguments.input>
</cffunction>
Personally, I don't like setting or changing arguments in my functions and methods. I'd rather keep them unadulterated as you have in your second block of code. But even there, I would explicitly scope the arguments so that you know where it came from -- even if not flagged by varscoper
<cfoutput>#testit(1)#</cfoutput>
<cffunction name="testit">
<cfargument name="input">
<cfset var output = 3 + arguments.input>
<cfdump var="#variables#" label="variables">
<cfdump var="#arguments#" label="arguments">
<cfdump var="#local#" label="local">
<cfreturn output>
</cffunction>
Last thing to be added here if it's not clear is that var scoping puts everything int he local scope. You could also do this and it would be functionally equivalent to the previous block of code:
<cfoutput>#testit(1)#</cfoutput>
<cffunction name="testit">
<cfargument name="input">
<cfset local.output = 3 + arguments.input>
<cfdump var="#variables#" label="variables">
<cfdump var="#arguments#" label="arguments">
<cfdump var="#local#" label="local">
<cfreturn local.output>
</cffunction>
You should use arguments.input:
<cfset arguments.input = 3>
Although even better would be to use your second example, with the arguments scope:
<cfset var output = 3 + arguments.input >
Don't modify arguments, leave them as they are when they arrive, incase you want to re-use the original value later on.
http://help.adobe.com/livedocs/coldfusion/8/htmldocs/help.html?content=buildingComponents_29.html

How to pass a struct to Coldfusion CFC using CFINVOKE?

I have a CFC file which handles all of the emails I'm sending form an application (using Coldfusion8).
I was using CFINVOKE to call the respective function inside this CFC and passed a struct with all user data along like so:
<cfscript>
var User.data = {};
User.data.name = "John Doe";
User.data.email = "john#doe.com";
...
</cfscript>
// call mailer
<cfinvoke component="mailer_user" method="say_hi">
<cfinvokeargument name="userData" value="#User.data#">
</cfinvoke>
And inside my mailer.cfc
<cffunction name="say_hi" access="public" output="false">
<cfargument name="userData" type="struct" required="true" />
....
For some reason this now fails and I can only get it to work if I pass fields seperately as cfargument, which is a a pain, since I'm passing a lot of data.
Question:
How can I get this to work using argumentCollection.
Even if I CFINVOKE like this:
<cfinvoke component="mailer_user" argumentcollection="#User.data#" method="say_hi"></cfinvoke>
it still doesn't do a thing. I'm setting output flags right before the cfinvoke and after, as well as inside the "say_hi" function going in and out. I'm only getting the flag before CFINVOKE.
Side note: This is all done through AJAX and I'm only getting back success="false" if my CFC has an error somewhere. I only work remotely on the system, so I can't set AJAX debugging in CFADMIN
As I typed the comment above it occurred to me what the problem is likely to be.
You are passing in a structure to your function. You pass User.data which has name,email,blah,etc as keys in that structure. Those keys need to match the arguments in your function
<cffunction name="say_hi" access="public" output="false">
<cfargument name="name" type="struct" required="true" />
<cfargument name="email" type="struct" required="true" />
<cfargument name="blah" type="struct" required="true" />
<cfargument name="etc" type="struct" required="true" />
If you want to pass in the structure as a argument, you would need to have a user.userData as your structure of user data and your function should be
<cffunction name="say_hi" access="public" output="false">
<cfargument name="userData" type="struct" required="true" />
When you pass the collection as argumentCollection you should do argumentCollection="#user#", so that the userData part matches your cfargument in the function.
Clear as mud?
I think you should stay in cfscript style by writing
// call mailer
mailUser = createObject("component", "mailer_user"); // or new mailer_user(); for CF9+
mailUser.say_hi(User.data);
That should work, if it doesn't, it's somewhere else in your code. Try looking at the error log.
You should map the variable to the data you pass, then no problem sending a struct. Do it this way
<cfset objMailer = createObject("component","mailer_user") />
<cfset objMailer.say_hi(userData:user.data)/>
This works even in CF7.
Ok. There was a typo inside my mailer CFC, where I had a variable with "##". As is was inside my email text
it went unnoticed...
So you can pass a struct allright using this:
<cfinvoke component="mailer_user" method="say_hi">
<cfinvokeargument name="userData" value="#User.userdata#">
</cfinvoke>
and grab it inside your called function like so:
<cffunction name="say_hi" access="public" output="false" hint="">
<cfargument name="userData" type="struct" required="true" hint="user data passed" />
<cfscript>
var internalInfo = "";
var User = {};
User.userdata = userData;
</cfscript>
...
Maybe someone else can use the snippet.

Testing for existence of FORM scope / struct in ColdFusion

Problem: When requesting the WSDL for a CFC, I get the following error: Variable FORM is undefined. It happens in this line of code, in the OnRequestStart method in application.cfc
<cfif structKeyExists(form,'resetappvars')>
<cfset OnApplicationStart() />
</cfif>
If I request a specific method, it works fine. I have considered using cfparam to create a default form struct if none exists, but that seems like an ugly hack and I worry it will actually create the form struct in the variables or this scope of the CFC. Maybe this is a legitimate bug as well?
Note: This only happens when I request the WSDL, if I invoke a method directly - the code executes as expected without problems.
Update: Application.cfc code sample - just add any CFC to your app and request it with ?wsdl to see the issue. This has been tested (and failed) on ColdFusion 7 and ColdFusion 8.
<cfcomponent output="false">
<cffunction name="OnApplicationStart" access="public" returntype="boolean" output="false" hint="Fires when the application is first created.">
<cfset application.dsn = "my_dsn" />
<cfreturn true />
</cffunction>
<cffunction name="OnRequestStart" access="public" returntype="boolean" output="false" hint="Fires at first part of page processing.">
<cfargument name="TargetPage" type="string" required="true" />
<cfif structKeyExists(form,'resetappvars')>
<cfset OnApplicationStart() />
</cfif>
<cfreturn true />
</cffunction>
</cfcomponent>
Maybe try adding a:
<cfif IsDefined("form")>...</cfif>
around the above code?
You could also cfparam the variable you're looking for then just change your logic a little (assuming resetAppVars is a boolean:
<cfparam name="form.resetAppVars" default="false" />
...
<cfif form.resetAppVars>
<cfset OnApplicationStart() />
</cfif>
Edit: I'm not sure if the above code could be considered a hack, but it seems pretty standard CF, to me.
This post of Ben Nadel gives detailed list of scopes available for different types of requests.
By reading it you can easily find out that form scope is not available in given context, but url is.
I've heard it's just a matter of opinion, but it seems to me that it is improper to reference your form scope within a CFC, as there is no guarantee that the form scope will be available when your cfc is invoked and when your method is called. It is better to ensure that any data that needs to be available to the method is provided explicitly to your object. This can be done either by including an argument:
<cfargument name="resetAppVars" type="boolean" required="false" default="false" />
Then you check arguments.resetAppVars, and it is always defined, but defaulted to false.
Or by creating an attribute on your object and creating an explicit set method:
(at the top of your cfc)
<cfset this.resetAppVars = false />
<cffunction name="setResetAppVars" access="public" returnType="void" output="false">
<cfargument name="flagValue" type="boolean" required="true" />
<cfset this.resetAppVars = arguments.flagValue />
</cffunction>
In which case you will check against this.resetAppVars. You can also scope this locally using <cfset var resetAppVars = false /> as the declaration, which makes it a private attribute of your object, and is probably proper, so code that invokes the object cannot improperly overwrite this variable with a non-boolean type. In that case, you would simply refer directly to resetAppvars in your test, instead of using this scope.
You could also do this:
<cfif NOT isSoapRequest()>...
and stick your remaining logic inside that chunk.

Can a ColdFusion cfc method determine its own name?

I am creating an API, and within each method I make a call to a logging method for auditing and troubleshooting. Something like:
<cffunction name="isUsernameAvailable">
<cfset logAccess(request.userid,"isUsernameAvailable")>
......
</cffunction>
I'd like to avoid manually repeating the method name. Is there a way to programatically determine it?
I've looked at GetMetaData() but it only returns info about the component (including all the methods) but nothing about which method is currently being called.
So now 3 ways.
If you are using ColdFusion 9.0 or higher there is now a function named GetFunctionCalledName(). It will return what you are looking for.
http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WS7cc222be8a31a47d-6e8b7083122cebfc8f2-8000.html
OR
Use ColdSpring and Aspect Oriented Programming (http://www.coldspringframework.org/coldspring/examples/quickstart/index.cfm?page=aop) to handle this for you.
OR
Use a cfthrow to generate a stack trace that has the information for you:
<cffunction name="determineFunction" output="FALSE" access="public" returntype="string" hint="" >
<cfset var functionName ="" />
<cfset var i = 0 />
<cfset var stackTraceArray = "" />
<cftry>
<cfthrow />
<cfcatch type="any">
<cfset stacktraceArray = ListToArray(Replace(cfcatch.stacktrace, "at ", " | ", "All"), "|") />
<!---Rip the right rows out of the stacktrace --->
<cfloop index ="i" to="1" from="#ArrayLen(stackTraceArray)#" step="-1">
<cfif not findNoCase("runFunction", stackTraceArray[i]) or FindNoCase("determineFunction", stackTraceArray[i])>
<cfset arrayDeleteAt(stackTraceArray, i) />
</cfif>
</cfloop>
<!---Whittle down the string to the func name --->
<cfset functionName =GetToken(stacktraceArray[1], 1, ".") />
<cfset functionName =GetToken(functionName, 2, "$")/>
<cfset functionName =ReplaceNoCase(functionName, "func", "", "once")/>
<cfreturn functionName />
</cfcatch>
</cftry></cffunction>
My recommendation would be use getFunctionCalledName, or if not on CF 9 ColdSpring, as it will probably buy you some other things.
I agree w/ tpryan. ColdSpring makes this very easy. However, here is another alternative. Instead of parsing the stack trace, you can parse the CFC file itself.
<cffunction name="foo" displayname="foo" hint="this is just a test function" access="public" returntype="string">
<cfset var test = getFunctionName(getMetaData().path, getPageContext().getCurrentLineNo()) />
<cfreturn test />
</cffunction>
<cffunction name="getFunctionName" hint="returns the function name based on the line number" access="public" returntype="string">
<cfargument name="filepath" type="string" required="true" />
<cfargument name="linenum" type="any" required="true" />
<cfset var line = "" />
<cfset var functionName = "" />
<cfset var i = 1 />
<!---- loop over CFC by line ---->
<cfloop file="#ARGUMENTS.filepath#" index="line">
<cfif findNoCase('cffunction', line, 1)>
<cfset functionName = line />
</cfif>
<cfif i EQ ARGUMENTS.linenum><cfbreak /></cfif>
<cfset i++ />
</cfloop>
<!---- parse function name ---->
<cfset functionName = REMatchNoCase("(\bname=[""|'])+[a-z]*[""|']", functionName) />
<cfset functionName = REMatchNoCase("[""']+[a-z]*[""']", functionName[1]) />
<cfset functionName = ReReplaceNoCase(functionName[1], "[""']", "", "all") />
<!---- return success ---->
<cfreturn functionName />
</cffunction>
The above is written for ColdFusion 8. CFLOOP added support for looping over files line by line (and doesn't read the entire file into memory). I did a few tests comparing the stack trace method vs. file parsing. Both performed equally well on a small CFC being called directly from a single CFM template. Obviously if you have very large CFCs the parsing method might be a bit slower. On the other hand, if you have a large stack trace (like if you are using any of the popular frameworks) then file parsing may be faster.
-= Viva ColdFusion =-
Well you might try this:
<cffunction name="getFunctionName" returntype="any">
<cfset meta =getMetaData(this)>
<cfreturn meta.functions[numberOfFunction].name>
</cffunction>
I've tried various things, and this is not accurate as the functions seem to be added to the array of functions in reverse alphabetical order. This seems limiting (and not solving the problem). I would imagine some native java code could be invoked, but i'm going to need to look into that.
This and This look like interesting reading on related internal functions.
Re: The other answer on coldspring. I found this in depth article on function metadata with coldspring.
Related question : How to get the name of the component that’s extending mine in ColdFusion?
I thought of another way that could work.
Setup an OnMissingMethod something like this:
<cffunction name="onMissingMethod">
<cfargument name="missingMethodName" type="string">
<cfargument name="missingMethodNameArguments" type="struct">
<cfset var tmpReturn = "">
<cfset var functionToCallName = "Hidden" & Arguments.missingMethodName>
<cfset arguments.missingMethodArguments.calledMethodName = Arguments.missingMethodName>
<cfinvoke method="#functionToCallName#" argumentcollection="#Arguments.missingMethodArguments#" returnvariable="tmpReturn" />
<cfreturn tmpReturn>
</cffunction>
Then name each of the regular methods with a prefix ("Hidden" in this example), and mark them as private. So my initial example would become:
<cffunction name="HiddenisUsernameAvailable" access="private">
<cfset logAccess(request.userid,Arguments.calledMethodName)>
......
</cffunction>
Now all the calls will be intercepted by onMissingMethod, which will add the method name to the arguments that get passed to the real method.
The downsides I see to this are that introspection no longer works properly, and you must be using named arguments to call all your functions. If you are not using named arguments, the args will randomly change order in the missingMethodNameArguments structure.
getFunctionCalledName() gives you the name of the active method.