Flourish PHP Unframework

fSession

The fSession class provides an enhanced interface to PHPs native session handling and $_SESSION superglobal features.

Configuration (Security)

There are three options for configuring the session, the setPath(), setLength() and ignoreSubdomain() static methods. All must be called before any other fSession methods.

Session File Path

The most important method to call when setting up a site is setPath(). This static method accepts a single parameter, the $directory to save all session files in. The directory specified must be writable by the web server, and should not contain anything except for session files because the session manager will delete old files after the predetermined session time has expired.

By default, all sites on a server use the same temporary directory to store the session files. This opens the opportunity for cross-site session transfer since a valid session ID can be pasted from from one session cookie to another. By setting the session directory per site, this type of attack is prevented. For additional security, it is wise to set the session directory to a location that is not readable by other users so they can not find it and set their session directory to the same place.

fSession::setPath('/path/to/private/writable/dir');

Duration

The static method setLength() allows you to set the minimum length of the session, using English descriptions of a timespan. Note that the minimum length, not the exact length, is specified since the session garbage collector uses a probabilistic approach to cleaning up session data. If the session length is set, the session directory should also be set via setPath() or else other sites on the server may delete session files that they consider "old", but that have not expired for the current site.

Here are a few example of setting the session length:

fSession::setLength('30 minutes');
fSession::setLength('1 hour');
fSession::setLength('1 day 2 hours');

There is a second, optional, parameter $persistent_timespan which is discussed in the section Keeping Users Logged In.

Spanning Subdomains

By default PHP will only allow access to the $_SESSION superglobal values by pages on the same subdomain, such that www.example.com could access the session, but example.com could not. Calling ignoreSubdomain() removes that restriction and allows access to any subdomain.

Preventing Session Fixation (Security)

Session fixation is an exploit where an attacker provides a user with a known session id and then uses the same session id to access their authentication session once they have logged in. Below is a simple example of a URL that allows the attacker to know the users session id:

http://example.com/login.php?PHPSESSID=abcdef1234567890

After the unsuspecting user has logged into the site, the attacker simply needs to set the same session id in his browser and hell have full access to the users session and information.

The fSession class prevents against such session fixation attacks by automatically setting the session.use_cookies and session.use_only_cookies ini settings so that session ids will not be accepted in a query string or POST data, but only in cookies.

When using the fAuthorization class, an additional layer of protected is added because all operations that add user information to the session will automatically regenerate the session id. This way even if an attacker was able to influence the session id, it will change once any useful information is present.

Controlling the Session

A session can be in one of three states: open, closed, and non-existent. An open session can have data written to the $_SESSION superglobal. A closed session retains all information, however the information can not be read or written. A non-existent session is exactly that, not present at all.

Opening

The session is automatically opened when any session method such as set(), get() or destroy() is called. It can also be opened explicitly by calling the static method open(). In the case that a Cannot send session cache limiter - headers already sent warning is generated, be sure to call open() before any output is sent to the browser.

// If you arent using the session until after content has been output,
// be sure to explicitly open the session before any content is echoed
fSession::open();

Closing

To close the session, simply call close(). The session information can be erased by calling destroy().

During normal usage of (see Storing and Retrieving Values for details) you can read and write throughout the script or page. However, if close() has been called on a page, no data can be read from or written to the session cache after that point.

There is, however, some benefit to closing the session once you are done, rather than waiting for the page to finish execution and the session to be closed automatically. The biggest limitation of PHP is that only a single page can be reading from or writing to a single session. This means a user with multiple browsers or tabs open to a site will only be able to load data from one page at a time. Any other pages being requested that need session data will have to wait until the first page is complete. On most sites with fast-loading pages this may not be an issue, however if any pages take any significant amount of time to the load, users may notice the site will become unresponsive.

// If you are about to execute a time-intensive block of code and no longer need the seesion, close it
fSession::close();

Destroying

Finally, the destroy() method will completely erase all data from a session and destroy the session id, preventing it from being opened again. This method is most useful when a logged-in user logs out.

// If a user is logging out, remove the information you have stored about them
fSession::destroy();

