How do I force evaluation of a cfif stored in a string? - coldfusion

I am trying to store coldfusion code in a database to be used for the subject of a cfmail. The code stored is as follows:
"RE: <cfif myData.general.legalName NEQ """"> {{dotlegalname}}<cfelse>{{docketLegalName}}</cfif>,
DOT## {{dot}}, Docket ##(s) {{docketString}}"
When I retrieve string from the database, I use cfsavecontent to attempt to evaluate it.
<cfsavecontent variable="subject">
<cfoutput>#myData.email.subject#</cfoutput>
</cfsavecontent>
I also tried
<cfsavecontent variable="subject">
<cfoutput>#evaluate(myData.email.subject)#</cfoutput>
</cfsavecontent>
And then I replace all the {{ }} with the appropriate values.
However, the subject of the email is stubbornly refusing to contain an evaluated cfif, and is instead showing the cfif as if it were a string.
Any ideas?

The only way to dynamically evaluate code that you are creating at runtime is via writing it out to a file, and then executing it.
The easiest way would be to write it a .cfm page in the Virtual File System (probably name the file after a UUID, so it's unique), and then it where you need to run the contents.
I wouldn't normally advocate generating code at runtime like this, but it can be the most elegant solution in some cases.
As an alternative, instead of storing the CFML code in the database, you have a set of CFML email template files that get stored in a directory on your server, and in your database you simply record which template needs to be included either via cfinclude or cfmodule.

You can't dynamically evaluate CFML stored in a database without first writing it to file and then using <cfinclude> to include it.

Further to Mark's answer here is some psuedo code:
<cfset fileName = createUUID() & ".cfm">
<cfset fileWrite( fileName, [CODE_FROM_DB]>
<cfinclude template="#fileName#">
<cfset fileDelete( fileName )>
I have used code like this before with no problems. Anything in the Virtual File System flies as it is all run in RAM. For best practice do remember to delete the files created ;)

If you absolutely have to do this, look at the evaluate() function. This, essentially, fires up a new CF thread, compiles the string passed to it, runs it, and returns the result.
If at all possible, I would try to find a way to move your logic to the actual file being run, not the string from the database. I assume you are pulling the data based on some string you've already built, so you might consider appending something to it, so you are looking up subjectDotLegal and subjectDocketLegal or something similar.
Remember, evaluate() is slow, ugly, and can be dangerous (it will run anything passed to it!). If there's a way around it, I suggest you use it.

why not just use something like mustache?
http://mustache.github.com/
https://github.com/pmcelhaney/Mustache.cfc
it has the ability to not only do some of the logic that you want in your script dynamically. i really would suggest you check out the project and maybe even improve and contribute on it.
OH and just for the chance to be on a soapbox: I've been emailing Adobe for years saying that we need the ability to dynamically parse and render CFML. Sadly my cries have only gotten ignored. maybe if more people complained that this feature needs to be added, it would get the attention it deserves.

To give an example: Assume code.txt is a text file that contains the following (just to facilitate simulating CFML stored in a db): <cfoutput>#now()#</cfoutput>
The following code would work:
<cfset q = queryNew("code") />
<cfset queryAddRow(q,1) />
<cfset querySetCell(q, "code", fileRead(expandPath('code.txt')), 1) />
<cfdump var="#q#">
<cfset newCodeFile = expandPath('dynamic.cfm') />
<cfset fileWrite(newCodeFile, q.code[1]) />
<cfinclude template="dynamic.cfm" />

In OpenBlueDragon there is the render function, which can do this.
You can mimic this function in Railo by creating a custom built-in function that saves the file into RAM then cfincludes it, using the following code:
<cffunction name="render" output="Yes" returntype="string"><!---
---><cfargument name="Code" required="Yes" type="string"><!---
---><cfset local.mapping = {'/render_ram_resource':'ram://'}><!---
---><cfapplication action="update" mappings="#local.mapping#"><!---
---><cfset local.fileName = "/render_ram_resource/_render_" &
createUUID() & ".cfm"><!---
---><cffile action="WRITE" file="#fileName#"
output="#arguments.Code#"><!---
---><cfinclude template="#fileName#"><!---
---><cffile action="DELETE" file="#fileName#"><!---
---></cffunction>
(This looks unusual because it needs to allow output, but prevent extra whitespace, hence why all the comments. Unfortunately SO's syntax highlighting seems to be confused by them.)
If you need an ACF-compatible solution, you'll need to use the regular filesystem and a pre-created mapping. (Well, in ACF9 and above you can use the RAM virtual filesystem, but afaik you can't create mappings on the fly like this.)

There's a better way, namely using in memory files. This way you don't have any I/O on the disk and therefore much faster:
For tags that take logical path, define mapping in Administrator. Execute in-memory CFM pages using the cfinclude tag:
Create a mapping for ram:/// so that it can be used in the tags. In this example, /inmemory is the mapping that points to ram:///.
For tags that take absolute path, specify the syntax as provided in the following example:
You can also delete the file from the ram usinf cffile and action delete.

Here's how I stored my header and footers for all pages in a record. This code can go at the top of each page. But I have it in the APPLICATION.cfm and it seems to be working great.
The key here is not use #pound# signs on your expressions. User [square braces]. The code will pick them and evaluate them and return the result back to the template.
It will substitute the number 0 if it can not evaluate an expression as a means of error handling.
<CFSET FooterID=1234> <!-- ID of the record you want to use -->
<CFQUERY NAME="StoredHeader" Datasource="DS1">
Select Body from templates where id=#FooterID#
</CFQUERY>
<CFSET Parse=StoredHeader.Body>
<CFLOOP CONDITION="FindNoCase('[',Parse,1) GT 0">
<CFSET STB=FindNoCase('[',Parse,1)>
<CFSET ENB=FindNoCase(']',Parse,1)>
<CFIF ENB-STB GT 0>
<CFSET BracketExp=Mid(Parse,STB+1,ENB-1-STB)>
<CFTRY>
<CFSET BracketValue=Evaluate(BracketExp)>
<CFSET Parse=ReplaceNoCase(Parse,'['&BracketExp&']',Evaluate(#BracketExp#))>
<cfcatch type="any">
<div>'Using ZERO 0 for missing <cfoutput>#BracketExp#' </cfoutput> </div>
<CFSET Parse=ReplaceNoCase(Parse,'['&BracketExp&']','0')>
</cfcatch>
</CFTRY>
</CFIF>
</CFLOOP>
<CFSET Footer=Parse>
<cfoutput>FOOTER</cfoutput>

I would try the built-in QuoteName function.

Related

how can I use cfdirectory to make a list of documents downloadable using ColdFusion/Lucee?

In my Application.cfc, I setup a mapping
this.mappings["/downloads"]="J:\Downloads\documents";
In my template, I have
<cfdirectory action="list" directory="#expandpath("/downloads")#" filter="*.zip|*.docx" name="downloads" recurse="yes">
<!--- <cfdump var="#expandpath("/software")#"> --->
<cfdump var="#downloads#">
<ul>
<cfoutput query="#downloads#">
<li>#downloads.name#</li>
</cfoutput>
</ul>
I'm trying to make the documents downloadable but when the link is clicked, nothing is happening which makes me think my links are not correct however when I mouse over the link, I see the full path which is correct.
What am I missing to make the list of documents clickable?
Here is the URL displayed when mouseover the 3rd document for example.
Since the files are outside of your webroot you will need to have ColdFusion read the file and send it back to the browser.
You will need to create a page, like download.cfm, that can accept a URL parameter to know which file to access. Once you have selected the file you can use something like the following to stream the file.
<cfheader name="Content-disposition" value="attachment;filename=#datafile#">
<cfcontent file="#datafile#" type="application/pdf">
The above code was pulled from https://www.raymondcamden.com/2006/03/10/Ask-a-Jedi-Using-ColdFusion-to-serve-files
WARNING:
Reading URL parameters in this way and giving people access to the filesystem is extremely unsafe. Safer alternatives should be considered before moving something like this into a production environment.
All I needed to do for this exercise is to setup a mapping in my Application.cfc. As others have stated, there is zero security here but for the purpose of this exercise of understanding virtual directories (IIS) and aliases (CommandBox), this is sufficient.
this.mappings["/guides"]="J:\guides";
Then I can use cfdirectory to build my query object
<cfdirectory action="list" directory="j:\guides" recurse="false" name="nameofqry" type="file" sort="datelastmodified desc" filter="*.docx">
Next, perform a cfoutput using my alias as the a href link
<cfoutput query="nameofqry" maxrows="40">
<li>#nameofqry.name#</li>
</cfoutput>

Export to Excel - Hidden Field not generating results

I've a simple CFC file that contains the different functions for different queries & a separate function that displays the reports dynamically based on the queries.
All the queries work except one which returns approx. 50k rows. Its just a blank screen & I get no error. When I dump the query results, they do get dumped on the screen but while displaying it in a tabular report it gives nothing.
I've a another CFM file that returns 100k rows & works fine.
Below is CFC code that is not working.
<cfcomponent>
<cfparam name="qry1" default="">
<cffunction name="showqry1" access="remote">
<cfquery name="qry1" dataSource="myds" cachedwithin="#CreateTimeSpan(0, 2, 0, 0)#">
<!--- myquery --->
</cfquery>
<cfset Display()>
</cffunction>
<cffunction name="showqry2" access="remote">
<cfquery name="qry1" dataSource="myds" cachedwithin="#CreateTimeSpan(0, 2, 0, 0)#">
<!--- myquery --->
</cfquery>
<cfset Display()>
</cffunction>
<cffunction name="Display" access="private">
<cfdump var="#rptQry#" top="20">
<cfsavecontent variable="myrpt">
<table>
<!--- make a tabular report here using cfloop over the query--->
</table>
</cfsavecontent>
<cfform action="test.cfm" method="post" name="ExcelData">
<cfoutput>#myrpt#</cfoutput>
<cfinput type="hidden" name="excel_data" value="#myrpt#"/><!---This is giving the error. --->
<cfinput type="submit" name="test" value="Export" />
</cfform>
</cffunction>
</cfcomponent>
Any idea why CFM works fine but CFC doesn't? I need my CFC to work & dont want it to convert it to CFM...
UPDATE:
I've added a comment("This is giving the error") in the above code that is cause of the error. Irrespective of CFC/CFM this doesn't work.
I use the hidden field to pass data to another file which exports data to excel. Any alternate suggestions??
Any help is highly appreciated.
Thanks
You still need to read that doc I put in the comment about how to ask questions clearly.
However you are putting your recordset into a variable qry1, but trying to dump a variable rptQry. But that would just error, unless there's some code you're not showing us that populates rptQry.
Also, from a coding practice POV, you shouldn't really be outputting stuff in your functions: that's best done in a CFM page. Get your data with a CFC method; display it with a CFM.
I also recommend you read up on how to do OO with CFML (or in general). Perhaps get Matt Gifford's book "Object-Oriented Programming in ColdFusion"
Your Display function has cfsavecontent with tabular data and you are putting it into a cfform inside a cfc. I don't know why you are doing that. Insted, simply do an ajax call which return that cfsavecontent and then show it in the cfm.
Else, I guess you may have to output the cfform in the Display function. I may be wrong, but I don't think you can simply place a cfform inside a cfc and expect it to show up on the browser. CFC is not for browser rendering, it should be in a cfm.
Regarding the comment, "This is because I need to export to excel on click of a button for which I'd need cfform. Can you suggest some alternate to this functionality?", I will give you some things to think about.
First, you talk about recordsets containing several thousand rows and you have code where you attempt to display that in a browser. Quite simply, that will take an enormous amount of time to render. So, it's a bad idea.
Next, your code has functions for various queries but just one display function. Unless that's a cleverly written function that figures out the column names, it will only work if all the queries have the same columns. If that's the case, maybe you only need one query and some variables.
My suggestion is to start with a form where the user sends the appropriate information which determines what sql gets written. This form should also include a way for them to choose whether they want the results rendered in excel or html. If they choose html, do something to ensure that the data being returned does not overwhelm their browser.
By the way, re-useable code for displaying query results is a good idea. However, a custom tag might be a more conventional way to do it.

cfInclude without cfoutput tags

Ok, I have template files which I know will require to be between <cfoutput> tags, however placing a <cfoutput> tag around a <cfinclude> won't work, and anything with a <cfmodule> won't work as that doesn't allow me to manipulate the variables scope.
So, any ideas - no matter how complex - which would allow me to include such a template file and have it act as if it's between <cfoutput> tags?
Bit of context: It's for a 'framework' I am working on and requiring every template file to start and end with a <cfoutput> tag seems a real waste, especially because the less 'coldfusiony' the template files look, the better IMO.
I was going to suggest the render() option, with the caveat it's a bloody awful bit of functionality in OpenBDML (or whatever they want to call their version of CFML), and I think should be avoided. I can't see how it doesn't cause the CFML to be recompiled every request, which is a helluva overhead. I think you're better off modifying the mark-up when it gets saved/read to wrap/unwrap it in <cfoutput> tags, that way the resultant CFML will only be recompiled when the file actually changes. Which will be really a lot less often than it's read.
Prompted by your question, I did a bit of a write up on the CFML compile process, showing why having the <cfoutput> tags in a separate file doesn't work. Apologies it took so long to write & follow-up with here.
What we do in wheels is just wrap the cfinclude with a cfsavecontent tag
<cffunction name="renderInclude">
<cfargument name="template" value="string" required="true">
<cfset var myOutput = "">
<cfsavecontent variable="myOutput"><cfoutput><cfinclude template="#arguments.template#"></cfoutput></cfsavecontent>
<cfreturn trim(myOutput)>
</cffunction>
Found an OpenBD specific way to solve this problem. Apparently I wasn't the only one who encountered this problem and OpenBD contains a useful render() which takes care of evaluating cfml content. So I ended up with
<cfset cfml = fileRead(expandPath(...))>
...
<cfoutput>#render("<cfoutput>"&cfml&"</cfoutput>")#</cfoutput>
It's not a beautiful solution, as I destroy the per page compilation the engine would otherwise do, however as the cfml is relatively simple on these pages I assume this not to be too much of an issue. At least it should be less of a performance hit than actually writing the file to disk.

How to properly use Coldfusion's FileExist() method?

I don't use coldfusion much at all, I'm needed to patch up some code though. Basically I'm trying to check and see if a file I uploaded exist and if it does exist, increment a variable by 1. Then repeat untill I get a unique file name. For whatever reason I can't figure out the proper way to use FileExist(). Some forums suggest using it with len() but those are from 2006 and when I do that it seems to always come out true. Also, when I look at http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c66.html it says it returns either Yes or No. I tried to check against the result various ways, but no luck.
This is the portion of code I have which I am dealing with. The application.filepath is just a variable in my application file which store the expandpath().
<cffile action="upload" destination="#Application.filePath#ListingsGallery/" filefield="iconImage" nameconflict="makeunique">
<cfset iconPlace = #cffile.serverfile#>
<cfset myExt = listLast(iconPlace,".")>
<cfset i = 1 >
<cfset myVar = false>
<cfloop condition="myVar EQ false">
<cfset newIconName = "iconPhoto" & i &"."& myExt>
<cfset iconName = Application.filePath & "ListingsGallery/" & #newIconName#>
<cfoutput>#iconName#</cfoutput><br />//just checking to see if it is the correct path, it is.
<cfif FileExists(iconName) EQ 'Yes'>
<cfoutput>#myVar#</cfoutput> //checking the value, it never hits here.
<cfelse>
<cfoutput>#myVar#</cfoutput><br /> //checking the value, it always hits here.
<cfset myVar = true>
<cfoutput>#myVar#</cfoutput> //Again check the value.
</cfif>
<cfset i++>
</cfloop>
<cffile action="rename" source="#Application.filePath#ListingsGallery/#iconPlace#" destination="#Application.filePath#ListingsGallery/#newIconName#">
The absolute path on a unix server is something like, /var/www/website folder name/ etc....
Correct? That's the absolute server path, the coldfusion docs seem to specify at least a microsoft absolute server path so I'm assuming this is what is needed.
Edit---------------------------
PS: I can' only give one of you credit, so I gave it to Kruger since he came a minute earlier.
lol...
FileExists() returns a boolean value. This should work fine now that the typo has been fixed:
<cfif fileExists(TheFile)>
// do this
<cfelse>
// do that
</cfif>
Assuming your application.Filepath is the correct file path you are on the right track. It looks like your upload directory might be beneath the web root - considering moving it outside the web root for security. Take a look at #expandPath('.')# as a way of creating guaranteed file paths without typos :) Also makes your code more portable.
To my eye the code above would work. FYI - you don't need "EQ 'YES'. You are fine to just do:
<Cfif FileExists(iconName)>...
You could also do
condition="NOT myVar">
There are several ways to handle logic code in CF.
If your fileExists() never hits take a closer look at your rename. Are you throwing an eror?
I can't add notes to answers yet, but I wanted to let the OP know that CF is typeless when it comes to boolean evaluations in functions. 0 is the same as "no" is the same as "false", whereas any positive number is the same as "yes" is the same as "true".
Its great to have back-end security, but this should have been handled on the front-end so you never get values you don't want. The new HTML5 input patterns would prevent this from ever being submitted, so you wouldn't have to fix this on the back end.
http://www.w3schools.com/tags/att_input_pattern.asp

What security scripts/code do you add to your application.cfm?

I am working on redoing our company's code, and I want to have a clear, easy to read, and reasonably secure application.cfm.
And no, we are not using application.cfc. So let's not discuss that please.
Just want to know what scripts you would add for security.
I am using coldfusion 8 standard, sql 2008.
Here is one of the scripts I am currently using, but I want to hear from some other coldfusion programmers.
<cfset temp = cleanScopes('form,url') />
<!--- another method to clean url/form data from http://www.garyrgilbert.com/tools/coldfusion/cleanScopes.cfm.txt --->
<cffunction name="cleanScopes" access="public" returntype="void">
<cfargument name="scopesToClean" type="string" required="yes">
<cfargument name="charlist" type="string" required="no" default="">
<cfscript>
reTags ="<[^/>]*>|</.*>";
</cfscript>
<cfloop list="#scopestoClean#" index="scopeName">
<cfif not findnocase("multipart/form-data",cgi.CONTENT_TYPE)>
<cfscript>
s=Evaluate(scopeName);
for(field in s)
if (isSimpleValue(s[field])){
if(reTags neq '')
do { prev=s[field];
s[field]=REReplaceNoCase(s[field],reTags,"","ALL");
} while (prev NEQ s[field]);
structUpdate(s,field,prev);
if (charlist neq '')
s[field] = replacelist(s[field],charlist,'');
}
</cfscript>
</cfif>
</cfloop>
<cfreturn>
</cffunction>
Thank you for your time.
I would advise against attempting to catch everything in a global fashion. There will inevitably be a few things that slip through the cracks, no matter how complex and convoluted your global protection code gets.
Instead, the "correct" (for what it's worth) method is to sanitize all content being presented on a page (or in an email, etc) -- during output -- that began its life as user input.
That said, take a look at OWASP. They have excellent libraries for protecting from all kinds of attacks, including the various ones you mention (sqli, xss, crlf). A coworker of mine recently wrapped up some of those libraries into a CFC that we can use in our applications, and explained how to use it on our developers blog:
AntiSamy
If your application accepts user generated HTML, say blog comments for example, you need to make sure you sanitize your input to prevent XSS attacks. You wouldn’t want someone to be able to enter malicious code in your blog comments so you need some way to filter the input. Enter AntiSamy. AntiSamy allows you to easily filter user generated HTML according to what it terms policies. AntiSamy is a Java project, so I have packaged it into a CFC for easy use from ColdFusion.
The simplist way to use AntiSamy is to create an instance of the AntiSamy component (cfc.owasp.AntiSamy) and call the getCleanHTML() method on the input.
<cfset antisamy = CreateObject("component","cfc.owasp.antisamy") />
<cfset cleanHTML = antisamy.scan(form.someInput) />
This will run AntiSamy with the default (fairly permissive) policy file and return the clean HTML markup.
ESAPI Encoder
The next library I’ve brought over from the OWASP project is the ESAPI Encoder. Again this is a Java project which I have wrapped in a CFC for easier use. The encoder provides several methods for encoding beyond those included with ColdFusion. Some of the more useful methods include encodeForJavaScript(), encodeForHTMLAttribute(), and encodeForCSS(). Using the component is pretty straight forward, just instantiate it and call the appropriate method.
<cfset encoder = CreateObject("component","cfc.owasp.Encoder") />
<cfset html = encoder.encodeForHTML("<body onload=""alert('XSS')"">Test</body>") />
One very useful method this library provides is the canonicalize method. The documentation from the beta version of the ESAPI Encoder gives a good description of what this method does.
However, if you insist on a global solution, why reinvent the wheel? Why not try out something like FuseGuard. The price is probably less than the cost of the development-hours that would be spent cobbling together, debugging, and dealing with security problems that break through your home-grown system.
Personally, I'm not really sure this "global" approach is the best. I check all incoming data in all models that accept external data, with specific validation rules for each situation. So additional layer looks overkill.
Such scripts wont protect you from putting string into the numeric id passed into the URL -- you have to check it any way. You have to use HTMLEditFormat/XMLFormat in the views any way, and so on.
P.S. List loop for CFScript:
for (i=1; i LTE ListLen(scopestoClean); i++) {
scopeName = ListGetAt(scopestoClean,i);
//... following code
}