Section 10.3. Using Sessions


10.3. Using Sessions

Sessions store temporary data about your visitors and are particularly good when you don't want that data to be accessible from outside of your server. They are an alternative to cookies if the client has disabled cookie access on her machine, because PHP can automatically rewrite URLs to pass a session ID around for you.

10.3.1. Starting a Session

A session is a combination of a server-side file containing all the data you wish to store, and a client-side cookie containing a reference to the server data. The file and the client-side cookie are created using the function session_start( ) it has no parameters but informs the server that sessions are going to be used.

When you call session_start( ), PHP will check to see whether the visitor sent a session cookie. If it did, PHP will load the session data. Otherwise, PHP will create a new session file on the server, and send an ID back to the visitor to associate the visitor with the new file. Because each visitor has his own data locked away in his unique session file, you need to call session_start( ) before you try to read session variablesfailing to do so will mean that you simply will not have access to his data. Furthermore, as session_start( ) needs to send the reference cookie to the user's computer, you need to have it before the body of your web pageeven before any spaces.

10.3.2. Adding Session Data

All your session data is stored in the session superglobal array, $_SESSION, which means that each session variable is one element in that array, combined with its value. Adding variables to this array is done in the same way as adding variables to any array, with the added bonus that session variables will still be there when your user browses to another page.

To set a session variable, use syntax like this:

     $_SESSION['var'] = $val;     $_SESSION['FirstName'] = "Jim"; 

Older versions of PHP used the function session_register( ); however, use of this function is strongly discouraged, as it will not work properly in default installations of PHP 5. If you have scripts that use session_register( ), you should switch them over to using the $_SESSION superglobal, as it is more portable and easier to read.

Before you can add any variables to a session, you need to have already called the session_start( ) functiondon't forget!

You cannot store resources such as database connections in sessions, because these resources are unique to each PHP script and are usually cleaned when that script terminates.


10.3.3. Reading Session Data

Once you have put your data away, it becomes available in the $_SESSION superglobal array with the key of the variable name you gave it. Here is an example of setting data and reading it back out again:

     $_SESSION['foo'] = 'bar';     print $_SESSION['foo']; 

Unlike cookies, session data is available as soon as it is set.

10.3.4. Removing Session Data

Removing a specific value from a session is as simple as using the function unset( ) , just as you would for any other variable. It is important that you unset only specific elements of the $_SESSION array, not the $_SESSION array itself, because that would leave you unable to manipulate the session data at all.

To extend the previous script to remove data, use this:

     $_SESSION['foo'] = 'bar';     print $_SESSION['foo'];     unset($_SESSION['foo']);

10.3.5. Ending a Session

A session lasts until your visitor closes her browserif she navigates away to another page, then returns to your site without having closed her browser, her session will still exist. Your visitor's session data might potentially last for days, as long as she keeps browsing around your site, whereas cookies usually have a fixed lifespan.

If you want to explicitly end a user's session and delete his data without him having to close his browser, you need to clear the $_SESSION array, then use the session_destroy( ) function. The session_destroy( ) function removes all session data stored on your hard disk, leaving you with a clean slate.

To end a session and clear its data, use this code:

     session_start( );     $_SESSION = array( );     session_destroy( ); 

There are two important things to note there. First, session_start( ) is called so that PHP loads the user's session, and second, we use an empty call to the array( ) function to make $_SESSION an empty arrayeffectively wiping it. If session_start( ) is not called, neither of the following two lines will work properly, so always call session_start( ).

10.3.6. Checking Session Data

