@madpilot rants

Cookie-less sessions in PHP

There is a fairly good chance that all but the most trivial dynamic sites will use sessions to emulate a stateful environment. Before the creation of sessions, the developer would have to manually pass all of the variables the next page needed via hidden input fields or cookies. As you can imagine, this is a bit of a security risk. Not to mention that cookies are limited to 4k each – if you have a large number of variables, this can quickly run out.

PHP, like most server languages can handle your sessions for you – but how does PHP keep track of sessions? There are two ways – using cookies and hidden fields. The former is the preferred way as it is easiest and is more secure (But not with out it’s risks. Check out the PHP session documentation for more info on the safe use of session variables). PHP writes a cookie which holds the PHPSESSID variable. It looks for this value when start_session() is called and if it exists, matches it to the stored session. But what happens when cookies aren’t available or are turned off? PHP is smart enough to work this out and will re-write all links and forms on the fly to ensure that the PHPSESSID is passed on every action that will refresh the page.

Well, almost. When I code, I prefer to postback to the same page, do some processing (such as error validation and storing of required session variables) and then use header(“Location: “) to re-direct the user. This makes coding much easier because all of the business logic for that page is kept in one file. Unfortunately, PHP isn’t smart enough to re-write these redirect, so we will have to help it out a bit.

append_sid

The following function will look at a URL (Whether it be relative or absolute) and append the SID if and only if PHP is in cookieless mode. I couldn’t find a PHP function that will tell you whether cookies are working, however after a bit of thought it was quite easy. PHP has a super-global called $_COOKIES. In this super-global, the PHPSESSID variable is referrenced. By checking whether it exists (After a call to session_start) we can work out whether we are in cookie or cookie-less mode:


function append_sid($link) {

    if(session_id() !== NULL && !isset($_COOKIE['PHPSESSID'])) {

        if(strpos($link, "?") === FALSE) {

            return $link . "?PHPSESSID=" . session_id();

        } else {

            return $link . "&PHPSESSID=" . session_id();

        }

    } else {

        return $link;

    }

}

Basically what happens, if the function checks to see if the session has been started – if it has, it then checks if the cookie entry exists. If it does, it just returns the link unchanged, otherwise it appends the session id. The inner most if statement checks for a ‘?’. If it exists, we can assume that the link already has some get parameters, so we will append the PHPSESSID using an ‘&’. Otherwise, just append it with a ‘?’.

JavaScript

Don’t forget that if you are re-directing client using javascript or using sessions when making AJAX calls you need to pass the session id as well. The best way to do that is client side, especically if you are generating parameters on the fly. The same theory applies, except we will use JavaScript this time:


function append_sid(link) {

    < ?php if(session_id() !== NULL && !isset($_COOKIE['PHPSESSID'])) { ?>

        var session_id = '< ?php echo session_id ?>';

            if(link.indexOf('?') == -1) {

                return link + '?PHPSESSID=' + session_id;

            } else {

                return link + '&PHPSESSID=' + session_id;

           }

    < ?php } else { ?>

        return link;

    < ?php } ?>

}

The reason there is PHP code interleaved (I know. I hate it too) is because we need to work out whether the session has actually been started and we need the session_id. However, we don’t want to display the session id UNLESS there is a requirement for it as it can be a security risk.

A caveat – passing session id by URL requires the session.session.use_trans_sid tio be set to 1. Most shared hosts turn this off, but you can usually override it by putting:

php_value session.use_trans_sid = 1 in the .htaccess file. You can also try the function:

ini_set('session.use_trans_sid', '1')

On every PHP page.

Now, hopefully, you won’t be cutting off those users that don’t use cookies!

10 comments

  1. awesome! - nice clear explanation thanks madpilot - i will be suing these methods myself.
  2. No problems! Glad you found it helpful.



    (I assume you mean using and that you aren't planning on starting a lawsuit agains PHP session :P)
  3. You were the solution to my problem! Thanks for publishing this explanation. I will definately NOT sue you for helping me out.
  4. I have amended it ever so slightly because of a problem I was having with the sessionid being blank:





    function append_sid($link) {

    if(session_id() !== '' && !isset($_COOKIE[’PHPSESSID’])) {

    if (strpos($link, '?') == FALSE) {

    return $link . '?PHPSESSID=' . session_id();

    } else {

    return $link . '&PHPSESSID=' . session_id();

    }

    } else {

    return $link;

    }

    }

  5. why you dont change the value in cake/libs/session.php for session.use_trans_sid param?



    mfg
  6. I didnt use cookie as its costly for normal wap user
  7. I don't like this solution because of the unnecessary 2 HTTP requests. You say you POST to the same page, do processing and then redirect. It wastes bandwidth.
  8. A redirect "wastes" a couple of hundred bytes of data. I can live with that.
  9. I've hit a wall trying to get cookieless sessions to work in php 5.3.3, they worked fine in 5.2.x, Do you know if anything has changed?
  10. Hi Nick,



    Sorry, don't know as I'm not using PHP anymore

Leave a comment