Couch Sessions

Session management for your Web site in PHP 4.0.

Enter The Shrink

<click>

Psychiatrist: So, how are we feeling today, Victor?

Patient: Not too good, Doc. I've been feeling a little blue lately...

Psychiatrist: And why is that, Victor?

Patient: I don't know, Doc. I haven't been sleeping too well, and I can't seem to work up an appetite at all. We went to an Italian restaurant the other day and ordered pasta - but when they brought it to the table, I couldn't bring myself to eat it. I just stared at it, with the theme song to "The Sopranos" playing over and over in my head...

Psychiatrist: How's the family?

Patient: Doing OK, I think. Marge spends most of her time in the kitchen, trying out recipes she's downloaded off the Web. And the kids are out of the house all the time - earlier, we used to see them at mealtimes, but now they've started eating at Burger King. Can't say I blame them, either.

Psychiatrist: And work - everything good there?

Patient: Not really - I've got this sadistic monster of a boss, and he seems determined to turn my life into the Dilbert Zone!

Psychiatrist: Tell me a little more about him.

Patient: Well, you know what I do - I'm a Web programmer over at Used Socks, Inc. Our new Web site is going live next week, and we're doing something completely unique - an online store for people to put up their used socks for sale. We've even got some angel investment - six million dollars, with more to come if we become the Web's most popular used socks portal.

Psychiatrist: Sounds like things are going well for you.

Patient: Yeah, you'd think. But then the boss came in the other day, and said that he was assigning me the responsibility of developing the online shopping cart. And he specifically wanted me to use something called "sessions". And, of course, just to make things interesting, he said that he wanted it up and running in two days...the sadistic little freak!

Psychiatrist: Is that a problem?

Patient: Yup, especially since I don't know the first thing about what a "session" is, or how to go about using one. I mean, I thought a session is something a shrink does with a patient - kinda like what we're doing right now.

Psychiatrist: Oh, Victor, Victor...is that all that's bothering you? I think I have something that might help...

<click>

Stateless In Seattle

It's one of the things geeks say to each other when they want to impress the young women in earshot: "HTTP is a stateless protocol, and the Internet is a stateless development environment". In simple language, all this means is that the HyperText Transfer Protocol, which is the backbone of the Web, is unable to retain a memory of the identity of each client that connects to a Web site, and therefore treats each request for a Web page as a unique and independent connection, with no relationship whatsoever to the connections that preceded it - very similar to the behaviour of some of today's more adventurous teenagers, who get drunk every night, wake up the next morning with no memory at all of what happened, and go out again in the evening to do the same thing all over again...

Now, so long as you're aimlessly surfing from one site to another, this works without a problem. But what if you've decided to buy a few books from Amazon.com? In a "stateless environment", it would be very difficult to keep track of all the items you've shortlisted for purchase, as the stateless nature of the HTTP protocol would make it impossible to keep track of the items selected.

Consequently, what is required is a method that makes it possible to "maintain state", something that allows client connections to be tracked and connection-specific data to be maintained. And thus came about "cookies", which allowed Web sites to store client-specific information in a file on the client system, and access the information in the file whenever required. So, in the shopping cart example above, the items selected would be added to the cookie, and would be retrieved and presented to the customer in a consolidated list during the billing process.

The only problem with this cookie-based approach is that it is dependent on the cookie being accepted by the client. And so, another common approach is the use of a "session" to store specific bits of information when a client visits a Web site; this session data is preserved for the duration of the visit, and is usually destroyed on its conclusion. A session can thus be considered a basket of information which contains a host of variable-value pairs; these variable-value pairs exist for the duration of the visit, and can be accessed at any point during it. This approach provides an elegant solution to the "stateless" nature of the protocol, and is used on many of today's largest sites to track and maintain information for personal and commercial transactions.

Every session created is associated with a unique identification string; this string is sent to the client, while a temporary entry with the same unique identification number is created on the server, either in a flat file or in a database. It now becomes possible to register any number of "session variables" - these are ordinary variables, which can be used to store textual or numeric information, and can be read from, or written to, throughout the session.

Now, if you've been following the open source movement, you already know about PHP, the hottest scripting language on the planet. The latest release of the language, PHP4, includes support for session creation and maintenance, and we'll be showing you how to use it over the next few pages. If you still use PHP3, don't despair - we'll also be covering PHPLIB, a set of powerful PHP classes which adds seamless session management to PHP3-based sites.

