How to handle a request in ColdFusion - coldfusion

I am a newbie to ColdFusion, I created a result.cfm page, now I just want to do some actions in Application.cfc when the user calls /result.cfm. Something like below:
<cfif 'if the request is for result.cfm'>
<!-- do some action -->
</cfif>
Is there any way to handle the request?

A CFC is what Coldfusion calls a component, but it's essentially an object with methods. When any page on your site is requested coldfusion sends the name of your page to the onRequest method of your Application.cfc. By default that method looks something like this...
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true" />
<cfinclude template = "#arguments.targetPage#" />
</cffunction>
The TargetPage is the relative path to the page that has been requested.
I'm not sure what you're trying to do do, but you can either just create the page result.cfm and do your coding in there, or if you need to you can intercept the call by creating your own onRequest method and putting it in your application.cfc
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true" />
<cfif arguments.targetPage is "requestresult.cfm">
<!--- Do something else --->
<cfelse>
<cfinclude template = "#arguments.targetPage#" />
</cfif>
</cffunction>
Note that onRequest isn't the only method in Application.cfc, so that's worth looking up.
Also note you might want to output arguments.targetPage when you try this to just double check if the slash comes with the request or not (can't remember)

<cfif REFindNoCase("^/result.cfm", CGI.SCRIPT_NAME)>
<!--- do some action --->
</cfif>
or if you want to match more pages and subfolders you could do:
<cfset patterns = [
"^/foo/",
"^/bar/",
"^/etc/",
"^/login.cfm",
"^/baz.cfm"
] />
<cfif REFindNoCase("(" & ArrayToList(patterns, ")|(") & ")", CGI.SCRIPT_NAME)>
<!--- do some action --->
</cfif>

Related

How to call a ColdFusion function from a .cfc file?

I have a .cfc file with all my functions in it (wrapped in a <cfcomponent> tag), including this one:
<cffunction name="getFooter" output="false" access="public" returnType="string">
<cfargument name="showFooter" type="string" required="false" default="" />
<cfreturn footer />
<cfset application.lib.getFooter(arguments.footer)>
</cffunction>
<cfset footer = getFooter(footer="<footer class="text-center">I am a footer.</footer>") />
And in my .cfm file, I put:
<cfoutput>#footer#</cfoutput>
It is not displaying the footer.
When I have all of this in a single .cfm file, it works fine.
I need to be able to store the function in my .cfc file and call it from anywhere in the application.
What am I missing?
Yet another way to cut it:
Application.cfc
<cfcomponent displayname="Application" output="false" hint="Handle the application.">
<!--- Set up the application. --->
<cfset this.Name = "AppCFC" />
<cfset this.ApplicationTimeout = createTimeSpan( 1, 0, 0, 0 ) />
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 30, 0 ) />
<cfset this.sessionManagement = true />
<cffunction
name="OnApplicationStart"
access="public"
returntype="boolean"
output="false"
hint="Fires when the application is first created.">
<!--- These variables are available to every CFM page in the application --->
<cfset application.lib = new path_to_Lib_CFC()>
<cfset application.footer=application.lib.getFooter()>
<cfreturn true />
</cffunction>
</cfcomponent>
Lib.cfc
<cfcomponent displayname="Lib" hint="Library of application CFCs">
<cffunction
name="getFooter"
output="false"
access="public"
returnType="string">
<cfset var footer = "<footer class=""text-center"">I am a footer.</footer>" />
<cfreturn footer />
</cffunction>
</cfcomponent>
Then, in any CFM file in the application:
<cfoutput>#application.footer#</cfoutput>
You explain your requirement clearly:
I need to be able to...call it from anywhere in the application.
So, don't do this:
"have a .cfc file with all my functions in it (wrapped in a
tag), including this one:"
The requirement, "call it from anywhere in the application", implies just one thing in ColdFusion: an application-scoped variable.
So, do the following instead: transfer the footer functionality from that CFC to your Application.cfc.
Let's assume the following is an excerpt of your Application.cfc.
Then, do something like:
<cfcomponent displayname="Application" output="true" hint="Handle the application.">
<!--- Set up the application. --->
<cfset this.Name = "AppCFC" />
<cfset this.ApplicationTimeout = createTimeSpan( 1, 0, 0, 0 ) />
<cfset this.sessionTimeout = createTimeSpan( 0, 0, 30, 0 ) />
<cfset this.sessionManagement = true />
<cffunction
name="OnApplicationStart"
access="public"
returntype="boolean"
output="false"
hint="Fires when the application is first created.">
<!--- This variable is available to every CFM page in the application --->
<cfset application.footer=getFooter()>
<cfreturn true />
</cffunction>
<cffunction
name="getFooter"
output="false"
access="public"
returnType="string">
<cfset var footer = "<footer class=""text-center"">I am a footer.</footer>" />
<cfreturn footer />
</cffunction>
</cfcomponent>
Then, in any CFM file in the application:
<cfoutput>#application.footer#</cfoutput>
You stated, we store all of our functions in a lib.cfc file.. So, in that file, write your function.
<cffunction name = "writeAppABCFooter" <!---descriptive name in case there is another footer --->
access = "public"
output = "yes" <!--- this is important --->
returntype = "void">
html code for footer
</cffunction>
To call your function, first create an object of lib.cfc.
<cfobject name = "FooterObject" component = "lib">
Then call the function.
<cfset FooterObject.writeAppABCFooter()>
This assumes that lib.cfc exists in a location that enables it to be called by any application.
I am going to ask and answer what I think you want.
Question
I have an application and it needs to have common footers. My footers are going to need the ability to have some sort of business logic. Right now it is Just static text. I think my footers need to be a function.
How can I do that? Oh, and I need to do this with tags, not script
Answer
First, we need a function with a very wide scope. I am going to put it in application.cfc. It is true that application.cfc is a .cfc, but it is highly special.
<!--- application.cfc --->
<cfcomponent>
...
<cffunction name="getFooter">
<cfsavecontent variable="local.result">
</cfsavecontent>
<cfreturn local.result>
</cffunction>
<cfset application.getFooter = getFooter>
...
</cfcomponent>
Now inside of each of the .cfm files, you can
<cfoutput>#application.getFooter()#</cfoutput>
Turns out this was a lot simpler than most us made it out to be. The <cfsavecontent> tag wasn't necessary. Storing the HTML in a variable wasn't required. I don't know if it was me or not, but this got way over complicated.
Ultimately, this is where I ended up going.
lib.cfc file
<cffunction name="getFooter" output="true" access="public" returntype="string">
<footer>I am a footer.</footer>
</cffunction>
index.cfm file
<cfoutput>
#application.lib.getFooter()#
</cfoutput>
I find it useful to just put simple reuseable things in their own CFM and just include them when needed.
/app/includes/footer.cfm
<p>I am the footer</p>
index.html
<cfinclude template="app/includes/footer.cfm">