You can check whether a variable has been set in a user's session using isset( ) , as you would a normal variable. Because the $_SESSION superglobal is only initialized once session_start( ) has been called, you need to call session_start( ) before using isset( ) on a session variable. For example:

     session_start( );     if (isset($_SESSION['FirstName'])) {             /// your code here     } 

You can also use empty( ) with session data, or indeed any other functionthe $_SESSION array and its data can be used like any other array.

10.3.7. Files Versus Databases

The session-handling system in PHP is actually quite basic at its core, simply storing and retrieving values from flat files based upon unique session IDs handed out when a session is started. While this system works very well for small-scale solutions, it does not work too well when multiple servers come into play. The problem is down to location: where should session data be stored?

If session data is stored in files, the files would need to be in a shared location somewherenot ideal for performance or locking reasons. However, if the data is stored in a database, that database could then be accessed from all machines in the web server cluster, thereby eliminating the problem. PHP's session storage system was designed to be flexible enough to cope with this situation.

PHP saves its session data to your /tmp directory by default, which is usually readable by everyone who has access to your server. As a result, be careful what you store in your sessions or, better yet, either change the save location or use a database with finer-grained security controls!


To use your own solution in place of the standard session handlers, you need to call the function session_set_save_handler( ), which takes several parameters. In order to handle sessions, you need to have your own callback functions that handle a set of events, which are:

  • Session open (called by session_start( ))

  • Session close (called at page end)

  • Session read (called after session_start( ) )

  • Session write (called when session data is to be written)

  • Session destroy (called by session_destroy( ) )

  • Session garbage collect (called randomly)

To handle these six events, you need to create six functions with very specific numbers of functions and return types. Then you pass these six functions into session_set_save_handler( ) in that order, and you are all set. This sets up all the basic functions, and prints out what gets passed to the function so you can see how the session operations work:

     function sess_open($sess_path, $sess_name) {             print "Session opened.\n";             print "Sess_path: $sess_path\n";             print "Sess_name: $sess_name\n\n";             return true;     }     function sess_close( ) {             print "Session closed.\n";             return true;     }     function sess_read($sess_id) {             print "Session read.\n";             print "Sess_ID: $sess_id\n";             return '';     }     function sess_write($sess_id, $data) {             print "Session value written.\n";             print "Sess_ID: $sess_id\n";             print "Data: $data\n\n";             return true;     }     function sess_destroy($sess_id) {             print "Session destroy called.\n";             return true;     }     function sess_gc($sess_maxlifetime) {             print "Session garbage collection called.\n";             print "Sess_maxlifetime: $sess_maxlifetime\n";             return true;     }     session_set_save_handler("sess_open", "sess_close", "sess_read",                     "sess_write", "sess_destroy", "sess_gc");     session_start( );     $_SESSION['foo'] = "bar";     print "Some text\n";     $_SESSION['baz'] = "wombat"; 

That will give the following output:

     Session opened.     Sess_path: /tmp     Sess_name: PHPSESSID     Session read.     Sess_ID: m4v94bsp45snd6llbvi1rvv2n5     Some text     Session value written.     Sess_ID: m4v94bsp45snd6llbvi1rvv2n5     Data: foo|s:3:"bar";baz|s:6:"wombat";     Session closed. 

There are four important things to note in that example:

  1. You can, if you want, ignore the parameters passed into sess_open( ). We're going to be using a database to store our session data, so we do not need the values at all.

  2. Writing data comes just once, even though our two writes to the session are nonsequentialthere is a print statement between them.

  3. Reading data is done just once, and passes in the session ID.

  4. All the functions return true except sess_read( ).

Item 1 is not true if you actually care about where the user asks you to save files. If you are using your own session filesystem, you might want to actually use $sess_path when it gets passed inthis is your call.

Items 2 and 3 are important, as they show that PHP only does its session reading and writing once. When it writes, it gives you the session ID to write and the whole contents of that session; when it reads, it just gives you the session ID to read and expects you to return the whole session data value.

The last item shows that sess_read( ) is the one function that needs to return a meaningful value to PHP. All the others just need to return true, but reading data from a session needs to either return the data or return an empty string: ''.

If you return TRue or false from your session read function, it is likely that PHP will crashalways return either the session string or an empty string.


What we're going to do is use MySQL as our database system for session data using the same functions as those abovein essence, we're going to modify the script so that it actually works.

We need to create a table to handle the session data, and here's how it will look:

     CREATE TABLE sessions (ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,     SessionID CHAR(26), Data TEXT DEFAULT '', DateTouched INT); 

The ID field is not required, as it is not likely we will ever need to manipulate the database by hand.

Now, before you try this next code, you need to tweak two values in your php.ini file: session.gc_probability and session.gc_maxlifetime. The first one, in tandem with session.gc_divisor, sets how likely it is for PHP to trigger session clean up with each page request. By default, session.gc_probability is 1 and session.gc_divisor is 1000, which means it will execute session clean up once in every 1000 scripts. As we're going to be testing our script out, you will need to change session.gc_probability to 1000, giving us a 1000/1000 chance of executing the garbage collection routine. In other words, it will always run.

The second change to make is to lower session.gc_maxlifetime. By default, it is 1440 seconds (24 minutes), which is far too long to wait to see if our garbage collection routine works. Set this value to 20, meaning that when running our garbage collection script, we should consider everything older than 20 seconds to be unused and deletable. Of course, in production scripts, this value needs to be set back to 1440 so that people do not get their sessions timing out before they can even read a simple web page!

With that in mind, here's the new script:

     mysql_connect("localhost", "phpuser", "alm65z");     mysql_select_db("phpdb");     function sess_open($sess_path, $sess_name) {             return true;     }     function sess_close( ) {             return true;     }     function sess_read($sess_id) {             $result = mysql_query("SELECT Data FROM sessions WHERE SessionID                      = '$sess_id';");             $CurrentTime = time( );             if (!mysql_num_rows($result)) {                     mysql_query("INSERT INTO sessions (SessionID, DateTouched)     VALUES                      ('$sess_id', $CurrentTime);");                     return '';             } else {                     extract(mysql_fetch_array($result), EXTR_PREFIX_ALL,     'sess');                     mysql_query("UPDATE sessions SET DateTouched = $CurrentTime     WHERE                              SessionID = '$sess_id';");                     return $sess_Data;             }     }     function sess_write($sess_id, $data) {             $CurrentTime = time( );             mysql_query("UPDATE sessions SET Data = '$data', DateTouched =                      $CurrentTime WHERE SessionID = '$sess_id';");             return true;     }     function sess_destroy($sess_id) {             mysql_query("DELETE FROM sessions WHERE SessionID = '$sess_id';");             return true;     }     function sess_gc($sess_maxlifetime) {             $CurrentTime = time( );             mysql_query("DELETE FROM sessions WHERE DateTouched + $sess_     maxlifetime                      < $CurrentTime;");             return true;     }     session_set_save_handler("sess_open", "sess_close", "sess_read",              "sess_write", "sess_destroy", "sess_gc");     session_start( );     $_SESSION['foo'] = "bar";     $_SESSION['baz'] = "wombat"; 

As that script starts, it forms a connection to the local SQL server, which is used through the script for the session-handling functions. When a session is read, sess_read( ) is called and given the session ID to read. This is used to query our sessions tableif the ID exists, its value is returned. If not, an empty session row is created with that session ID and an empty string is returned. The empty row is put in there so that we can later say UPDATE while writing and will not need to bother with whether the row exists already; we'll know we created it when reading. The sess_write( ) function updates the session with ID $sess_id so that it holds the data passed in with $data.

The last function of interest is sess_gc( ), which is called randomly to handle deletion of old session information. We edited php.ini so that randomly means "every time" right now, and this function receives the lifespan in seconds of session data, and deletes all rows that have not been read or updated in that time. We can tell how long it has been since a row was last read/written because both sess_read( ) and sess_write( ) update the DateTouched field to the current time. Therefore, to tell whether or not a record was touched after the garbage collection time limit, we simply take DateTouched and add the time limit $sess_maxlifetime to itif that value is under the current time, the session data is no longer valid.

It is interesting to note that you need not use databases or files to store your sessions. As we've seen, you get to define the storage and retrieval method for your system, so if you really wanted, you could write your own extension called PigeonStore that sends and retrieves session data through pigeons. It really doesn't matter, because PHP just calls the functions you tell it to; what you do in there is up to you, so use it wisely.



PHP in a Nutshell
Ubuntu Unleashed
ISBN: 596100671
EAN: 2147483647
Year: 2003
Pages: 249

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net