The next few pages assume that you have a Web server that supports either PHP4 or PHPLIB. In case you don't, you should probably download both those packages, and install them on your development machine. PHP4, which is now release-quality code, is available on the PHP Web site at http://www.php.net, while the latest version of PHPLIB can be found at http://phplib.netuse.de/

The First Session

One of the standard examples used to demonstrate how a session works is the hit counter application - this is a simple session-based counter that initializes a variable the first time you visit a Web page, and increments it each time you reload the page. Take a look at the code:

<?php

// initialize a session
session_start();

// register a session variable
session_register('counter');

?>

Every session in PHP4 begins with a call to the session_start() function; this function checks to see whether a session already exists, and creates one if it doesn't. Next, the session_register() function is used to register the variables that will exist throughout the session - in the example above, the variable is called "counter", and has been initialized with no value whatsoever.

Now, let's add a couple of additional lines to the example above, and the hit counter will begin working as advertised:

<?php

// initialize a session
session_start();

// register a session variable
session_register('counter');

// increment and display the value of the counter
$counter++;
echo("You have visited this page $counter times! Don't you have anything
else to do, you bum?!");

?>

Go on - try it out! Each time you reload the page, the value of the counter will increase, illustrating how the value of the variable is preserved in the session.

How does this happen? Well, each time a session is initiated, a session cookie [called PHPSESSID] is created on the client system, and is assigned a randomly-generated number; at the same time, a similar entry is created on the server containing the values of the variables registered during the session. This correspondence between the server and the client, with the session id as the common denominator, makes it possible to store the values of different variables throughout the session.

How about something a little more complex? Take a look at this example, which demonstrates a timer that uses session variables to tell you how long it's been since you last reloaded the page.

<?php

session_start();

// session variable to store the counter.
session_register('counter');

// session variable to store the value when the page was last loaded;
// this value is maintained so that difference can be calculated.
session_register('timeAtLastLoad');

// current time
$timeNow = time();

// increment counter
$counter++;

// calculate the time lapsed from last visit.
$timeLapsed = $timeNow - $timeAtLastLoad;

// display appropriate message
if ($counter > 1) {
    echo "<b>It's been $timeLapsed seconds since you last viewed this page.</b>";
} else {
    echo "<b>First time here? Reload this page to see how the session
works!</b>";
}

$timeAtLastLoad = $timeNow;

?>

Playing The Market

Now that you've got the basics down, how about something a little more complex, just to demonstrate a real-world application of sessions. Let's assume that we have a financial portal, which allows its users to select four stocks and then displays the current market price of those stocks on each and every page that the user visits in his journey through the site.

In the example below, we're assuming that the user has already been authenticated and logged in to the Web site. A MySQL database, containing a "user_info" table, is used to store the user's four stocks together with his unique username. Once a session has been initiated, we register variables to store the values of the username and the four stocks, and then connect to the database to retrieve these values and display them on the page.

The code might look something like this:

<?php

//initiate a session
session_start();

// register the session variables

// username
session_register('username');

// variables for selected stocks
session_register('stock1');
session_register('stock2');
session_register('stock3');
session_register('stock4');

// connect to MySQL
$db = mysql_connect("someserver.com", "tom", "jones");

// select database on MySQL server
mysql_select_db("stock_db", $db);

// query database using SQL
$query = "select stock_pref1,stock_pref2,stock_pref3,stock_pref4 from
user_info where username='$username'";

$result = mysql_query($query, $db);

// get stock symbols from database
// and assign to session variables
list($stock1, $stock2, $stock3, $stock4) = mysql_fetch_row($result);

echo "Hi $username!<br>";
echo "Your selected stocks are:<br>";
echo "$stock1<br>";
echo "$stock2<br>";
echo "$stock3<br>";
echo "$stock4<br>";

// code to generate rest of page

?>

PHP4 comes with numerous other session-related functions - most of them are self-explanatory, and are listed below.

session_destroy() Destroy all session data [this comes in very useful when a user logs out of a site and you need to destroy all the variables created during his visit]

session_name() Set or read the current session name

session_id() Set or read the current session id

session_unregister(session_variable_name) De-register variables from a particular session.

session_is_registered() Checks whether or not a session variable has already been registered. For example,

<?php

session_start();

if (session_is_registered(username)) {
    echo "A session variable by the name \"username\" already exists";
} else {
        echo "No variable named \"username\" registered yet. Registering...";
        session_register(username);
    }

?>

session_encode() and session_decode() Encodes and decodes session data as a string. Here's how you could use them:

<?php

session_start();

session_register('someString');
$someString="I hate cats!";

// encode all the session variables into a single string
$sessStr = session_encode();

// which can be seen here
echo $sessStr;

echo "<br><br>";

// replace any appearance of cats with dogs
$sessStr  = ereg_replace("cats", "dogs", $sessStr);

// update session variables after decoding
session_decode($sessStr);

// and display it again
echo $sessStr;

?>

Finally, before we get to PHPLIB, there's one technical issue you should be aware of - all the examples above use cookies to store the session id on the client. But what happens if the client browser is set to reject cookies?

In such an eventuality, it becomes necessary to pass the session id from one page to another by embedding it in the URL. For example,

<a href="http://www.someserver.com/admin/preferences.php3?PHPSESSID=<?php echo
"$PHPSESSID"; ?>">Edit Your Portfolio!</a>.

This helps to ensure that session variables are available on subsequent pages.

But There's More Than One Way To Skin A Cat...

Of course, if your Web server is still running PHP3, you're not going to be able to use any of the code provided thus far. But don't despair - there does exist an alternate solution for PHP3 users. It's called PHPLIB, and it provides a number of useful PHP classes that allow you to add session management capabilities to PHP3. Installation instructions are available in the package, and you'll also need to modify the "local.inc" configuration file to create your own classes.

As in PHP4, you need to call a predefined page_open() function each time you initiate a session. PHPLIB comes with a default session class named Example_Session - you can modify this by changing the values in the "local.inc" file - which is what we've used in the following example:

<?php

page_open(array("sess" => "Example_Session"));

?>

It's important that the page_open() call happen before any output is sent to the browser. And in order to register your session variables, the following statement will do the job.

<?php

// initiate a session
page_open(array("sess" => "Example_Session"));

// register a variable for the session.
$sess->register('username');

?>

Each page must also have a corresponding page_close() function, which is used to make sure that all changes are saved to the database.

<?php

page_close();

?>

Other than this, most of your code stays the same. Take a look at this PHPLIB version of the previous example:

<?php

// initialize a session
session_start();

// register a session variable
session_register('counter');

?>

As you can see, once you've got the hang of the PHP4 version, it's not too difficult to understand the PHPLIB version - not at all strange when you consider that the native session support in PHP4 is heavily based on the PHPLIB model. And if you're interested, PHPLIB actually takes session management much further with its authentication and permission classes, which allow you to grant or deny access to users based on permissions in a database - take a look at the documentation for examples on how to use these features.

PHPLIB also comes with some interesting built-in functions.

unregister(variable) Allow you to de-register the variables from a particular session. Note that in this case, the variable is not deleted, though its value will be lost at the end of a page, as it is no longer saved to the database.

<?php

// initialize a session
session_start();

// register a session variable
session_register('counter');

?>

is_registered(variable) Returns true if the variable is registered with the session, false otherwise.

<?php

// initialize a session
session_start();

// register a session variable
session_register('counter');

?>

delete() Destroy the current session.

An interesting point to be noted here: In PHPLIB's cookie mode, it's possible to start a new session after the delete() function has been called, set a new cookie on the client, and even re-register some of the previous session variables - essentially changing the session on the fly. Of course, if you do things like this, you need to get yourself a life...fast!

url($url) Allows you to redirect users to a new page.

self_url() Returns a URL referencing the current page, including PHP_SELF and QUERY_STRING information.

And finally, for those of you unfortunate enough to have an ISP which supports neither PHP4 nor PHPLIB - remember that it's always possible to simulate a session with good old cookie technology. All you need to do is set a cookie containing the information you would like to remain persistent throughout the user's visit to your site, and access this information each time the user visits a new page. Crude - but it works, and sometimes you can't beat the simple ways of doing things!

The Patient Has Left The Building

<click>

Patient: Wow, Doc - that was fantastic! Thanks so much for straightening me out!

Psychiatrist: No problem at all, Victor. I'm glad I could help. Are you feeling better now?

Patient: Oh, definitely! When I first came in, the whole day looked gray and depressing - now, the view from this penthouse window has never looked better...

Psychiatrist: Ummm...Victor...I'd be careful out there if I were you. The railing's a little weak, and it might not be safe to go out there.

Patient: Not to worry, Doc - on a day like this, I feel invinc...Aaargh!!!!

<click>

This article was first published on 24 Oct 2000.