apllication.cfc does not fire any default cffunction? Coldfusion

Can anyone tell me what the problem is? I tried to run some .cfm files but it does not trigger any effect of cffunction except cfcomponent? Am I missing something? Can anyone explain to me?
<cfcomponent>
<cfset THIS.Name = "formdemo">
<cfset THIS.SessionManagement = true>
<cfset This.Sessiontimeout="#createtimespan(0,0,20,0)#">
<cfset This.applicationtimeout="#createtimespan(5,0,0,0)#">
--Entered cfcomponent--
<cffunction name="onApplicationStart" returnType="boolean" output="false">
--Entered Application Start--
<cfset application.portfolioUploadRoot = "ram:///portfoliouploads">
<cfif not directoryExists(application.portfolioUploadRoot)>
<cfdirectory action="create" directory="#application.portfolioUploadRoot#">
</cfif>
<cfreturn true>
</cffunction>
<cffunction name="onSessionStart" returnType="void" output="false">
--Entered Session Start--
<cfset session.myuploadroot = application.portfolioUploadRoot & "/" & replace(createUUID(), "-", "_", "all")>
<cfif not directoryExists(session.myuploadroot)>
<cfdirectory action="create" directory="#session.myuploadroot#">
</cfif>
</cffunction>
<cffunction name="onApplicationEnd" returnType="void" output="false">
--Entered Application End--
<cfargument name="applicationScope" required="true">
<cfif directoryExists(arguments.applicationScope.portfolioUploadRoot)>
<cfdirectory action="delete" recurse="true" directory="#arguments.applicationScope.portfolioUploadRoot#">
</cfif>
</cffunction>
<cffunction name="onSessionEnd" returnType="void" output="false">
--Entered Session End--
<cfargument name="sessionScope" type="struct" required="true">
<cfargument name="appScope" type="struct" required="false">
<cfif directoryExists(arguments.sessionScope.myuploadroot)>
<cfdirectory action="delete" recurse="true" directory="#arguments.sessionScope.myuploadroot#">
</cfif>
</cffunction>
</cfcomponent>
The result only shows "--Entered cfcomponent--" on the beginning of cfmpage.cfm.
cfmpage.cfm:
<cfparam name="form.textname" default="">
<cfparam name="form.textemail" default="">
<cfparam name="form.docattach" default="">
<cfif structKeyExists(form, "Submit")>
<cfset form.textname = trim(htmlEditFormat(form.textname))>
<cfset form.textemail = trim(htmlEditFormat(form.textemail))>
<cflocation url="formcomplete.cfm" addToken="false">
</cfif>
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<form method="post" enctype="multipart/form-data">
<cfoutput>
<input id="textname" name="textname" type="text" class="input-large" required="" value="#form.textname#">
<input id="textemail" name="textemail" type="text" class="input-large" required="" value="#form.textemail#">
</cfoutput>
</form>
</body>
</html>
It is doing as it should.
onApplicationStart -- Runs when ColdFusion receives the first request for a page in the application.
For this, to easily see this, you can try changing the name of the application, then
visit a page within.
onSessionStart -- Only run upon the first visit within the session. If you wait til after the
timeout and then come back, you'll see this. Changing the application name will should also
retrigger this.
onSessionEnd -- Run when the session ends. It will trigger after the timeout, it's used so that
you can clean up activity. For instance, if you're using something like Application.NumberOnline.
OnSessionEnd can substract one (where onSessionStart) can add one.
onApplicationEnd -- Runs when the application timeout occurs or the server is shutting down.
Neither of the latter two will ever show any text on screen because you can't see that event while visiting the page. You can however call them manually to trigger their effects. You can, however, log these actions however you choose. You may use cflog, for instance, in this fashion:
<cffunction name="onApplicationEnd">
<cfargument name="ApplicationScope" required=true/>
<cflog file="#This.Name#" type="Information"
text="Application #Arguments.ApplicationScope.applicationname# Ended" >
</cffunction>
In other words:
<cfscript>
ap = createObject("component","Application");
ap.onSessionEnd(session,application);
</cfscript>
Will display the text because it is firing the event.
Finally, if you're wanting something to happen on each page, onRequestStart and onRequestEnd or onRequest are great options. OnRequest is a method that wraps around the page, so you can do header and footer actions in the same request, but you must explicitly include the file, wheras onRequestStart / onRequestEnd execute at the start and end of the request.
The order of action methods invoked is
onApplicationStart (runs on first application activity)
onSessionStart (runs on first session activity)
onRequestStart
onRequest
onRequestEnd
Lastly, functions don't fire unless they're called. This applies to functions you write yourself as well.
<cfscript>
function foo() {
writeoutput("bar");
}
</cfscript>
Won't do anything until you actually try something like <cfoutput>#foo()#</cfoutput>.
In the case of "default functions", these are just special functions/methods that CF calls at certain points if they're present.

