Introduction

Here is a script that track user login/logout times on a website. It's a simple script
that I have used on some of the sites I've made. Also with this script you can see how many users are online at
your site.

For this you need first a site with a 'login to enter' (member based community site). You
also need a database to keep the users and the records of their login/logout times.
You also need the global.asa file so you can use the Session_OnEnd event to track the time when Session.Abandon occurs or Session.Timeout expires. That is when a user hit logout or quits your application.

The Database

The database for this demo is a MS Access 2000 database (.mdb file) and it contains 2 tables: Members table and User_LogTimes table.
In the Members table I keep the a minimal login information such as: user name, Password, user first name and user last name.

In the picture below you can see the design of the Members table. This table is not relevant for this article but
I talked about it so you can understand the SQL queries that will be presented further in the article.

Now take a look over the design of User_LogTime table. In this table we will keep the records of the user login/logout times plus from this table we can get how many users
are online on your site.

In the picture below you can see the design of the table.

This is short description of the table fields.

id

-

Its the primary key of this table to uniquely identify each record

user_id

-

The id of the user from the Members table which will be shown in a picture below

SID

-

The Session.SessionID of each session opened on the site when a user runs for the first time any page in your application.

Login_Time

-

The time when the user login on the site.

Logout_Time

-

The time when the user logout off the site.

offline

-

Boolean value which is used to tell how many user are online on the site.

How this script works

login.asp

When a user will login on the site, the script in login.asp will be executed first. That's why
I will begin to explain this code first.

With the user and password entered in the login form you will build a query to to get the user's id value from the Members table.
That value you will store in a session variable.

' Get the user name and the password from the login form
UserName = Request.Form ("UserName")
Password = Request.Form ("Password")
...
...
set conn = Server.CreateObject ("ADODB.Connection")
conn.Open Application("connString")
query = "SELECT Id FROM Members WHERE UserName='" &_
UserName & "' AND Password='" & Password &_
"'"
' Get the user id from the databaseset rs = conn.Execute (query)
...
...
' set the user id value from the Members table in a session variable
Session("member") = rs("Id")

You have the user id value in the Session("member") variable. Now we have to modify all the records in the User_LogTime for this user
that have the offline field set as False (that means he is marked as being online) and set that field to True. The fields changed in this way will not have a LogOut time.
Normally this operation should not affect any record in the table. Records with offline set to False may
exist when they were not closed properly when the user previously logged out.

Then we will insert a new record in the User_LogTime table with the id of the user, the SessionID of this user and with the time of login.

global.asa

The code above was called when the Session began and you got the login time and wrote it in the database.

When the user hits logout then Session.Abandon will be called. If
the user quit your application without hitting logout then after the session.Timeout expires Session_OnEnd will be executed.
In this procedure you will update the record written in login.asp and
you will update the Logout_time and the offline field to True.

That's all there is for tracking login/logout times. You have these values in the User_LogTimes
and you can display them however you want. You can take a look at how I've done
this in the project demo (see the 1st pic above).

Online users

Having the offline field in the database makes this very easy. You can make an SQL query like this:

Execute that query and the number of records in the recordset will be the number of
your online users. Alternatively you can call

query = "SELECT COUNT(*) as NumOnline FROM User_LogTime WHERE offline=False"

To return a recordset with one record and one field ("NumOnline")
that has the number of online users.

See the demo application for examples.

Remarks

when you store SessionID in the database, data type of that
field are set always to a number. If you want to compare the value from that field with the Session.SessionID
then this will save you for some trouble.

On PWS on Win95/98 this should work fine but on IIS5 remember that this Session_OnEnd will be run by IWAM_machine and not by IUSR,
so set write/modify rights on the database where you will keep the login/logout times.

Happy Programming!!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Comments and Discussions

I had no idea about the bug but I've tested the application on IIS 5.0 and IIS 4.0 and it worked on both.

I have on my personal machine IIS 5.0 and Service Pack 2 installed and I can run the application.

if you cannot use the solution with the session object then another idea would be to move the session management in the database.
generate a session ID each time the user login, associate the session id with the user id, build an "expire" mechanism in the db and the rest of the idea is the same as in this article.

I tried everything as it was directed in the article to try and get the online user system working. I set the permissions on the database, debugged and tested the firing of each sub in the global.asa. Everything was good, but the code was still not setting the "online" flag in the database.

As it was, IIS did not like the "new line" under each of the sub declarations in the global.asa file and therefore didn't complete the routine.

Just thought I'd let you all know, if in case you too have tried everything and it's still not working and you have a new line under your decs.

here are the detailed instructions how to make this script work.
this is for win2k.

1. unzip the zip archive in a folder on ur hdd.

2. from Internet Services Manager ( Control pannel > Administrative tools > Internet Service Manager) make a virtual directory to point on the folder where u unzipped the files.

3. Edit Global.asa file and make the folowing modification at the line 34:
instead of the line:Application("connString") = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=path to test.mdb on ur server."
replace it with this one:Application("connString") = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=" & Server.MapPath( "test.mdb" )

4. make sure that the permissions are set corectly on the file called "test.mdb".
corectly means that the user IUSR_<machine> and IWAM_<machine> have modify rights on "test.mdb" file.

this should be all.

if IUSR_<machine> doesnt have rights to write on the access database u wont be able to insert a record and u will receive an error message like this:[Microsoft][ODBC Microsoft Access Driver] Operation must use an updateable query.

if IWAM_<machine> doesnt have modify rights on test.mdb then the Session_OnEnd procedure wont be executed and the time when u logout wont be recorded, instead u will see a N/A.

run 1rst login.asp page and for username and pass u can take a look in the db and u will see that there are 2 users:
1. user1/pass1
2. user2/pass2

