1

I am using Codeigniter 3 for my development and below is the Database configuration details. I have also enabled database session, so I can store session data in the Database.

Here is my Database configuration

$active_group = 'default';
$query_builder = TRUE;

$db['default'] = array(
    'dsn'   => '',
    'hostname' => 'localhost',
    'username' => 'root',
    'password' => '',
    'database' => 'tel',
    'dbdriver' => 'mysqli',
    'dbprefix' => '',
    'pconnect' => FALSE,
    'db_debug' => TRUE,
    'cache_on' => TRUE,
    'cachedir' =>  '/application/cache',
    'char_set' => 'utf8',
    'dbcollat' => 'utf8_general_ci',
    'swap_pre' => '',
    'encrypt' => TRUE,
    'compress' => TRUE,
    'stricton' => FALSE,
    'failover' => array(),
    'save_queries' => TRUE
);

After enabling sessions, I get an exception

An uncaught Exception was encountered

Type: Exception

Message: Configured database connection has cache enabled. Aborting.

Filename: D:\My data\project\wamp\www\fertilize\system\libraries\Session\drivers\Session_database_driver.php

Line Number: 98

Backtrace:

File: D:\My data\project\wamp\www\fertilize\application\core\MY_Controller.php
Line: 11
Function: __construct

File: D:\My data\project\wamp\www\fertilize\application\libraries\Main_Controller.php

I am not sure what is the reason for this, please help.

2 Answers 2

3

Above exception is not an error but a Codeigniter 3 security feature built into the framework. If you check system/Session/drivers/Session_database_driver.php, you can see this exception in the code along with few other exceptions.

