PHP DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Managing Sessions and State with PHP

by Brian Fioca
05/18/2006

MVC Frameworks, such as WASP, provide a solid jumping-off point for entry-level programmers to produce strong, well-formed code. The framework simplifies such things as creating a page (using a kind of page object) and creating or searching for data (using database table objects).

However, probably the most difficult concept for novice PHP programmers to grasp is handling their application's state and session data. This article will address that issue by providing a simple strategy for state management using the WASP framework.

WASP is an MVC framework written for PHP and based on concepts outlined in previous articles on this site. "Simplify PHP Development with WASP" introduced WASP. This article uses WASP version 1.2.

Page State vs. Session State

To understand state and session management in an MVC framework, you must understand the difference between the two, and when to use one instead of the other.

Session State

A web application session is a single start-to-finish interaction between a user and the application. When the user begins the application, the session saves certain variables to keep track of his progress through the application. For example, when a user visits an online store such as Amazon.com, his session begins when he first loads the page. The session then keeps track of the stores he browses to and which items, if any, he adds to his shopping cart. Finally, it allows him to check out and complete his purchase of any items stored in the session at the end.

The application server handles session management. Typically, it assigns a unique identifier to a user by using a browser cookie or by adding it to the request using a hidden entry on the page. A well-designed application or framework can track the user's session on every page where it is appropriate to know the state of her progress through the application. The session lives through the end of the user's interaction with the application, and possibly persists in the user's browser so that the visit can continue when she returns to the site later.

Page State

Page state is much smaller in scope than session state. Page state, by definition, only applies to the state of the current page or possibly a group of pages, such as a wizard. Page state stores such things as form validation errors, progression through a series of data collection forms, or page data-display toggles or switches based on user input. For example, when an Amazon.com user logs in to the site, the pages "recognize" him and tailor the displayed items for sale based on his information. The pages themselves are the same, but the state has changed.

Page state management usually works through the user's browser, maintaining query string parameters or hidden entry form data. Page state data should not be stored in the session, because subsequent page visits will retain their previous state unless you clear the session when you leave the page. With an application comprised of many complicated pages, it can be troublesome to clear the session; thus, it is a good practice not to store page state data in the session.

Session State Example

The article "Simplify PHP Development with WASP" showed how to build a simple Task List application to create and view a list of tasks. To illustrate session management, I'll add features to that application. I recommend working through the tutorial in that article to get to the point where you can follow along with this example.

This example will show how to add simple login capability to your todo application. Everyone will be able to see the list, but only certain people can create entries. Once logged in, you will be able to create as many entries as you like without having to provide your credentials.

First, to modify the controller (the C in MVC) for the Entry page to enforce login restrictions, edit the file Todo/Entry/EntryIndexPage.php:

        //Check for Add button presses
        if (Request::getParameter('Add') != null)
        {
                $oTask = new TaskWrapper();
                $oTask->fillFromRequest();
                $oTask->save();
                $this->redirect('../');
         }

Remember from the previous tutorial that this is where the application saves entries submitted when a user clicks the Add button. To ensure that only properly authenticated users can actually add entries, protect the code:

        //Check for Add button presses
        if (Request::getParameter('Add') != null)
        {
            //Make sure the user has been logged in, and the
            //appropriate session variable has been set
            if (SessionManager::getParameter('user') != null)
            {
                $oTask = new TaskWrapper();
                $oTask->fillFromRequest();
                $oTask->save();
                $this->redirect('../');
            }
            else  //Present an error to the user.
            {
                $this->reportError("You must log in first.");
            }
        }

The line

            if (SessionManager::getParameter('user') != null)

checks the WASP SessionManager for a variable called user, and if it is set, lets the user save her entry. I haven't discussed the code to set this parameter yet, so for now you won't be able to save any entries.

In the case where the user has not logged in, the code

        $this->reportError("Invalid Username or Password.");

tells the WASP framework to present the user with an error message on the page. This happens in the View (the V in MVC). Open the file Todo/Entry/templates/index.chunk to make the change:

<html>
  <body>
    <form name="entry" method="post">
      <h4>Create Entry</h4>
      <div flexy:foreach="arErrors,key,value" class="error">
        {value}</div>
      <p>
        You must log in to create an entry.<br/>
        Username: <input type="text" name="user"/>
        Password: <input type="password" name="password"/>
        <input type="submit" name="Login" value="Login"/>
      </p>
      <p>
        Name:<br/>
        <input type="text" name="Name"/>
      </p>
      <p>
        Date Due (format mm/dd/yyyy):<br/>
        <input type="text" name="Due"/>
      </p>
      <input type="submit" name="Add" value="Add"/>
    </form>
  </body>
 </html>

The lines

      <div flexy:foreach="arErrors,key,value" class="error">
        {value}</div>

ensure that all error messages appear at the top of the page. You don't have to set the placeholder for arErrors because the framework handles it when you call reportError().

The rest of the changes allow you to submit login credentials to the application. You must handle the Login button press back in the controller code. Go back to EntryIndexPage.php and add some code to the handleEvents() method right under the code for handling the Add button press:

        //Check for Login button presses
        if (Request::getParameter('Login') != null)
        {
            //Check user and password
            if (Request::getParameter('user') == 'login' &&
                Request::getParameter('password') == 'password')
            {
                //Save the session state
                SessionManager::setParameter('user', 
                                             Request::getParameter('user'));
            }
            else
            {
                $this->reportError("Invalid Username or Password.");
            }
        }

When a user clicks the Login button, her username and password are checked to ensure they're valid. Note that in a real application, you wouldn't want to hardcode the username and password here, but I've done this to keep this example simple. More typical code would load a UserWrapper database object with the passed-in username and, if it exists, check that the password matches.

After this code has verified the credentials, these lines of code

                SessionManager::setParameter('user',
                                             Request::getParameter('user'));

store a variable called user in the session set to the value submitted in the form. From now on, anywhere in the application, you can discover the username of the logged-in user by calling

        SessionManager::getParameter('user');

which, if you remember, is the same technique used to protect the Add button from unauthenticated users.

Now when you visit the page you won't be able to add an entry unless you've filled out the user and password information and clicked Login first. Notice, however, that even though you can successfully log in and then create entries (try it; it works!), the login form entries are always present. You can fix this by using page state management.

Pages: 1, 2

Next Pagearrow




Valuable Online Certification Training

Online Certification for Your Career
Earn a Certificate for Professional Development from the University of Illinois Office of Continuing Education upon completion of each online certificate program.

PHP/SQL Programming Certificate — The PHP/SQL Programming Certificate series is comprised of four courses covering beginning to advanced PHP programming, beginning to advanced database programming using the SQL language, database theory, and integrated Web 2.0 programming using PHP and SQL on the Unix/Linux mySQL platform.

Enroll today!


Sponsored by: