WP_Session: A Proposal

My first experience with WordPress was when a client asked me to hack apart the registration system to allow for simple custom referral links.  They wanted users to be placed at different user levels depending on the URL they used to sign up for an account.

My initial attempt was … atrocious   When a user hit a referral link, I used a hook to change the default user level, then changed it back after they registered.  The problems with this approach are so glaring, I won’t bother explaining them.  Seriously, it was a stupid idea.

My refined attempt tried to hack WordPress to add PHP session support.  The redefined user level was stored in the $_SESSION superglobal and pulled back out upon registration.  Less stupid, but still not very elegant.

The Problem with Sessions

Split Servers

I came to despise sessions the first time I worked with a distributed system.  Basically, the system was composed of two web servers positioned behind a load balancer.  Both web services pulled information from the same database.  When you requested the domain, the load balancer would forward your request to whichever server was under less of a load.  It was fast and efficient.  But we consistently had problems logging in.

The issue was that both webservers handled their sessions internally, and authentication was session based.  You could be logged in according to one server and be moving along just fine.  Then, on a subsequent request when the load balancer moved you to the other server, you were no longer logged in.

Queue months of headaches and debating session handling with the IT guys.

Validation

When you’re using a normal PHP $_SESSION, there’s a session cooking stored in your browser that gets sent with every request.  The server reads this cookie, finds the appropriate session file on the server, unserializes the data, and populates the superglobal.  Unfortunately, there’s no way to verify that you are actually the owner of the session.

The chances of someone guessing your session ID are miniscule, but possible.  All they’d need to do is spoof your session ID and voila, they’d have access to all of your session data as well.

Use Case in WordPress

I can hear you saying now, “so what?”  You’ll probably never want to use sessions in WordPress.  But I can think of a few situations where either $_SESSION is already being used or where it would be hugely useful.

Shopping Carts

Just about every quality shopping cart solution I’ve seen for WordPress uses sessions or some form of custom server-side data store based on them.  It’s important to keep the actual cart and purchase information on the server to protect it from tampering.

Per-User API Caching

Recently I built a project that requested large chunks of appointment information from a remote API.  This is somewhat sensitive data, requested over SSL to protect it from prying eyes, and specific to each user so it can’t be cached in a generic WordPress option.  Originally, I passed the API response through to a cookie so it would live in the user’s browser (the data needs to be presented across multiple pages).  However, cookies have a finite size and some larger responses were being lost.

Instead, I ended up creating a transient with a unique ID for every response and storing this unique ID in a cookie so WordPress could map cached data to the user later.  Wait, that sounds exactly like a PHP session …

A Proposal

I propose adding an object to WordPress.  Something that looks and feels a lot like $_SESSION to developers, but takes advantage of WordPress’ database model and caching systems.

Essentially, every visitor will be issued a session by something like wp_session_start().  This session will be identified by a key stored as a browser cookie.  It will also be validated against the visitor’s IP address (stored in the WP_Session instance itself).

Each WP_Session object will act as a key-value store (similar to $_SESSION):

// Start a session.  This can be called directly or hard-coded
// into WordPress' init functionality.
wp_session_start();

global $wp_session;
$wp_session['string'] = 'This is a string';
$wp_session['object'] = new stdClass();
$wp_session['array'] = array();

// Write out the session. Can be called directly or hard-coded
// into WordPress' shutdown functionality.
wp_session_commit();

Storage

The actual data in a WordPress session object will be stored in a short-lived transient.  The expiration date of the transient will be advanced every time the object is touched (either a read or a write) because it’s still active.  It will essentially just be a serialized associative array and can store just about anything WordPress needs ot to store.

The advantage of using transients (which are just WordPress options) is that they can be backed by memcached in certain optimized configurations.  Also, the session data will always be available where WordPress’ data is available since they both exist in the same place.

Thoughts?

Not everyone will have a use for sessions when developing with WordPress.  But having a standard, core object people can code against would be useful.  Is this something you could see yourself using?  When, where, and why?  Is this something that should be baked in to core to be available to all, or should it remain plugin territory?

Comments

  1. says

    Very interesting idea. Just a few thoughts:

    I’m not sure I see the value in baking an IP check into the API. I understand its use in helping to prevent session hijacking, but I think (if I understand the situation correctly) it would end up being more of an inconvenience to legitimate users than illegitimate ones. For example, if I were on a VPN for the first half of a transaction (e.g. adding items to a shopping cart) and not for the second half (e.g. checkout), if I understand correctly, the server would not recognize my cookie as a valid session identifier because of the mismatching IP addresses.

    I like the idea of making the API super easy to add/delete/edit data from, a la using an array. Would it make sense instead to use a singleton design pattern with a class that implements ArrayAccess and maybe Traversible? That would allow lots of behind-the-scenes wizardry to take place, such as allowing (if the developer so desires) changes to autosave to the database instead of committing changes at the end of the request.

    All in all a very cool idea. I can definitely see lots of useful applications. I’m not sure I see this as core material. It’s just way too niche a need. I doubt even a half of all installs would have a need for something like this. I’d certainly use it, though.

    • says

      I can see the hesitation with the IP check, though there are probably ways around that. I would argue that this would be a solid addition to core … I mean, how many people use the transient and filesystem APIs that are already there? I’m a big fan of standardization, and making something like this core material would definitely aid in adoption.

      • says

        Well, WordPress itself uses transients and FS APIs. Core doesn’t need a sessions API.

        IMO, what would make more sense in core than this is a robust dependency management solution for plugins and themes, like Scribu’s plugin (http://scribu.net/wordpress/plugin-dependencies). This, more than anything would make ‘library’ plugins much more practical and would make the question of core inclusion completely moot. In fact, there are probably some parts of core that could be *removed* if we had good dependency management.

  2. says

    Eric, while I haven’t had a need, yet, for using sessions, I can see the value of them. I think a pluin that works out all the kinks and then becomes popular among developers might then be considered for core.

    • says

      The problem with making this a separate plugin is in building wide adoption. How likely are end users to install both a plugin that needs these kind of sessions and this plugin? If a developer installs both to begin with, what’s the likelyhood of a user accidentally deleting one because they don’t know what it’s for?

      Just about everyone has their own way to handle plugin dependencies like this … and without a standard practice there, attempting to introduce a separate standard just gets messy.

      • says

        I agree, this is not something we want to leave to the end users. I never thought about some user deleting a plugin without knowing what it does, or why it’s there in the first place. But now that you bring it up, end users often do really silly things.

        Your comment about plugin dependencies not being handled in a standard way is something that needs to be addressed, whether or not sessions capabilities are added as a plugin or to core. @John P. Bloch makes a good point about this above.

        Whether introduced as a plugin, or added to core, the ability to utilize $_SESSION type of functionality would be very useful!

  3. mordauk says

    Really cool idea, Eric. I’d love to get behind this, especially as sessions are something I have to work with a lot.

    I can see this being build as a separate class that developers can simply include in their projects, then, if we’re lucky, it could get added to core.

    I’d be happy to help build it.

    • says

      I’ve got at all built in my head, actually. It’s just a matter of taking an hour or so to code it up. My plan (for now) is to build a class that could be readily included in WordPress, but bundle it in a quick plug-in as a proof of concept. It will definitely be up on GitHub so others can see it, poke at it, and decide how it needs to change.

      My ultimate goal is to get something like this in core … baby steps.

    • says

      Table-based sessions will handle the load balancing issue. But they won’t address the issue that arises when sessions are entirely disabled. Since WordPress doesn’t normally use sessions, many preconfigured WordPress installations lack session support at all. So building a custom session provider won’t work in those cases.

Leave a Reply