EllisLab text mark
Advanced Search
     
Fixing inefficient session handling
Posted: 12 June 2009 07:44 PM
Joined: 2008-02-29
3 posts

Example of session handling as of CI 1.7.1: http://ellislab.com/forums/viewthread/120044/

I am using CI sessions with database. The problem with CI sessions is that it writes to DB each time you call $this->session->set_userdata(‘item’, ‘value’) or $this->session->set_flashdata(‘item’, ‘value’) and it is not the behaviour you want or expect.

To fix it, I am going to extend the original Session class without breaking the existing system. It will use following methods:

$this->session->set(‘item’, ‘value’); (instead of set_userdata())
$this->session->get(‘item’); (instead of get_userdata()) *if used without ‘item’, it will return full session array
$this->session->rm(‘item’);  (instead of unset_userdata())

$this->session->setFlash(‘item’, ‘value’);
$this->session->getFlash(‘item’);
$this->session->keepFlash(‘item’);

Manual save of all session data in one go:

$this->session->save(TRUE); (if true is not passed, the session data will not be saved, you will understand why if you examine the code).

If you do not want to change your code, just rename the methods, to match the original names used in the session class.

#1 Download file gin_CI_Session.tar.gz and extract it your library folder;

#2 Add this line to /application/config/hooks.php:

$hook[‘post_controller’] = array(

  ‘class’=>‘SaveSession’,
  ‘function’=>‘save’,
  ‘filename’=>‘SaveSession.php’,
  ‘filepath’=>‘libraries’
);

#3 Enable hooks in /application/config/config.php:
    $config[‘enable_hooks’] = TRUE;

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * More efficient session handling
 * 
 * @package        CodeIgniter
 * @author        Gin - http://soho.lt, http://oldornot.com
 */