As i wrote earlier i modified the rights and the database connection.
The problem was the code was not running. I had to modify the "where part" of the update query
and set the session variable to some variable (not directly to field Userid) and then again the variable to the SV.

try www.oledu.com/mls.html. This site is full of awesome courses like these, over 130 in total including asp, asp.net all for only $199.95 for one year access to all these courses. In order to get the discount price contact the owner of the page michaelsandrock@hotmail.com (subject = oledu)there is also a free trial for you.

First of all, thank you for the good article. However, I want to point something out to you.

Let's say that timeout of the site is set to 30 minutes and user spends 5 minutes on the site on average. I think that most users do not click logout and simply close the browser or go to the other site. Since you are only capturing logoff time on Session_OnEnd your times on average will be 5-6 times greater than real times spent by average user on your site. If this is really the case - it renders results of your time capturing almost useless for any kind of meaningful analysis.

I believe that the accuracy can be greatly improved by using a Session variable that will store the time of last page processed. Of cause, it will not work for html (non-ASP) pages, but one have to assume that site that uses login script will actually have ASP pages across the board. Most ASP applications have some kind of include files that are being included in every ASP page. For example, all my pages include file with common functions. So my solution will be to include a simple line

Session("LastProcessTime") = Now()

somewhere in your common include file. Then all you need to do is to store Session("LastProcessTime") in your database as your Logout_Time on Session_OnEnd instead of storing current time.

This approach will still not give you perfect times. Actually, the times you record will always be a little shorter than times spent by user, but I believe that it will give you a much more accurate results.

You can take it even farther and store both Now() and Session("LastProcessTime") in your database. You can simply show both to your users or use some kind of time approximation or averaging algorithm to estimate "real" logoff time.

That doesn't make much sense because that's exactly how IIS measures timeouts. It logs the time of last page access, and from then on, it starts a countdown of Timeout minutes. It doesn't make sense because when the session timeouts you can measure the time of "logout" by substracting Timeout from Now ().
So you can calculate your
Session("LastProcessTime") = Now () - Session.Timeout
What someone could do is to measure the average session for a period of time, and adjust statistically the length of the session so that it has as little impact on web server performance, but still take advantage of ASP sessions.

These are custom changes that everyone can do to improve the accuracy.
You can also do a statistic and adjusting automaticaly the session.timeout like Ciprian Miclaus said but the purpose of this article is to show how you can uses the Session object to do some nice tools like tracking who is online on your site.

Its true that u can expand this scriptlet and customize it how u want . this is just an example.

I have had to do away with session useage on my sites due to the load on the server during high traffic times.
I haven't regretted it.
Another possibility is to use cookies instead of session info.
Cookies have another advantage, some users browse a site with more than one browser window open. With sessions, each window is treated as a seperate session. It can be a bit disorienting to be placing things in a shopping cart and find them gone in the other browser. With cookies both browsers have current info. Example you can add an item to the shopping cart and view the cart in the other browser and all is well.
Just a thought.

hmm.. i dont think that the server will open another session for each window opened. the session is based on cookies too so it will have the same behaviour like using cookies and exactly like cookies they on the browser. so u could open new browser windows and the session will be mentained.
i've made shoping carts based on session and worked fine even if i would browse the site with more than 1 window. maybe i will post an article like that

I know for sure that session info is "not" maintained common to multiple browser windows.
One of my sites uses session stored usernames. When a visitor logs on to the site, the site displays the user's name at the top of every webpage visited. I can open two browsers and have seperate users logged on with no interaction between them.
My understanding is that when a browser window requests an asp page that a unique sessionid is created and is sent back and forth between the browser and the webserver in the webpage header.

i thought that u r refering to open in a new window a link from a site and in that new window the session is not mentained. if u open a browser and u request manualy a page from ur site u r rite the session is not mentained and u can have 2 users logined from the same computer but from 2 browser windows opened.

Is there a way to use the user's IP to track the user? That way, it would be cross window and browser. Only problem is you would need to use a cookie and assign a different IP every time it changes, for all the dynamic IP people out there.

Companies may have hundreds of people sharing a fixed IP router which they use to access the internet...
So IP addresses wouldn't be useful.
You could use the NICs MAC address, but to get it you need write access on your server and most ISPs won't allow that.
Heres the code if it helps:

First of all Session is not only connected with Server but also with the application. So when in new window you open script from the same application of course you do transfer your session. Besides you transfer session when you open scripts outside the application (folder) but you have to load script from the same server and using relative path. So for example you have one folder c:\inetpub\wwwroot\application1 and it stands for application1. And you have another folder c:\inetpub\wwwroot\folder-side containing test.asp script. When you open a new window from application1 using window.open("./folder-side/test.asp", .....) and you transfer your current session. But opening using absolute path like "http://server_name/folder-side/test.asp you create a new session. At least in iis i had this kind of experience.

if your logout time isnt writtenb in the db its possible that u dont have write/modify permisions on the database for the IWAM user.

u can check if that is the problem by debuging the Sub session_OnEnd puting there on error resume next and after the execution of the query check the error like this:

conn.Execute (query)
if err.number <> 0 then
Application("err") = err.description
end if

and in another asp file do a Response.Write Application("err") and if you get a message like "Operation must use an updatable query.." then that's the problem. i dont know exactly the corect error message.

Thanx for the answer, but I have onemore little question. I'm not shore that I really know haw to set the write/modify rights for IWAM user.
I thing that the real problem is that nothing in the global.asa executes. What can be the reason.

are u sure that nothing in global.asa executes? not even Application_OnStart?

u can check if session_OnEnd executes by seting an application variable in that procedure and with another page on ur site do a response.write on that application var. if the value in that application var is written on the browser then the sub is executed.

the modify permisions u can set it from the same place where u set the rights for other users like IUSR.