Keeping Users Logged In

On most sites that have a user login system, it will often be desirable to provide an option for a user to stay logged in even after their browser closes. Obviously this can be a security issue, however many large websites control the functionality via a checkbox in the login form that is labelled Keep me logged in. This will usually keep a user logged in for a week or two.

To implement this is Flourish, the static method fSession::setLength() allows for an optional second parameter, $persistent_timespan, which enables persistent logins and sets their length. Whenever using this functionality please be sure to set a custom session file path.

fSession::setLength('30 minutes', '1 week');

This will not cause all users to stay logged in for a week. The session files will only be garbage collected after a week, but fSession uses a timestamp in the session superglobal to log normal sessions out after 30 minutes.

To enable a user to stay logged in for the whole $persistent_timespan and to stay logged in across browser restarts, the static method fSession::enablePersistence() must be called when they log in. Here is an example:

if ($login == 'test' && fCryptography::checkPasswordHash($password, $hash)) {
    fAuthorization::setUserToken('test');
    if (fRequest::get('keep_me_logged_in', 'boolean')) {
        fSession::enablePersistence();
    }
}

Please note that setLength() must be called before enablePersistence().

Storing and Retrieving Values

Now that we have discussed how to control the session, lets get into the heart of the matter, storing and retrieving values. There are two methods available to accomplish this task, set() and get().

The set() method takes two parameters, $key and $value. In a fairly straight-forward manner, $key specifies what identifier to save the $value under.

The default prefix is 'fSession::'. It is recommended that under normal use the prefix is not changed. A logical place to change the prefix would be for values specific to another class. For example, the fAuthorization class changes the prefix to that all authorization-related session data does not conflict with anything a developer may add.

Here are some examples of adding data to the session:

// This is equivalent to $_SESSION['fSession::current_user_id'] = 5;
fSession::set('current_user_id', 5);
fSession::set('last_viewed_article', 42);

// Using the prefix here could allow us to not worry about overwriting values
// This is equivalent to $_SESSION['forum::current_user_id'] = 2;
fSession::set('current_user_id', 2, 'forum::');

Hand-in-hand with the set() method is get(). get() allows retrieval of session values with a twist. The first parameter, $key specifies what value to retrieve. The second (optional) parameter is $default_value. This value will be returned if the requested $key has no value set. Here are some example of getting values out of the session:

$current_user_id = fSession::get('current_user_id');
$user_groups     = fSession::get('user_groups', array(1,2));

Deleting Values

If you wish to unset a session value, simply use the delete() method. It accepts the name of the $key and returns the value:

$name = fSession::delete('name');

An optional second parameter allows providing a $default_value to be returned if the key specified is not set.

$name = fSession::delete('name', 'No name specified');

To delete all keys for a specific prefix, use the clear() method:

// Clear the default fSession:: prefix
fSession::clear();

// Clear all keys that start with MyPrefix_
fSession::clear('MyPrefix_');

Adding and Removing Values

The static methods add() and remove() allow adding and removing values from arrays stored in the session. add() accepts a $key and the $value to add. If the key is not an array, an array will be created and the new value will be added.

// Add John Smith at the end of users
fSession::add('users', 'John Smith');

The new value will be added at the end of the array unless the optional third parameter, $beginning, is set to TRUE.

// Add Jane Smith at the beginning of users
fSession::add('users', 'Jane Smith', TRUE);

remove() accepts one parameter, the $key to remove a value from, and returns the removed value. The value will be removed from the end of the array unless the second optional parameter, $beginning, is set to TRUE.

$last_value  = fSession::remove('users');
$first_value = fSession::remove('users', TRUE);

Array Dereferencing

When a value stored in the session is an array, it is possible to use array dereference syntax in the element name to access a specific array key. This syntax works with set(), get(), delete(), add() and remove().

fSession::set(
    'user',
    array(
        'first_name' => 'John',
        'last_name'  => 'Smith'
    )
);
// This will echo John
echo fSession::get('user[first_name]');

Array dereferencing can be any number of layers deep.

echo fSession::get('user[groups][0][name]');