【问题标题】:Why Database cache errors in Codeigniter3?为什么 Codeigniter 3 中出现数据库缓存错误?
【发布时间】:2015-09-13 16:56:49
【问题描述】:

我正在使用 Codeigniter 3 进行开发,下面是数据库配置详细信息。我还启用了数据库会话,因此我可以将会话数据存储在数据库中。

这是我的数据库配置

$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
);

启用会话后,出现异常

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

我不知道这是什么原因,请帮忙。

【问题讨论】:

    标签: codeigniter codeigniter-3


    【解决方案1】:

    上述异常不是错误,而是框架中内置的 Codeigniter 3 安全功能。如果您检查 system/Session/drivers/Session_database_driver.php,您可以在代码中看到此异常以及其他一些异常。

    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';
        }
    

    异常的原因是因为您同时使用全局数据库缓存启用会话(存储在数据库中)。通过这样做,您的会话查询将保存到缓存中,从而构成安全风险。您可以通过使用本地数据库缓存来避免这种情况。

    有关如何使用本地数据库缓存的更多详细信息 - http://www.codeigniter.com/user_guide/database/caching.html?highlight=database%20cache

    作为一个好的做法,请确保在 application/cache(application/cache/db) 下创建一个文件夹调用 db 并将其用于数据库缓存,以将文件缓存与数据库缓存分开。

    如果您仍想保持数据库缓存全局,您可以使用 Redis 或 Memcache 作为会话驱动程序,这将避免数据库中的会话查询并解决您的问题 (http://www.codeigniter.com/user_guide/libraries/sessions.html?highlight=session%20class)。

    【讨论】:

      【解决方案2】:

      我通过更改 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();
          }
      }
      

      【讨论】:

        【解决方案3】:

        只需转到config/database.php 并设置$db['default']['pconnect'] = FALSE;

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-24
          • 1970-01-01
          • 1970-01-01
          • 2019-11-12
          • 1970-01-01
          • 2015-05-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多