xaiborweb
xaiborweb

Reputation: 61

Error codeigniter generates multiple sessions for the same user

I'm a novice in this framework. But create a project with codeigniter 3.19 and Ion Auth 3 as a method of authentication and user registration.

on my local server xampp windows, it works perfectly generates a session for each user. But in my web linux ubuntu 16.04, vestacp, with cloudflare, I generate 10 sessions every 1 sg constantly having millions of session records and taking into account that I have very little traffic I assume it is an error that creates duplicate sessions for each user.

session capture in all fields ip_address gives me the ip of my server.

enter image description here web to verify the problem tvglu.net attached configurations, very grateful any help.

/application/config/config.php 

$config['sess_driver'] = 'database'; 
$config['sess_cookie_name'] = 'cisession'; 
$config['sess_expiration'] = 7200; 
$config['sess_save_path'] = 'ci_session'; 
$config['sess_match_ip'] = FALSE; 
$config['sess_time_to_update'] = 300; 
$config['sess_regenerate_destroy'] = FALSE; 

$config['cookie_prefix']    = 'cisession'; 
$config['cookie_domain']    = ''; 
$config['cookie_path']        = '/'; 
$config['cookie_secure']    = FALSE; 
$config['cookie_httponly']     = FALSE; 

$config['proxy_ips'] = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '';
/application/config/autoload.php 

$autoload['libraries'] = array('ion_auth'); 

tabla base de datos 

