Welcome Guest, Not a member yet? Register   Sign In
Fixing inefficient session handling
#1

[eluser]Unknown[/eluser]
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;

Code:
<?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 */

Code:
<?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 */
#2

[eluser]Yorick Peterse[/eluser]
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.
#3

[eluser]Wuushu[/eluser]
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.
#4

[eluser]Unknown[/eluser]
[quote author="Yorick Peterse" date="1244909023"]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.[/quote]

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
#5

[eluser]Yorick Peterse[/eluser]
[quote author="Gintaras Valatka" date="1244924527"][quote author="Yorick Peterse" date="1244909023"]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.[/quote]

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[/quote]

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.
#6

[eluser]Wuushu[/eluser]
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!
#7

[eluser]Xeoncross[/eluser]
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.
#8

[eluser]Xeoncross[/eluser]
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.

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

//... continue code




Theme © iAndrew 2016 - Forum software by © MyBB