24 October 2006
Session Management in PHP
Session management is one of the features that sets PHP apart from other languages which happen to be used on the web. It is easy enough to understand how to use $_SESSION, but many programmers seem to learn how to use it and nothing more.
$_SESSION serves a single, useful purpose. It makes variables available across multiple pageviews. It can keep objects across multiple pages. The best comparison to it I can think of is a plain-old Module in Visual Basic versions 1-6. There’s only one instance of $_SESSION per visitor. It can store practically anything. It’s almost always available. And it’s generally much more convenient than dumping data to hidden variables on a page.
During PHP version 3’s lifetime, SESSION took some work to use. Since the superglobal variable $_SESSION was not available, you worked with normal variables but called a special function to make them into session variables. PHP version 4.2 was the revision which effectively mandated holding session variables in the $_SESSION superglobal array. Depending on the server’s configuration, it may or may not be necessary to call session_start(). Most well formed code will explicitly call it, and it’s practically required if you’re using any kind of user-defined classes. But let’s start more basically:
session_start();
if (array_key_exists (”counter”, $_SESSION)) {
$_SESSION[”counter”]++;
} else {
$_SESSION[”counter”] = 0;
}
This code establishes a variable called counter and increments each starting on the second and subsequent visits to pages which contain it. But how does it work?
Assuming your visitor allows cookies, session_start grabs the session ID from a cookie which is managed by PHP. It then looks up a session data file in a temporary directory by that ID. It reads in that data and populates the array. It also arranges to send a cookie back out to refer back to that session data. As your script runs, it mutilates the $_SESSION array. Finally, when your script finishes, it writes the contents of the array back out to the temporary file.
But many special cases exist:
- If output buffering is not enabled (it is by default)
session_start()must be called before any data is outputted. - If you make a call to
header (”location: …\n”);the page which resumes execution will not have access to$_SESSION. Therefore, redirects need to happen with HTTP-EQUIV meta tags, JavaScript or forcing users to click links. - Both of these issues are because the session ID cookie must be transmitted in HTTP’s headers.
Of course, there are other things to be aware of.
For one, $_SESSION can store almost anything: Arrays, scalars and objects are all fair game. Resources generally don’t work, so file handles or database connections should be re-established as necessary. Arrays and scalars will just work. There’s nothing special developers need to do. But Objects take a little bit more work. Objects can be easily put into $_SESSION. There’s nothing special required there. But to get an object out of $_SESSION takes a condition. The class must be defined before session_start() is called. Otherwise, the object coming out of $_SESSION will belong to the class __php_incomplete_class. This is a special case in PHP. None of PHP’s introspection or reflection functions can process it. The variable is defined, but for all intents, has no value.
class person {
var $name;
var $age;
}
session_start();
if (array_key_exists (”user”, $_SESSION)) {
$p = $_SESSION[”user”];
} else {
$p = new person;
$p->name = “bob”;
$p->age = 0;
}
$_SESSION[”user”] = $p;
In php.ini, session auto-starting should be disabled. I have seen $_SESSION work with objects when it is enabled. But it doesn’t always. Portable code should assume it is off. Even if you don’t deal with objects, you should still assume it’s off, but you could get away with much simpler code:
session.php
if (!$_SESSION) session_start();
But there are issues with $_SESSION beyond technical ones.
One of the first things people think to do with $_SESSION is use it to manage paged data. Search results seem to be especially common. But as soon as individualized page data ends up in $_SESSION you’ve crippled your site for power users. Suddenly, a user cannot preform two searches in two windows (or tabs) at once. The second search will obliterate the stored results of the first. This can be avoided in many ways: the two most obvious are to cache the results to a hidden form element on the page, or to abstract the results away with a layer of indirection.
Let’s look first at caching the results. This leads to an entity similar to ASP.net’s ViewState. For many things, that’s fine. For a small amount of data, that’s fine. But for ten-thousand search results of 1kb each, your site is no longer usable for mobile devices or low-bandwidth visitors. Perhaps that’s OK, perhaps it’s not. But it’s a solution and the tradeoff you assume by implementing this solution.
Alternatively, you can create an array in $_SESSION, store results in it and then just embed the index to the results in your hidden form field on your output page. This has the advantage that the storage is kept on the server and doesn’t need to be transmitted on every page load. It has a disadvantage in that it consumes physical disk space on the server, and that your code becomes responsible for performing garbage collection on the wrapper array.
There is of course a third option for search results, and that is to only select a subset of results from each query. Then only two control variables need to be tracked on a page (the result index and the count of returned results) and the appropriate subset can be retrieved as necessary. But not all problems can be solved with this method.
There is data which will only ever have one value. And this is the kind of thing $_SESSION is really meant to hold. Things like authenticated user information is well suited for $_SESSION. No well designed PHP application is going to have a different authenticated user for a different part of the site. Permission levels can be a part of users if that is the rationale for different simultaneous users from the same visitor. Another good use of $_SESSION are options for a web application. Application options will affect each page. They may be ignored but they’ll never be different — and when changed, the change should propagate to any number of open windows to the site instantly.
So that’s $_SESSION. It has uses, is very convenient, is frequently misused and shouldn’t be. And its one of many features PHP offers which really sets web languages apart from languages which happen to be used on the web.