CREATE TABLE `ci_session` ( 
 `id` varchar(128) NOT NULL, 
 `ip_address` varchar(45) NOT NULL, 
 `timestamp` int(10) unsigned NOT NULL DEFAULT '0', 
 `data` blob NOT NULL, 
 PRIMARY KEY (`id`), 
 KEY `ci_sessions_timestamp` (`timestamp`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1

/application/libraries/Ion_auth.php 

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

class Ion_auth 
{ 
    /** 
     * account status ('not_activated', etc ...) 
     * 
     * @var string 
     **/ 
    protected $status; 

    /** 
     * extra where 
     * 
     * @var array 
     **/ 
    public $_extra_where = array(); 

    /** 
     * extra set 
     * 
     * @var array 
     **/ 
    public $_extra_set = array(); 

    /** 
     * caching of users and their groups 
     * 
     * @var array 
     **/ 
    public $_cache_user_in_group; 

    /** 
     * __construct 
     * 
     * @return void 
     * @author Ben 
     **/ 
    public function __construct() 
    { 
        $this->load->config('ion_auth', TRUE); 
        $this->load->library(array('email')); 
        $this->lang->load('ion_auth'); 
        $this->load->helper(array('cookie', 'language','url')); 

        $this->load->library('session'); 

        $this->load->model('ion_auth_model'); 

        $this->_cache_user_in_group =& $this->ion_auth_model->_cache_user_in_group; 

        //auto-login the user if they are remembered 
        if (!$this->logged_in() && get_cookie($this->config->item('identity_cookie_name', 'ion_auth')) && get_cookie($this->config->item('remember_cookie_name', 'ion_auth'))) 
        { 
            $this->ion_auth_model->login_remembered_user(); 
        } 

        $email_config = $this->config->item('email_config', 'ion_auth'); 

        if ($this->config->item('use_ci_email', 'ion_auth') && isset($email_config) && is_array($email_config)) 
        { 
            $this->email->initialize($email_config); 
        } 

        $this->ion_auth_model->trigger_events('library_constructor'); 
    } 

    /** 
     * __call 
     * 
     * Acts as a simple way to call model methods without loads of stupid alias' 
     * 
     **/ 
    public function __call($method, $arguments) 
    { 
        if (!method_exists( $this->ion_auth_model, $method) ) 
        { 
            throw new Exception('Undefined method Ion_auth::' . $method . '() called'); 
        } 
        if($method == 'create_user') 
        { 
            return call_user_func_array(array($this, 'register'), $arguments); 
        } 
        if($method=='update_user') 
        { 
            return call_user_func_array(array($this, 'update'), $arguments); 
        } 
        return call_user_func_array( array($this->ion_auth_model, $method), $arguments); 
    } 

    /** 
     * __get 
     * 
     * Enables the use of CI super-global without having to define an extra variable. 
     * 
     * I can't remember where I first saw this, so thank you if you are the original author. -Militis 
     * 
     * [MENTION=178865]Access[/MENTION]    public 
     * @param    $var 
     * @return    mixed 
     */ 
    public function __get($var) 
    { 
        return get_instance()->$var; 
    } 


    /** 
     * forgotten password feature 
     * 
     * @return mixed  boolian / array 
     * @author Mathew 
     **/ 
    public function forgotten_password($identity)    //changed $email to $identity 
    { 
        if ( $this->ion_auth_model->forgotten_password($identity) )   //changed 
        { 
            // Get user information 
            $user = $this->where($this->config->item('identity', 'ion_auth'), $identity)->where('active', 1)->users()->row();  //changed to get_user_by_identity from email 

            if ($user) 
            { 
                $data = array( 
                    'identity'        => $user->{$this->config->item('identity', 'ion_auth')}, 
                    'forgotten_password_code' => $user->forgotten_password_code 
                ); 

                if(!$this->config->item('use_ci_email', 'ion_auth')) 
                { 
                    $this->set_message('forgot_password_successful'); 
                    return $data; 
                } 
                else 
                { 
                    $message = $this->load->view($this->config->item('email_templates', 'ion_auth').$this->config->item('email_forgot_password', 'ion_auth'), $data, true); 
                    $this->email->clear(); 
                    $this->email->from($this->config->item('admin_email', 'ion_auth'), $this->config->item('site_title', 'ion_auth')); 
                    $this->email->to($user->email); 
                    $this->email->subject($this->config->item('site_title', 'ion_auth') . ' - ' . $this->lang->line('email_forgotten_password_subject')); 
                    $this->email->message($message); 

                    if ($this->email->send()) 
                    { 
                        $this->set_message('forgot_password_successful'); 
                        return TRUE; 
                    } 
                    else 
                    { 
                        $this->set_error('forgot_password_unsuccessful'); 
                        return FALSE; 
                    } 
                } 
            } 
            else 
            { 
                $this->set_error('forgot_password_unsuccessful'); 
                return FALSE; 
            } 
        } 
        else 
        { 
            $this->set_error('forgot_password_unsuccessful'); 
            return FALSE; 
        } 
    } 

    /** 
     * forgotten_password_complete 
     * 
     * @return void 
     * @author Mathew 
     **/ 
    public function forgotten_password_complete($code) 
    { 
        $this->ion_auth_model->trigger_events('pre_password_change'); 

        $identity = $this->config->item('identity', 'ion_auth'); 
        $profile  = $this->where('forgotten_password_code', $code)->users()->row(); //pass the code to profile 

        if (!$profile) 
        { 
            $this->ion_auth_model->trigger_events(array('post_password_change', 'password_change_unsuccessful')); 
            $this->set_error('password_change_unsuccessful'); 
            return FALSE; 
        } 

        $new_password = $this->ion_auth_model->forgotten_password_complete($code, $profile->salt); 

        if ($new_password) 
        { 
            $data = array( 
                'identity'     => $profile->{$identity}, 
                'new_password' => $new_password 
            ); 
            if(!$this->config->item('use_ci_email', 'ion_auth')) 
            { 
                $this->set_message('password_change_successful'); 
                $this->ion_auth_model->trigger_events(array('post_password_change', 'password_change_successful')); 
                    return $data; 
            } 
            else 
            { 
                $message = $this->load->view($this->config->item('email_templates', 'ion_auth').$this->config->item('email_forgot_password_complete', 'ion_auth'), $data, true); 

                $this->email->clear(); 
                $this->email->from($this->config->item('admin_email', 'ion_auth'), $this->config->item('site_title', 'ion_auth')); 
                $this->email->to($profile->email); 
                $this->email->subject($this->config->item('site_title', 'ion_auth') . ' - ' . $this->lang->line('email_new_password_subject')); 
                $this->email->message($message); 

                if ($this->email->send()) 
                { 
                    $this->set_message('password_change_successful'); 
                    $this->ion_auth_model->trigger_events(array('post_password_change', 'password_change_successful')); 
                    return TRUE; 
                } 
                else 
                { 
                    $this->set_error('password_change_unsuccessful'); 
                    $this->ion_auth_model->trigger_events(array('post_password_change', 'password_change_unsuccessful')); 
                    return FALSE; 
                } 

            } 
        } 

        $this->ion_auth_model->trigger_events(array('post_password_change', 'password_change_unsuccessful')); 
        return FALSE; 
    } 

    /** 
     * forgotten_password_check 
     * 
     * @return void 
     * @author Michael 
     **/ 
    public function forgotten_password_check($code) 
    { 
        $profile = $this->where('forgotten_password_code', $code)->users()->row(); //pass the code to profile 

        if (!is_object($profile)) 
        { 
            $this->set_error('password_change_unsuccessful'); 
            return FALSE; 
        } 
        else 
        { 
            if ($this->config->item('forgot_password_expiration', 'ion_auth') > 0) { 
                //Make sure it isn't expired 
                $expiration = $this->config->item('forgot_password_expiration', 'ion_auth'); 
                if (time() - $profile->forgotten_password_time > $expiration) { 
                    //it has expired 
                    $this->clear_forgotten_password_code($code); 
                    $this->set_error('password_change_unsuccessful'); 
                    return FALSE; 
                } 
            } 
            return $profile; 
        } 
    } 

    /** 
     * register 
     * 
     * @return void 
     * @author Mathew 
     **/ 
    public function register($username, $password, $email, $additional_data = array(), $group_ids = array()) //need to test email activation 
    { 
        $this->ion_auth_model->trigger_events('pre_account_creation'); 

        $email_activation = $this->config->item('email_activation', 'ion_auth'); 

        if (!$email_activation) 
        { 
            $id = $this->ion_auth_model->register($username, $password, $email, $additional_data, $group_ids); 
            if ($id !== FALSE) 
            { 
                $this->set_message('account_creation_successful'); 
                $this->ion_auth_model->trigger_events(array('post_account_creation', 'post_account_creation_successful')); 
                return $id; 
            } 
            else 
            { 
                $this->set_error('account_creation_unsuccessful'); 
                $this->ion_auth_model->trigger_events(array('post_account_creation', 'post_account_creation_unsuccessful')); 
                return FALSE; 
            } 
        } 
        else 
        { 
            $id = $this->ion_auth_model->register($username, $password, $email, $additional_data, $group_ids); 

            if (!$id) 
            { 
                $this->set_error('account_creation_unsuccessful'); 
                return FALSE; 
            } 

            $deactivate = $this->ion_auth_model->deactivate($id); 

            if (!$deactivate) 
            { 
                $this->set_error('deactivate_unsuccessful'); 
                $this->ion_auth_model->trigger_events(array('post_account_creation', 'post_account_creation_unsuccessful')); 
                return FALSE; 
            } 

            $activation_code = $this->ion_auth_model->activation_code; 
            $identity        = $this->config->item('identity', 'ion_auth'); 
            $user            = $this->ion_auth_model->user($id)->row(); 

            $data = array( 
                'identity'   => $user->{$identity}, 
                'id'         => $user->id, 
                'email'      => $email, 
                'activation' => $activation_code, 
            ); 
            if(!$this->config->item('use_ci_email', 'ion_auth')) 
            { 
                $this->ion_auth_model->trigger_events(array('post_account_creation', 'post_account_creation_successful', 'activation_email_successful')); 
                $this->set_message('activation_email_successful'); 
                    return $data; 
            } 
            else 
            { 
                $message = $this->load->view($this->config->item('email_templates', 'ion_auth').$this->config->item('email_activate', 'ion_auth'), $data, true); 

                $this->email->clear(); 
                $this->email->from($this->config->item('admin_email', 'ion_auth'), $this->config->item('site_title', 'ion_auth')); 
                $this->email->to($email); 
                $this->email->subject($this->config->item('site_title', 'ion_auth') . ' - ' . $this->lang->line('email_activation_subject')); 
                $this->email->message($message); 

                if ($this->email->send() == TRUE) 
                { 
                    $this->ion_auth_model->trigger_events(array('post_account_creation', 'post_account_creation_successful', 'activation_email_successful')); 
                    $this->set_message('activation_email_successful'); 
                    return $id; 
                } 

            } 

            $this->ion_auth_model->trigger_events(array('post_account_creation', 'post_account_creation_unsuccessful', 'activation_email_unsuccessful')); 
            $this->set_error('activation_email_unsuccessful'); 
            return FALSE; 
        } 
    } 

    /** 
     * logout 
     * 
     * @return void 
     * @author Mathew 
     **/ 
    public function logout() 
    { 
        $this->ion_auth_model->trigger_events('logout'); 

        $identity = $this->config->item('identity', 'ion_auth'); 
                $this->session->unset_userdata( array($identity => '', 'id' => '', 'user_id' => '') ); 

        //delete the remember me cookies if they exist 
        if (get_cookie($this->config->item('identity_cookie_name', 'ion_auth'))) 
        { 
            delete_cookie($this->config->item('identity_cookie_name', 'ion_auth')); 
        } 
        if (get_cookie($this->config->item('remember_cookie_name', 'ion_auth'))) 
        { 
            delete_cookie($this->config->item('remember_cookie_name', 'ion_auth')); 
        } 

        //Destroy the session 
        $this->session->sess_destroy(); 

        //Recreate the session 
        if (substr(CI_VERSION, 0, 1) == '2') 
        { 
            $this->session->sess_create(); 
        } 
        else 
        { 
            $this->session->sess_regenerate(TRUE); 
        } 

        $this->set_message('logout_successful'); 
        return TRUE; 
    } 

    /** 
     * logged_in 
     * 
     * @return bool 
     * @author Mathew 
     **/ 
    public function logged_in() 
    { 
        $this->ion_auth_model->trigger_events('logged_in'); 

        return (bool) $this->session->userdata('identity'); 
    } 

    /** 
     * logged_in 
     * 
     * @return integer 
     * @author jrmadsen67 
     **/ 
    public function get_user_id() 
    { 
        $user_id = $this->session->userdata('user_id'); 
        if (!empty($user_id)) 
        { 
            return $user_id; 
        } 
        return null; 
    } 


    /** 
     * is_admin 
     * 
     * @return bool 
     * @author Ben Edmunds 
     **/ 
    public function is_admin($id=false) 
    { 
        $this->ion_auth_model->trigger_events('is_admin'); 

        $admin_group = $this->config->item('admin_group', 'ion_auth'); 

        return $this->in_group($admin_group, $id); 
    } 

    /** 
     * in_group 
     * 
     * @param mixed group(s) to check 
     * @param bool user id 
     * @param bool check if all groups is present, or any of the groups 
     * 
     * @return bool 
     * @author Phil Sturgeon 
     **/ 
    public function in_group($check_group, $id=false, $check_all = false) 
    { 
        $this->ion_auth_model->trigger_events('in_group'); 

        $id || $id = $this->session->userdata('user_id'); 

        if (!is_array($check_group)) 
        { 
            $check_group = array($check_group); 
        } 

        if (isset($this->_cache_user_in_group[$id])) 
        { 
            $groups_array = $this->_cache_user_in_group[$id]; 
        } 
        else 
        { 
            $users_groups = $this->ion_auth_model->get_users_groups($id)->result(); 
            $groups_array = array(); 
            foreach ($users_groups as $group) 
            { 
                $groups_array[$group->id] = $group->name; 
            } 
            $this->_cache_user_in_group[$id] = $groups_array; 
        } 
        foreach ($check_group as $key => $value) 
        { 
            $groups = (is_string($value)) ? $groups_array : array_keys($groups_array); 

            /** 
             * if !all (default), in_array 
             * if all, !in_array 
             */ 
            if (in_array($value, $groups) xor $check_all) 
            { 
                /** 
                 * if !all (default), true 
                 * if all, false 
                 */ 
                return !$check_all; 
            } 
        } 
        /** 
         * if !all (default), false 
         * if all, true 
         */ 
        return $check_all; 
    } 
}

Upvotes: 1

Views: 330

Answers (1)

Javier Larroulet
Javier Larroulet

Reputation: 3237

I had a similar problem a couple months ago.

Since you are on cloudflare, which has multiple exit nodes that need to know constantly if your application is alive or not, you're probably getting hit with multiple health checks. If the health checks are directed to a part of your site that loads the session library, each health check will create an empty session (you can check... Most of the session rows in the table will have an empty data field)

Since you're autoloading ion auth and within it you're loading the session library in the constructor, this adds up.

There's ways around this: You may have Cloudflare point its health checks to some part of your site that doesn't use sessions. If that's an option, it's the easiest/cleanest fix and requires zero coding.

If you can't change where Cloudflare sends its checks, not all is lost. You can set an exception that doesn't autoload Ion and/or the session library for the specific controller/method where the health checks go. A good pointer on how to do that can be found here:

Codeigniter: Change autoload libraries for one controller?

If that isn't an option either and you cannot "protect" yourself from this, you may set up a simple housekeeping script that deletes empty sessions periodically. It's not optimal, but it helps

Upvotes: 1

Related Questions