coldfusion 9 audit trail - coldfusion

I want to audit how many times a certain page is executed. I was hoping to add <cfinclude template="audit.cfm"> to the end of the page and log simple data, like user, date, script name.
Question: how do I pass a current script name into <cfinclude>?
I am using CF9 and application.cfm. I thought I can add code to onSessionEnd(), but I don't think it will work. Here is my onSessionEnd() and onRequestEnd()
<cffunction name="onSessionEnd">
<cfset SESSION.session_time = TimeFormat(Now() - SessionScope.started, "H:mm:ss")> <=== want to do this!!!
<cfset structClear(SESSION)> <=== currently in place
</cffunction>
<cffunction name="onRequestEnd">
<cfif NOT isDefined("URL.contentonly")>
<p align="right">
<cfoutput>
<font size="2" face="sans-serif" color="black">
<i>©#Year(Now())# Seattle Pacific Industries Inc</i><BR>
</cfoutput>
</p>
</cfif>
</cffunction>
Thanks,

Related

ColdFusion cfoutput & excluding items

<cfif dir.name IS NOT "Thumbs.db">
This code excludes Thumbs.db from being called in the cfoutput query, but what if I want another file excluded? Not sure how to exclude more than one item though.
Right now have
<cfset counter = 1 />
<cfoutput query="dir1">
<cfif !listfindNoCase( 'Thumbs.db,2. Electric Accounts Tracking Report.xls,1. Electric Accounts Performance Analytics.xls', dir1.name) >
<a href="/091_AU20100226/020_Cost_Analyses/010_Electric/Flatten_Files/#dir1.name#" target="_blank">
#dir1.name#</a><br />
<cfset counter++ /> </cfif> </cfoutput>
You can use listFind() or listFindNoCase().
<cfif !listfindNoCase( 'Thumbs.db,otherFile.txt', dir.name) >
...do stuff...
</cfif>

Next Page, for data editing

