Zend Framework: Zend_Session

Introduction

In this article I will introduce you to the Zend_Session component of the Zend Framework. This component is built upon PHP’s native session-handling functionality, making it easier to manage session data, as well as providing more advanced features.

Firstly I will show you how to read and write data using Zend_Session, then I will show you how to implement a “remember me” feature for logging-in users on your web site.

This article requires Zend Framework, downloadable from http://framework.zend.com. At time of writing, the current version of Zend Framework is 1.9.6.

<!–nextpage–>

Creating Session Namespaces

The Zend Framework provides advanced session handling using the Zend_Session component. Using this component, you no longer need to access PHP’s $_SESSION global variable.

Note: In fact, you should not access $_SESSION at all when using Zend_Session.

Zend_Session uses namespaces to store your session data. That is, when you want to read or write session data you must first specify a namespace. This allows you to easily store different session data without worrying too much about other values stored in the session.

You create a new session namespace by instantiating the Zend_Session_Namespace class. The first argument to the constructor is the name of the namespace. Listing 1 shows an example of this.

Listing 1 Creating a namespace for storing user identity data (listing-1.php)
<?php
    require_once('Zend/Session.php');

    $session = new Zend_Session_Namespace('identity');
?>

We can now read or write session data in the identity namespace using the $session variable. I will show you how to do this shortly.

Note also that you do not need to manually start sessions (using the session_start() function) as you might have in the past when using sessions in PHP. Instantiating this class takes care of this for you.

Note: As always, session handling must be performed prior to performing any output. This is easy to achieve if you’re using Model-View-Controller (or similar – that is, performing any required processing in your scripts prior to output), or if you use output buffering. If you want to force sessions to start earlier in your script without creating a specific namespace, you can call Zend_Session::start() instead.

Internally, the above code will be accessing data in the $_SESSION['identity'] variable. You should never access this directly.

<!–nextpage–>

Writing and Reading Session Data

Once you have instantiated Zend_Session_Namespace, you can then write to the session using the created object. To write a new value, treat the nam of the value as a property of the object. For example, to create a session value called foo with a value of bar, use $session->foo = 'bar';. You can then read the value from the session by accessing $session->foo.

Additionally, you can use isset() to check if a session value is set.

Listing 2 shows an example of creating the namespace, writing a value, then outputting it.

Listing 2 Writing a value to session then outputting it (listing-2.php)
<?php
    require_once('Zend/Session.php');

    // create the session namespace
    $session = new Zend_Session_Namespace('identity');

    // write a value to the session
    $session->country = 'Australia';

    // output the value
    echo sprintf('Your country is %s', $session->country);

    // checking if a value is set
    if (isset($session->country)) {
        // value is set in session
    }
?>

Typically though, you would write to the session on one page then access the value on the next page. For example, if you had a log in form, the identity data would be written when the user logs in, then on subsequent pages you might output a message to indicate they are logged in.

To demonstrate this, here are two PHP scripts. Note that the functionality is not complete but will hopefully demonstrate how this works.

In this example, the user submits their username and password to the login.php script. If the log in attempt is successful, some data is written to session and the user is redirected to members.php.

Listing 3 Writing to session data on one script (login.php)
<?php
    $username = $_POST['username'];
    $password = $_POST['password'];

    if (log_in_user($username, $password)) {
        require_once('Zend/Session.php');

        $session = new Zend_Session_Namespace('identity');
        $session->username = $username;

        header('Location: members.php');
        exit;
    }
    else {
        // some error message for invalid login
    }
?>
Listing 4 Reading from the session data in a subsequent script (members.php)
<?php
    if (!is_logged_in()) {
        // some error message or redirect to log in form
        exit;
    }

    $session = new Zend_Session_Namespace('identity');

    echo sprintf('Welcome %s!', $session->username);
?>

While some of these methods are fictional (such as is_logged_in()), hopefully this demonstrates how to use session data.

<!–nextpage–>

Removing Session Data

To remove a value from a session, use PHP’s unset() function on the object property. This is demonstrated in Listing 5.

Listing 5 Removing a value from a session namespace (listing-5.php)
<?php
    require_once('Zend/Session.php');

    $session = new Zend_Session_Namespace('identity');
    unset($session->username);
?>

In some cases you might want to remove all data in a namespace. You can do this either by looping over all values in the namespace and calling unset() on each one, or you can use the Zend_Session::namespaceUnset(). This method accepts the name of the namespace as its only argument, as demonstrated in Listing 6.

Listing 6 Removing an entire namespace from a session (listing-6.php)
<?php
    require_once('Zend/Session.php');

    Zend_Session::namespaceUnset('identity');
?>

You can destroy the entire current session using the Zend_Session::destroy() static function.

<!–nextpage–>

Implementing “Remember Me” Functionality

A common feature of web sites where users can log in is the ability to be automatically logged-in when the user next visits the web site.

By default, PHP sessions use session cookies, which are cookies that the web browser stores in memory while the browser is running, and destroyed when the browser is exited.

To implement “remember me” functionality, you must change the lifetime of the session cookie so it is not destroyed when the user closes their browser. Zend_Session makes this easy to do.

Additionally, your PHP installation will also periodically delete session cookies after the time specified in the PHP configuration. If this occurs to soon, it doesn’t matter whether the user’s browser has remember their session ID – the session data will no longer be saved on the server!

