Shaun Mccran

My digital playground

03
J
U
L
2009

Function for getting the last modified date of a template

Whilst looking at creating dynamic Sitemaps for Google bot spidering I found that I needed to populate an XML node with the last modified date of the templates. I figured there must be a programmatic way of doing this, so after some searching around this is what I ended out with:

view plain print about
1<cfset mod_time = createObject("java", "java.util.Date").init(createObject("java", "java.io.File").init(getcurrenttemplatepath()).lastModified())>

This creates a java object, using the date and file utilities we can use 'getcurrenttemplatepath()' to provide the path data, finally referencing the lastModified property.

A handy and relatively quick way of getting the last modified date.

It is a bit of a mouthful though, so might be easier to create it as a handy referencable object:

view plain print about
1<cffunction name="modStamp" access="public" returntype="date" output="no" hint="Gets the last mod date of a file, returns a ts">
2    <cfargument name="file" type="string" required="yes" hint="File to get mod date">
3        <cfset var mod_time = now()>
4        
5        <cfif fileexists(arguments.file)>
6            <cfset mod_time = createObject("java", "java.util.Date").init(createObject("java", "java.io.File").init(arguments.file).lastModified())>
7        </cfif>
8        
9    <cfreturn mod_time>
10</cffunction>

Then you can just do:

view plain print about
1<cfset variables.fileMod = modStamp()>

02
J
U
L
2009

Coldfusion dropping session ID in fusebox application

I recently rolled out beta version of a new application I've been writing, only to discover that there was a bizarre session problem that didn't exist in dev, but does in live.

I've worked it out, but I thought I'd explore it some more. It is a fusebox 5.5 non xml application. The error I had was that as soon as I made a call through a "new" circuit, IE one I hadn't called before ColdFusion would generate a new session ID, and thus invalidate my current active session.

Looking through my application CFC I had this line of code present.

view plain print about
1<cfset this.SetClientCookies = false />

Setting this to true fixed the issue. This is because ColdFusion relies on the CFID and CFTOKEN to maintain the session state. You can either pass these two variables through the URL on every page request, which is a bit messy, or you can use a cookie. It is the variable above that lets the application use cookies on the user's session.

The problem with setClientCookies is that it is persistent, IE it is built for that session, and left on the user's pc, even after the session has expired, or they have left the application. Also some users will accept per-session cookies, but not persistent session cookies.

They are a lot more secure as per-session cookies, as they cannot be duplicated and hacked to spoof a previous user's session, and if you pass the token through the URL it is easy changed.

You could put something like this in your onRequestend function in application.cfc

view plain print about
1<cfif IsDefined("Cookie.CFID") AND
2IsDefined("Cookie.CFTOKEN")>

3<cfset cfid_local = Cookie.CFID>
4<cfset cftoken_local = Cookie.CFTOKEN>
5<cfcookie name="CFID" value="#cfid_local#">
6<cfcookie name="CFTOKEN" value="#cftoken_local#">
7</cfif>

This will make them per-session. I originally thought that it was something to do with the Fusebox framework, but I had overlooked the simple fact that it was still a new page request, so would be lost. Although this doesn't explain why I wasn't getting this error in my development environment but did in live.

29
J
U
N
2009

Geo coding Latitude and Longitude address in coldfusion using CFhttp

One piece of recently functionality to a site I'm writing is the ability to look up places on a Google powered map.

There are a variety of ways to insert a Google map into your site, but the first real hurdle is the lookup code.

Google does not use an address to position its map, it uses the Latitude and Longitude co-ordinates to place the map area around the desired location.

Google has pretty extensive documentation around this here:

http://code.google.com/apis/maps/documentation/geocoding/index.html

Rather than translate the locations on the fly on a per-hit basis I thought I would perform the lookup when the record is submitted to the database, that way I can cut down the number of google hits, and just reference the local data. Google also prefers this method, as it is less process intensive on their end of things.

First you need an API key:

http://code.google.com/apis/maps/signup.html

This application already has methods for setting the data in a table, so I am simply going to call another packaged method to calculate the latitude and longitude, and store them in the table with the other data.

view plain print about
1<cffunction name="fetchGeo" displayname="fetch Geo" hint="Gets the Geo lat long for an address: docs at http://code.google.com/apis/maps/documentation/geocoding/index.html" access="public" output="false" returntype="struct">
2        <cfargument name="address" displayName="Address to Geo" type="string" hint="String of the address to Geo code" required="true" />
3        <cfset var geoDetails = structNew()>
4
5        <cfset var apiKey = "Your API key here">
6
7        <!--- initial string --->
8        <cfset var requestString = "http://maps.google.com/maps/geo?">
9
10        <!--- q= address to geo code --->
11        <cfset requestString = requestString & "q=28+Morley+Street,Swindon,SN1+1SG" & "&">
12
13        <!--- key = API key --->
14        <cfset requestString = requestString & "key=" & apiKey & "&">
15
16        <!--- sensor = does the requestor have a location sensor? --->
17        <cfset requestString = requestString & "sensor=false" & "&">
18
19        <!--- output = output format --->
20        <cfset requestString = requestString & "output=csv" & "&">
21
22        <!--- oe = output encoding format --->
23        <cfset requestString = requestString & "oe=utf8" & "&">
24
25        <!--- gl= Country code pointer --->
26        <cfset requestString = requestString & "gl=uk">
27
28        <cfhttp url="#requestString#" method="get" result="response"></cfhttp>
29
30        <!--- returns 4 elements statuscode/accuracy/lat/long
31             Higher accuracy is better --->

32        <cfset geoDetails.status = listGetAt(response.filecontent,'1',',')>
33        <cfset geoDetails.accuracy = listGetAt(response.filecontent,'2',',')>
34        <cfset geoDetails.lat = listGetAt(response.filecontent,'3',',')>
35        <cfset geoDetails.long = listGetAt(response.filecontent,'4',',')>
36
37        <cfreturn geoDetails />
38    </cffunction>

As you can see from above, I am simply creating a text string URL, and using cfhttp to GET the result from http://maps.google.com/maps/geo?

The screenshot below show the returned responses, and the http status code.

The result is parsed into a struct and returned to the parent function to be stored. Far less overhead than doing this for every map call.

Please note that this is far more heavily commented for Blog purposes. Now to actually call the service using the lat and long variables stored, but thats another article.

17
J
U
N
2009

Removing duplicate list items

I was looking to remove duplicate items from a list, a valueList() from a query in fact, and ended out hitting upon the idea to use a struct. ColdFusion structures cannot have duplicate keys, so if I create my list as a struct, it will effectively over right any duplicate values.

Just to clean it up on the other end I extract all the keys back out the structure, giving me a cleaned list.

view plain print about
1<cfset variables.tmpList = '1,1,2,4,4,4,5,6,7,7,9'>
2
3Original: <cfoutput>variables.tmpList = #variables.tmpList#</cfoutput>
4
5<cfset variables.setter = StructNew()>
6<cfloop index="elem" list="#variables.tmpList#">
7    <cfset variables.setter[elem] = "">
8
9<cfoutput>
10variables.setter[#elem#]<br/>
11</cfoutput>
12
13</cfloop>
14<!--- Convert the set back to a list --->
15<cfset variables.tmpList = StructKeyList(variables.setter)>
16
17Filtered:<cfoutput>variables.tmpList = #variables.tmpList#</cfoutput>

_UNKNOWNTRANSLATION_ /