CodeIgniter Forums

Full Version: RICK: Any solution yet, to get session expired on browser close?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2

El Forum

[eluser]mindprojects[/eluser]
I'm using CI,and my client now asked me to destroy the session,for security reasons, on browser close?
I have read a lot of posts.but no one is giving a good and a definitive answer.

I tried to play with config parameters with no luck at all!!!
Thanks

El Forum

[eluser]i_like_ponies[/eluser]
Don't think you can do that out of the box with CI. You'd have to override the Session library as you can see from the code below.

Code:
89         if ($this->sess_expiration == 0)
     90         {
     91             $this->sess_expiration = (60*60*24*365*2);
     92         }
...
    634     function _set_cookie($cookie_data = NULL)
    635     {
    636         if (is_null($cookie_data))
    637         {
    638             $cookie_data = $this->userdata;
    639         }
    640
    641         // Serialize the userdata for the cookie
    642         $cookie_data = $this->_serialize($cookie_data);
    643
    644         if ($this->sess_encrypt_cookie == TRUE)
    645         {
    646             $cookie_data = $this->CI->encrypt->encode($cookie_data);
    647         }
    648         else
    649         {
    650             // if encryption is not used, we provide an md5 hash to prevent userside tampering
    651             $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
    652         }
    653
    654         // Set the cookie
    655         setcookie(
    656                     $this->sess_cookie_name,
    657                     $cookie_data,
    658                     $this->sess_expiration + time(),
    659                     $this->cookie_path,
    660                     $this->cookie_domain,
    661                     0
    662                 );
    663     }

From the PHP manual:

Code:
bool setcookie  ( string $name  [, string $value  [, int $expire= 0  [, string $path  [, string $domain  [, bool $secure= false  [, bool $httponly= false  ]]]]]] )

expire

    The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch. In other words, you'll most likely set this with the time() function plus the number of seconds before you want it to expire. Or you might use mktime(). time()+60*60*24*30 will set the cookie to expire in 30 days. If set to 0, or omitted, the cookie will expire at the end of the session (when the browser closes).

        Note: You may notice the expire parameter takes on a Unix timestamp, as opposed to the date format Wdy, DD-Mon-YYYY HH:MM:SS GMT, this is because PHP does this conversion internally.
        expire is compared to the client's time which can differ from server's time.

So if you override that setcookie command you make it so it would expire the cookie at the end of the browser session (at least supposedly based on documentation).

El Forum

[eluser]drewbee[/eluser]
Exactly. You will need to extend the session class. I think its kind of weird that it assumes we want it set for a set amount of time.

Personally, for me, I've changed around the session class so much that you wouldn't even recognize the original CI Library. Thanks for pointing this out, it will be something I will be doing really soon.

I didn't like the fact that it made the assumption, and it was removed as i_like_ponies pointed out above.

Alas, it is easiest just to make a config option and go with that, so we don't mess with the session class too much. I am setting a configuration option that when TRUE, will follow code igniters current setup. We want to set a non-persistant cookie if we want it to expire at browser close.

In your config file add a new configuration option:
Code:
$config['sess_persistant_cookie']     = TRUE;

Update the base constructor to load the configuration value and set a default.

In your extended session library variable initialization:
find:
Code:
var $sess_expiration = 7200;

Replace with:

Code:
var $sess_expiration = 7200;
    var $sess_persistant_cookie = TRUE;

In the constructor, find:

Code:
// Set all the session preferences, which can either be set
        // manually via the $params array above or via the config file
        foreach (array (
                'sess_encrypt_cookie',
                'sess_use_database',
                'sess_table_name',
                'sess_expiration',
                'sess_match_ip',
                'sess_match_useragent',
                'sess_cookie_name',
                'cookie_path',
                'cookie_domain',
                'sess_time_to_update',
                'time_reference',
                'cookie_prefix',
                'encryption_key'
            ) as $key) {
            $this-> $key = (isset ($params[$key])) ? $params[$key] : $this->CI->config->item($key);
        }

Replace with:

Code:
// Set all the session preferences, which can either be set
        // manually via the $params array above or via the config file
        foreach (array (
                'sess_encrypt_cookie',
                'sess_use_database',
                'sess_table_name',
                'sess_expiration',
                'sess_persistant_cookie',
                'sess_match_ip',
                'sess_match_useragent',
                'sess_cookie_name',
                'cookie_path',
                'cookie_domain',
                'sess_time_to_update',
                'time_reference',
                'cookie_prefix',
                'encryption_key'
            ) as $key) {
            $this-> $key = (isset ($params[$key])) ? $params[$key] : $this->CI->config->item($key);
        }

Now in the function _set_cookie
find:
Code:
function _set_cookie($cookie_data = NULL) {
        if (is_null($cookie_data)) {
            $cookie_data = $this->userdata;
        }

        // Serialize the userdata for the cookie
        $cookie_data = $this->_serialize($cookie_data);

        if ($this->sess_encrypt_cookie == TRUE) {
            $cookie_data = $this->CI->encrypt->encode($cookie_data);
        } else {
            // if encryption is not used, we provide an md5 hash to prevent userside tampering
            $cookie_data = $cookie_data . md5($cookie_data . $this->encryption_key);
        }
        
        // Session or persistant cookie...
        
        // Set the cookie
        setcookie($this->sess_cookie_name, $cookie_data, $this->sess_expiration + time(), $this->cookie_path, $this->cookie_domain, 0);
    }

Replace with:

Code:
function _set_cookie($cookie_data = NULL) {
        if (is_null($cookie_data)) {
            $cookie_data = $this->userdata;
        }

        // Serialize the userdata for the cookie
        $cookie_data = $this->_serialize($cookie_data);

        if ($this->sess_encrypt_cookie == TRUE) {
            $cookie_data = $this->CI->encrypt->encode($cookie_data);
        } else {
            // if encryption is not used, we provide an md5 hash to prevent userside tampering
            $cookie_data = $cookie_data . md5($cookie_data . $this->encryption_key);
        }
        
        // Session or persistant cookie...
        
        
        $expiration = $this->sess_expiration + time();
        // We want the cookie to expire when browser session closes
        if ($this->sess_persistant_cookie == FALSE)
        {
            $expiration = 0;
        }
        // Set the cookie
        setcookie($this->sess_cookie_name, $cookie_data, $expiration, $this->cookie_path, $this->cookie_domain, 0);
    }

Simply set your new configuration option to FALSE to have it expire at session close. Enjoy Smile

I just implemented this in my code base and it works like a charm. If the configuration option is set to TRUE all works as normal.

El Forum

[eluser]mindprojects[/eluser]
Thanks guys it works like a charm....it was pretty new to me,that setting the cookie expiration time to zero,would make a cookie to expire on browser close.

I've created a library called MY_SESSION inside my application folder.It's perfect....!
Thanks a lot,i like when people a sharing such a knowledge.

Marco

El Forum

[eluser]mindprojects[/eluser]
Why they, from Ellislab, are not integrating such a config parameter,it's so easy and useful...

El Forum

[eluser]drewbee[/eluser]
Politics is one of the best answers to that Smile

IMO a lot of the classes are almost where they need to be, and just need slight modifications to help them fit a good portion of needs.

For instance, the upload class I think needs to have the ability to overwrite a file if it already exists instead of renaming it to another file name (but as a configuration option).

CI is growing and continuing to become an even better system. One of the biggest things right now is I think most of the ellislabs folks are completely wrapped up with EE at the moment. CI is simply on the back burner it seems.

El Forum

[eluser]littleram[/eluser]
Hey guys, thanks for all the info here. I incorporated the sess_persistent_cookie config variable and then realised that I needed a way of overriding it for individual sessions.

The rationale being that I want users who are logging in to be able to tick a "Remember me?" checkbox. Ticking the box should cause the cookie to be persisted across browser sessions. Not ticking it should cause the cookie to expire when the browser closes.

So I added a value called persistent_cookie which gets stored in the cookie itself. I also added a method - sess_persistent_cookie to be able to override this value at any point during execution.

I've attched my MY_Session class with this change as well as a fix for serializing Objects (see http://ellislab.com/forums/viewthread/95690/).

Enjoy.

El Forum

[eluser]nuwanda[/eluser]
This was bugging me, too, then I found this thread. But I suspected there had to be an easier solution.

I think there is.

The CI cookie helper allows you to set a cookie with duration 0, which kills the cookie when the browser closes. This acts as a true session indicator.

Why not simply create a cookie with duration=0 to kill the session, or duration=required_time_in_secs for a remember me option?

You check for the presence of the cookie next time to see if the user needs to be logged in based upon the data in the regular CI session cookie.

El Forum

[eluser]nottRobin[/eluser]
Thanks for all your help above. I've implemented my own solution to this from the code above, and it's pretty simple.

The Simplest Solution!

Just download my attached MY_Session.php file and place it in
Code:
system/application/libraries
Then add this line to system/application/config/config.php:
Code:
['sess_persistant_cookie']   = FALSE;

That's it!

-----------------------

Or if you already have a MY_Session.php file, you can edit it accordingly. Here's the contents of MY_Session:
Code:
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_Session extends CI_Session {
    private $sess_persistant_cookie = true;
    
    function __construct($params = array()) {
        // Run the parent's cookie
        parent::CI_Session($params);
        
        // Set the persistant cookie parameter:
        $this->sess_persistant_cookie = (isset($params['sess_persistant_cookie'])) ? $params['sess_persistant_cookie'] : $this->CI->config->item('sess_persistant_cookie');
    }
    
    /**
     * Write the session cookie
     *
     * @access    public
     * @return    void
     */
    /* Exact copy of the original function except where it says //=== new === */
    function _set_cookie($cookie_data = NULL) {
        if (is_null($cookie_data))
        {
            $cookie_data = $this->userdata;
        }

        // Serialize the userdata for the cookie
        $cookie_data = $this->_serialize($cookie_data);

        if ($this->sess_encrypt_cookie == TRUE)
        {
            $cookie_data = $this->CI->encrypt->encode($cookie_data);
        }
        else
        {
            // if encryption is not used, we provide an md5 hash to prevent userside tampering
            $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key);
        }
        
        //=== new ===
        // Session or persistant cookie...
        $expire = ($this->sess_persistant_cookie) ? $this->sess_expiration + time() : 0;
        
        // Set the cookie
        $ci =& get_instance();
        $ci->load->helper('cookie');
        set_cookie(array(
            'name'      => $this->sess_cookie_name,
            'value'     => $cookie_data,
            'expire'    => $expire,
            'domain'    => $this->cookie_domain,
            'path'      => $this->cookie_path
        ));
        //=== end new ===
    }
}

El Forum

[eluser]jordan314[/eluser]
Thanks to littleram for the "remember me" solution. I set my $config['sess_expiration'] to 604800 so that if remember me is checked it will remain open a week, but if it's not checked it will expire on browser exit.
Thanks!
Pages: 1 2