Looking for Struct Keys in Session

I am trying to write a session helper and facing to problem to test if a Struct key in session exists?
I am trying like
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="Any" />
<cfreturn Evaluate( "StructKeyExists( Session, #Arguments.Key# )" ) />
</cffunction>
Where I am calling the function like
<cfif Exists("data.fromdate") >
...
</cfif>
How should I write it?
Thanks
if you are checking to see if key "Test" exists in the session struct, try something like this:
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="String" />
<cfreturn StructKeyExists(session, arguments.Key) />
</cffunction>
<cfif Exists("Test") >
....
</cfif>
Another concept, or two, since you are looking for a struct within the session would be:
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="Key" required="true" type="String" />
<cfreturn (structKeyExists(session, listFirst(arguments.Key,"."))
AND structKeyExists(session[listFirst(arguments.Key,".")], listLast(arguments.Key, "."))) />
</cffunction>
<cfif Exists("data.Test") >
....
</cfif>
and
<cffunction name="Exists" access="public" output="false" returntype="boolean" >
<cfargument name="struct" required="true" type="String" />
<cfargument name="Key" required="true" type="String" />
<cfreturn (structKeyExists(session, arguments.struct)
AND structKeyExists(session[arguments.struct], arguments.key)) />
</cffunction>
<cfif Exists("data", "Test") >
....
</cfif>
Hope all this helps point you in the right direction, good luck!
The following code will check any depth struct, and also correctly locks the Session scope.
<cffunction name="Exists" access="public" output="false" returntype="boolean">
<cfargument name="Key" required="true" type="string">
<cfset local.mainKeyList = ListChangeDelims(ListDeleteAt(Arguments.Key, ListLen(Arguments.Key, "."), "."), ",", ".")>
<cfset local.StructChain = "Session">
<cfloop list="#local.mainKeyList#" index="local.CurrentKey">
<cfset local.StructChain &= '["#local.CurrentKey#"]'>
</cfloop>
<cflock scope="session" type="readonly" timeout="3">
<cftry>
<cfset local.Exists = StructKeyExists(Evaluate(local.StructChain), ListLast(Arguments.Key, "."))>
<cfcatch>
<cfset local.Exists = false>
</cfcatch>
</cftry>
</cflock>
<cfreturn local.Exists>
</cffunction>
<cflock scope="session" type="exclusive" timeout="3">
<cfset Session.data.log.deep = "I'm here!">
</cflock>
<cfoutput>#Exists("data.log.deep")#</cfoutput>
Hopefully the amount of code in this function will justify why a helper function would be useful, to those pondering your reasons. This doesn't currently, but could be enhanced to, deal with Structs inside of Arrays as well. This also doesn't deal with an empty Arguments.Key, or fail gracefully on a cflock timeout, but should get you started.
Additionally, those that want to comment that cflock isn't required, please read the ColdFusion cflock docs first.
Simplified, but may provide inaccurate results in extremely rare conditions
Doing an IsDefined inline in your code will provide the opportunity for false positives, however having the IsDefined inside a udf or cfc method reduces this risk greatly to the point it may not need be a consideration. If you're happy to take that chance then you can simplify the function using IsDefined as Peter Boughton suggests.
<cffunction name="Exists" access="public" output="false" returntype="boolean">
<cfargument name="Key" required="true" type="string">
<cflock scope="session" type="readonly" timeout="3">
<cfset local.Exists = IsDefined("Session." & Arguments.Key)>
</cflock>
<cfreturn local.Exists>
</cffunction>
As Al Everett mentioned above, I don't remember the last time I had an app that didn't have session enabled. I guess if you can't be sure of that, then it makes sense to see if Session exists. My code for this would include:
<!--- in the application.cfc --->
<cffunction name="onSessionStart" output="false">
<!--- default session structure, you can also add default values to the data
structure here to ensure they exist later --->
<cfset session.data = {} />
</cffunction>
<!--- then in code use structKeyExists instead of a whole new function --->
<cfif structKeyExists(session.data, myKey)>
<!--- if you really wanted the "exists" function --->
<cffunction name="dataKeyExists" returntype="boolean" output="false">
<cfargument name="key" required="true" />
<cfreturn structKeyExists(session.data, arguments.key) />
</cffunction>
Depending on what's going on, I might choose to pass in the session to maintain encapsulation. But it doesn't always make sense to be a slave to OO and introduce complexity just for the sake of maintaining a pattern. Passing in the session structure and evaluating the key is really just a big workaround to using the "structKeyExists" function.
I also dislike having a function called "exists" because it tells me nothing about what it's really evaluating. I'd assume a function like that was like "isDefined" and more generic than just testing for a key in a specific structure.
<cfif structkeyexists(session, "data") and structkeyexists(session["data"], key)>
...
</cfif>
Why not just call <cfif isNull(session.data.fromdate)>
If the key data does not exist in session it will not throw, just returns false.