I did SEARCHing code, something like this.
--pageone.cfm--
<cfparam name="Form.studNo" default="" />
<form action="pagetwo.cfm" method="POST">
<label> Please insert ID:
<input name="studNo" value="<cfoutput>#Form.studNo#</cfoutput>" />
</label>
<input type="submit" value="Search" />
</form>
--pagetwo--
SELECT * FROM students
WHERE students_ID IN (#Form.studNo#)
On page two, I will display the details of student's info and user can edit a new information if the data is not right.
I'm thinking of, displaying data of one student per page and user can click Next for the next students (ID that has been inserted) on pageone.cfm
Can anyone help me with these?
#henry.
I did try something like this.
--example.cfm--
<CFPARAM NAME="StartRow" DEFAULT="1">
<CFPARAM NAME="DisplayRows" DEFAULT="1">
<CFQUERY NAME="getStudent" DATASOURCE="#dsn#"
CACHEDWITHIN="#CreateTimeSpan(0,0,15,0)#">
SELECT *
FROM students
</CFQUERY>
<CFSET ToRow = StartRow + (DisplayRows - 1)>
<CFIF ToRow GT getStudent.RecordCount>
<CFSET ToRow = getStudent.RecordCount>
</CFIF>
<HTML>
<HEAD>
<TITLE>Next/Previous Record Browsing</TITLE>
</HEAD>
<BODY>
<CFOUTPUT>
<H4>Displaying records #StartRow# - #ToRow# from the
#getStudent.RecordCount# data inserted.</H4>
</CFOUTPUT>
<!--- create the header for the table --->
<TABLE CELLPADDING="3" CELLSPACING="0">
<TR BGCOLOR="#888888">
<TH>Name</TH>
<TH>ID</TH>
<TH>Gender</TH>
<TH>E-mail</TH>
</TR>
<CFOUTPUT QUERY="getStudent" STARTROW="#StartRow#"
MAXROWS="#DisplayRows#">
<TR BGCOLOR="##C0C0C0">
<TD>#Name#</TD>
<TD>#ID#</TD>
<TD>#Gender#</TD>
<TD>#Email#</TD>
</TR>
</CFOUTPUT>
</TABLE>
<CFSET Next = StartRow + DisplayRows>
<CFSET Previous = StartRow - DisplayRows>
<!--- Create a previous records link if the records being displayed aren't the
first set --->
<CFOUTPUT>
<CFIF Previous GTE 1>
<A HREF="example.cfm?StartRow=#Previous#"><B>Previous #DisplayRows#
Records</B></A>
<CFELSE>
Previous Records
</CFIF>
<CFIF Next LTE getStudent.RecordCount>
<A HREF="example.cfm?StartRow=#Next#"><B>Next
<CFIF (getStudent.RecordCount - Next) LT DisplayRows>
#Evaluate((getStudent.RecordCount - Next)+1)#
<CFELSE>
#DisplayRows#
</CFIF> Records</B></A>
<CFELSE>
Next Records
</CFIF>
</CFOUTPUT>
</BODY>
</HTML>
You may use session to store the specified IDs in pageone.cfm, then go through the array of IDs and use array index as the current page number, and array length as the total page count.
However in this day and age, using JS to display a record at a time makes more sense.
Your approach is ok, but I'd recommend using existing libaries that do the trick of paginating and even constructing HTML for displaying page number buttons, next-previous links and what not.
Please revise http://paginationcfc.riaforge.org/ - a ColdFusion project that deals with pagination quite well and is very easy to implement, saving you tons of work. You could even set it do display one record per page, and the rest (next-previous buttons and maybe "page numbers") would be automagically done by the pagination component.
Ah, doing so (one big query and subsequent sub-queries) I strongly suggest caching.
HTH.

Newbie, very basic CRUD via Application.cfc

So I've been using in-line (correct term?) ColdFusion code to run all my pages and have gotten to a point where I think I have a decent understanding of the basics, and want to take the next step. After a lot of cross-referencing, research, and trial and error, I've come up with the following 4 pages of which the intent is to be able to enter a username and password in the form page (crud.cfm), then, after submission, redirect the user to a page which displays the newly entered data, as well as any past entries.
I can do all of this with simple in-line code and an Application.CFM but I want to migrate toward a more OOP/Modular approach going forward, as presently I find myself rewriting/copy-pasting scads of code across several different pages. The error that I get when I submit from 'crud.cfm' is:
"The component attribute in cfinvoke tag has invalid value."
I have tried it without hashes and without the uppercase "A" to no avail. Here is my non-working code:
Application.cfc
<cfcomponent output="false">
<cffunction name="insertrecord" access="public" output="false">
<cfargument name="data" type="struct" required="true">
<cfquery name="create" datasource="test">
INSERT INTO logins(
username,
password)
VALUES(
'trim(form.username)',
'trim(form.password)')
</cfquery>
</cffunction>
</cfcomponent>
crud.cfm
<h3> Enter new user/password </h3>
<cfform name="thisform" method="post" action="procpage.cfm">
Username:<cfinput type="text" name="username" value="">
Password:<cfinput type="password" name="password" value="">
<input type="submit" value="submit">
</cfform>
procpage.cfm
<cfif !StructIsEmpty(form)>
<cfinvoke component="#Application#" method="insertrecord">
<cfinvokeargument name="data" value="#form#">
</cfinvoke>
</cfif>
<cflocation url="resultpage.cfm" addtoken="no">
resultpage.cfm
<cfquery name="read" datasource="test">
SELECT * FROM logins
</cfquery>
<table>
<tr>
<th>LOGIN</th>
<th>USERNAME</th>
<th>PASSWORD</th>
</tr>
<cfloop query="read">
<tr>
<td>#read.login#</td>
<td>#read.username#</td>
<td>#read.password#</td>
</tr>
</cfloop>
</table>
ColdFusion version 8, MSSQL 2005 database.
Thank you all in advance for your help, looking forward to your responses!
Application.cfc is a special file in ColdFusion.
http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=AppEvents_01.html
You'll need to name your component something else. Application.cfc is where you put Application events, setup code, etc.
In answer to your question to Miguel, Yes. The application.cfc is called each time a cfm is called. So when you hit the crud.cfm, application.cfc runs. When you hit procpage.cfm application.cfc runs etc..
so you want your procpage.cfm to look more like
<cfif !StructIsEmpty(form)>
<cfinvoke component="functions" method="insertrecord">
<cfinvokeargument name="data" value="#form#">
</cfinvoke>
</cfif>
and your functions.cfc looks more like
<cfcomponent output="false">
<cffunction name="insertrecord" access="public" output="false" returntype="void">
<cfargument name="data" type="struct" required="true">
<cfquery name="create" datasource="test">
INSERT INTO logins(
username,
password)
VALUES(
<cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(form.username)#">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(form.password)#">
)
</cfquery>
</cffunction>
<cffunction name="readRecord" access="public" returntype="query">
<cfargument name="loginID" type="numeric" required="false" default="0">
<cfquery name="read" datasource="test">
SELECT * FROM logins
where loginID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.loginID#">
</cfquery>
<cfreturn read/>
</cffunction>
</cfcomponent>
resultsPage.cfm
<cfscript>
f = createObject('component','functions');
r= f.readRecord(theIdToPass);
</cfscript>
<table>
<tr>
<th>LOGIN</th>
<th>USERNAME</th>
<th>PASSWORD</th>
</tr>
<cfloop query="r">
<tr>
<td>#r.login#</td>
<td>#r.username#</td>
<td>#r.password#</td>
</tr>
</cfloop>
</table>
You will find that cfqueryparam not only has a small performance boost but will protect you from sql attacks and such, USE IT!! Always.
You also might think about doing arguments for each one expect instead of using struct variables, since writting error trapping for a struct without know what you are expecting to be passed can be pretty frustrating.
Hopefully this can get you off to a positive start with CF!

Unwanted Facebook button at first time use of my FB application in coldfusion

I am playing around with facebook application, making them in iframe using coldfusion.
Following is the url of my app http://apps.facebook.com/firstones/
Instead of going directly going to the permissions page, it goes to the page shown below in picture.
And after clicking on that big 'Facebook' button it goes to ask for applications permission. And once permissions are granted it takes to my website, where I have hosted the application, instead of opening it in Facebook only.
Following is the code of my canvas url [http://www.dkyadav.com/firstOnes/auth/]
index.cfm
<cfparam name="client_id" default="1234"> <!---same as app_id --->
<cfparam name="redirect_uri" default="http://www.dkyadav.com/firstOnes/auth/">
<cfparam name="redirect_uri_final" default="http://www.dkyadav.com/firstOnes/">
<cfparam name="scope" default="user_education_history,user_hometown,friends_education_history ">
<cfparam name="client_secret" default="56789"> <!---- App_secret key ---->
<cfif not isdefined('url.code')>
<Cflocation url="https://www.facebook.com/dialog/oauth?client_id=#client_id#&redirect_uri=#redirect_uri#&scope=#scope#" >
<Cfelse>
<Cfif isdefined('url.error')>
<Cfoutput>
#url.error#<br />
Access denied.
</Cfoutput>
<cfelse>
<cfoutput>#url.code#<br />
<cfhttp url="https://graph.facebook.com/oauth/access_token" result="token">
<cfhttpparam name="client_id" value="#client_id#" encoded="no" type="url">
<cfhttpparam name="redirect_uri" value="#redirect_uri#" encoded="no" type="url">
<cfhttpparam name="client_secret" value="#client_secret#" encoded="no" type="url">
<cfhttpparam name="code" value="#url.code#" encoded="no" type="url">
</cfhttp>
<cflocation url="#redirect_uri_final#?#token.filecontent#" addtoken="no">
</cfoutput>
</Cfif>
</cfif>
And in http://www.dkyadav.com/firstOnes/index.cfm I look for access_token and have rest of my application.
I does the above said things only for the first time it run. Once its permission get approved, it works normally as expected.
You can try out this app running yourself http://apps.facebook.com/firstones/
Please help and let me know what I am actually missing. Thanks!!
I think the problem you have is that your initial display page on Facebook is actually bursting out of the iframe.
You can see the Javascript doing that on http://www.dkyadav.com/firstOnes/index.cfm in the fbLogin() function:
top.location.href = "https://graph.facebook.com/oauth/authorize?...
top refers to the window at the top of your window hierarchy which in your case will mean the actual Facebook home page with the iframe in it.
Hope that helps!
I think I dont need access_token, I just need oauth_token that I get by Decoding the result I got from submitting my client_id to 'https://www.facebook.com/dialog/oauth....'
Below is the code that I am using:
<cfif isdefined('signed_request')>
<cfoutput>
<cfset b64 = signed_request>
<!--- Split the param by the . --->
<cfset raw_str = ListGetAt(b64, 2, ".")>
<cfset res = Len(raw_str) % 4>
<cfif res eq 2>
<cfset raw_str &= "==">
<cfelseif res eq 3>
<cfset raw_str &= "=">
</cfif>
<!--- Base 64 Decode --->
<cfset result = ToString(BinaryDecode(raw_str, "Base64"))>
<!--- String to JSON --->
<cfset json = DeserializeJSON(result)>
<cfif StructKeyExists(json,'oauth_token')>
<Cfset at = json.oauth_token>
<cfhttp url="https://graph.facebook.com/me/friends?access_token=#at#" result="newsFeed" />
<cfif IsJSON(newsFeed.filecontent)>
<cfset cfData=DeserializeJSON(newsFeed.filecontent)>
<cfdump var = #cfData#>
<cfelse>
filecontent not in json format
</cfif>
<cfelse>
<script>
top.location.href='https://www.facebook.com/dialog/oauth?client_id=12345XXX&redirect_uri=http://apps.facebook.com/test_app/&scope=read_stream,email'
</script>
</cfif>
</cfoutput>
</cfif>

Nesting queries in CF

I'm using this code to display a list of platforms. If a platformID was specified upon entering the page, I would like to create a list of genres underneath the specified platform.
browse.cfm was accessed via a link that specified a platformID of 1
browse.cfm will list all available platforms
browse.cfm will now list all available genres under platformID of 1.
<ul>
<li>Browse</li>
<cfoutput query="qGetPlatforms">
<li>
#qGetPlatforms.pName#
<cfif URL.platformID EQ qGetPlatforms.platformID>
<ul>
<cfoutput query="qGetGenres">
<li>#qGetGenres.gName#</li>
</cfoutput>
</ul>
</cfif>
</li>
</cfoutput>
</ul>
By using this approach, however, I'm getting an invalid nesting configuration. How do I fix this? Or is there another approach to achieve the same idea?
Thanks
MY queries:
<!---Get platforms--->
<cffunction
name="fGetPlatforms"
access="public"
returntype="query"
output="false"
hint="I get all the platforms">
<!---Local var--->
<cfset qGetPlatforms = "">
<!---Database query--->
<cfquery name="qGetPlatforms" datasource="#REQUEST.datasource#">
SELECT
platforms.platformID,
platforms.platformName AS pName
FROM
platforms
</cfquery>
<cfreturn qGetPlatforms>
</cffunction>
<!---Get genres--->
<cffunction
name="fGetGenres"
access="public"
returntype="query"
output="false"
hint="I get all the genres">
<!---Local var--->
<cfset qGetGenres = "">
<!---Database query--->
<cfquery name="qGetGenres" datasource="#REQUEST.datasource#">
SELECT
genres.genreID,
genres.genreName AS gName
FROM
genres
</cfquery>
<cfreturn qGetGenres>
</cffunction>
You can use <cfloop query="qGetGenres"></cfloop>, they can be nested.
IMO, using cfoutput for looping over the queries is old style and should be avoided. Use cfoutput for output, cfloop for looping and you'll have more readable code.
more food for thought is to use an inner join between the two tables, combine and retrieve everything in one query and then use cfoutput's group attribute to display the results:
<cfset URL.platformID = int(val(URL.platformID))>
<cfquery name="getPlatformsAndGenres" datasource="#REQUEST.datasource#">
SELECT
p.platformID AS platformID
,p.platformName AS pName
,g.genreID AS genreID
,g.genreName AS gName
FROM
platforms p
INNER JOIN genres g
ON p.platformID = g.platformID
WHERE
p.platformID = <cfqueryparam cfsqltype="cf_sql_integer" value="#URL.platformID#">
ORDER BY
pName
,genreName
</cfquery>
Once you have everything in one query, you can use <cfoutput query="getPlatformsAndGenres" group="pName">
to lessen your code:
<ul>
<li>Browse</li>
<cfoutput query="getPlatformsAndGenres" group="pName">
<li>
#pName#
<ul>
<cfoutput>
<li>#gName#</li>
</cfoutput>
</ul>
</cfif>
</li>
</cfoutput>
</ul>