PHP allows you to implement a highly effective session management infrastructure in your applications, but you have to do a lot of the hard work yourself.
As you'll see in this section, PHP's built-in session handling isn't really appropriate for enterprise-class applications. Luckily, it has been made extensible enough to give you a head start when you're writing your own more robust solution.
Take a look at the following code. Enter it and save it as firstpage.php.
<?php session_start(); $_SESSION['favorite_artist'] - 'Tori Amos'; ?>Currently, my favorite artist is Tori Amos. It may also interest you to know that my identifer for this browser session, as allocated by PHP, is <?=session_id()?>. <BR><BR> <A HREF="secondpage.php">Go to the second page</A> ?>
Now start a brand-new bit of code. Call this secondpage.php.
<?php session_start(); ?>Having checked, I can tell you that my favorite artist is still <?=$_SESSION['favorite_artist']?>. At the moment, my identifier for this browser session, as allocated by PHP, is <?=session_id()?>. <BR><BR> <A HREF="firstpage.php">Go back to the first page</A> ?>
Run the first of these and you should get some predictable output. It turns out that my favorite artist is Tori Amos, and PHP has given me a session identifier (see Figure 15-2).
You can see that the session identifier is 32 characters in length. PHP actually uses the full alphabet as well as 0-9. This increases the number of possible session identifiers to 3632. If you click the link, you should see something that looks like Figure 15-3.
There are two important things to note. The session identifier is the same, and the second script seems to have remembered my musical preferences.
This result is obtained in a straightforward manner. First, use session_start() to tell PHP to enable sessions, well before the first character of HTML of the script. Using session_start() is important because the session data sent to the Web browser needs to go in the HTTP headers, and the first use of any HTML (or even whitespace) precludes this from happening.
Second, register a session variable by adding to the $_SESSION global associative array (or hash). This can come anywhere in the script because it won't send anything to the Web browser; it just makes a note on the server side, as you will see shortly.
On the second page, call session_start() just as you did on the first to enable session management, but now you can read from $_SESSION just as you wrote to it on the first page. Lo and behold, the value Tori Amos has been successfully retained from one page to the next. This value has been inextricably associated with the session identifier, which explains why the server remembered it.
But how did PHP remember the session identifier from the first page to the second?
Take a look on your server in /tmp. Perform a directory listing using ls for all files starting with sess_ (the word sess followed by an underscore). Notice a file called sess_ followed by the session ID you were allocated in the previous example. Open it using the editor of your choice. You should see something that looks like Figure 15-4.
The output there looks quite straightforward. You should see the session variable you created and its contents in plain text:
In fact, its format might look familiar. It's the output from the PHP function serialize(), a string representation of a PHP data structure.
Regardless of how complex or large the data structure you create in the $_SESSION variable is, PHP will store its contents in this file by default. The location for storing such files, as well as the length of time for which they are stored, are all settings that can be altered in php.ini.
That's really all there is to native PHP sessions. Let's look now at some of their limitations to see why they can't be used in an enterprise environment.
There are a few key problems with implementing sessions in this manner, most of which relate to the manner in which PHP stores its session data on disk.
What if you have multiple Web servers servicing your request with a load balancer appliance round-robin dividing traffic between them? You would have to implement some kind of shared /tmp using NFS, and this would be dreadfully slow.
Second, if you're running on a shared Web server (with a hosting company, for example), the directory listing of /tmp is readable by all even if the contents of its files aren't. Given that PHP uses the session identifiers as part of the filename, a malicious fellow user on that Web server could quite easily get a full listing of all the session identifiers created as well as when they were created. This would once again open the door for easy session hijacks as discussed earlier.
Third, this implementation of session handling is not very efficient. Not one of the additional measures discussed earlier is employed for additional security, nor is it easily possible to employ them in this state. So as far as a secure environment for a production Web site using sessions is concerned, PHP session handling in its off-the-shelf state isn't really a viable option.
Finally, given that you store the rest of your application's data in a database, you are bound to have times when you need to construct queries that consult both session variables and database tables in tandem. With session data totally exterior to the database, you must first extract that data using PHP and then inject it into an SQL statement. Serious performance implications are associated with this approach when compared to conducting a single SQL query to extract the data you need. On a production server, for example, this could become quite a serious issue. The solution to this problem is to integrate the PHP session management with a database.