Paul asked me this morning if there was a simple way to track the users currently using your site. There are a couple of ways you can handle this. Let's consider a simple example where you want to track known (i.e. logged in) users of an application. This means two things:
- When a user logs on, add her to a list of logged in users.
- When a user logs out, remove her from the list.
First off, let's build a method to store the logged in users. An application variable makes sense for this, so let's default it in the onApplicationStart method of our Application.cfc file:
<cffunction name="onApplicationStart" returnType="boolean" output="false">
<cfset application.users = structNew()>
<cfreturn true>
</cffunction>
In the onApplicationStart method above, I created a structure that will store my users. A list or array would work fine as well, but a struct lets me store more information. I'll show an example of that later.
To record the user, all you do is update the structure when the user logs on. This code will be unique per application, but assuming "username" equals their username, you could store them like so:
<cfset application.users[username] = structNew()>
I stored the user as a blank structure, but you could store information in there like their real name, age, or whatever. You could also update information as the user browses the site. Consider:
<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true">
<cfif userLoggedOn>
<cfset application.users[username].lasthit = now()>
</cfif>
<cfreturn true>
</cffunction>
In the onRequestStart code above, I checked to see if the user is logged in, and if so, I record when the user last hit the site. (Obviously the variable names and conditionals would change based on your application.) By storing the last hit, I could do interesting things like seeing how active the users are on the site.
If the user logs out, you will need to remove them from the application variable. In a logout() method, you would do:
<cfset structDelete(application.users, username)>
And as I mentioned above, you need something similar to handle the session timing out:
<cffunction name="onSessionEnd" returnType="void" output="false">
<cfargument name="sessionScope" type="struct" required="true">
<cfargument name="appScope" type="struct" required="false">
<cfif structKeyExists(arguments.appScope, arguments.sessionScope)>
<cfset structDelete(arguments.appScope, arguments.sessionScope.username)>
</cfif>
</cffunction>
The only difference here is that both the session and application scopes are passed as arguments. You can't reference them directly.
Lastly, to answer the simple question of getting a count of users, a simple structCount(application.users) would return the number of users. If you store other information, you could return the number of boys versus girls, lefties versus right handers, or whatever else you may know about users.