What's the most efficient way to redirect a user to the home page if the requested page doesn't exist?

I am using ColdFusion 9.1.
I am rebuilding a site from scratch and pointing an existing domain name to it. The site is still getting a few hits each day and I want to take advantage of that. I want to redirect those page requests to the home page, and not the error that is currently being served.
I am looking ONLY for a ColdFusion solution to move the bad request to the home page. So, if they request domain.com/BadPage.cfm?QString=XYZ, they will be moved to domain.com/.
I tried using the following method in the Application.cfc, but I couldn't get to work as described. It seemed to have no effect.
<cffunction name="OnError" access="public" returntype="void" output="true">
<cfargument name="Exception" type="any" required="true" /">
<cfargument name="EventName" type="string" required="false" default="" />
<cfif Exception>
<cflocation url="http://www.MyDomain.cfom/">
</cfif>
<!--- Return out. --->
<cfreturn />
</cffunction>
In short, what is the simplest ColdFusion means to redirect bad requests?
onError will not catch missing templates. Add an onMissingTemplate Handler to Application.cfc:
<cffunction name="onMissingTemplate" returntype="Boolean" output="false">
<cfargument name="templateName" required="true" type="String" />
<!--- Put your home page file name here --->
<cflocation url="/index.cfm" />
<cfreturn true />
</cffunction>
Use onMissingTemplate()
<cffunction name="onMissingTemplate">
<cfargument type="string" name="targetPage" required=true/>
<cflocation url="http://www.MyDomain.cfom/">
</cffunction>

