CFinclude issue - coldfusion

I am trying to cfinclude a file and also pass some values to that specific file. I don't know if it is possible so any reply is appreciated.
This is my code:
<cfoutput>
<cfset path = "?id=#email_id#&contactid=#email_contactid#&ownerid=#email_ownerid#">
<cfinclude template="/email_results#path#">
</cfoutput>
My mapping goes something like this:
E:\sites\exampleCom\cf_modules\reports\resultsTemplate.cfm
I did a #expandPath("/email_results#path#")# and it is giving me the correct output
(E:\sites\exampleCom\cf_modules\reports\resultsTemplate.cfm?id=123&contactid=123&ownerid=123)
but when I am trying to include the file it bugs out. Can I pass in variables through the cfinclude? Is this what it bugs out my code?

No, you do not pass variables to an include page. The include will be execute in the same context, so it can directly see the email_id and other variables.

Related

Why do CFM templates being included with cfinclude need their own <cfoutput> wrappers?

I am using <cfinclude> to include various pages within a master page. In my master page all the body content is wrapped in <cfoutput> tags. However I noticed that after testing, the included .cfm page don't see the <cfoutput> tags at all and hence don't display the dynamic data.
<body>
<cfoutput>
<cfinclude template="page1.cfm" />
<cfinclude template="page2.cfm" />
<cfinclude template="page3.cfm" />
</cfoutput>
</body>
In the above example, the included templates that have dynamic data in them will not display properly. To solve this I have to add <cfoutput> tags within each of the CFM files. How come they can't use the <cfoutput> tags that are already there within the body?
Because each CFML file is compiled separately, and whether or not to output something is determined at compile time, not runtime.
Set aside how ColdFusion works, you want to do this. The point of using something like CFINCLUDE is that you're able to write a chunk of code once and use it in multiple situations.
Think of it as a poor mans' encapsulation. Someone should be able to use that included template without getting bogged down in the mundane details of the template that is being included.

How can I confirm a cffile write is successful?

I am using cffile to create a new file or update an existing file, depending on what the user requested. The request comes through a form from the previous procedure, so the code involving cffile looks like this:
<cfset thefile = "#form.dyn#">
<cfoutput>
<cfsavecontent variable = "testvar">
#form.editor1#
</cfsavecontent>
<cffile action = "write"
file = "/var/www/reports/#thefile#.cfm"
output = "#testvar#">
</cfoutput>
When I am done writing to the file, I want to confirm to the user that this happened. For a new file I could use IsDefined to check that it is there. But I can't think of a way to check for an existing file that was updated. I considered a try/catch on the cffile, but the catch operates only if nothing seems to go wrong. If I don't get an error on the catch, can I assume everything is all right? I would prefer a direct check if possible. Does anyone have an idea?
If <cffile> doesn't work, it'll tell you by throwing an exception. If it doesn't do that, you can safely assume it has worked. Don't over-engineer your app.
You could use cfdirectory with the action="list" and filter="your-filename" to get the following information about the uploaded file:
If action = "list", cfdirectory returns the following result columns, which you can reference in a cfoutput tag:
name: Directory entry name. The entries "." and ".." are not returned.
directory: Directory that contains the entry.
size: Directory entry size.
type: File type: file, for a file; dir, for a directory.
dateLastModified: The date that an entry was last modified.
attributes: File attributes, if applicable.
mode: Empty column; retained for backward compatibility with ColdFusion 5 applications on UNIX.
Of interest to you is the dateLastModified column.
So you should be able to do something like:
<cfdirectory action="list" name="dirQuery" directory="C:/var/www/reports/" filter="#thefile#.cfm">
Then you can dump that result to see what information is available to you:
<cfdump var="#dirQuery#">
The dateLastModified column can be accessed like:
<cfoutput>#dirQuery.dateLastModified#</cfoutput>
Use CFDirectory to get the file's dateLastModified before you update the file and then again afterwards. If they are not the same, then it was updated.

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

Is it possible to download a file variable in coldfusion?

Using Coldfusion's SpreadSheet() object I have created an excel file and now the user needs to be able to download it.
mySS = SpreadsheetNew();
format1 = StructNew();
format1.color="dark_green";
format1.size="24";
SpreadSheetSetCellValue(mySS, 7,2,3);
SpreadSheetFormatCell(mySS, format1, 2, 3);
essentially I would like something like
<cfdownload var="#mySS#">
however it's almost never that simple. I realize that I can write the file and then use cfheader \ cfcontent however I am trying to avoid writing the file if possible.
Edit
Based on the suggestion I got from speshak I tried
<cfcontent variable="#mySS#" type="application/msexcel">
and the error I got was, am I missing something?
coldfusion.excel.ExcelInfo is not a supported variable type. The
variable is expected to contain binary data.
Alright so thanks to Raymond Camden's Post and speshak here is the final solution.
<cfheader name="Content-Disposition" value="attachment;filename=filename.xls">
<cfcontent variable="#spreadsheetReadBinary(mySS)#" type="application/msexcel">
Try:
<cfcontent variable="#mySS#">
You probably want to set the type attribute as well so the browser knows it's not HTML.

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

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.