class MY_Session extends CI_Session
{
    
private $saveSession FALSE;

    
/**
     * Add or change data in the "userdata" array
     *
     * @access    public
     * @param     string|array
     * @return    void
     */
    
public function set($data = array(), $value '')
    
{
        
if (is_string($data)) $data = array($data => $value);

        if (
count($data) > 0):
        
            foreach (
$data as $key => $val):
            
                
$this->userdata[$key] $val;
                
            endforeach;
            
        
$this->saveSession TRUE;
        
        endif;
        
    
}
    
    
/**
     * Just a shorter version of $this->session->userdata('myData')
     * If no key suppled, will return full session array
     *
     * @access    public
     * @param    string
     * @return    string|array
     */
    
public function get($key '')
    
{
        
return ($key != '') ? $this->userdata($key) : $this->all_userdata();
    
}
    
    
/**
     * Removes data from the "userdata" array
     *
     * @access    public
     * @param    string|array $key
     * @return    void
     */
    
public function rm($key)
    
{
        
if (is_string($key)) $key = array($key => '');

        if(
count($keys) > 0):
        
            foreach (
$keys as $key => $val):

                unset(
$this->userdata[$key]);
            
            endforeach;
            
            
$this->saveSession TRUE;
            
        endif;
    
}
    
    
/**
     * Add or change flashdata, only available
     * until the next request
     *
     * @access    public
     * @param    mixed
     * @param    string
     * @return    void
     */
    
public function setFlash($data$value)
    
{
        
        
if (is_string($data)) $data = array($data => $value);

        if (
count($data) > 0)
        
{
            
foreach ($newdata as $key => $val)
            
{
                $flashdata_key 
$this->flashdata_key.':new:'.$key;
                
#$this->set_userdata($flashdata_key, $val);
            
}
            
        $this
->saveSession TRUE;
        
        
}

    }
    
    
/**
     * Fetch a specific flashdata item from the session array
     *
     * @access    public
     * @param    string
     * @return    string
     */
    
public function getFlash($key)
    
{
        $flashdata_key 
$this->flashdata_key.':old:'.$key;
        return 
$this->userdata($flashdata_key);
    
}
    
    
/**
     * Keeps existing flashdata available to next request.
     *
     * @access    public
     * @param    string
     * @return    void
     */
    
public function keepFlash($key)
    
{
        $old_flashdata_key 
$this->flashdata_key.':old:'.$key;
        
$value $this->userdata($old_flashdata_key);

        
$new_flashdata_key $this->flashdata_key.':new:'.$key;
        
#$this->set_userdata($new_flashdata_key, $value);
        
        
$this->saveSession TRUE;
    
}
    
    
/**
     * Saves session data if it has been changed
     * Call it directly $this->session->save(TRUE); or add as a hook
     *
     * @access    public
     * @param     bool
     * @return    void
     */
    
public function save($save FALSE)
    
{
        
if($save || $this->saveSession$this->sess_write();
    
}
}

// END MY_Session class

/* End of file My_Session.php */
/* Location: ./system/application/libraries/My_Session.php */ 
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * More efficient session handling
 *
 * This class is used by a 'hook' to save the session data.
 * You should not call $this->session->save() method directly from a hook
 * as it would create a new instance of session class...
 * ...(would consume memory, time, money and repeat SELECT query :)-
 * 
 * @package        CodeIgniter
 * @author        Gin - http://soho.lt, http://oldornot.com
 */
class SaveSession {

    
public function save()
    
{
        $CI 
=& get_instance();
        
$CI->session->save();
    
}
}

/* End of file SaveSession.php */
/* Location: ./system/application/libraries/SaveSession.php */ 
 Signature 


http://soho.lt/
http://oldornot.com/

 
Posted: 13 June 2009 08:03 AM   [ # 1 ]   [ Rating: 0 ]
Joined: 2009-05-02
553 posts

And why wouldn’t we want it to behave that way ? Why isn’t $this->session->set_userdata(‘item’, ‘value’) supposed to write the database ? It seems that you don’t understand the idea behind the session class.

 
Posted: 13 June 2009 08:20 AM   [ # 2 ]   [ Rating: 0 ]
Joined: 2007-12-09
104 posts

Because in large applications you might have 5 different libraries all on their own setting different session data on intervalls. As it happens you could then by chance get a pageview that has 5 different (in a row) calls to update session table. And this is not by poor application design. That is why if you could get those 5 calls into 1, would be great.

Thanks Gintaras.

 
Posted: 13 June 2009 12:22 PM   [ # 3 ]   [ Rating: 0 ]
Joined: 2008-02-29
3 posts
Yorick Peterse - 13 June 2009 12:03 PM

And why wouldn’t we want it to behave that way ? Why isn’t $this->session->set_userdata(‘item’, ‘value’) supposed to write the database ? It seems that you don’t understand the idea behind the session class.

Maybe this will convince you: example of CI session behavior from my other post

And this is just using one call $this->session->set_flashdata(‘item’, ‘value’);

What if you add 10 session vars ? What if you store session data in an encrypted cookie on the client side ? How fast can you go ?

wink

 Signature 


http://soho.lt/
http://oldornot.com/

 
Posted: 13 June 2009 04:47 PM   [ # 4 ]   [ Rating: 0 ]
Joined: 2009-05-02
553 posts
Gintaras Valatka - 13 June 2009 04:22 PM
Yorick Peterse - 13 June 2009 12:03 PM

And why wouldn’t we want it to behave that way ? Why isn’t $this->session->set_userdata(‘item’, ‘value’) supposed to write the database ? It seems that you don’t understand the idea behind the session class.

Maybe this will convince you: example of CI session behavior from my other post

And this is just using one call $this->session->set_flashdata(‘item’, ‘value’);

What if you add 10 session vars ? What if you store session data in an encrypted cookie on the client side ? How fast can you go ?

wink

I don’t store session data in the database so it isn’t a problem for me. Besides, the performance increase when using a cookie with your modified session class will most likely be very small.

 
Posted: 13 June 2009 04:50 PM   [ # 5 ]   [ Rating: 0 ]
Joined: 2007-12-09
104 posts

He meant this as an improvement for those using session with database, i believe he stated so in his original post. smile

“I am using CI sessions with database. The problem with CI sessions is that it writes to DB each time you call”

Thanks, I haven’t tried this yet but I might give it a go tonight!

 
Posted: 14 June 2009 10:27 PM   [ # 6 ]   [ Rating: 0 ]
Avatar
Joined: 2008-07-16
411 posts

1+ this.

I hate that the session lib keeps sending data back to the database for each new session item. I mean, I store most data in the DB - but all the keys and tokens HAVE to go in the session. 6 DB queries a page just for session data isn’t cool.

 Signature 

My Blog, C2D, PHP Videos, Résumé, Super .htaccess, Extra hooks, and MicroMVC

 
Posted: 14 June 2009 10:55 PM   [ # 7 ]   [ Rating: 0 ]
Avatar
Joined: 2008-07-16
411 posts

Actually, the reason that this probably isn’t implemented is that some pages end/redirect before the script finishes. i.e. you will have some PHP programmers complain when the session isn’t saved.

However, this is easily fixed by adding a force save method to the session lib right before a redirect or error.

if(something{
    $this
->session->save();
    
redirect();
}

//... continue code 
 Signature 

My Blog, C2D, PHP Videos, Résumé, Super .htaccess, Extra hooks, and MicroMVC