Extending the Session Cookie Lifetime

To make the browser session cookie stay alive when users close their browser, use the Zend_Session::rememberMe() static method. This method takes an optional single argument, which is the number of seconds before the cookie will expire. If no value is specified then a default of two weeks is used.

Listing 7 demonstrates how to use this function. You should call rememberMe() before performing any other session-related activity. Typically this would appear in your global bootstrapping script.

Listing 7 Changing session behaviour to remember the cookie for 7 days (listing-7.php)
<?php
    require_once('Zend/Session.php');

    $seconds = 60 * 60 * 24 * 7; // 7 days
    Zend_Session::rememberMe($seconds);

    // now the session cookie won't be deleted
    // when the browser is closed
?>

The forgetMe() function is the opposite of rememberMe() – it changes the session cookie so it will be removed when the browser is closed.

Increasing the PHP Session Garbage Collection Time

Every time a new session is created, a new file is written to the server to hold the session data. Over time this can result in a large number of files. To combat this, PHP has a garbage collection system that automatically deletes untouched session files (files that haven’t been updated) after a specified amount of time. By default this time is 24 minutes (1440 seconds).

If the garbage collection time is too low then extending the length of the session cookie will have no effect, since the session data will no longer be stored on the server. To deal with this, you must ensure the PHP session.gc_maxlifetime setting is at least the same value as the value passed to rememberMe().

In the previous listing, we used a value of 7 days (604800 seconds). In your PHP configuration (either in php.ini file, your Apache httpd.conf file, or in a .htaccess file), use the setting in Listing 8.

Listing 8 Changing the garbage collection time to 7 days (.htaccess)
php_value session.gc_maxlifetime 604800
Caution: Ensure your sessions are written to a different filesystem location than for other web sites, since another site will likely use the lower garbage collection time, thereby resulting in your sessions being cleaned-up anyway.

You must be aware though that increasing the garbage collection time will result in a much larger number of session files stored at any one time. You should monitor your server after making this change to ensure not too much space is used.

An Example of Implementing “Remember Me”

Now that you know how to implement “remember me” functionality, let’s look at a solid example. Many sites that offer this functionality ask the user if they want to be remembered. This example will offer that also.

Listing 9 shows the form you might use for logging in. This form consists of inputs for username and password, as well as the option to remember the user and a submit button.

Listing 9 A log in form with the option to remember the user (listing-9.php)
<form method="post" action="login.php">
    <div>
        Username:
        <input type="text" name="username" />

        Password:
        <input type="password" name="password" />
        <label>
            <input type="checkbox" name="remember" value="1" />
            Remember Me
        </label>

        <input type="submit" value="Log In" />
    <div>
</form>

Next we process this form, as shown in Listing 10. We’ll skip the details here for authenticating a user by using a fictional log_in_user() function. If the user successfully logs in, we then check whether or not they want to be remembered. If they do, we call rememberMe(), otherwise we call forgetMe().

Note: Technically you probably don’t need to call forgetMe() since the default PHP setting is to expire the cookie on browser close anyway.

This code is based on the code in Listing 3.

Listing 10 Processing the user log in and whether or not they want to be remembered (login.php)
<?php
    $username = $_POST['username'];
    $password = $_POST['password'];

    if (log_in_user($username, $password)) {
        require_once('Zend/Session.php');

        $remember = isset($_POST['remember']) && $_POST['remember'];
        $seconds  = 60 * 60 * 24 * 7; // 7 days

        if ($remember) {
            Zend_Session::RememberMe($seconds);
        }
        else {
            Zend_Session::ForgetMe();
        }

        $session = new Zend_Session_Namespace('identity');
        $session->username = $username;

        header('Location: members.php');
        exit;
    }
    else {
        // some error message for invalid login
    }
?>

<!–nextpage–>

Other Zend_Session Functionality

In addition to what’s been covered so far in this article, there are some other advanced features that can be used with Zend_Session. This section shows introduces you to these features and provides a link for more information about the feature.

Storing Sessions in a Database

By default, PHP stores session data on the filesystem of the server. You can change this so session data is stored in a database. The database must be a connection made using the Zend_Db component. You can then make use of the Zend_Session_SaveHandler_DbTable class with the Zend_Session::setSaveHandler() method.

Tip: If you don’t use Zend_Db for accessing your database (or you want to save session data using some other method), you can create your own save handler by implementing the Zend_Session_SaveHandler_Interface interface.

Storing session data in your database is useful in a load-balanced environment, where subsequent user requests may be handled by different front-end servers (all sharing the same database server).

For more information on saving session data to the database, refer to http://framework.zend.com/manual/en/zend.session.savehandler.dbtable.html.

Session Value and Namespace Expiration

You can make values in a session namespace (or an entire namespace) automatically expire after a set period of time. The time can be measured either in seconds or “hops” (that is, you can make a value only be set for the specified number of subsequent page requests).

For details on automatic expiration of session values refer to http://framework.zend.com/manual/en/zend.session.advanced_usage.html#zend.session.advanced_usage.expiration.

<!–nextpage–>

Summary

In this article I introduced you to the Zend_Session component of the Zend Framework.

First I showed you how to create session namespaces. Next I showed you how to write session data, read session data, and clear session data. Finally, I showed you how to implement a “remember me” feature for your web site.

Further reading:

Other Options

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s