The personal blog of Ralph Broenink
One of the (pure PHP) ways PHP offers for saving user data across several pages are Sessions. They come in different flavours: at first, there’s the one that makes your URL ugly, but makes them usable for all users. Secondly you can use cookies. That’s much nicer, but doesn’t work for all browsers. Surf2me.nl uses the latter.
But what are sessions? It’s something like a cookies: a variable that belongs to a specific user. The disadventage of cookies is that they can be changed by the user and twenty variables is a bit too much to save at the user’s side. That’s why sessions are created by PHP. Sessions are nothing more or less then a set variables linked to a specific key, which is saved at the user’s side.
This may sound weird, but it isn’t. For example, the variable ‘username’ can be given the value ‘user’ and the variable ‘password’ the value ‘pass’. At the server, this is saved:
/tmp/session.abcdef1234567890.txt username = user password = pass
Now, at the user’s side, a cookies is created. (It is also possible to do this using GET- and POST-variables, but this creats URLS like index.php?PHPSESSID=abcdef1234567890, which is, in my opinion, not nice.) The cookies has this value:
PHPSESSID = abcdef1234567890
Now, PHP understands this is an indicator for a session and fills the super global $_SESSION with the session values.
<? echo $_SESSION['username'] . " - " . $_SESSION['password']; ?>
The previous code gives as result:
user – pass
In fact, I can’t think of any reason not to use sessions. Sessions are always available and can always be set. It doesn’t require cookies and the values aren’t adjustable or readable by users. It requires little attention from the developer and sessions are very powerful.
As noted before, sessions require little configuration. Especially the garbage collector of PHP isn’t easy to understand. The garbage collector, or gc, cleans the sessions after a while, since it isn’t required to keep all sessions in the memory.
Before we discuss this, first the configuration of Surf2me.nl. You can put this in an .htaccess file in the website root, but you can also use ini_set.
php_value session.save_path /.../sessions php_value session.cookie_lifetime 7200 php_flag session.use_cookies on php_flag session.use_only_cookies on php_flag session.auto_start on php_value session.name session php_value session.gc_maxlifetime 86400 php_value session.gc_probability 1 php_value session.gc_divisor 100
Of course, this aren’t all available variables, but it are the variables I need. I will discuss them below, but if you want more information, refer to the PHP Manual.
For the safe path, I don’t use /tmp, the default of PHP, but my own directory. At first, on a shared server it’s possible someone else can read all files in /tmp and therefore all session data. This way you protect your own session data from others. Of course this should be a folder which is readable by everyone (for example, a folder in public_html). Secondly, it is possible that different garabage collectors clean up your files.
Note that this path should be writable by PHP, so you most likely have to chmod that directory.
With this variable, you define how long the session cookie should stay on the remote computer. A value of zero tells the browser to remove the cookie if the browser is closed. Every other positive value is the number of seconds since the start of the session. I’m not sure, but the cookie won’t be lengthened automatically. To do this, I use this code:
setcookie(session_name(),session_id(),time()+7200,'/');
Very intuitive, if you want to use cookies, this is on.
This one is also very clear: if you only want to use cookies, this is on.
If this one is on, it isn’t necessary to start the session manual in every script. If this one is off, you have to put session_start() in every script that uses sessions. If this is on, this is implicitly placed in every script that uses a session.
This is the name of the session. It defaults to PHPSESSID, as used in the example above. Surf2me.nl uses ‘session’ as name, but you can use whatever you like.
The most confusion settings of the sessions are those of the Garbage Collector. The Garbage Collector (or GC) cleans your old session files and removes them. There are three settings important for the GC: session.gc_maxlifetime, session.gc_devisor and session.gc_probability.
To prevent that the GC will clean up everytime a page is generated (to be more precise, when a session is created), you can set session.gc_devisor and session.gc_probability. The chance the GC gets active is session.gc_probability out of session.gc_devisor.
So, if you want to get a visit of the GC every 1 out of 100 times, you set session.gc_probability = 1 and session.gc_devisor = 100. With these settings, the GC will give a visit every 100 times a page is generated. If you have a big site, you can decrease this value (to 1:1000 for example), because the GC will get active enough times.
The setting session.gc_maxlifetime defines the life span of a session. In other words, the minimum time a session exist. The time, in seconds, is calculated from the latest adjustment to the session file (in PHP <= 4.2.2 this is the latest access to the file). If this time has been exceeded, the GC is allowed to remove this file. To prevent the file to be removed to early, every time I read from the session, I adjust one variable.
One final note to maxlifetime: if you have two different GC’s on the same folder, the shortest maxlifetime will be effective. PHP can’t make any difference between two different maxlifetimes, so if a GC is initiated, it will use its own maxlifetime.
PHP fills the super global $_SESSION with all variables it can load when session_start() is executed (or the session handler is initiated if session.auto_start is on). If you want to change any variable, just use $_SESSION['name'] = 'value';.
One final note on security: it is possible for hijackers to act like another user, by copying the session name and value to its own computer. You can prevent such hijacking by saving the user IP in the session and checking if this value matches with the current user’s IP. If these don’t match, you don’t accept the session.
Note that this doesn’t work if an user is behind a NAT, because multiple users will have the same IP. You might also want to safe data like the user agent, but remember that this information is very easy to spoof.
However you should be able to trust all values in the $_SESSION super global, don’t! It is always possible that these are spoofed by someone with server access.
This item appeared earlier in Dutch on my previous blog.
This website is the personal weblog of Ralph Broenink. He studies Computer Science at the University of Twente and is lead software engineer at Antagonist webhosting. Furthermore, he was member of the board of study association Inter-Actief. More information about him can be found at the 'About me'-page.
Leave a reply