public function __construct(&$params)
{
    parent::__construct($params);

    $CI =& get_instance();
    isset($CI->db) OR $CI->load->database();
    $this->_db = $CI->db;

    if ( ! $this->_db instanceof CI_DB_query_builder)
    {
        throw new Exception('Query Builder not enabled for the configured database. Aborting.');
    }
    elseif ($this->_db->pconnect)
    {
        throw new Exception('Configured database connection is persistent. Aborting.');
    }
    elseif ($this->_db->cache_on)
    {
        throw new Exception('Configured database connection has cache enabled. Aborting.');
    }

    $db_driver = $this->_db->dbdriver.(empty($this->_db->subdriver) ? '' : '_'.$this->_db->subdriver);
    if (strpos($db_driver, 'mysql') !== FALSE)
    {
        $this->_platform = 'mysql';
    }
    elseif (in_array($db_driver, array('postgre', 'pdo_pgsql'), TRUE))
    {
        $this->_platform = 'postgre';
    }

The reason for the exception is since you are enabling sessions(stored in the database) at the same time using database caching globally. By doing this, your session queries will save to cache posing a security risk. You can avoid this by using local database caching.

for more details on how to use local db cache - http://www.codeigniter.com/user_guide/database/caching.html?highlight=database%20cache

As a good practice make sure to create a folder call db under application/cache(application/cache/db) and use it for database cache, to separate file cache from Database cache.

If you still want to keep database caching global, you can use Redis or Memcache as session driver which will avoid session queries in database and fix your problem (http://www.codeigniter.com/user_guide/libraries/sessions.html?highlight=session%20class).

Sign up to request clarification or add additional context in comments.

Comments

0

I solved by changing some code in Session_database_driver.php

    <?php

/**
 * CodeIgniter
 *
 * An open source application development framework for PHP
 *
 * This content is released under the MIT License (MIT)
 *
 * Copyright (c) 2014 - 2018, British Columbia Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @package CodeIgniter
 * @author  EllisLab Dev Team
 * @copyright   Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
 * @copyright   Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
 * @license http://opensource.org/licenses/MIT  MIT License
 * @link    https://codeigniter.com
 * @since   Version 3.0.0
 * @filesource
 */
defined('BASEPATH') or exit('No direct script access allowed');

/**
 * CodeIgniter Session Database Driver
 *
 * @package CodeIgniter
 * @subpackage  Libraries
 * @category    Sessions
 * @author  Andrey Andreev
 * @link    https://codeigniter.com/user_guide/libraries/sessions.html
 */
class CI_Session_database_driver extends CI_Session_driver implements SessionHandlerInterface
{

    /**
     * DB object
     *
     * @var object
     */
    protected $_db;

    /**
     * Row exists flag
     *
     * @var bool
     */
    protected $_row_exists = FALSE;

    /**
     * Lock "driver" flag
     *
     * @var string
     */
    protected $_platform;

    // ------------------------------------------------------------------------

    /**
     * Class constructor
     *
     * @param   array   $params Configuration parameters
     * @return  void
     */
    public function __construct(&$params)
    {
        parent::__construct($params);

        $CI = &get_instance();
        isset($CI->db) or $CI->load->database();
        $this->_db = $CI->db;

        if (!$this->_db instanceof CI_DB_query_builder) {
            throw new Exception('Query Builder not enabled for the configured database. Aborting.');
        } elseif ($this->_db->pconnect) {
            throw new Exception('Configured database connection is persistent. Aborting.');
        } elseif ($this->_db->cache_on) {
            //20210908 - MP - Removed check on cache active. Managed to disabled cache just before running session queries, reactivating cache after that
            //throw new Exception('Configured database connection has cache enabled. Aborting.');
        }

        $db_driver = $this->_db->dbdriver . (empty($this->_db->subdriver) ? '' : '_' . $this->_db->subdriver);
        if (strpos($db_driver, 'mysql') !== FALSE) {
            $this->_platform = 'mysql';
        } elseif (in_array($db_driver, array('postgre', 'pdo_pgsql'), TRUE)) {
            $this->_platform = 'postgre';
        }

        // Note: BC work-around for the old 'sess_table_name' setting, should be removed in the future.
        if (!isset($this->_config['save_path']) && ($this->_config['save_path'] = config_item('sess_table_name'))) {
            log_message('debug', 'Session: "sess_save_path" is empty; using BC fallback to "sess_table_name".');
        }
    }

    // ------------------------------------------------------------------------

    /**
     * Open
     *
     * Initializes the database connection
     *
     * @param   string  $save_path  Table name
     * @param   string  $name       Session cookie name, unused
     * @return  bool
     */
    public function open($save_path, $name)
    {
        if (empty($this->_db->conn_id) && !$this->_db->db_connect()) {
            return $this->_fail();
        }

        return $this->_success;
    }

    // ------------------------------------------------------------------------

    /**
     * Read
     *
     * Reads session data and acquires a lock
     *
     * @param   string  $session_id Session ID
     * @return  string  Serialized session data
     */
    public function read($session_id)
    {
        if ($cache_enabled = $this->_db->cache_on) {

            $this->_db->cache_off();
        }
        if ($this->_get_lock($session_id) !== FALSE) {
            // Prevent previous QB calls from messing with our queries
            $this->_db->reset_query();

            // Needed by write() to detect session_regenerate_id() calls
            $this->_session_id = $session_id;

            $this->_db
                ->select('data')
                ->from($this->_config['save_path'])
                ->where('id', $session_id);

            if ($this->_config['match_ip']) {
                $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
            }

            if (!($result = $this->_db->get()) or ($result = $result->row()) === NULL) {
                // PHP7 will reuse the same SessionHandler object after
                // ID regeneration, so we need to explicitly set this to
                // FALSE instead of relying on the default ...
                $this->_row_exists = FALSE;
                $this->_fingerprint = md5('');

                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return '';
            }

            // PostgreSQL's variant of a BLOB datatype is Bytea, which is a
            // PITA to work with, so we use base64-encoded data in a TEXT
            // field instead.
            $result = ($this->_platform === 'postgre')
                ? base64_decode(rtrim($result->data))
                : $result->data;

            $this->_fingerprint = md5($result);
            $this->_row_exists = TRUE;
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return $result;
        }

        $this->_fingerprint = md5('');
        if ($cache_enabled) {
            $this->_db->cache_on();
        }
        return '';
    }

    // ------------------------------------------------------------------------

    /**
     * Write
     *
     * Writes (create / update) session data
     *
     * @param   string  $session_id Session ID
     * @param   string  $session_data   Serialized session data
     * @return  bool
     */
    public function write($session_id, $session_data)
    {
        if ($cache_enabled = $this->_db->cache_on) {
            $this->_db->cache_off();
        }
        // Prevent previous QB calls from messing with our queries
        $this->_db->reset_query();

        // Was the ID regenerated?
        if (isset($this->_session_id) && $session_id !== $this->_session_id) {
            if (!$this->_release_lock() or !$this->_get_lock($session_id)) {
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return $this->_fail();
            }

            $this->_row_exists = FALSE;
            $this->_session_id = $session_id;
        } elseif ($this->_lock === FALSE) {
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return $this->_fail();
        }

        if ($this->_row_exists === FALSE) {
            $insert_data = array(
                'id' => $session_id,
                'ip_address' => $_SERVER['REMOTE_ADDR'],
                'timestamp' => time(),
                'data' => ($this->_platform === 'postgre' ? base64_encode($session_data) : $session_data)
            );

            if ($this->_db->insert($this->_config['save_path'], $insert_data)) {
                $this->_fingerprint = md5($session_data);
                $this->_row_exists = TRUE;
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return $this->_success;
            }
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return $this->_fail();
        }

        $this->_db->where('id', $session_id);
        if ($this->_config['match_ip']) {
            $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
        }

        $update_data = array('timestamp' => time());
        if ($this->_fingerprint !== md5($session_data)) {
            $update_data['data'] = ($this->_platform === 'postgre')
                ? base64_encode($session_data)
                : $session_data;
        }

        if ($this->_db->update($this->_config['save_path'], $update_data)) {
            $this->_fingerprint = md5($session_data);
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return $this->_success;
        }
        if ($cache_enabled) {
            $this->_db->cache_on();
        }
        return $this->_fail();
    }

    // ------------------------------------------------------------------------

    /**
     * Close
     *
     * Releases locks
     *
     * @return  bool
     */
    public function close()
    {
        return ($this->_lock && !$this->_release_lock())
            ? $this->_fail()
            : $this->_success;
    }

    // ------------------------------------------------------------------------

    /**
     * Destroy
     *
     * Destroys the current session.
     *
     * @param   string  $session_id Session ID
     * @return  bool
     */
    public function destroy($session_id)
    {
        if ($cache_enabled = $this->_db->cache_on) {
            $this->_db->cache_off();
        }
        if ($this->_lock) {
            // Prevent previous QB calls from messing with our queries
            $this->_db->reset_query();

            $this->_db->where('id', $session_id);
            if ($this->_config['match_ip']) {
                $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
            }

            if (!$this->_db->delete($this->_config['save_path'])) {
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return $this->_fail();
            }
        }

        if ($this->close() === $this->_success) {
            $this->_cookie_destroy();
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return $this->_success;
        }
        if ($cache_enabled) {
            $this->_db->cache_on();
        }
        return $this->_fail();
    }

    // ------------------------------------------------------------------------

    /**
     * Garbage Collector
     *
     * Deletes expired sessions
     *
     * @param   int     $maxlifetime    Maximum lifetime of sessions
     * @return  bool
     */
    public function gc($maxlifetime)
    {
        if ($cache_enabled = $this->_db->cache_on) {
            $this->_db->cache_off();
        }
        // Prevent previous QB calls from messing with our queries
        $this->_db->reset_query();
        $ret = $this->_db->delete($this->_config['save_path'], 'timestamp < ' . (time() - $maxlifetime));
        if ($cache_enabled) {
            $this->_db->cache_on();
        }
        return ($ret)
            ? $this->_success
            : $this->_fail();
    }

    // ------------------------------------------------------------------------

    /**
     * Get lock
     *
     * Acquires a lock, depending on the underlying platform.
     *
     * @param   string  $session_id Session ID
     * @return  bool
     */
    protected function _get_lock($session_id)
    {
        if ($cache_enabled = $this->_db->cache_on) {
            $this->_db->cache_off();
        }
        if ($this->_platform === 'mysql') {
            $arg = md5($session_id . ($this->_config['match_ip'] ? '_' . $_SERVER['REMOTE_ADDR'] : ''));
            if ($this->_db->query("SELECT GET_LOCK('" . $arg . "', 300) AS ci_session_lock")->row()->ci_session_lock) {
                $this->_lock = $arg;
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return TRUE;
            }
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return FALSE;
        } elseif ($this->_platform === 'postgre') {
            $arg = "hashtext('" . $session_id . "')" . ($this->_config['match_ip'] ? ", hashtext('" . $_SERVER['REMOTE_ADDR'] . "')" : '');
            if ($this->_db->simple_query('SELECT pg_advisory_lock(' . $arg . ')')) {
                $this->_lock = $arg;
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return TRUE;
            }
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return FALSE;
        }
        if ($cache_enabled) {
            $this->_db->cache_on();
        }
        return parent::_get_lock($session_id);
    }

    // ------------------------------------------------------------------------

    /**
     * Release lock
     *
     * Releases a previously acquired lock
     *
     * @return  bool
     */
    protected function _release_lock()
    {
        if (!$this->_lock) {
            return TRUE;
        }
        if ($cache_enabled = $this->_db->cache_on) {
            $this->_db->cache_off();
        }
        if ($this->_platform === 'mysql') {
            if ($this->_db->query("SELECT RELEASE_LOCK('" . $this->_lock . "') AS ci_session_lock")->row()->ci_session_lock) {
                $this->_lock = FALSE;
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return TRUE;
            }

            return FALSE;
        } elseif ($this->_platform === 'postgre') {
            if ($this->_db->simple_query('SELECT pg_advisory_unlock(' . $this->_lock . ')')) {
                $this->_lock = FALSE;
                if ($cache_enabled) {
                    $this->_db->cache_on();
                }
                return TRUE;
            }
            if ($cache_enabled) {
                $this->_db->cache_on();
            }
            return FALSE;
        }
        if ($cache_enabled) {
            $this->_db->cache_on();
        }
        return parent::_release_lock();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.