NTLM Authentication in ColdFusion

Is there a recommended (and preferably free) way in ColdFusion to access a remote file that is protected by NTLM authentication? The cfhttp tag appears to only support Basic authentication.
This CFX Tag - CFX_HTTP5 - should do what you need. It does cost $50, but perhaps it's worth the cost? Seems like a small price to pay.
Here is some code I found in:
http://www.bpurcell.org/downloads/presentations/securing_cfapps_examples.zip
There are also examples for ldap, webservices, and more.. I'll paste 2 files here so you can have an idea, code looks like it should still work.
<cfapplication name="example2" sessionmanagement="Yes" loginStorage="Session">
<!-- Application.cfm -->
<!-- CFMX will check for authentication with each page request. -->
<cfset Request.myDomain="allaire">
<cfif isdefined("url.logout")>
<CFLOGOUT>
</cfif>
<cflogin>
<cfif not IsDefined("cflogin")>
<cfinclude template="loginform.cfm">
<cfabort>
<cfelse>
<!--Invoke NTSecurity CFC -->
<cfinvoke component = "NTSecurity" method = "authenticateAndGetGroups"
returnVariable = "userRoles" domain = "#Request.myDomain#"
userid = "#cflogin.name#" passwd = "#cflogin.password#">
<cfif userRoles NEQ "">
<cfloginuser name = "#cflogin.name#" password = "#cflogin.password#" roles="#stripSpacesfromList(userRoles)#">
<cfset session.displayroles=stripSpacesfromList(userRoles)><!--- for displaying roles only --->
<cfelse>
<cfset loginmessage="Invalid Login">
<cfinclude template="loginform.cfm">
<cfabort>
</cfif>
</cfif>
</cflogin>
<!-- strips leading & trailing spaces from the list of roles that was returned -->
<cffunction name="stripSpacesfromList">
<cfargument name="myList">
<cfset myArray=listtoarray(arguments.myList)>
<cfloop index="i" from="1" to="#arraylen(myArray)#" step="1">
<!--- <cfset myArray[i]=replace(trim(myArray[i]), " ", "_")>
out<br>--->
<cfset myArray[i]=trim(myArray[i])>
</cfloop>
<cfset newList=arrayToList(myArray)>
<cfreturn newList>
</cffunction>
This is the cfc that might be of interest to you:
<!---
This component implements methods for use for NT Authentication and Authorization.
$Log: NTSecurity.cfc,v $
Revision 1.1 2002/03/08 22:40:41 jking
Revision 1.2 2002/06/26 22:46 Brandon Purcell
component for authentication and authorization
--->
<cfcomponent name="NTSecurity" >
<!--- Authenticates the user and outputs true on success and false on failure. --->
<cffunction name="authenticateUser" access="REMOTE" output="no" static="yes" hint="Authenticates the user." returntype="boolean">
<cfargument name="userid" type="string" required="true" />
<cfargument name="passwd" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
// authenticateUser throws an exception if it fails,
ntauth.authenticateUser(arguments.userid, arguments.passwd);
</cfscript>
<cfreturn true>
<cfcatch>
<cfreturn false>
</cfcatch>
</cftry>
</cffunction>
<!---
Authenticates the user and outputs true on success and false on failure.
--->
<cffunction access="remote" name="getUserGroups" output="false" returntype="string" hint="Gets user groups." static="yes">
<cfargument name="userid" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
groups = ntauth.GetUserGroups(arguments.userid);
// note that groups is a java.util.list, which should be
// equiv to a CF array, but it's not right now???
groups = trim(groups.toString());
groups = mid(groups,2,len(groups)-2);
</cfscript>
<cfreturn groups>
<cfcatch>
<cflog text="Error in ntsecurity.cfc method getUserGroups - Error: #cfcatch.message#" type="Error" log="authentication" file="authentication" thread="yes" date="yes" time="yes" application="no">
<cfreturn "">
</cfcatch>
</cftry>
</cffunction>
<!---
This method combines the functionality of authenticateUser and getUserGroups.
--->
<cffunction access="remote" name="authenticateAndGetGroups" output="false" returntype="string" hint="Authenticates the user and gets user groups if it returns nothing the user is not authticated" static="yes">
<cfargument name="userid" type="string" required="true" />
<cfargument name="passwd" type="string" required="true" />
<cfargument name="domain" type="string" required="true" />
<cftry>
<cfscript>
ntauth = createObject("java", "jrun.security.NTAuth");
ntauth.init(arguments.domain);
// authenticateUser throws an exception if it fails,
// so we don't have anything specific here
ntauth.authenticateUser(arguments.userid, arguments.passwd);
groups = ntauth.GetUserGroups(arguments.userid);
// note that groups is a java.util.list, which should be
// equiv to a CF array, but it's not right now
groups = trim(groups.toString());
groups = mid(groups,2,len(groups)-2);
</cfscript>
<cfreturn groups>
<cfcatch>
<cfreturn "">
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
If the code from Brandon Purcell that uses the jrun.security.NTauth class doesn't work for you in cf9 (it didn't for me) the fix is to use the coldfusion.security.NTAuthentication class instead. Everything worked fine for me.
You could try following the guidance here: http://cfsilence.com/blog/client/index.cfm/2008/3/17/ColdFusionSharepoint-Integration--Part-1--Authenticating
Here is what it boils down to you doing:
edit the client-config.wsdd
Change
<transport
name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender">
</transport>
to
<transport
name="http"
pivot="java:org.apache.axis.transport.http.CommonsHTTPSender">
</transport>
In my case I fixed this problem using 'NTLM Authorization Proxy Server'
http://www.tldp.org/HOWTO/Web-Browsing-Behind-ISA-Server-HOWTO-4.html
work fine for me :)