Assume the following site architecture:
/Application.cfc
/index.cfm
/sub/Application.cfc
/sub/index.cfm
/login/index.cfm
Now, here's some really basic pseudo-code:
/Application.cfc:
<cffunction name="onSessionStart" returntype="Void" output="false">
<cfscript>
SESSION.IsLoggedIn = false;
return;
</cfscript>
</cffunction>
<cffunction name="onRequestStart" returnType="Boolean" output="false">
<cfargument name="targetPage" type="string" required="true">
<cfscript>
if (SESSION.IsLoggedIn)
REQUEST.Cart = {};
</cfscript>
<cfreturn true />
</cffunction>
/sub/Application.cfc
<cffunction name="onRequestStart" returnType="Boolean" output="false">
<cfargument name="targetPage" type="string" required="true">
<cfscript>
SUPER.onRequestStart(ARGUMENTS.targetpage);
</cfscript>
<cfif NOT SESSION.IsLoggedIn>
<cflocation url="/login/" addtoken="false" />
</cfif>
<cfreturn true />
</cffunction>
When I request /sub/index.cfm, I get the following exception: Element ISLOGGEDIN is undefined in a Java object of type class [Ljava.lang.String;.
On my local development machine, I have Debugging Information turned on, so I can see that the SESSION is initialized, at least from a cookie standpoint, but, as you can see, my SESSION variables is NOT initialized:
Session Variables:
cfid=149415
cftoken=b7740eb6d2219f83-619FF01B-78AC-C0A4-1997EC503DA43982
sessionid=PRUDENTIAL_2UA1130DBK_2_149415_b7740eb6d2219f83-619FF01B-78AC-C0A4-1997EC503DA43982
urltoken=CFID=149415&CFTOKEN=b7740eb6d2219f83-619FF01B-78AC-C0A4-1997EC503DA43982
I cannot understand why onRequestStart() is being called before onSessionStart(). Shouldn't onSessionStart() be called first?
Related
I have system that I built and for this project I used Ajax with JQuery. On back end I use ColdFusion and session management to handle users session variables. There is two situations (actually three if we consider closing the browser) where users session will end. One situation is if they click Logout then I have function that will clear SESSION scope with all information in it but session is not ended. Also CFID and CFTOKEN are still the same. Here is example of Logout function:
<cffunction name="LogOut" access="remote" output="yes" returnformat="JSON" hint="Used in session timeout handling">
<cfset fnResults = structNew()>
<cfset dt = createODBCDateTime(now())>
<cfif structKeyExists(SESSION,"LoggedIn")>
<cfset temp = structClear(SESSION)>
<cfset fnResults.status = "200">
<cfelse>
<cfset fnResults.status = "400">
<cfset fnResults.message = "Error!">
</cfif>
<cfreturn fnResults>
</cffunction>
Second scenario is once user session timeout. Here is example of that fucntion:
<cffunction name="timeoutSession" access="remote" output="yes" verifyclient="no" securejson="false">
<cfset temp = structClear(SESSION)>
</cffunction>
Both of these functions will clear the session scope but not end the user session. I have used cfdump to check session scope once user logs out and CFID/CFTOKEN remains the same. I'm wondering how session cna be ended once they hit LogOut or timeoutSession function? Also should I rewrite the CFID and CFTOKEN every time user logs in the system? Here is example of my Application.cfc:
<cfcomponent output="false">
<cfset THIS.name = "MyApplication">
<cfset THIS.sessionManagement = true>
<cfset THIS.applicationTimeout = CreateTimeSpan(0, 8, 0, 0)>
<cfset THIS.sessionTimeout = CreateTimeSpan(0, 2, 0, 0)>
<cfset THIS.requestTimeOut = "60">
<cffunction name="onApplicationStart" access="public" returntype="boolean" output="false">
<cfset APPLICATION.appStarted = now()>
<cfset APPLICATION.title = "My Application">
<cfset APPLICATION.functions = CreateObject("component","udfs").init()>
<cfset APPLICATION.sessionMinutes = 30>
<cfreturn true>
</cffunction>
<!--- Runs when your session starts --->
<cffunction name="OnSessionStart" access="public" returntype="void" output="false">
<!--- Clear the session. --->
<cfset StructClear( SESSION ) />
<!--- Set loggedin flag to false. --->
<cfset SESSION.loggedin = false>
<cfreturn />
</cffunction>
<!--- Run before the request is processed. --->
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cfset REQUEST.appCode = 'SPA'>
<cfset REQUEST.appName = 'Single Page Application'>
<cfset var page = listLast(arguments.thePage,"/")>
<!---<cfset onApplicationStart()>--->
<cfif !listFindNoCase("Login.cfm,Authentication.cfc",page)>
<cfif !structKeyExists(SESSION, "loggedin") OR SESSION.loggedin EQ false>
<cflocation url="Login.cfm" addToken="false">
</cfif>
</cfif>
<cfreturn true>
</cffunction>
</cfcomponent>
I'm not sure if session can be ended in Application.cfc or I have to do that in my cffunctions. Same for CFID and CFTOKEN what is the best place to set new values if user logs in again? If aynone have experience with this please let me know. I'm trying to prevent user to use the same session and raise level of security in my SPA.
Please consider two files (I am working inside Sessions). Inside my .cfm page, I am creating an instance of a component and setting some values like following:
reports.cfm
<cfset LineChartObj = createObject("component", "#LocalSessionDotPath#.lib.report.testchart").init() />
<cfset LineChartObj.setTitle("Type of Events") />
<cfset LineChartObj.setYAxisTitle("Event Rate") />
testchart.cfc (relevant functions)
<cffunction name="setTitle" returntype="void" output="false" access="public" hint="Set title for chart">
<cfargument name="_Title" type="string" />
<cfset variables.title = arguments._Title >
</cffunction
<cffunction name="setXAxisTitle" returntype="void" output="false" access="public" hint="Set xAxisTitle for chart">
<cfargument name="_xAxisTitle" type="string" />
<cfset variables.xAxisTitle = arguments._xAxisTitle >
</cffunction>
<cffunction name="getXAxisTitle" returntype="string" access="public" hint="Get xAxisTitle of chart">
<cfreturn variables.xAxisTitle>
</cffunction>
My questions are:
The function name defined as "_Title" in setTitle() function can be anything, right? Not mandatory to take "_Title" ?
In <cfset variables.title = arguments._Title >, from where does the variables.title came from. Does it has something to do with session scope?
Right. Whatever the name you use for the argument defines the name you need to use to refer to it in your function body.
The variables scope is the default 'private' scope of storing variables & functions in a CFC. The code just explicitly declare to store title in the variables scope.
http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7ff1.html
I have a silly question but I am a newbie. I am trying to make a cross-domain request (via ajax) using extjs4 library. As server side language I am using ColdFusion. The whole code that I have written so far is working on same domain. I need to separate static files (javascript, css, and html) placing them on Apache server and the dynamic content (cfm, CFC) placing them over Tomcat (openbd). So the front end scripts (on Apache->javascript mainly) making requests on Tomcat in order to fetch content. This definitely is cross-domain requests.
A code block that I am using in order to pull data (CFC) is:
<cfcomponent output="false">
<cfprocessingdirective pageencoding="utf-8">
<cfset setEncoding("URL", "utf-8")>
<cffunction name="getContent" access="remote" returnFormat="JSON" output="false" >
<cfargument name="start" default="0"/>
<cfargument name="limit" default="1000"/>
<cfargument name="id" default="0" required="false" type="numeric">
<cfargument name="model" default="" required="false" type="any">
<cfset var arrNomoi = ArrayNew(1)>
<cfset var stcReturn = "">
<!--- When going back to base state, ExtJS will make the function call with start set to 0. If this is the case
we set it to 1 --->
<cfset Arguments.start = Arguments.start + 1>
<cfif arguments.model EQ 'n_2664_1998'>
<cfquery name="getNomoi" datasource="ktimatologio">
SELECT CONCAT_WS('_',id,model) AS id, id AS 'id1', CONCAT_WS(' ',title,fek,date) AS 'title', description, body, model
FROM n_2664_1998
WHERE id = #arguments.id#
ORDER BY id ASC
</cfquery>
<cfelseif arguments.model EQ 'n_2308_1995'>
<cfquery name="getNomoi" datasource="ktimatologio">
SELECT CONCAT_WS('_',id,model) AS id, id AS 'id1', CONCAT_WS(' ',title,fek,date) AS 'title', description, body, model
FROM n_2308_1995
WHERE id = #arguments.id#
ORDER BY id ASC
</cfquery>
<cfelseif arguments.model EQ 'n_3889_2010'>
<cfquery name="getNomoi" datasource="ktimatologio">
SELECT CONCAT_WS('_',id,model) AS id, id AS 'id1', CONCAT_WS(' ',title,fek,date) AS 'title', description, body, model
FROM n_3889_2010
WHERE id = #arguments.id#
ORDER BY id ASC
</cfquery>
</cfif>
<cfset arrNomoi = convertQueryToExtJS(getNomoi,Arguments.start,Arguments.limit)>
<cfset stcReturn = {"data"=arrNomoi,dataset=#getNomoi.RecordCount#}>
<cfreturn stcReturn>
</cffunction>
<cffunction name="convertQueryToExtJS" access="public" hint="Convert Query to JSON usable by ExtJS Grid" returntype="array">
<cfargument name="qryData" type="query" required="true" hint="Query to convert">
<cfargument name="intStart" type="numeric" required="true" hint="Start of Result Set">
<cfargument name="intLimit" type="numeric" required="true" hint="How many records to return">
<!--- For the Array --->
<cfset var i = 1>
<cfset var end = ((Arguments.intStart) + arguments.intLimit)-1>
<cfset var arrNomoi = ArrayNew(1)>
<cfloop query="qryData" startrow="#Arguments.intStart#" endrow="#end#">
<cfset stcNomoi = StructNew()>
<cfset stcNomoi['id'] = #qryData.id#>
<cfset stcNomoi['id1'] = #qryData.id1#>
<cfset stcNomoi['title'] = #qryData.title#>
<!---<cfset stcNomoi['fek'] = #qryData.fek#>
<cfset stcNomoi['date'] = #qryData.date#>--->
<cfset stcNomoi['description'] = #qryData.description#>
<cfset stcNomoi['body'] = #qryData.body#>
<cfset stcNomoi['model'] = #qryData.model#>
<cfset arrNomoi[i] = stcNomoi>
<cfset i = i + 1>
</cfloop>
<cfreturn arrNomoi>
</cffunction>
</cfcomponent>
The question is: how do I wrap the above function into a variable (named “callback”) and post it on client?
I have seen a similar code block on PHP but I don’t understand. Below is the PHP code block:
<?php
$callback = $_REQUEST['callback'];
// Create the output object.
$output = array('id' => 1, 'url' => 'loianegroner.com');
//start output
if ($callback) {
header('Content-Type: text/javascript');
echo $callback . '([' . json_encode($output) . ']);';
} else {
header('Content-Type: application/x-json');
echo json_encode($output);
}
?>
With respect,
Tom
Greece
Take a look at these two files:
The index.cfm is the handler where you submit an AJAX request to and it will return a JSON result
http://websvn.openbd.org/websvn/filedetails.php?repname=OpenBD&path=%2Ftrunk%2Fwebapp%2Fmanual%2Fapi%2Findex.cfm
The index.cfm interacts with this CFC to fetch the information and return the result.
http://websvn.openbd.org/websvn/filedetails.php?repname=OpenBD&path=%2Ftrunk%2Fwebapp%2Fmanual%2Fapi%2Findex.cfc
When I was writing this API wrapper I had issues with returnFormat=JSON
I ran into an issue this morning after deploying of some files to a ColdFusion website/application.
I updated an existing CFC with some new code. The CFC has an init() method that returns the instantiated Object:
Original MyObject.cfc:
<cfscript>
VARIABLES.MyParam = "";
</cfscript>
<cffunction name="init" returntype="MyObject" output="false">
<cfargument name="MyParam" type="String" required="true" />
<cfscript>
VARIABLES.MyParam = ARGUMENTS.MyParam;
return THIS;
</cfscript>
</cffunction>
New MyObject.cfc:
<cfscript>
VARIABLES.MyParam = "";
</cfscript>
<cffunction name="init" returntype="MyObject" output="false">
<cfargument name="MyParam" type="String" required="true" />
<cfscript>
setMyParam(ARGUMENTS.MyParam);
return THIS;
</cfscript>
</cffunction>
<cffunction name="setMyParam" output="false" returntype="Void">
<cfargument name="MyParam" type="String" required="true" />
<cfset VARIABLES.MyParam = Trim(ARGUMENTS.MyParam) />
</cffunction>
<cffunction name="getMyParam" output="false" returntype="String">
<cfreturn VARIABLES.MyParam />
</cffunction>
Any time an Object that extended this CFC called init(), it was throwing an exception:
"The value returned from the init function is not of type MyObject."
This issue did not occur in any of the other environments in which this change was deployed - only in Production.
The only thing that fixed it was clearing the template cache in ColdFusion Administrator.
So, I'm either looking for a way to prevent this from happening in the future and/or a way to automatically clear the template cache when I deploy files.
FYI, I currently deploy files using Tortoise SVN.
In your init() (or more preferably, in another reload-style method), programmatically call the Admin API's clearTrustedCache() method:
<cfscript>
// Login is always required (if the administrator password
// is enabled in the ColdFusion Administrator).
// This example uses two lines of code.
adminObj = createObject("component","cfide.adminapi.administrator");
adminObj.login("admin");
// Instantiate the runtime object.
myObj = createObject("component","cfide.adminapi.runtime");
// clear cache
myObj.clearTrustedCache();
// Stop and restart trusted cache. However, only the clearTrustedCache function needs to be called.
myObj.setCacheProperty("TrustedCache", 0);
myObj.setCacheProperty("TrustedCache", 1);
</cfscript>
This functionality's been in place as far back as CF7 (Source). Note that you will need the CF Admin password for this.
I would also recommend clearing the component cache, if you have that option enabled in your admin:
myObj.clearComponentCache();
I have tried multiple tutorials on this topic from Forta.com and yet run into the same error:
"Error invoking CFC/....(file path)../wgn.cfc: Internal Server Error [Enable
debugging by adding 'cfdebug to your URL parameters to see more info]"
I am working on my local machine and testing as localhost. Running WinXP Pro with sp3. Using Coldfusion's web server.
Both my .cfm and .cfc are in the same folder under the the webroot. In my case:
c:\ColdFusion9\wwwroot\bridges(.cfm and .cfc here)
So, they are in a "bridges" folder under wwwroot.
The code should generate some autosuggest functionality when the user types in the input box. Instead, it just spits back the above error.
This is my cfc named wgn.cfc:
<cfcomponent output="false">
<cfset THIS.dsn="bridges">
<!--- Lookup used for auto suggest --->
<cffunction name="getWGN" access="remote" returntype="array">
<cfargument name="search" type="any" required="false" default="">
<!--- Define variables --->
<cfset var data="">
<cfset var result=ArrayNew(1)>
<!--- Do search --->
<cfquery datasource="#THIS.dsn#" name="data">
SELECT tblIDs.ID
FROM tblIDs
WHERE (tblIDs.IDType = 'xxx') AND (tblIDs.ID Like ('#ARGUMENTS.search#%'));
</cfquery>
<!--- Build result array --->
<cfloop query="data">
<cfset ArrayAppend(result, searchIDs)>
</cfloop>
<!--- And return it --->
<cfreturn result>
</cffunction>
</cfcomponent>
And this is the relevant part of the form from my .cfm page:
<cfform .....>
<cfinput name="searchIDs" type="text" autosuggest="cfc:wgn.getWGN({cfautosuggestvalue})">
//......more to form, obviously
</cfform>
UPDATE
Solution:
change
<cfset ArrayAppend(result, searchIDs)>
to
<cfset ArrayAppend(result, ID)>