Initial commit
This commit is contained in:
256
system/libraries/Cache/Cache.php
Normal file
256
system/libraries/Cache/Cache.php
Normal file
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 2.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Caching Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache extends CI_Driver_Library {
|
||||
|
||||
/**
|
||||
* Valid cache drivers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $valid_drivers = array(
|
||||
'apc',
|
||||
'dummy',
|
||||
'file',
|
||||
'memcached',
|
||||
'redis',
|
||||
'wincache'
|
||||
);
|
||||
|
||||
/**
|
||||
* Path of cache files (if file-based cache)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_cache_path = NULL;
|
||||
|
||||
/**
|
||||
* Reference to the driver
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_adapter = 'dummy';
|
||||
|
||||
/**
|
||||
* Fallback driver
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_backup_driver = 'dummy';
|
||||
|
||||
/**
|
||||
* Cache key prefix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $key_prefix = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Initialize class properties based on the configuration array.
|
||||
*
|
||||
* @param array $config = array()
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
isset($config['adapter']) && $this->_adapter = $config['adapter'];
|
||||
isset($config['backup']) && $this->_backup_driver = $config['backup'];
|
||||
isset($config['key_prefix']) && $this->key_prefix = $config['key_prefix'];
|
||||
|
||||
// If the specified adapter isn't available, check the backup.
|
||||
if ( ! $this->is_supported($this->_adapter))
|
||||
{
|
||||
if ( ! $this->is_supported($this->_backup_driver))
|
||||
{
|
||||
// Backup isn't supported either. Default to 'Dummy' driver.
|
||||
log_message('error', 'Cache adapter "'.$this->_adapter.'" and backup "'.$this->_backup_driver.'" are both unavailable. Cache is now using "Dummy" adapter.');
|
||||
$this->_adapter = 'dummy';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backup is supported. Set it to primary.
|
||||
log_message('debug', 'Cache adapter "'.$this->_adapter.'" is unavailable. Falling back to "'.$this->_backup_driver.'" backup adapter.');
|
||||
$this->_adapter = $this->_backup_driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get
|
||||
*
|
||||
* Look for a value in the cache. If it exists, return the data
|
||||
* if not, return FALSE
|
||||
*
|
||||
* @param string $id
|
||||
* @return mixed value matching $id or FALSE on failure
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
return $this->{$this->_adapter}->get($this->key_prefix.$id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Save
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Cache TTL (in seconds)
|
||||
* @param bool $raw Whether to store the raw value
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl, $raw);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return $this->{$this->_adapter}->delete($this->key_prefix.$id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
return $this->{$this->_adapter}->increment($this->key_prefix.$id, $offset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
return $this->{$this->_adapter}->decrement($this->key_prefix.$id, $offset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the cache
|
||||
*
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return $this->{$this->_adapter}->clean();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* @param string $type = 'user' user/filehits
|
||||
* @return mixed array containing cache info on success OR FALSE on failure
|
||||
*/
|
||||
public function cache_info($type = 'user')
|
||||
{
|
||||
return $this->{$this->_adapter}->cache_info($type);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param string $id key to get cache metadata on
|
||||
* @return mixed cache item metadata
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
return $this->{$this->_adapter}->get_metadata($this->key_prefix.$id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is the requested driver supported in this environment?
|
||||
*
|
||||
* @param string $driver The driver to test
|
||||
* @return array
|
||||
*/
|
||||
public function is_supported($driver)
|
||||
{
|
||||
static $support;
|
||||
|
||||
if ( ! isset($support, $support[$driver]))
|
||||
{
|
||||
$support[$driver] = $this->{$driver}->is_supported();
|
||||
}
|
||||
|
||||
return $support[$driver];
|
||||
}
|
||||
}
|
218
system/libraries/Cache/drivers/Cache_apc.php
Normal file
218
system/libraries/Cache/drivers/Cache_apc.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 2.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter APC Caching Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_apc extends CI_Driver {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Only present so that an error message is logged
|
||||
* if APC is not available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( ! $this->is_supported())
|
||||
{
|
||||
log_message('error', 'Cache: Failed to initialize APC; extension not loaded/enabled?');
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get
|
||||
*
|
||||
* Look for a value in the cache. If it exists, return the data
|
||||
* if not, return FALSE
|
||||
*
|
||||
* @param string
|
||||
* @return mixed value that is stored/FALSE on failure
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$success = FALSE;
|
||||
$data = apc_fetch($id, $success);
|
||||
|
||||
return ($success === TRUE) ? $data : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Save
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Length of time (in seconds) to cache the data
|
||||
* @param bool $raw Whether to store the raw value (unused)
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
return apc_store($id, $data, (int) $ttl);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param mixed unique identifier of the item in the cache
|
||||
* @return bool true on success/false on failure
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return apc_delete($id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
return apc_inc($id, $offset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
return apc_dec($id, $offset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the cache
|
||||
*
|
||||
* @return bool false on failure/true on success
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return apc_clear_cache('user');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* @param string user/filehits
|
||||
* @return mixed array on success, false on failure
|
||||
*/
|
||||
public function cache_info($type = NULL)
|
||||
{
|
||||
return apc_cache_info($type);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param mixed key to get cache metadata on
|
||||
* @return mixed array on success/false on failure
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
$cache_info = apc_cache_info('user', FALSE);
|
||||
if (empty($cache_info) OR empty($cache_info['cache_list']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
foreach ($cache_info['cache_list'] as &$entry)
|
||||
{
|
||||
if ($entry['info'] !== $id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$success = FALSE;
|
||||
$metadata = array(
|
||||
'expire' => ($entry['ttl'] ? $entry['mtime'] + $entry['ttl'] : 0),
|
||||
'mtime' => $entry['ttl'],
|
||||
'data' => apc_fetch($id, $success)
|
||||
);
|
||||
|
||||
return ($success === TRUE) ? $metadata : FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* is_supported()
|
||||
*
|
||||
* Check to see if APC is available on this system, bail if it isn't.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return (extension_loaded('apc') && ini_get('apc.enabled'));
|
||||
}
|
||||
}
|
173
system/libraries/Cache/drivers/Cache_dummy.php
Normal file
173
system/libraries/Cache/drivers/Cache_dummy.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 2.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Dummy Caching Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_dummy extends CI_Driver {
|
||||
|
||||
/**
|
||||
* Get
|
||||
*
|
||||
* Since this is the dummy class, it's always going to return FALSE.
|
||||
*
|
||||
* @param string
|
||||
* @return bool FALSE
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Save
|
||||
*
|
||||
* @param string Unique Key
|
||||
* @param mixed Data to store
|
||||
* @param int Length of time (in seconds) to cache the data
|
||||
* @param bool Whether to store the raw value
|
||||
* @return bool TRUE, Simulating success
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param mixed unique identifier of the item in the cache
|
||||
* @return bool TRUE, simulating success
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the cache
|
||||
*
|
||||
* @return bool TRUE, simulating success
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* @param string user/filehits
|
||||
* @return bool FALSE
|
||||
*/
|
||||
public function cache_info($type = NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param mixed key to get cache metadata on
|
||||
* @return bool FALSE
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is this caching driver supported on the system?
|
||||
* Of course this one is.
|
||||
*
|
||||
* @return bool TRUE
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
287
system/libraries/Cache/drivers/Cache_file.php
Normal file
287
system/libraries/Cache/drivers/Cache_file.php
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 2.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter File Caching Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_file extends CI_Driver {
|
||||
|
||||
/**
|
||||
* Directory in which to save cache files
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_cache_path;
|
||||
|
||||
/**
|
||||
* Initialize file-based cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$CI =& get_instance();
|
||||
$CI->load->helper('file');
|
||||
$path = $CI->config->item('cache_path');
|
||||
$this->_cache_path = ($path === '') ? APPPATH.'cache/' : $path;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch from cache
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @return mixed Data on success, FALSE on failure
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$data = $this->_get($id);
|
||||
return is_array($data) ? $data['data'] : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Save into cache
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time to live in seconds
|
||||
* @param bool $raw Whether to store the raw value (unused)
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
$contents = array(
|
||||
'time' => time(),
|
||||
'ttl' => $ttl,
|
||||
'data' => $data
|
||||
);
|
||||
|
||||
if (write_file($this->_cache_path.$id, serialize($contents)))
|
||||
{
|
||||
chmod($this->_cache_path.$id, 0640);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param mixed unique identifier of item in cache
|
||||
* @return bool true on success/false on failure
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return is_file($this->_cache_path.$id) ? unlink($this->_cache_path.$id) : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return New value on success, FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
$data = $this->_get($id);
|
||||
|
||||
if ($data === FALSE)
|
||||
{
|
||||
$data = array('data' => 0, 'ttl' => 60);
|
||||
}
|
||||
elseif ( ! is_int($data['data']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$new_value = $data['data'] + $offset;
|
||||
return $this->save($id, $new_value, $data['ttl'])
|
||||
? $new_value
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return New value on success, FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
$data = $this->_get($id);
|
||||
|
||||
if ($data === FALSE)
|
||||
{
|
||||
$data = array('data' => 0, 'ttl' => 60);
|
||||
}
|
||||
elseif ( ! is_int($data['data']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$new_value = $data['data'] - $offset;
|
||||
return $this->save($id, $new_value, $data['ttl'])
|
||||
? $new_value
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the Cache
|
||||
*
|
||||
* @return bool false on failure/true on success
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return delete_files($this->_cache_path, FALSE, TRUE);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* Not supported by file-based caching
|
||||
*
|
||||
* @param string user/filehits
|
||||
* @return mixed FALSE
|
||||
*/
|
||||
public function cache_info($type = NULL)
|
||||
{
|
||||
return get_dir_file_info($this->_cache_path);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param mixed key to get cache metadata on
|
||||
* @return mixed FALSE on failure, array on success.
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
if ( ! is_file($this->_cache_path.$id))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$data = unserialize(file_get_contents($this->_cache_path.$id));
|
||||
|
||||
if (is_array($data))
|
||||
{
|
||||
$mtime = filemtime($this->_cache_path.$id);
|
||||
|
||||
if ( ! isset($data['ttl'], $data['time']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return array(
|
||||
'expire' => $data['time'] + $data['ttl'],
|
||||
'mtime' => $mtime
|
||||
);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is supported
|
||||
*
|
||||
* In the file driver, check to see that the cache directory is indeed writable
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return is_really_writable($this->_cache_path);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get all data
|
||||
*
|
||||
* Internal method to get all the relevant data about a cache item
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @return mixed Data array on success or FALSE on failure
|
||||
*/
|
||||
protected function _get($id)
|
||||
{
|
||||
if ( ! is_file($this->_cache_path.$id))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$data = unserialize(file_get_contents($this->_cache_path.$id));
|
||||
|
||||
if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl'])
|
||||
{
|
||||
file_exists($this->_cache_path.$id) && unlink($this->_cache_path.$id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
314
system/libraries/Cache/drivers/Cache_memcached.php
Normal file
314
system/libraries/Cache/drivers/Cache_memcached.php
Normal file
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 2.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Memcached Caching Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_memcached extends CI_Driver {
|
||||
|
||||
/**
|
||||
* Holds the memcached object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $_memcached;
|
||||
|
||||
/**
|
||||
* Memcached configuration
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_config = array(
|
||||
'default' => array(
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'weight' => 1
|
||||
)
|
||||
);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Setup Memcache(d)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Try to load memcached server info from the config file.
|
||||
$CI =& get_instance();
|
||||
$defaults = $this->_config['default'];
|
||||
|
||||
if ($CI->config->load('memcached', TRUE, TRUE))
|
||||
{
|
||||
$this->_config = $CI->config->config['memcached'];
|
||||
}
|
||||
|
||||
if (class_exists('Memcached', FALSE))
|
||||
{
|
||||
$this->_memcached = new Memcached();
|
||||
}
|
||||
elseif (class_exists('Memcache', FALSE))
|
||||
{
|
||||
$this->_memcached = new Memcache();
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', 'Cache: Failed to create Memcache(d) object; extension not loaded?');
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->_config as $cache_server)
|
||||
{
|
||||
isset($cache_server['hostname']) OR $cache_server['hostname'] = $defaults['host'];
|
||||
isset($cache_server['port']) OR $cache_server['port'] = $defaults['port'];
|
||||
isset($cache_server['weight']) OR $cache_server['weight'] = $defaults['weight'];
|
||||
|
||||
if ($this->_memcached instanceof Memcache)
|
||||
{
|
||||
// Third parameter is persistence and defaults to TRUE.
|
||||
$this->_memcached->addServer(
|
||||
$cache_server['hostname'],
|
||||
$cache_server['port'],
|
||||
TRUE,
|
||||
$cache_server['weight']
|
||||
);
|
||||
}
|
||||
elseif ($this->_memcached instanceof Memcached)
|
||||
{
|
||||
$this->_memcached->addServer(
|
||||
$cache_server['hostname'],
|
||||
$cache_server['port'],
|
||||
$cache_server['weight']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch from cache
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @return mixed Data on success, FALSE on failure
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$data = $this->_memcached->get($id);
|
||||
|
||||
return is_array($data) ? $data[0] : $data;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Save
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data being cached
|
||||
* @param int $ttl Time to live
|
||||
* @param bool $raw Whether to store the raw value
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
if ($raw !== TRUE)
|
||||
{
|
||||
$data = array($data, time(), $ttl);
|
||||
}
|
||||
|
||||
if ($this->_memcached instanceof Memcached)
|
||||
{
|
||||
return $this->_memcached->set($id, $data, $ttl);
|
||||
}
|
||||
elseif ($this->_memcached instanceof Memcache)
|
||||
{
|
||||
return $this->_memcached->set($id, $data, 0, $ttl);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param mixed $id key to be deleted.
|
||||
* @return bool true on success, false on failure
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return $this->_memcached->delete($id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
if (($result = $this->_memcached->increment($id, $offset)) === FALSE)
|
||||
{
|
||||
return $this->_memcached->add($id, $offset) ? $offset : FALSE;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
if (($result = $this->_memcached->decrement($id, $offset)) === FALSE)
|
||||
{
|
||||
return $this->_memcached->add($id, 0) ? 0 : FALSE;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the Cache
|
||||
*
|
||||
* @return bool false on failure/true on success
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return $this->_memcached->flush();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* @return mixed array on success, false on failure
|
||||
*/
|
||||
public function cache_info()
|
||||
{
|
||||
return $this->_memcached->getStats();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param mixed $id key to get cache metadata on
|
||||
* @return mixed FALSE on failure, array on success.
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
$stored = $this->_memcached->get($id);
|
||||
|
||||
if (count($stored) !== 3)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
list($data, $time, $ttl) = $stored;
|
||||
|
||||
return array(
|
||||
'expire' => $time + $ttl,
|
||||
'mtime' => $time,
|
||||
'data' => $data
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is supported
|
||||
*
|
||||
* Returns FALSE if memcached is not supported on the system.
|
||||
* If it is, we setup the memcached object & return TRUE
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return (extension_loaded('memcached') OR extension_loaded('memcache'));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class destructor
|
||||
*
|
||||
* Closes the connection to Memcache(d) if present.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->_memcached instanceof Memcache)
|
||||
{
|
||||
$this->_memcached->close();
|
||||
}
|
||||
elseif ($this->_memcached instanceof Memcached && method_exists($this->_memcached, 'quit'))
|
||||
{
|
||||
$this->_memcached->quit();
|
||||
}
|
||||
}
|
||||
}
|
348
system/libraries/Cache/drivers/Cache_redis.php
Normal file
348
system/libraries/Cache/drivers/Cache_redis.php
Normal file
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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 Redis Caching Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author Anton Lindqvist <anton@qvister.se>
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_redis extends CI_Driver
|
||||
{
|
||||
/**
|
||||
* Default config
|
||||
*
|
||||
* @static
|
||||
* @var array
|
||||
*/
|
||||
protected static $_default_config = array(
|
||||
'socket_type' => 'tcp',
|
||||
'host' => '127.0.0.1',
|
||||
'password' => NULL,
|
||||
'port' => 6379,
|
||||
'timeout' => 0
|
||||
);
|
||||
|
||||
/**
|
||||
* Redis connection
|
||||
*
|
||||
* @var Redis
|
||||
*/
|
||||
protected $_redis;
|
||||
|
||||
/**
|
||||
* An internal cache for storing keys of serialized values.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_serialized = array();
|
||||
|
||||
/**
|
||||
* del()/delete() method name depending on phpRedis version
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_delete_name;
|
||||
|
||||
/**
|
||||
* sRem()/sRemove() method name depending on phpRedis version
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $_sRemove_name;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Setup Redis
|
||||
*
|
||||
* Loads Redis config file if present. Will halt execution
|
||||
* if a Redis connection can't be established.
|
||||
*
|
||||
* @return void
|
||||
* @see Redis::connect()
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( ! $this->is_supported())
|
||||
{
|
||||
log_message('error', 'Cache: Failed to create Redis object; extension not loaded?');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset(static::$_delete_name, static::$_sRemove_name))
|
||||
{
|
||||
if (version_compare(phpversion('redis'), '5', '>='))
|
||||
{
|
||||
static::$_delete_name = 'del';
|
||||
static::$_sRemove_name = 'sRem';
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$_delete_name = 'delete';
|
||||
static::$_sRemove_name = 'sRemove';
|
||||
}
|
||||
}
|
||||
|
||||
$CI =& get_instance();
|
||||
|
||||
if ($CI->config->load('redis', TRUE, TRUE))
|
||||
{
|
||||
$config = array_merge(self::$_default_config, $CI->config->item('redis'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$config = self::$_default_config;
|
||||
}
|
||||
|
||||
$this->_redis = new Redis();
|
||||
|
||||
try
|
||||
{
|
||||
if ($config['socket_type'] === 'unix')
|
||||
{
|
||||
$success = $this->_redis->connect($config['socket']);
|
||||
}
|
||||
else // tcp socket
|
||||
{
|
||||
$success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']);
|
||||
}
|
||||
|
||||
if ( ! $success)
|
||||
{
|
||||
log_message('error', 'Cache: Redis connection failed. Check your configuration.');
|
||||
}
|
||||
|
||||
if (isset($config['password']) && ! $this->_redis->auth($config['password']))
|
||||
{
|
||||
log_message('error', 'Cache: Redis authentication failed.');
|
||||
}
|
||||
}
|
||||
catch (RedisException $e)
|
||||
{
|
||||
log_message('error', 'Cache: Redis connection refused ('.$e->getMessage().')');
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get cache
|
||||
*
|
||||
* @param string $key Cache ID
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$value = $this->_redis->get($key);
|
||||
|
||||
if ($value !== FALSE && $this->_redis->sIsMember('_ci_redis_serialized', $key))
|
||||
{
|
||||
return unserialize($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Save cache
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to save
|
||||
* @param int $ttl Time to live in seconds
|
||||
* @param bool $raw Whether to store the raw value (unused)
|
||||
* @return bool TRUE on success, FALSE on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
if (is_array($data) OR is_object($data))
|
||||
{
|
||||
if ( ! $this->_redis->sIsMember('_ci_redis_serialized', $id) && ! $this->_redis->sAdd('_ci_redis_serialized', $id))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
isset($this->_serialized[$id]) OR $this->_serialized[$id] = TRUE;
|
||||
$data = serialize($data);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_redis->{static::$_sRemove_name}('_ci_redis_serialized', $id);
|
||||
}
|
||||
|
||||
return $this->_redis->set($id, $data, $ttl);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from cache
|
||||
*
|
||||
* @param string $key Cache key
|
||||
* @return bool
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
if ($this->_redis->{static::$_delete_name}($key) !== 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_redis->{static::$_sRemove_name}('_ci_redis_serialized', $key);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
return $this->_redis->incrBy($id, $offset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
return $this->_redis->decrBy($id, $offset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean cache
|
||||
*
|
||||
* @return bool
|
||||
* @see Redis::flushDB()
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return $this->_redis->flushDB();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get cache driver info
|
||||
*
|
||||
* @param string $type Not supported in Redis.
|
||||
* Only included in order to offer a
|
||||
* consistent cache API.
|
||||
* @return array
|
||||
* @see Redis::info()
|
||||
*/
|
||||
public function cache_info($type = NULL)
|
||||
{
|
||||
return $this->_redis->info();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get cache metadata
|
||||
*
|
||||
* @param string $key Cache key
|
||||
* @return array
|
||||
*/
|
||||
public function get_metadata($key)
|
||||
{
|
||||
$value = $this->get($key);
|
||||
|
||||
if ($value !== FALSE)
|
||||
{
|
||||
return array(
|
||||
'expire' => time() + $this->_redis->ttl($key),
|
||||
'data' => $value
|
||||
);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check if Redis driver is supported
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return extension_loaded('redis');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class destructor
|
||||
*
|
||||
* Closes the connection to Redis if present.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->_redis)
|
||||
{
|
||||
$this->_redis->close();
|
||||
}
|
||||
}
|
||||
}
|
218
system/libraries/Cache/drivers/Cache_wincache.php
Normal file
218
system/libraries/Cache/drivers/Cache_wincache.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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 Wincache Caching Class
|
||||
*
|
||||
* Read more about Wincache functions here:
|
||||
* https://www.php.net/manual/en/ref.wincache.php
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author Mike Murkovic
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_wincache extends CI_Driver {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Only present so that an error message is logged
|
||||
* if APC is not available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( ! $this->is_supported())
|
||||
{
|
||||
log_message('error', 'Cache: Failed to initialize Wincache; extension not loaded/enabled?');
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get
|
||||
*
|
||||
* Look for a value in the cache. If it exists, return the data,
|
||||
* if not, return FALSE
|
||||
*
|
||||
* @param string $id Cache Ide
|
||||
* @return mixed Value that is stored/FALSE on failure
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$success = FALSE;
|
||||
$data = wincache_ucache_get($id, $success);
|
||||
|
||||
// Success returned by reference from wincache_ucache_get()
|
||||
return ($success) ? $data : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Save
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time to live (in seconds)
|
||||
* @param bool $raw Whether to store the raw value (unused)
|
||||
* @return bool true on success/false on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
return wincache_ucache_set($id, $data, $ttl);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param mixed unique identifier of the item in the cache
|
||||
* @return bool true on success/false on failure
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return wincache_ucache_delete($id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
$success = FALSE;
|
||||
$value = wincache_ucache_inc($id, $offset, $success);
|
||||
|
||||
return ($success === TRUE) ? $value : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
$success = FALSE;
|
||||
$value = wincache_ucache_dec($id, $offset, $success);
|
||||
|
||||
return ($success === TRUE) ? $value : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the cache
|
||||
*
|
||||
* @return bool false on failure/true on success
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* @return mixed array on success, false on failure
|
||||
*/
|
||||
public function cache_info()
|
||||
{
|
||||
return wincache_ucache_info(TRUE);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param mixed key to get cache metadata on
|
||||
* @return mixed array on success/false on failure
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
if ($stored = wincache_ucache_info(FALSE, $id))
|
||||
{
|
||||
$age = $stored['ucache_entries'][1]['age_seconds'];
|
||||
$ttl = $stored['ucache_entries'][1]['ttl_seconds'];
|
||||
$hitcount = $stored['ucache_entries'][1]['hitcount'];
|
||||
|
||||
return array(
|
||||
'expire' => $ttl - $age,
|
||||
'hitcount' => $hitcount,
|
||||
'age' => $age,
|
||||
'ttl' => $ttl
|
||||
);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* is_supported()
|
||||
*
|
||||
* Check to see if WinCache is available on this system, bail if it isn't.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return (extension_loaded('wincache') && ini_get('wincache.ucenabled'));
|
||||
}
|
||||
}
|
11
system/libraries/Cache/drivers/index.html
Normal file
11
system/libraries/Cache/drivers/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
11
system/libraries/Cache/index.html
Normal file
11
system/libraries/Cache/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
547
system/libraries/Calendar.php
Normal file
547
system/libraries/Calendar.php
Normal file
File diff suppressed because it is too large
Load Diff
568
system/libraries/Cart.php
Normal file
568
system/libraries/Cart.php
Normal file
File diff suppressed because it is too large
Load Diff
343
system/libraries/Driver.php
Normal file
343
system/libraries/Driver.php
Normal file
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Driver Library Class
|
||||
*
|
||||
* This class enables you to create "Driver" libraries that add runtime ability
|
||||
* to extend the capabilities of a class via additional driver objects
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Driver_Library {
|
||||
|
||||
/**
|
||||
* Array of drivers that are available to use with the driver class
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $valid_drivers = array();
|
||||
|
||||
/**
|
||||
* Name of the current class - usually the driver class
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $lib_name;
|
||||
|
||||
/**
|
||||
* Get magic method
|
||||
*
|
||||
* The first time a child is used it won't exist, so we instantiate it
|
||||
* subsequents calls will go straight to the proper child.
|
||||
*
|
||||
* @param string Child class name
|
||||
* @return object Child class
|
||||
*/
|
||||
public function __get($child)
|
||||
{
|
||||
// Try to load the driver
|
||||
return $this->load_driver($child);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load driver
|
||||
*
|
||||
* Separate load_driver call to support explicit driver load by library or user
|
||||
*
|
||||
* @param string Driver name (w/o parent prefix)
|
||||
* @return object Child class
|
||||
*/
|
||||
public function load_driver($child)
|
||||
{
|
||||
// Get CodeIgniter instance and subclass prefix
|
||||
$prefix = config_item('subclass_prefix');
|
||||
|
||||
if ( ! isset($this->lib_name))
|
||||
{
|
||||
// Get library name without any prefix
|
||||
$this->lib_name = str_replace(array('CI_', $prefix), '', get_class($this));
|
||||
}
|
||||
|
||||
// The child will be prefixed with the parent lib
|
||||
$child_name = $this->lib_name.'_'.$child;
|
||||
|
||||
// See if requested child is a valid driver
|
||||
if ( ! in_array($child, $this->valid_drivers))
|
||||
{
|
||||
// The requested driver isn't valid!
|
||||
$msg = 'Invalid driver requested: '.$child_name;
|
||||
log_message('error', $msg);
|
||||
show_error($msg);
|
||||
}
|
||||
|
||||
// Get package paths and filename case variations to search
|
||||
$CI = get_instance();
|
||||
$paths = $CI->load->get_package_paths(TRUE);
|
||||
|
||||
// Is there an extension?
|
||||
$class_name = $prefix.$child_name;
|
||||
$found = class_exists($class_name, FALSE);
|
||||
if ( ! $found)
|
||||
{
|
||||
// Check for subclass file
|
||||
foreach ($paths as $path)
|
||||
{
|
||||
// Does the file exist?
|
||||
$file = $path.'libraries/'.$this->lib_name.'/drivers/'.$prefix.$child_name.'.php';
|
||||
if (file_exists($file))
|
||||
{
|
||||
// Yes - require base class from BASEPATH
|
||||
$basepath = BASEPATH.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php';
|
||||
if ( ! file_exists($basepath))
|
||||
{
|
||||
$msg = 'Unable to load the requested class: CI_'.$child_name;
|
||||
log_message('error', $msg);
|
||||
show_error($msg);
|
||||
}
|
||||
|
||||
// Include both sources and mark found
|
||||
include_once($basepath);
|
||||
include_once($file);
|
||||
$found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need to search for the class?
|
||||
if ( ! $found)
|
||||
{
|
||||
// Use standard class name
|
||||
$class_name = 'CI_'.$child_name;
|
||||
if ( ! class_exists($class_name, FALSE))
|
||||
{
|
||||
// Check package paths
|
||||
foreach ($paths as $path)
|
||||
{
|
||||
// Does the file exist?
|
||||
$file = $path.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php';
|
||||
if (file_exists($file))
|
||||
{
|
||||
// Include source
|
||||
include_once($file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Did we finally find the class?
|
||||
if ( ! class_exists($class_name, FALSE))
|
||||
{
|
||||
if (class_exists($child_name, FALSE))
|
||||
{
|
||||
$class_name = $child_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
$msg = 'Unable to load the requested driver: '.$class_name;
|
||||
log_message('error', $msg);
|
||||
show_error($msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate, decorate and add child
|
||||
$obj = new $class_name();
|
||||
$obj->decorate($this);
|
||||
$this->$child = $obj;
|
||||
return $this->$child;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CodeIgniter Driver Class
|
||||
*
|
||||
* This class enables you to create drivers for a Library based on the Driver Library.
|
||||
* It handles the drivers' access to the parent library
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author EllisLab Dev Team
|
||||
* @link
|
||||
*/
|
||||
class CI_Driver {
|
||||
|
||||
/**
|
||||
* Instance of the parent class
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $_parent;
|
||||
|
||||
/**
|
||||
* List of methods in the parent class
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_methods = array();
|
||||
|
||||
/**
|
||||
* List of properties in the parent class
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_properties = array();
|
||||
|
||||
/**
|
||||
* Array of methods and properties for the parent class(es)
|
||||
*
|
||||
* @static
|
||||
* @var array
|
||||
*/
|
||||
protected static $_reflections = array();
|
||||
|
||||
/**
|
||||
* Decorate
|
||||
*
|
||||
* Decorates the child with the parent driver lib's methods and properties
|
||||
*
|
||||
* @param object
|
||||
* @return void
|
||||
*/
|
||||
public function decorate($parent)
|
||||
{
|
||||
$this->_parent = $parent;
|
||||
|
||||
// Lock down attributes to what is defined in the class
|
||||
// and speed up references in magic methods
|
||||
|
||||
$class_name = get_class($parent);
|
||||
|
||||
if ( ! isset(self::$_reflections[$class_name]))
|
||||
{
|
||||
$r = new ReflectionObject($parent);
|
||||
|
||||
foreach ($r->getMethods() as $method)
|
||||
{
|
||||
if ($method->isPublic())
|
||||
{
|
||||
$this->_methods[] = $method->getName();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($r->getProperties() as $prop)
|
||||
{
|
||||
if ($prop->isPublic())
|
||||
{
|
||||
$this->_properties[] = $prop->getName();
|
||||
}
|
||||
}
|
||||
|
||||
self::$_reflections[$class_name] = array($this->_methods, $this->_properties);
|
||||
}
|
||||
else
|
||||
{
|
||||
list($this->_methods, $this->_properties) = self::$_reflections[$class_name];
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __call magic method
|
||||
*
|
||||
* Handles access to the parent driver library's methods
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $args = array())
|
||||
{
|
||||
if (in_array($method, $this->_methods))
|
||||
{
|
||||
return call_user_func_array(array($this->_parent, $method), $args);
|
||||
}
|
||||
|
||||
throw new BadMethodCallException('No such method: '.$method.'()');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __get magic method
|
||||
*
|
||||
* Handles reading of the parent driver library's properties
|
||||
*
|
||||
* @param string
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($var)
|
||||
{
|
||||
if (in_array($var, $this->_properties))
|
||||
{
|
||||
return $this->_parent->$var;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __set magic method
|
||||
*
|
||||
* Handles writing to the parent driver library's properties
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @return mixed
|
||||
*/
|
||||
public function __set($var, $val)
|
||||
{
|
||||
if (in_array($var, $this->_properties))
|
||||
{
|
||||
$this->_parent->$var = $val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2491
system/libraries/Email.php
Normal file
2491
system/libraries/Email.php
Normal file
File diff suppressed because it is too large
Load Diff
522
system/libraries/Encrypt.php
Normal file
522
system/libraries/Encrypt.php
Normal file
File diff suppressed because it is too large
Load Diff
942
system/libraries/Encryption.php
Normal file
942
system/libraries/Encryption.php
Normal file
File diff suppressed because it is too large
Load Diff
1599
system/libraries/Form_validation.php
Normal file
1599
system/libraries/Form_validation.php
Normal file
File diff suppressed because it is too large
Load Diff
668
system/libraries/Ftp.php
Normal file
668
system/libraries/Ftp.php
Normal file
File diff suppressed because it is too large
Load Diff
1843
system/libraries/Image_lib.php
Normal file
1843
system/libraries/Image_lib.php
Normal file
File diff suppressed because it is too large
Load Diff
857
system/libraries/Javascript.php
Normal file
857
system/libraries/Javascript.php
Normal file
File diff suppressed because it is too large
Load Diff
1077
system/libraries/Javascript/Jquery.php
Normal file
1077
system/libraries/Javascript/Jquery.php
Normal file
File diff suppressed because it is too large
Load Diff
11
system/libraries/Javascript/index.html
Normal file
11
system/libraries/Javascript/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
478
system/libraries/Migration.php
Normal file
478
system/libraries/Migration.php
Normal file
@@ -0,0 +1,478 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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');
|
||||
|
||||
/**
|
||||
* Migration Class
|
||||
*
|
||||
* All migrations should implement this, forces up() and down() and gives
|
||||
* access to the CI super-global.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author Reactor Engineers
|
||||
* @link
|
||||
*/
|
||||
class CI_Migration {
|
||||
|
||||
/**
|
||||
* Whether the library is enabled
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_migration_enabled = FALSE;
|
||||
|
||||
/**
|
||||
* Migration numbering type
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_migration_type = 'sequential';
|
||||
|
||||
/**
|
||||
* Path to migration classes
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_migration_path = NULL;
|
||||
|
||||
/**
|
||||
* Current migration version
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_migration_version = 0;
|
||||
|
||||
/**
|
||||
* Database table with migration info
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_migration_table = 'migrations';
|
||||
|
||||
/**
|
||||
* Whether to automatically run migrations
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_migration_auto_latest = FALSE;
|
||||
|
||||
/**
|
||||
* Migration basename regex
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_migration_regex;
|
||||
|
||||
/**
|
||||
* Error message
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_error_string = '';
|
||||
|
||||
/**
|
||||
* Initialize Migration Class
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
// Only run this constructor on main library load
|
||||
if ( ! in_array(get_class($this), array('CI_Migration', config_item('subclass_prefix').'Migration'), TRUE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($config as $key => $val)
|
||||
{
|
||||
$this->{'_'.$key} = $val;
|
||||
}
|
||||
|
||||
log_message('info', 'Migrations Class Initialized');
|
||||
|
||||
// Are they trying to use migrations while it is disabled?
|
||||
if ($this->_migration_enabled !== TRUE)
|
||||
{
|
||||
show_error('Migrations has been loaded but is disabled or set up incorrectly.');
|
||||
}
|
||||
|
||||
// If not set, set it
|
||||
$this->_migration_path !== '' OR $this->_migration_path = APPPATH.'migrations/';
|
||||
|
||||
// Add trailing slash if not set
|
||||
$this->_migration_path = rtrim($this->_migration_path, '/').'/';
|
||||
|
||||
// Load migration language
|
||||
$this->lang->load('migration');
|
||||
|
||||
// They'll probably be using dbforge
|
||||
$this->load->dbforge();
|
||||
|
||||
// Make sure the migration table name was set.
|
||||
if (empty($this->_migration_table))
|
||||
{
|
||||
show_error('Migrations configuration file (migration.php) must have "migration_table" set.');
|
||||
}
|
||||
|
||||
// Migration basename regex
|
||||
$this->_migration_regex = ($this->_migration_type === 'timestamp')
|
||||
? '/^\d{14}_(\w+)$/'
|
||||
: '/^\d{3}_(\w+)$/';
|
||||
|
||||
// Make sure a valid migration numbering type was set.
|
||||
if ( ! in_array($this->_migration_type, array('sequential', 'timestamp')))
|
||||
{
|
||||
show_error('An invalid migration numbering type was specified: '.$this->_migration_type);
|
||||
}
|
||||
|
||||
// If the migrations table is missing, make it
|
||||
if ( ! $this->db->table_exists($this->_migration_table))
|
||||
{
|
||||
$this->dbforge->add_field(array(
|
||||
'version' => array('type' => 'BIGINT', 'constraint' => 20),
|
||||
));
|
||||
|
||||
$this->dbforge->create_table($this->_migration_table, TRUE);
|
||||
|
||||
$this->db->insert($this->_migration_table, array('version' => 0));
|
||||
}
|
||||
|
||||
// Do we auto migrate to the latest migration?
|
||||
if ($this->_migration_auto_latest === TRUE && ! $this->latest())
|
||||
{
|
||||
show_error($this->error_string());
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Migrate to a schema version
|
||||
*
|
||||
* Calls each migration step required to get to the schema version of
|
||||
* choice
|
||||
*
|
||||
* @param string $target_version Target schema version
|
||||
* @return mixed TRUE if no migrations are found, current version string on success, FALSE on failure
|
||||
*/
|
||||
public function version($target_version)
|
||||
{
|
||||
// Note: We use strings, so that timestamp versions work on 32-bit systems
|
||||
$current_version = $this->_get_version();
|
||||
|
||||
if ($this->_migration_type === 'sequential')
|
||||
{
|
||||
$target_version = sprintf('%03d', $target_version);
|
||||
}
|
||||
else
|
||||
{
|
||||
$target_version = (string) $target_version;
|
||||
}
|
||||
|
||||
$migrations = $this->find_migrations();
|
||||
|
||||
if ($target_version > 0 && ! isset($migrations[$target_version]))
|
||||
{
|
||||
$this->_error_string = sprintf($this->lang->line('migration_not_found'), $target_version);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($target_version > $current_version)
|
||||
{
|
||||
$method = 'up';
|
||||
}
|
||||
elseif ($target_version < $current_version)
|
||||
{
|
||||
$method = 'down';
|
||||
// We need this so that migrations are applied in reverse order
|
||||
krsort($migrations);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Well, there's nothing to migrate then ...
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Validate all available migrations within our target range.
|
||||
//
|
||||
// Unfortunately, we'll have to use another loop to run them
|
||||
// in order to avoid leaving the procedure in a broken state.
|
||||
//
|
||||
// See https://github.com/bcit-ci/CodeIgniter/issues/4539
|
||||
$pending = array();
|
||||
foreach ($migrations as $number => $file)
|
||||
{
|
||||
// Ignore versions out of our range.
|
||||
//
|
||||
// Because we've previously sorted the $migrations array depending on the direction,
|
||||
// we can safely break the loop once we reach $target_version ...
|
||||
if ($method === 'up')
|
||||
{
|
||||
if ($number <= $current_version)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
elseif ($number > $target_version)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($number > $current_version)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
elseif ($number <= $target_version)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for sequence gaps
|
||||
if ($this->_migration_type === 'sequential')
|
||||
{
|
||||
if (isset($previous) && abs($number - $previous) > 1)
|
||||
{
|
||||
$this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$previous = $number;
|
||||
}
|
||||
|
||||
include_once($file);
|
||||
$class = 'Migration_'.ucfirst(strtolower($this->_get_migration_name(basename($file, '.php'))));
|
||||
|
||||
// Validate the migration file structure
|
||||
if ( ! class_exists($class, FALSE))
|
||||
{
|
||||
$this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class);
|
||||
return FALSE;
|
||||
}
|
||||
elseif ( ! method_exists($class, $method) OR ! (new ReflectionMethod($class, $method))->isPublic())
|
||||
{
|
||||
$this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$pending[$number] = array($class, $method);
|
||||
}
|
||||
|
||||
// Now just run the necessary migrations
|
||||
foreach ($pending as $number => $migration)
|
||||
{
|
||||
log_message('debug', 'Migrating '.$method.' from version '.$current_version.' to version '.$number);
|
||||
|
||||
$migration[0] = new $migration[0];
|
||||
call_user_func($migration);
|
||||
$current_version = $number;
|
||||
$this->_update_version($current_version);
|
||||
}
|
||||
|
||||
// This is necessary when moving down, since the the last migration applied
|
||||
// will be the down() method for the next migration up from the target
|
||||
if ($current_version <> $target_version)
|
||||
{
|
||||
$current_version = $target_version;
|
||||
$this->_update_version($current_version);
|
||||
}
|
||||
|
||||
log_message('debug', 'Finished migrating to '.$current_version);
|
||||
return $current_version;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets the schema to the latest migration
|
||||
*
|
||||
* @return mixed Current version string on success, FALSE on failure
|
||||
*/
|
||||
public function latest()
|
||||
{
|
||||
$migrations = $this->find_migrations();
|
||||
|
||||
if (empty($migrations))
|
||||
{
|
||||
$this->_error_string = $this->lang->line('migration_none_found');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$last_migration = basename(end($migrations));
|
||||
|
||||
// Calculate the last migration step from existing migration
|
||||
// filenames and proceed to the standard version migration
|
||||
return $this->version($this->_get_migration_number($last_migration));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets the schema to the migration version set in config
|
||||
*
|
||||
* @return mixed TRUE if no migrations are found, current version string on success, FALSE on failure
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->version($this->_migration_version);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Error string
|
||||
*
|
||||
* @return string Error message returned as a string
|
||||
*/
|
||||
public function error_string()
|
||||
{
|
||||
return $this->_error_string;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieves list of available migration scripts
|
||||
*
|
||||
* @return array list of migration file paths sorted by version
|
||||
*/
|
||||
public function find_migrations()
|
||||
{
|
||||
$migrations = array();
|
||||
|
||||
// Load all *_*.php files in the migrations path
|
||||
foreach (glob($this->_migration_path.'*_*.php') as $file)
|
||||
{
|
||||
$name = basename($file, '.php');
|
||||
|
||||
// Filter out non-migration files
|
||||
if (preg_match($this->_migration_regex, $name))
|
||||
{
|
||||
$number = $this->_get_migration_number($name);
|
||||
|
||||
// There cannot be duplicate migration numbers
|
||||
if (isset($migrations[$number]))
|
||||
{
|
||||
$this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $number);
|
||||
show_error($this->_error_string);
|
||||
}
|
||||
|
||||
$migrations[$number] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
ksort($migrations);
|
||||
return $migrations;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Extracts the migration number from a filename
|
||||
*
|
||||
* @param string $migration
|
||||
* @return string Numeric portion of a migration filename
|
||||
*/
|
||||
protected function _get_migration_number($migration)
|
||||
{
|
||||
return sscanf($migration, '%[0-9]+', $number)
|
||||
? $number : '0';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Extracts the migration class name from a filename
|
||||
*
|
||||
* @param string $migration
|
||||
* @return string text portion of a migration filename
|
||||
*/
|
||||
protected function _get_migration_name($migration)
|
||||
{
|
||||
$parts = explode('_', $migration);
|
||||
array_shift($parts);
|
||||
return implode('_', $parts);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieves current schema version
|
||||
*
|
||||
* @return string Current migration version
|
||||
*/
|
||||
protected function _get_version()
|
||||
{
|
||||
$row = $this->db->select('version')->get($this->_migration_table)->row();
|
||||
return $row ? $row->version : '0';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Stores the current schema version
|
||||
*
|
||||
* @param string $migration Migration reached
|
||||
* @return void
|
||||
*/
|
||||
protected function _update_version($migration)
|
||||
{
|
||||
$this->db->update($this->_migration_table, array(
|
||||
'version' => $migration
|
||||
));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Enable the use of CI super-global
|
||||
*
|
||||
* @param string $var
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($var)
|
||||
{
|
||||
return get_instance()->$var;
|
||||
}
|
||||
|
||||
}
|
705
system/libraries/Pagination.php
Normal file
705
system/libraries/Pagination.php
Normal file
File diff suppressed because it is too large
Load Diff
249
system/libraries/Parser.php
Normal file
249
system/libraries/Parser.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Parser Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Parser
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/userguide3/libraries/parser.html
|
||||
*/
|
||||
class CI_Parser {
|
||||
|
||||
/**
|
||||
* Left delimiter character for pseudo vars
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $l_delim = '{';
|
||||
|
||||
/**
|
||||
* Right delimiter character for pseudo vars
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $r_delim = '}';
|
||||
|
||||
/**
|
||||
* Reference to CodeIgniter instance
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->CI =& get_instance();
|
||||
log_message('info', 'Parser Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a template
|
||||
*
|
||||
* Parses pseudo-variables contained in the specified template view,
|
||||
* replacing them with the data in the second param
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @param bool
|
||||
* @return string
|
||||
*/
|
||||
public function parse($template, $data, $return = FALSE)
|
||||
{
|
||||
$template = $this->CI->load->view($template, $data, TRUE);
|
||||
|
||||
return $this->_parse($template, $data, $return);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a String
|
||||
*
|
||||
* Parses pseudo-variables contained in the specified string,
|
||||
* replacing them with the data in the second param
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @param bool
|
||||
* @return string
|
||||
*/
|
||||
public function parse_string($template, $data, $return = FALSE)
|
||||
{
|
||||
return $this->_parse($template, $data, $return);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a template
|
||||
*
|
||||
* Parses pseudo-variables contained in the specified template,
|
||||
* replacing them with the data in the second param
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @param bool
|
||||
* @return string
|
||||
*/
|
||||
protected function _parse($template, $data, $return = FALSE)
|
||||
{
|
||||
if ($template === '')
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$replace = array();
|
||||
foreach ($data as $key => $val)
|
||||
{
|
||||
$replace = array_merge(
|
||||
$replace,
|
||||
is_array($val)
|
||||
? $this->_parse_pair($key, $val, $template)
|
||||
: $this->_parse_single($key, (string) $val, $template)
|
||||
);
|
||||
}
|
||||
|
||||
unset($data);
|
||||
$template = strtr($template, $replace);
|
||||
|
||||
if ($return === FALSE)
|
||||
{
|
||||
$this->CI->output->append_output($template);
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the left/right variable delimiters
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function set_delimiters($l = '{', $r = '}')
|
||||
{
|
||||
$this->l_delim = $l;
|
||||
$this->r_delim = $r;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a single key/value
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _parse_single($key, $val, $string)
|
||||
{
|
||||
return array($this->l_delim.$key.$this->r_delim => (string) $val);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a tag pair
|
||||
*
|
||||
* Parses tag pairs: {some_tag} string... {/some_tag}
|
||||
*
|
||||
* @param string
|
||||
* @param array
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _parse_pair($variable, $data, $string)
|
||||
{
|
||||
$replace = array();
|
||||
preg_match_all(
|
||||
'#'.preg_quote($this->l_delim.$variable.$this->r_delim).'(.+?)'.preg_quote($this->l_delim.'/'.$variable.$this->r_delim).'#s',
|
||||
$string,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
foreach ($matches as $match)
|
||||
{
|
||||
$str = '';
|
||||
foreach ($data as $row)
|
||||
{
|
||||
$temp = array();
|
||||
foreach ($row as $key => $val)
|
||||
{
|
||||
if (is_array($val))
|
||||
{
|
||||
$pair = $this->_parse_pair($key, $val, $match[1]);
|
||||
if ( ! empty($pair))
|
||||
{
|
||||
$temp = array_merge($temp, $pair);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$temp[$this->l_delim.$key.$this->r_delim] = $val;
|
||||
}
|
||||
|
||||
$str .= strtr($match[1], $temp);
|
||||
}
|
||||
|
||||
$replace[$match[0]] = $str;
|
||||
}
|
||||
|
||||
return $replace;
|
||||
}
|
||||
|
||||
}
|
575
system/libraries/Profiler.php
Normal file
575
system/libraries/Profiler.php
Normal file
File diff suppressed because it is too large
Load Diff
60
system/libraries/Session/CI_Session_driver_interface.php
Normal file
60
system/libraries/Session/CI_Session_driver_interface.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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) 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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');
|
||||
|
||||
/**
|
||||
* CI_Session_driver_interface
|
||||
*
|
||||
* A compatibility typeless SessionHandlerInterface alias
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
interface CI_Session_driver_interface {
|
||||
|
||||
public function open($save_path, $name);
|
||||
public function close();
|
||||
public function read($session_id);
|
||||
public function write($session_id, $session_data);
|
||||
public function destroy($session_id);
|
||||
public function gc($maxlifetime);
|
||||
public function updateTimestamp($session_id, $data);
|
||||
public function validateId($session_id);
|
||||
}
|
98
system/libraries/Session/OldSessionWrapper.php
Normal file
98
system/libraries/Session/OldSessionWrapper.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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) 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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');
|
||||
|
||||
/**
|
||||
* OldSessionWrapper
|
||||
*
|
||||
* PHP 8 Session handler compatibility wrapper, pre-PHP8 version
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
class CI_SessionWrapper implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
|
||||
|
||||
protected $driver;
|
||||
|
||||
public function __construct(CI_Session_driver_interface $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
public function open($save_path, $name)
|
||||
{
|
||||
return $this->driver->open($save_path, $name);
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
return $this->driver->close();
|
||||
}
|
||||
|
||||
public function read($id)
|
||||
{
|
||||
return $this->driver->read($id);
|
||||
}
|
||||
|
||||
public function write($id, $data)
|
||||
{
|
||||
return $this->driver->write($id, $data);
|
||||
}
|
||||
|
||||
public function destroy($id)
|
||||
{
|
||||
return $this->driver->destroy($id);
|
||||
}
|
||||
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
return $this->driver->gc($maxlifetime);
|
||||
}
|
||||
|
||||
public function updateTimestamp($id, $data)
|
||||
{
|
||||
return $this->driver->updateTimestamp($id, $data);
|
||||
}
|
||||
|
||||
public function validateId($id)
|
||||
{
|
||||
return $this->driver->validateId($id);
|
||||
}
|
||||
}
|
100
system/libraries/Session/PHP8SessionWrapper.php
Normal file
100
system/libraries/Session/PHP8SessionWrapper.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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) 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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');
|
||||
|
||||
/**
|
||||
* PHP8SessionWrapper
|
||||
*
|
||||
* PHP 8 Session handler compatibility wrapper
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
class CI_SessionWrapper implements SessionHandlerInterface, SessionUpdateTimestampHandlerInterface {
|
||||
|
||||
protected CI_Session_driver_interface $driver;
|
||||
|
||||
public function __construct(CI_Session_driver_interface $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
public function open(string $save_path, string $name): bool
|
||||
{
|
||||
return $this->driver->open($save_path, $name);
|
||||
}
|
||||
|
||||
public function close(): bool
|
||||
{
|
||||
return $this->driver->close();
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function read(string $id): mixed
|
||||
{
|
||||
return $this->driver->read($id);
|
||||
}
|
||||
|
||||
public function write(string $id, string $data): bool
|
||||
{
|
||||
return $this->driver->write($id, $data);
|
||||
}
|
||||
|
||||
public function destroy(string $id): bool
|
||||
{
|
||||
return $this->driver->destroy($id);
|
||||
}
|
||||
|
||||
#[\ReturnTypeWillChange]
|
||||
public function gc(int $maxlifetime): mixed
|
||||
{
|
||||
return $this->driver->gc($maxlifetime);
|
||||
}
|
||||
|
||||
public function updateTimestamp(string $id, string$data): bool
|
||||
{
|
||||
return $this->driver->updateTimestamp($id, $data);
|
||||
}
|
||||
|
||||
public function validateId(string $id): bool
|
||||
{
|
||||
return $this->driver->validateId($id);
|
||||
}
|
||||
}
|
1032
system/libraries/Session/Session.php
Normal file
1032
system/libraries/Session/Session.php
Normal file
File diff suppressed because it is too large
Load Diff
60
system/libraries/Session/SessionHandlerInterface.php
Normal file
60
system/libraries/Session/SessionHandlerInterface.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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');
|
||||
|
||||
/**
|
||||
* SessionHandlerInterface
|
||||
*
|
||||
* PHP 5.4 compatibility interface
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
interface SessionHandlerInterface {
|
||||
|
||||
public function open($save_path, $name);
|
||||
public function close();
|
||||
public function read($session_id);
|
||||
public function write($session_id, $session_data);
|
||||
public function destroy($session_id);
|
||||
public function gc($maxlifetime);
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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');
|
||||
|
||||
/**
|
||||
* SessionUpdateTimestampHandlerInterface
|
||||
*
|
||||
* PHP 7 compatibility interface
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
interface SessionUpdateTimestampHandlerInterface {
|
||||
|
||||
public function updateTimestamp($session_id, $data);
|
||||
public function validateId($session_id);
|
||||
}
|
202
system/libraries/Session/Session_driver.php
Normal file
202
system/libraries/Session/Session_driver.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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 Driver Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
abstract class CI_Session_driver {
|
||||
|
||||
protected $_config;
|
||||
|
||||
/**
|
||||
* Data fingerprint
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_fingerprint;
|
||||
|
||||
/**
|
||||
* Lock placeholder
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_lock = FALSE;
|
||||
|
||||
/**
|
||||
* Read session ID
|
||||
*
|
||||
* Used to detect session_regenerate_id() calls because PHP only calls
|
||||
* write() after regenerating the ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_session_id;
|
||||
|
||||
/**
|
||||
* Success and failure return values
|
||||
*
|
||||
* Necessary due to a bug in all PHP 5 versions where return values
|
||||
* from userspace handlers are not handled properly. PHP 7 fixes the
|
||||
* bug, so we need to return different values depending on the version.
|
||||
*
|
||||
* @see https://wiki.php.net/rfc/session.user.return-value
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_success, $_failure;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(&$params)
|
||||
{
|
||||
$this->_config =& $params;
|
||||
|
||||
if (is_php('7'))
|
||||
{
|
||||
$this->_success = TRUE;
|
||||
$this->_failure = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_success = 0;
|
||||
$this->_failure = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* PHP 5.x validate ID
|
||||
*
|
||||
* Enforces session.use_strict_mode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function php5_validate_id()
|
||||
{
|
||||
if ($this->_success === 0 && isset($_COOKIE[$this->_config['cookie_name']]) && ! $this->validateId($_COOKIE[$this->_config['cookie_name']]))
|
||||
{
|
||||
unset($_COOKIE[$this->_config['cookie_name']]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cookie destroy
|
||||
*
|
||||
* Internal method to force removal of a cookie by the client
|
||||
* when session_destroy() is called.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _cookie_destroy()
|
||||
{
|
||||
if ( ! is_php('7.3'))
|
||||
{
|
||||
$header = 'Set-Cookie: '.$this->_config['cookie_name'].'=';
|
||||
$header .= '; Expires='.gmdate('D, d-M-Y H:i:s T', 1).'; Max-Age=-1';
|
||||
$header .= '; Path='.$this->_config['cookie_path'];
|
||||
$header .= ($this->_config['cookie_domain'] !== '' ? '; Domain='.$this->_config['cookie_domain'] : '');
|
||||
$header .= ($this->_config['cookie_secure'] ? '; Secure' : '').'; HttpOnly; SameSite='.$this->_config['cookie_samesite'];
|
||||
header($header);
|
||||
return;
|
||||
}
|
||||
|
||||
return setcookie(
|
||||
$this->_config['cookie_name'],
|
||||
'',
|
||||
array(
|
||||
'expires' => 1,
|
||||
'path' => $this->_config['cookie_path'],
|
||||
'domain' => $this->_config['cookie_domain'],
|
||||
'secure' => $this->_config['cookie_secure'],
|
||||
'httponly' => TRUE,
|
||||
'samesite' => $this->_config['cookie_samesite']
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get lock
|
||||
*
|
||||
* A dummy method allowing drivers with no locking functionality
|
||||
* (databases other than PostgreSQL and MySQL) to act as if they
|
||||
* do acquire a lock.
|
||||
*
|
||||
* @param string $session_id
|
||||
* @return bool
|
||||
*/
|
||||
protected function _get_lock($session_id)
|
||||
{
|
||||
$this->_lock = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Release lock
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _release_lock()
|
||||
{
|
||||
if ($this->_lock)
|
||||
{
|
||||
$this->_lock = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
471
system/libraries/Session/drivers/Session_database_driver.php
Normal file
471
system/libraries/Session/drivers/Session_database_driver.php
Normal file
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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/userguide3/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_database_driver extends CI_Session_driver implements CI_Session_driver_interface {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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->_failure;
|
||||
}
|
||||
|
||||
$this->php5_validate_id();
|
||||
|
||||
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 ($this->_get_lock($session_id) === FALSE)
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// 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('');
|
||||
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;
|
||||
return $result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$this->_row_exists = FALSE;
|
||||
$this->_session_id = $session_id;
|
||||
}
|
||||
elseif ($this->_lock === FALSE)
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
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;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$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);
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
return ($this->_lock && ! $this->_release_lock())
|
||||
? $this->_failure
|
||||
: $this->_success;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
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']))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->close() === $this->_success)
|
||||
{
|
||||
$this->_cookie_destroy();
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Garbage Collector
|
||||
*
|
||||
* Deletes expired sessions
|
||||
*
|
||||
* @param int $maxlifetime Maximum lifetime of sessions
|
||||
* @return bool
|
||||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
// Prevent previous QB calls from messing with our queries
|
||||
$this->_db->reset_query();
|
||||
|
||||
return ($this->_db->delete($this->_config['save_path'], 'timestamp < '.(time() - $maxlifetime)))
|
||||
? $this->_success
|
||||
: $this->_failure;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update Timestamp
|
||||
*
|
||||
* Update session timestamp without modifying data
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @param string $data Unknown & unused
|
||||
* @return bool
|
||||
*/
|
||||
public function updateTimestamp($id, $unknown)
|
||||
{
|
||||
// Prevent previous QB calls from messing with our queries
|
||||
$this->_db->reset_query();
|
||||
|
||||
$this->_db->where('id', $id);
|
||||
if ($this->_config['match_ip'])
|
||||
{
|
||||
$this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
|
||||
}
|
||||
|
||||
return (bool) $this->_db->update($this->_config['save_path'], array('timestamp' => time()));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function validateId($id)
|
||||
{
|
||||
// Prevent previous QB calls from messing with our queries
|
||||
$this->_db->reset_query();
|
||||
|
||||
$this->_db->select('1')->from($this->_config['save_path'])->where('id', $id);
|
||||
empty($this->_config['match_ip']) OR $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
|
||||
$result = $this->_db->get();
|
||||
empty($result) OR $result = $result->row();
|
||||
|
||||
return ! empty($result);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 ($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;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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 ($this->_platform === 'mysql')
|
||||
{
|
||||
if ($this->_db->query("SELECT RELEASE_LOCK('".$this->_lock."') AS ci_session_lock")->row()->ci_session_lock)
|
||||
{
|
||||
$this->_lock = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
elseif ($this->_platform === 'postgre')
|
||||
{
|
||||
if ($this->_db->simple_query('SELECT pg_advisory_unlock('.$this->_lock.')'))
|
||||
{
|
||||
$this->_lock = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return parent::_release_lock();
|
||||
}
|
||||
}
|
449
system/libraries/Session/drivers/Session_files_driver.php
Normal file
449
system/libraries/Session/drivers/Session_files_driver.php
Normal file
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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 Files Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_files_driver extends CI_Session_driver implements CI_Session_driver_interface {
|
||||
|
||||
/**
|
||||
* Save path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_save_path;
|
||||
|
||||
/**
|
||||
* File handle
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $_file_handle;
|
||||
|
||||
/**
|
||||
* File name
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $_file_path;
|
||||
|
||||
/**
|
||||
* File new flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_file_new;
|
||||
|
||||
/**
|
||||
* Validate SID regular expression
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_sid_regexp;
|
||||
|
||||
/**
|
||||
* mbstring.func_overload flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $func_overload;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(&$params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (isset($this->_config['save_path']))
|
||||
{
|
||||
$this->_config['save_path'] = rtrim($this->_config['save_path'], '/\\');
|
||||
ini_set('session.save_path', $this->_config['save_path']);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('debug', 'Session: "sess_save_path" is empty; using "session.save_path" value from php.ini.');
|
||||
$this->_config['save_path'] = rtrim(ini_get('session.save_path'), '/\\');
|
||||
}
|
||||
|
||||
$this->_sid_regexp = $this->_config['_sid_regexp'];
|
||||
|
||||
isset(self::$func_overload) OR self::$func_overload = ( ! is_php('8.0') && extension_loaded('mbstring') && @ini_get('mbstring.func_overload'));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open
|
||||
*
|
||||
* Sanitizes the save_path directory.
|
||||
*
|
||||
* @param string $save_path Path to session files' directory
|
||||
* @param string $name Session cookie name
|
||||
* @return bool
|
||||
*/
|
||||
public function open($save_path, $name)
|
||||
{
|
||||
if ( ! is_dir($save_path))
|
||||
{
|
||||
if ( ! mkdir($save_path, 0700, TRUE))
|
||||
{
|
||||
log_message('error', "Session: Configured save path '".$this->_config['save_path']."' is not a directory, doesn't exist or cannot be created.");
|
||||
return $this->_failure;
|
||||
}
|
||||
}
|
||||
elseif ( ! is_writable($save_path))
|
||||
{
|
||||
log_message('error', "Session: Configured save path '".$this->_config['save_path']."' is not writable by the PHP process.");
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$this->_config['save_path'] = $save_path;
|
||||
$this->_file_path = $this->_config['save_path'].DIRECTORY_SEPARATOR
|
||||
.$name // we'll use the session cookie name as a prefix to avoid collisions
|
||||
.($this->_config['match_ip'] ? md5($_SERVER['REMOTE_ADDR']) : '');
|
||||
|
||||
$this->php5_validate_id();
|
||||
|
||||
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)
|
||||
{
|
||||
// This might seem weird, but PHP 5.6 introduces session_reset(),
|
||||
// which re-reads session data
|
||||
if ($this->_file_handle === NULL)
|
||||
{
|
||||
$this->_file_new = ! file_exists($this->_file_path.$session_id);
|
||||
|
||||
if (($this->_file_handle = fopen($this->_file_path.$session_id, 'c+b')) === FALSE)
|
||||
{
|
||||
log_message('error', "Session: Unable to open file '".$this->_file_path.$session_id."'.");
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
if (flock($this->_file_handle, LOCK_EX) === FALSE)
|
||||
{
|
||||
log_message('error', "Session: Unable to obtain lock for file '".$this->_file_path.$session_id."'.");
|
||||
fclose($this->_file_handle);
|
||||
$this->_file_handle = NULL;
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// Needed by write() to detect session_regenerate_id() calls
|
||||
$this->_session_id = $session_id;
|
||||
|
||||
if ($this->_file_new)
|
||||
{
|
||||
chmod($this->_file_path.$session_id, 0600);
|
||||
$this->_fingerprint = md5('');
|
||||
return '';
|
||||
}
|
||||
|
||||
// Prevent possible data corruption
|
||||
// See https://github.com/bcit-ci/CodeIgniter/issues/5857
|
||||
clearstatcache(TRUE, $this->_file_path.$session_id);
|
||||
}
|
||||
// We shouldn't need this, but apparently we do ...
|
||||
// See https://github.com/bcit-ci/CodeIgniter/issues/4039
|
||||
elseif ($this->_file_handle === FALSE)
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
else
|
||||
{
|
||||
rewind($this->_file_handle);
|
||||
}
|
||||
|
||||
$session_data = '';
|
||||
for ($read = 0, $length = filesize($this->_file_path.$session_id); $read < $length; $read += self::strlen($buffer))
|
||||
{
|
||||
if (($buffer = fread($this->_file_handle, $length - $read)) === FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
$session_data .= $buffer;
|
||||
}
|
||||
|
||||
$this->_fingerprint = md5($session_data);
|
||||
return $session_data;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 the two IDs don't match, we have a session_regenerate_id() call
|
||||
// and we need to close the old handle and open a new one
|
||||
if ($session_id !== $this->_session_id && ($this->close() === $this->_failure OR $this->read($session_id) === $this->_failure))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
if ( ! is_resource($this->_file_handle))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
elseif ($this->_fingerprint === md5($session_data))
|
||||
{
|
||||
return ( ! $this->_file_new && ! touch($this->_file_path.$session_id))
|
||||
? $this->_failure
|
||||
: $this->_success;
|
||||
}
|
||||
|
||||
if ( ! $this->_file_new)
|
||||
{
|
||||
ftruncate($this->_file_handle, 0);
|
||||
rewind($this->_file_handle);
|
||||
}
|
||||
|
||||
if (($length = strlen($session_data)) > 0)
|
||||
{
|
||||
for ($written = 0; $written < $length; $written += $result)
|
||||
{
|
||||
if (($result = fwrite($this->_file_handle, substr($session_data, $written))) === FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! is_int($result))
|
||||
{
|
||||
$this->_fingerprint = md5(substr($session_data, 0, $written));
|
||||
log_message('error', 'Session: Unable to write data.');
|
||||
return $this->_failure;
|
||||
}
|
||||
}
|
||||
|
||||
$this->_fingerprint = md5($session_data);
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks and closes file descriptor.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (is_resource($this->_file_handle))
|
||||
{
|
||||
flock($this->_file_handle, LOCK_UN);
|
||||
fclose($this->_file_handle);
|
||||
|
||||
$this->_file_handle = $this->_file_new = $this->_session_id = NULL;
|
||||
}
|
||||
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
if ($this->close() === $this->_success)
|
||||
{
|
||||
if (file_exists($this->_file_path.$session_id))
|
||||
{
|
||||
$this->_cookie_destroy();
|
||||
return unlink($this->_file_path.$session_id)
|
||||
? $this->_success
|
||||
: $this->_failure;
|
||||
}
|
||||
|
||||
return $this->_success;
|
||||
}
|
||||
elseif ($this->_file_path !== NULL)
|
||||
{
|
||||
clearstatcache();
|
||||
if (file_exists($this->_file_path.$session_id))
|
||||
{
|
||||
$this->_cookie_destroy();
|
||||
return unlink($this->_file_path.$session_id)
|
||||
? $this->_success
|
||||
: $this->_failure;
|
||||
}
|
||||
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Garbage Collector
|
||||
*
|
||||
* Deletes expired sessions
|
||||
*
|
||||
* @param int $maxlifetime Maximum lifetime of sessions
|
||||
* @return bool
|
||||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
if ( ! is_dir($this->_config['save_path']) OR ($directory = opendir($this->_config['save_path'])) === FALSE)
|
||||
{
|
||||
log_message('debug', "Session: Garbage collector couldn't list files under directory '".$this->_config['save_path']."'.");
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$ts = time() - $maxlifetime;
|
||||
|
||||
$pattern = ($this->_config['match_ip'] === TRUE)
|
||||
? '[0-9a-f]{32}'
|
||||
: '';
|
||||
|
||||
$pattern = sprintf(
|
||||
'#\A%s'.$pattern.$this->_sid_regexp.'\z#',
|
||||
preg_quote($this->_config['cookie_name'])
|
||||
);
|
||||
|
||||
while (($file = readdir($directory)) !== FALSE)
|
||||
{
|
||||
// If the filename doesn't match this pattern, it's either not a session file or is not ours
|
||||
if ( ! preg_match($pattern, $file)
|
||||
OR ! is_file($this->_config['save_path'].DIRECTORY_SEPARATOR.$file)
|
||||
OR ($mtime = filemtime($this->_config['save_path'].DIRECTORY_SEPARATOR.$file)) === FALSE
|
||||
OR $mtime > $ts)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
unlink($this->_config['save_path'].DIRECTORY_SEPARATOR.$file);
|
||||
}
|
||||
|
||||
closedir($directory);
|
||||
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update Timestamp
|
||||
*
|
||||
* Update session timestamp without modifying data
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @param string $data Unknown & unused
|
||||
* @return bool
|
||||
*/
|
||||
public function updateTimestamp($id, $unknown)
|
||||
{
|
||||
return touch($this->_file_path.$id);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function validateId($id)
|
||||
{
|
||||
$result = is_file($this->_file_path.$id);
|
||||
clearstatcache(TRUE, $this->_file_path.$id);
|
||||
return $result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe strlen()
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
protected static function strlen($str)
|
||||
{
|
||||
return (self::$func_overload)
|
||||
? mb_strlen($str, '8bit')
|
||||
: strlen($str);
|
||||
}
|
||||
}
|
414
system/libraries/Session/drivers/Session_memcached_driver.php
Normal file
414
system/libraries/Session/drivers/Session_memcached_driver.php
Normal file
@@ -0,0 +1,414 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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 Memcached Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_memcached_driver extends CI_Session_driver implements CI_Session_driver_interface {
|
||||
|
||||
/**
|
||||
* Memcached instance
|
||||
*
|
||||
* @var Memcached
|
||||
*/
|
||||
protected $_memcached;
|
||||
|
||||
/**
|
||||
* Key prefix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_key_prefix = 'ci_session:';
|
||||
|
||||
/**
|
||||
* Lock key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_lock_key;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(&$params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (empty($this->_config['save_path']))
|
||||
{
|
||||
log_message('error', 'Session: No Memcached save path configured.');
|
||||
}
|
||||
|
||||
if ($this->_config['match_ip'] === TRUE)
|
||||
{
|
||||
$this->_key_prefix .= $_SERVER['REMOTE_ADDR'].':';
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open
|
||||
*
|
||||
* Sanitizes save_path and initializes connections.
|
||||
*
|
||||
* @param string $save_path Server path(s)
|
||||
* @param string $name Session cookie name, unused
|
||||
* @return bool
|
||||
*/
|
||||
public function open($save_path, $name)
|
||||
{
|
||||
$this->_memcached = new Memcached();
|
||||
$this->_memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, TRUE); // required for touch() usage
|
||||
$server_list = array();
|
||||
foreach ($this->_memcached->getServerList() as $server)
|
||||
{
|
||||
$server_list[] = $server['host'].':'.$server['port'];
|
||||
}
|
||||
|
||||
if ( ! preg_match_all('#,?([^,:]+)\:(\d{1,5})(?:\:(\d+))?#', $this->_config['save_path'], $matches, PREG_SET_ORDER))
|
||||
{
|
||||
$this->_memcached = NULL;
|
||||
log_message('error', 'Session: Invalid Memcached save path format: '.$this->_config['save_path']);
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
foreach ($matches as $match)
|
||||
{
|
||||
// If Memcached already has this server (or if the port is invalid), skip it
|
||||
if (in_array($match[1].':'.$match[2], $server_list, TRUE))
|
||||
{
|
||||
log_message('debug', 'Session: Memcached server pool already has '.$match[1].':'.$match[2]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! $this->_memcached->addServer($match[1], $match[2], isset($match[3]) ? $match[3] : 0))
|
||||
{
|
||||
log_message('error', 'Could not add '.$match[1].':'.$match[2].' to Memcached server pool.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$server_list[] = $match[1].':'.$match[2];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($server_list))
|
||||
{
|
||||
log_message('error', 'Session: Memcached server pool is empty.');
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$this->php5_validate_id();
|
||||
|
||||
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 (isset($this->_memcached) && $this->_get_lock($session_id))
|
||||
{
|
||||
// Needed by write() to detect session_regenerate_id() calls
|
||||
$this->_session_id = $session_id;
|
||||
|
||||
$session_data = (string) $this->_memcached->get($this->_key_prefix.$session_id);
|
||||
$this->_fingerprint = md5($session_data);
|
||||
return $session_data;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 ( ! isset($this->_memcached, $this->_lock_key))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
// Was the ID regenerated?
|
||||
elseif ($session_id !== $this->_session_id)
|
||||
{
|
||||
if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$this->_fingerprint = md5('');
|
||||
$this->_session_id = $session_id;
|
||||
}
|
||||
|
||||
$key = $this->_key_prefix.$session_id;
|
||||
|
||||
$this->_memcached->replace($this->_lock_key, time(), 300);
|
||||
if ($this->_fingerprint !== ($fingerprint = md5($session_data)))
|
||||
{
|
||||
if ($this->_memcached->set($key, $session_data, $this->_config['expiration']))
|
||||
{
|
||||
$this->_fingerprint = $fingerprint;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
elseif (
|
||||
$this->_memcached->touch($key, $this->_config['expiration'])
|
||||
OR ($this->_memcached->getResultCode() === Memcached::RES_NOTFOUND && $this->_memcached->set($key, $session_data, $this->_config['expiration']))
|
||||
)
|
||||
{
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks and closes connection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (isset($this->_memcached))
|
||||
{
|
||||
$this->_release_lock();
|
||||
if ( ! $this->_memcached->quit())
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$this->_memcached = NULL;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
if (isset($this->_memcached, $this->_lock_key))
|
||||
{
|
||||
$this->_memcached->delete($this->_key_prefix.$session_id);
|
||||
$this->_cookie_destroy();
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Garbage Collector
|
||||
*
|
||||
* Deletes expired sessions
|
||||
*
|
||||
* @param int $maxlifetime Maximum lifetime of sessions
|
||||
* @return bool
|
||||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
// Not necessary, Memcached takes care of that.
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update Timestamp
|
||||
*
|
||||
* Update session timestamp without modifying data
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @param string $data Unknown & unused
|
||||
* @return bool
|
||||
*/
|
||||
public function updateTimestamp($id, $unknown)
|
||||
{
|
||||
return $this->_memcached->touch($this->_key_prefix.$id, $this->_config['expiration']);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function validateId($id)
|
||||
{
|
||||
$this->_memcached->get($this->_key_prefix.$id);
|
||||
return ($this->_memcached->getResultCode() === Memcached::RES_SUCCESS);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get lock
|
||||
*
|
||||
* Acquires an (emulated) lock.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
protected function _get_lock($session_id)
|
||||
{
|
||||
// PHP 7 reuses the SessionHandler object on regeneration,
|
||||
// so we need to check here if the lock key is for the
|
||||
// correct session ID.
|
||||
if ($this->_lock_key === $this->_key_prefix.$session_id.':lock')
|
||||
{
|
||||
if ( ! $this->_memcached->replace($this->_lock_key, time(), 300))
|
||||
{
|
||||
return ($this->_memcached->getResultCode() === Memcached::RES_NOTFOUND)
|
||||
? $this->_memcached->add($this->_lock_key, time(), 300)
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// 30 attempts to obtain a lock, in case another request already has it
|
||||
$lock_key = $this->_key_prefix.$session_id.':lock';
|
||||
$attempt = 0;
|
||||
do
|
||||
{
|
||||
if ($this->_memcached->get($lock_key))
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
$method = ($this->_memcached->getResultCode() === Memcached::RES_NOTFOUND) ? 'add' : 'set';
|
||||
if ( ! $this->_memcached->$method($lock_key, time(), 300))
|
||||
{
|
||||
log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_lock_key = $lock_key;
|
||||
break;
|
||||
}
|
||||
while (++$attempt < 30);
|
||||
|
||||
if ($attempt === 30)
|
||||
{
|
||||
log_message('error', 'Session: Unable to obtain lock for '.$this->_key_prefix.$session_id.' after 30 attempts, aborting.');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_lock = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Release lock
|
||||
*
|
||||
* Releases a previously acquired lock
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _release_lock()
|
||||
{
|
||||
if (isset($this->_memcached, $this->_lock_key) && $this->_lock)
|
||||
{
|
||||
if ( ! $this->_memcached->delete($this->_lock_key) && $this->_memcached->getResultCode() !== Memcached::RES_NOTFOUND)
|
||||
{
|
||||
log_message('error', 'Session: Error while trying to free lock for '.$this->_lock_key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_lock_key = NULL;
|
||||
$this->_lock = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
476
system/libraries/Session/drivers/Session_redis_driver.php
Normal file
476
system/libraries/Session/drivers/Session_redis_driver.php
Normal file
@@ -0,0 +1,476 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://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 Redis Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/userguide3/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_redis_driver extends CI_Session_driver implements CI_Session_driver_interface {
|
||||
|
||||
/**
|
||||
* phpRedis instance
|
||||
*
|
||||
* @var Redis
|
||||
*/
|
||||
protected $_redis;
|
||||
|
||||
/**
|
||||
* Key prefix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_key_prefix = 'ci_session:';
|
||||
|
||||
/**
|
||||
* Lock key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_lock_key;
|
||||
|
||||
/**
|
||||
* Key exists flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_key_exists = FALSE;
|
||||
|
||||
/**
|
||||
* Name of setTimeout() method in phpRedis
|
||||
*
|
||||
* Due to some deprecated methods in phpRedis, we need to call the
|
||||
* specific methods depending on the version of phpRedis.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_setTimeout_name;
|
||||
|
||||
/**
|
||||
* Name of delete() method in phpRedis
|
||||
*
|
||||
* Due to some deprecated methods in phpRedis, we need to call the
|
||||
* specific methods depending on the version of phpRedis.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_delete_name;
|
||||
|
||||
/**
|
||||
* Success return value of ping() method in phpRedis
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_ping_success;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(&$params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
// Detect the names of some methods in phpRedis instance
|
||||
if (version_compare(phpversion('redis'), '5', '>='))
|
||||
{
|
||||
$this->_setTimeout_name = 'expire';
|
||||
$this->_delete_name = 'del';
|
||||
$this->_ping_success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_setTimeout_name = 'setTimeout';
|
||||
$this->_delete_name = 'delete';
|
||||
$this->_ping_success = '+PONG';
|
||||
}
|
||||
|
||||
if (empty($this->_config['save_path']))
|
||||
{
|
||||
log_message('error', 'Session: No Redis save path configured.');
|
||||
}
|
||||
elseif (preg_match('#(?:tcp://)?([^:?]+)(?:\:(\d+))?(\?.+)?#', $this->_config['save_path'], $matches))
|
||||
{
|
||||
isset($matches[3]) OR $matches[3] = ''; // Just to avoid undefined index notices below
|
||||
$this->_config['save_path'] = array(
|
||||
'host' => $matches[1],
|
||||
'port' => empty($matches[2]) ? NULL : $matches[2],
|
||||
'password' => preg_match('#auth=([^\s&]+)#', $matches[3], $match) ? $match[1] : NULL,
|
||||
'database' => preg_match('#database=(\d+)#', $matches[3], $match) ? (int) $match[1] : NULL,
|
||||
'timeout' => preg_match('#timeout=(\d+\.\d+)#', $matches[3], $match) ? (float) $match[1] : NULL
|
||||
);
|
||||
|
||||
preg_match('#prefix=([^\s&]+)#', $matches[3], $match) && $this->_key_prefix = $match[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', 'Session: Invalid Redis save path format: '.$this->_config['save_path']);
|
||||
}
|
||||
|
||||
if ($this->_config['match_ip'] === TRUE)
|
||||
{
|
||||
$this->_key_prefix .= $_SERVER['REMOTE_ADDR'].':';
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open
|
||||
*
|
||||
* Sanitizes save_path and initializes connection.
|
||||
*
|
||||
* @param string $save_path Server path
|
||||
* @param string $name Session cookie name, unused
|
||||
* @return bool
|
||||
*/
|
||||
public function open($save_path, $name)
|
||||
{
|
||||
if (empty($this->_config['save_path']))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$redis = new Redis();
|
||||
if ( ! $redis->connect($this->_config['save_path']['host'], $this->_config['save_path']['port'], $this->_config['save_path']['timeout']))
|
||||
{
|
||||
log_message('error', 'Session: Unable to connect to Redis with the configured settings.');
|
||||
}
|
||||
elseif (isset($this->_config['save_path']['password']) && ! $redis->auth($this->_config['save_path']['password']))
|
||||
{
|
||||
log_message('error', 'Session: Unable to authenticate to Redis instance.');
|
||||
}
|
||||
elseif (isset($this->_config['save_path']['database']) && ! $redis->select($this->_config['save_path']['database']))
|
||||
{
|
||||
log_message('error', 'Session: Unable to select Redis database with index '.$this->_config['save_path']['database']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_redis = $redis;
|
||||
$this->php5_validate_id();
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 (isset($this->_redis) && $this->_get_lock($session_id))
|
||||
{
|
||||
// Needed by write() to detect session_regenerate_id() calls
|
||||
$this->_session_id = $session_id;
|
||||
|
||||
$session_data = $this->_redis->get($this->_key_prefix.$session_id);
|
||||
|
||||
is_string($session_data)
|
||||
? $this->_key_exists = TRUE
|
||||
: $session_data = '';
|
||||
|
||||
$this->_fingerprint = md5($session_data);
|
||||
return $session_data;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 ( ! isset($this->_redis, $this->_lock_key))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
// Was the ID regenerated?
|
||||
elseif ($session_id !== $this->_session_id)
|
||||
{
|
||||
if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
$this->_key_exists = FALSE;
|
||||
$this->_session_id = $session_id;
|
||||
}
|
||||
|
||||
$this->_redis->{$this->_setTimeout_name}($this->_lock_key, 300);
|
||||
if ($this->_fingerprint !== ($fingerprint = md5($session_data)) OR $this->_key_exists === FALSE)
|
||||
{
|
||||
if ($this->_redis->set($this->_key_prefix.$session_id, $session_data, $this->_config['expiration']))
|
||||
{
|
||||
$this->_fingerprint = $fingerprint;
|
||||
$this->_key_exists = TRUE;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
return ($this->_redis->{$this->_setTimeout_name}($this->_key_prefix.$session_id, $this->_config['expiration']))
|
||||
? $this->_success
|
||||
: $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks and closes connection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (isset($this->_redis))
|
||||
{
|
||||
try {
|
||||
if ($this->_redis->ping() === $this->_ping_success)
|
||||
{
|
||||
$this->_release_lock();
|
||||
if ($this->_redis->close() === FALSE)
|
||||
{
|
||||
return $this->_failure;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (RedisException $e)
|
||||
{
|
||||
log_message('error', 'Session: Got RedisException on close(): '.$e->getMessage());
|
||||
}
|
||||
|
||||
$this->_redis = NULL;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
if (isset($this->_redis, $this->_lock_key))
|
||||
{
|
||||
if (($result = $this->_redis->{$this->_delete_name}($this->_key_prefix.$session_id)) !== 1)
|
||||
{
|
||||
log_message('debug', 'Session: Redis::'.$this->_delete_name.'() expected to return 1, got '.var_export($result, TRUE).' instead.');
|
||||
}
|
||||
|
||||
$this->_cookie_destroy();
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_failure;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Garbage Collector
|
||||
*
|
||||
* Deletes expired sessions
|
||||
*
|
||||
* @param int $maxlifetime Maximum lifetime of sessions
|
||||
* @return bool
|
||||
*/
|
||||
public function gc($maxlifetime)
|
||||
{
|
||||
// Not necessary, Redis takes care of that.
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update Timestamp
|
||||
*
|
||||
* Update session timestamp without modifying data
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @param string $data Unknown & unused
|
||||
* @return bool
|
||||
*/
|
||||
public function updateTimestamp($id, $unknown)
|
||||
{
|
||||
return $this->_redis->{$this->_setTimeout_name}($this->_key_prefix.$id, $this->_config['expiration']);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function validateId($id)
|
||||
{
|
||||
return (bool) $this->_redis->exists($this->_key_prefix.$id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get lock
|
||||
*
|
||||
* Acquires an (emulated) lock.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
protected function _get_lock($session_id)
|
||||
{
|
||||
// PHP 7 reuses the SessionHandler object on regeneration,
|
||||
// so we need to check here if the lock key is for the
|
||||
// correct session ID.
|
||||
if ($this->_lock_key === $this->_key_prefix.$session_id.':lock')
|
||||
{
|
||||
return $this->_redis->{$this->_setTimeout_name}($this->_lock_key, 300);
|
||||
}
|
||||
|
||||
// 30 attempts to obtain a lock, in case another request already has it
|
||||
$lock_key = $this->_key_prefix.$session_id.':lock';
|
||||
$attempt = 0;
|
||||
do
|
||||
{
|
||||
if (($ttl = $this->_redis->ttl($lock_key)) > 0)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($ttl === -2 && ! $this->_redis->set($lock_key, time(), array('nx', 'ex' => 300)))
|
||||
{
|
||||
// Sleep for 1s to wait for lock releases.
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
elseif ( ! $this->_redis->setex($lock_key, 300, time()))
|
||||
{
|
||||
log_message('error', 'Session: Error while trying to obtain lock for '.$this->_key_prefix.$session_id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_lock_key = $lock_key;
|
||||
break;
|
||||
}
|
||||
while (++$attempt < 30);
|
||||
|
||||
if ($attempt === 30)
|
||||
{
|
||||
log_message('error', 'Session: Unable to obtain lock for '.$this->_key_prefix.$session_id.' after 30 attempts, aborting.');
|
||||
return FALSE;
|
||||
}
|
||||
elseif ($ttl === -1)
|
||||
{
|
||||
log_message('debug', 'Session: Lock for '.$this->_key_prefix.$session_id.' had no TTL, overriding.');
|
||||
}
|
||||
|
||||
$this->_lock = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Release lock
|
||||
*
|
||||
* Releases a previously acquired lock
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _release_lock()
|
||||
{
|
||||
if (isset($this->_redis, $this->_lock_key) && $this->_lock)
|
||||
{
|
||||
if ( ! $this->_redis->{$this->_delete_name}($this->_lock_key))
|
||||
{
|
||||
log_message('error', 'Session: Error while trying to free lock for '.$this->_lock_key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_lock_key = NULL;
|
||||
$this->_lock = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
11
system/libraries/Session/drivers/index.html
Normal file
11
system/libraries/Session/drivers/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
11
system/libraries/Session/index.html
Normal file
11
system/libraries/Session/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
539
system/libraries/Table.php
Normal file
539
system/libraries/Table.php
Normal file
File diff suppressed because it is too large
Load Diff
557
system/libraries/Trackback.php
Normal file
557
system/libraries/Trackback.php
Normal file
File diff suppressed because it is too large
Load Diff
425
system/libraries/Typography.php
Normal file
425
system/libraries/Typography.php
Normal file
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Typography Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Helpers
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/userguide3/libraries/typography.html
|
||||
*/
|
||||
class CI_Typography {
|
||||
|
||||
/**
|
||||
* Block level elements that should not be wrapped inside <p> tags
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul';
|
||||
|
||||
/**
|
||||
* Elements that should not have <p> and <br /> tags within them.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $skip_elements = 'p|pre|ol|ul|dl|object|table|h\d';
|
||||
|
||||
/**
|
||||
* Tags we want the parser to completely ignore when splitting the string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var';
|
||||
|
||||
/**
|
||||
* array of block level elements that require inner content to be within another block level element
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $inner_block_required = array('blockquote');
|
||||
|
||||
/**
|
||||
* the last block element parsed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $last_block_element = '';
|
||||
|
||||
/**
|
||||
* whether or not to protect quotes within { curly braces }
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $protect_braced_quotes = FALSE;
|
||||
|
||||
/**
|
||||
* Auto Typography
|
||||
*
|
||||
* This function converts text, making it typographically correct:
|
||||
* - Converts double spaces into paragraphs.
|
||||
* - Converts single line breaks into <br /> tags
|
||||
* - Converts single and double quotes into correctly facing curly quote entities.
|
||||
* - Converts three dots into ellipsis.
|
||||
* - Converts double dashes into em-dashes.
|
||||
* - Converts two spaces into entities
|
||||
*
|
||||
* @param string
|
||||
* @param bool whether to reduce more then two consecutive newlines to two
|
||||
* @return string
|
||||
*/
|
||||
public function auto_typography($str, $reduce_linebreaks = FALSE)
|
||||
{
|
||||
if ($str === '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
// Standardize Newlines to make matching easier
|
||||
if (strpos($str, "\r") !== FALSE)
|
||||
{
|
||||
$str = str_replace(array("\r\n", "\r"), "\n", $str);
|
||||
}
|
||||
|
||||
// Reduce line breaks. If there are more than two consecutive linebreaks
|
||||
// we'll compress them down to a maximum of two since there's no benefit to more.
|
||||
if ($reduce_linebreaks === TRUE)
|
||||
{
|
||||
$str = preg_replace("/\n\n+/", "\n\n", $str);
|
||||
}
|
||||
|
||||
// HTML comment tags don't conform to patterns of normal tags, so pull them out separately, only if needed
|
||||
$html_comments = array();
|
||||
if (strpos($str, '<!--') !== FALSE && preg_match_all('#(<!\-\-.*?\-\->)#s', $str, $matches))
|
||||
{
|
||||
for ($i = 0, $total = count($matches[0]); $i < $total; $i++)
|
||||
{
|
||||
$html_comments[] = $matches[0][$i];
|
||||
$str = str_replace($matches[0][$i], '{@HC'.$i.'}', $str);
|
||||
}
|
||||
}
|
||||
|
||||
// match and yank <pre> tags if they exist. It's cheaper to do this separately since most content will
|
||||
// not contain <pre> tags, and it keeps the PCRE patterns below simpler and faster
|
||||
if (strpos($str, '<pre') !== FALSE)
|
||||
{
|
||||
$str = preg_replace_callback('#<pre.*?>.*?</pre>#si', array($this, '_protect_characters'), $str);
|
||||
}
|
||||
|
||||
// Convert quotes within tags to temporary markers.
|
||||
$str = preg_replace_callback('#<.+?>#si', array($this, '_protect_characters'), $str);
|
||||
|
||||
// Do the same with braces if necessary
|
||||
if ($this->protect_braced_quotes === TRUE)
|
||||
{
|
||||
$str = preg_replace_callback('#\{.+?\}#si', array($this, '_protect_characters'), $str);
|
||||
}
|
||||
|
||||
// Convert "ignore" tags to temporary marker. The parser splits out the string at every tag
|
||||
// it encounters. Certain inline tags, like image tags, links, span tags, etc. will be
|
||||
// adversely affected if they are split out so we'll convert the opening bracket < temporarily to: {@TAG}
|
||||
$str = preg_replace('#<(/*)('.$this->inline_elements.')([ >])#i', '{@TAG}\\1\\2\\3', $str);
|
||||
|
||||
/* Split the string at every tag. This expression creates an array with this prototype:
|
||||
*
|
||||
* [array]
|
||||
* {
|
||||
* [0] = <opening tag>
|
||||
* [1] = Content...
|
||||
* [2] = <closing tag>
|
||||
* Etc...
|
||||
* }
|
||||
*/
|
||||
$chunks = preg_split('/(<(?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+>)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
// Build our finalized string. We cycle through the array, skipping tags, and processing the contained text
|
||||
$str = '';
|
||||
$process = TRUE;
|
||||
|
||||
for ($i = 0, $c = count($chunks) - 1; $i <= $c; $i++)
|
||||
{
|
||||
// Are we dealing with a tag? If so, we'll skip the processing for this cycle.
|
||||
// Well also set the "process" flag which allows us to skip <pre> tags and a few other things.
|
||||
if (preg_match('#<(/*)('.$this->block_elements.').*?>#', $chunks[$i], $match))
|
||||
{
|
||||
if (preg_match('#'.$this->skip_elements.'#', $match[2]))
|
||||
{
|
||||
$process = ($match[1] === '/');
|
||||
}
|
||||
|
||||
if ($match[1] === '')
|
||||
{
|
||||
$this->last_block_element = $match[2];
|
||||
}
|
||||
|
||||
$str .= $chunks[$i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($process === FALSE)
|
||||
{
|
||||
$str .= $chunks[$i];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Force a newline to make sure end tags get processed by _format_newlines()
|
||||
if ($i === $c)
|
||||
{
|
||||
$chunks[$i] .= "\n";
|
||||
}
|
||||
|
||||
// Convert Newlines into <p> and <br /> tags
|
||||
$str .= $this->_format_newlines($chunks[$i]);
|
||||
}
|
||||
|
||||
// No opening block level tag? Add it if needed.
|
||||
if ( ! preg_match('/^\s*<(?:'.$this->block_elements.')/i', $str))
|
||||
{
|
||||
$str = preg_replace('/^(.*?)<('.$this->block_elements.')/i', '<p>$1</p><$2', $str);
|
||||
}
|
||||
|
||||
// Convert quotes, elipsis, em-dashes, non-breaking spaces, and ampersands
|
||||
$str = $this->format_characters($str);
|
||||
|
||||
// restore HTML comments
|
||||
for ($i = 0, $total = count($html_comments); $i < $total; $i++)
|
||||
{
|
||||
// remove surrounding paragraph tags, but only if there's an opening paragraph tag
|
||||
// otherwise HTML comments at the ends of paragraphs will have the closing tag removed
|
||||
// if '<p>{@HC1}' then replace <p>{@HC1}</p> with the comment, else replace only {@HC1} with the comment
|
||||
$str = preg_replace('#(?(?=<p>\{@HC'.$i.'\})<p>\{@HC'.$i.'\}(\s*</p>)|\{@HC'.$i.'\})#s', $html_comments[$i], $str);
|
||||
}
|
||||
|
||||
// Final clean up
|
||||
$table = array(
|
||||
|
||||
// If the user submitted their own paragraph tags within the text
|
||||
// we will retain them instead of using our tags.
|
||||
'/(<p[^>*?]>)<p>/' => '$1', // <?php BBEdit syntax coloring bug fix
|
||||
|
||||
// Reduce multiple instances of opening/closing paragraph tags to a single one
|
||||
'#(</p>)+#' => '</p>',
|
||||
'/(<p>\W*<p>)+/' => '<p>',
|
||||
|
||||
// Clean up stray paragraph tags that appear before block level elements
|
||||
'#<p></p><('.$this->block_elements.')#' => '<$1',
|
||||
|
||||
// Clean up stray non-breaking spaces preceding block elements
|
||||
'#( \s*)+<('.$this->block_elements.')#' => ' <$2',
|
||||
|
||||
// Replace the temporary markers we added earlier
|
||||
'/\{@TAG\}/' => '<',
|
||||
'/\{@DQ\}/' => '"',
|
||||
'/\{@SQ\}/' => "'",
|
||||
'/\{@DD\}/' => '--',
|
||||
'/\{@NBS\}/' => ' ',
|
||||
|
||||
// An unintended consequence of the _format_newlines function is that
|
||||
// some of the newlines get truncated, resulting in <p> tags
|
||||
// starting immediately after <block> tags on the same line.
|
||||
// This forces a newline after such occurrences, which looks much nicer.
|
||||
"/><p>\n/" => ">\n<p>",
|
||||
|
||||
// Similarly, there might be cases where a closing </block> will follow
|
||||
// a closing </p> tag, so we'll correct it by adding a newline in between
|
||||
'#</p></#' => "</p>\n</"
|
||||
);
|
||||
|
||||
// Do we need to reduce empty lines?
|
||||
if ($reduce_linebreaks === TRUE)
|
||||
{
|
||||
$table['#<p>\n*</p>#'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have empty paragraph tags we add a non-breaking space
|
||||
// otherwise most browsers won't treat them as true paragraphs
|
||||
$table['#<p></p>#'] = '<p> </p>';
|
||||
}
|
||||
|
||||
return preg_replace(array_keys($table), $table, $str);
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Format Characters
|
||||
*
|
||||
* This function mainly converts double and single quotes
|
||||
* to curly entities, but it also converts em-dashes,
|
||||
* double spaces, and ampersands
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function format_characters($str)
|
||||
{
|
||||
static $table;
|
||||
|
||||
if ( ! isset($table))
|
||||
{
|
||||
$table = array(
|
||||
// nested smart quotes, opening and closing
|
||||
// note that rules for grammar (English) allow only for two levels deep
|
||||
// and that single quotes are _supposed_ to always be on the outside
|
||||
// but we'll accommodate both
|
||||
// Note that in all cases, whitespace is the primary determining factor
|
||||
// on which direction to curl, with non-word characters like punctuation
|
||||
// being a secondary factor only after whitespace is addressed.
|
||||
'/\'"(\s|$)/' => '’”$1',
|
||||
'/(^|\s|<p>)\'"/' => '$1‘“',
|
||||
'/\'"(\W)/' => '’”$1',
|
||||
'/(\W)\'"/' => '$1‘“',
|
||||
'/"\'(\s|$)/' => '”’$1',
|
||||
'/(^|\s|<p>)"\'/' => '$1“‘',
|
||||
'/"\'(\W)/' => '”’$1',
|
||||
'/(\W)"\'/' => '$1“‘',
|
||||
|
||||
// single quote smart quotes
|
||||
'/\'(\s|$)/' => '’$1',
|
||||
'/(^|\s|<p>)\'/' => '$1‘',
|
||||
'/\'(\W)/' => '’$1',
|
||||
'/(\W)\'/' => '$1‘',
|
||||
|
||||
// double quote smart quotes
|
||||
'/"(\s|$)/' => '”$1',
|
||||
'/(^|\s|<p>)"/' => '$1“',
|
||||
'/"(\W)/' => '”$1',
|
||||
'/(\W)"/' => '$1“',
|
||||
|
||||
// apostrophes
|
||||
"/(\w)'(\w)/" => '$1’$2',
|
||||
|
||||
// Em dash and ellipses dots
|
||||
'/\s?\-\-\s?/' => '—',
|
||||
'/(\w)\.{3}/' => '$1…',
|
||||
|
||||
// double space after sentences
|
||||
'/(\W) /' => '$1 ',
|
||||
|
||||
// ampersands, if not a character entity
|
||||
'/&(?!#?[a-zA-Z0-9]{2,};)/' => '&'
|
||||
);
|
||||
}
|
||||
|
||||
return preg_replace(array_keys($table), $table, $str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Format Newlines
|
||||
*
|
||||
* Converts newline characters into either <p> tags or <br />
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _format_newlines($str)
|
||||
{
|
||||
if ($str === '' OR (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required)))
|
||||
{
|
||||
return $str;
|
||||
}
|
||||
|
||||
// Convert two consecutive newlines to paragraphs
|
||||
$str = str_replace("\n\n", "</p>\n\n<p>", $str);
|
||||
|
||||
// Convert single spaces to <br /> tags
|
||||
$str = preg_replace("/([^\n])(\n)([^\n])/", '\\1<br />\\2\\3', $str);
|
||||
|
||||
// Wrap the whole enchilada in enclosing paragraphs
|
||||
if ($str !== "\n")
|
||||
{
|
||||
// We trim off the right-side new line so that the closing </p> tag
|
||||
// will be positioned immediately following the string, matching
|
||||
// the behavior of the opening <p> tag
|
||||
$str = '<p>'.rtrim($str).'</p>';
|
||||
}
|
||||
|
||||
// Remove empty paragraphs if they are on the first line, as this
|
||||
// is a potential unintended consequence of the previous code
|
||||
return preg_replace('/<p><\/p>(.*)/', '\\1', $str, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Protect Characters
|
||||
*
|
||||
* Protects special characters from being formatted later
|
||||
* We don't want quotes converted within tags so we'll temporarily convert them to {@DQ} and {@SQ}
|
||||
* and we don't want double dashes converted to emdash entities, so they are marked with {@DD}
|
||||
* likewise double spaces are converted to {@NBS} to prevent entity conversion
|
||||
*
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
protected function _protect_characters($match)
|
||||
{
|
||||
return str_replace(array("'",'"','--',' '), array('{@SQ}', '{@DQ}', '{@DD}', '{@NBS}'), $match[0]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Convert newlines to HTML line breaks except within PRE tags
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function nl2br_except_pre($str)
|
||||
{
|
||||
$newstr = '';
|
||||
for ($ex = explode('pre>', $str), $ct = count($ex), $i = 0; $i < $ct; $i++)
|
||||
{
|
||||
$newstr .= (($i % 2) === 0) ? nl2br($ex[$i]) : $ex[$i];
|
||||
if ($ct - 1 !== $i)
|
||||
{
|
||||
$newstr .= 'pre>';
|
||||
}
|
||||
}
|
||||
|
||||
return $newstr;
|
||||
}
|
||||
|
||||
}
|
407
system/libraries/Unit_test.php
Normal file
407
system/libraries/Unit_test.php
Normal file
@@ -0,0 +1,407 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 - 2022, CodeIgniter Foundation
|
||||
*
|
||||
* 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 - 2019, British Columbia Institute of Technology (https://bcit.ca/)
|
||||
* @copyright Copyright (c) 2019 - 2022, CodeIgniter Foundation (https://codeigniter.com/)
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.3.1
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Unit Testing Class
|
||||
*
|
||||
* Simple testing class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category UnitTesting
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/userguide3/libraries/unit_testing.html
|
||||
*/
|
||||
class CI_Unit_test {
|
||||
|
||||
/**
|
||||
* Active flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $active = TRUE;
|
||||
|
||||
/**
|
||||
* Test results
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $results = array();
|
||||
|
||||
/**
|
||||
* Strict comparison flag
|
||||
*
|
||||
* Whether to use === or == when comparing
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $strict = FALSE;
|
||||
|
||||
/**
|
||||
* Template
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_template = NULL;
|
||||
|
||||
/**
|
||||
* Template rows
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_template_rows = NULL;
|
||||
|
||||
/**
|
||||
* List of visible test items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_test_items_visible = array(
|
||||
'test_name',
|
||||
'test_datatype',
|
||||
'res_datatype',
|
||||
'result',
|
||||
'file',
|
||||
'line',
|
||||
'notes'
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
log_message('info', 'Unit Testing Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Run the tests
|
||||
*
|
||||
* Runs the supplied tests
|
||||
*
|
||||
* @param array $items
|
||||
* @return void
|
||||
*/
|
||||
public function set_test_items($items)
|
||||
{
|
||||
if ( ! empty($items) && is_array($items))
|
||||
{
|
||||
$this->_test_items_visible = $items;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Run the tests
|
||||
*
|
||||
* Runs the supplied tests
|
||||
*
|
||||
* @param mixed $test
|
||||
* @param mixed $expected
|
||||
* @param string $test_name
|
||||
* @param string $notes
|
||||
* @return string
|
||||
*/
|
||||
public function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '')
|
||||
{
|
||||
if ($this->active === FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (in_array($expected, array('is_object', 'is_string', 'is_bool', 'is_true', 'is_false', 'is_int', 'is_numeric', 'is_float', 'is_double', 'is_array', 'is_null', 'is_resource'), TRUE))
|
||||
{
|
||||
$result = $expected($test);
|
||||
$extype = str_replace(array('true', 'false'), 'bool', str_replace('is_', '', $expected));
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = ($this->strict === TRUE) ? ($test === $expected) : ($test == $expected);
|
||||
$extype = gettype($expected);
|
||||
}
|
||||
|
||||
$back = $this->_backtrace();
|
||||
|
||||
$report = array (
|
||||
'test_name' => $test_name,
|
||||
'test_datatype' => gettype($test),
|
||||
'res_datatype' => $extype,
|
||||
'result' => ($result === TRUE) ? 'passed' : 'failed',
|
||||
'file' => $back['file'],
|
||||
'line' => $back['line'],
|
||||
'notes' => $notes
|
||||
);
|
||||
|
||||
$this->results[] = $report;
|
||||
|
||||
return $this->report($this->result(array($report)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate a report
|
||||
*
|
||||
* Displays a table with the test data
|
||||
*
|
||||
* @param array $result
|
||||
* @return string
|
||||
*/
|
||||
public function report($result = array())
|
||||
{
|
||||
if (count($result) === 0)
|
||||
{
|
||||
$result = $this->result();
|
||||
}
|
||||
|
||||
$CI =& get_instance();
|
||||
$CI->load->language('unit_test');
|
||||
|
||||
$this->_parse_template();
|
||||
|
||||
$r = '';
|
||||
foreach ($result as $res)
|
||||
{
|
||||
$table = '';
|
||||
|
||||
foreach ($res as $key => $val)
|
||||
{
|
||||
if ($key === $CI->lang->line('ut_result'))
|
||||
{
|
||||
if ($val === $CI->lang->line('ut_passed'))
|
||||
{
|
||||
$val = '<span style="color: #0C0;">'.$val.'</span>';
|
||||
}
|
||||
elseif ($val === $CI->lang->line('ut_failed'))
|
||||
{
|
||||
$val = '<span style="color: #C00;">'.$val.'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
$table .= str_replace(array('{item}', '{result}'), array($key, $val), $this->_template_rows);
|
||||
}
|
||||
|
||||
$r .= str_replace('{rows}', $table, $this->_template);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Use strict comparison
|
||||
*
|
||||
* Causes the evaluation to use === rather than ==
|
||||
*
|
||||
* @param bool $state
|
||||
* @return void
|
||||
*/
|
||||
public function use_strict($state = TRUE)
|
||||
{
|
||||
$this->strict = (bool) $state;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Make Unit testing active
|
||||
*
|
||||
* Enables/disables unit testing
|
||||
*
|
||||
* @param bool
|
||||
* @return void
|
||||
*/
|
||||
public function active($state = TRUE)
|
||||
{
|
||||
$this->active = (bool) $state;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Result Array
|
||||
*
|
||||
* Returns the raw result data
|
||||
*
|
||||
* @param array $results
|
||||
* @return array
|
||||
*/
|
||||
public function result($results = array())
|
||||
{
|
||||
$CI =& get_instance();
|
||||
$CI->load->language('unit_test');
|
||||
|
||||
if (count($results) === 0)
|
||||
{
|
||||
$results = $this->results;
|
||||
}
|
||||
|
||||
$retval = array();
|
||||
foreach ($results as $result)
|
||||
{
|
||||
$temp = array();
|
||||
foreach ($result as $key => $val)
|
||||
{
|
||||
if ( ! in_array($key, $this->_test_items_visible))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
elseif (in_array($key, array('test_name', 'test_datatype', 'res_datatype', 'result'), TRUE))
|
||||
{
|
||||
if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val), FALSE)))
|
||||
{
|
||||
$val = $line;
|
||||
}
|
||||
}
|
||||
|
||||
$temp[$CI->lang->line('ut_'.$key, FALSE)] = $val;
|
||||
}
|
||||
|
||||
$retval[] = $temp;
|
||||
}
|
||||
|
||||
return $retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the template
|
||||
*
|
||||
* This lets us set the template to be used to display results
|
||||
*
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function set_template($template)
|
||||
{
|
||||
$this->_template = $template;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate a backtrace
|
||||
*
|
||||
* This lets us show file names and line numbers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _backtrace()
|
||||
{
|
||||
$back = debug_backtrace();
|
||||
return array(
|
||||
'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
|
||||
'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Default Template
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _default_template()
|
||||
{
|
||||
$this->_template = "\n".'<table style="width:100%; font-size:small; margin:10px 0; border-collapse:collapse; border:1px solid #CCC;">{rows}'."\n</table>";
|
||||
|
||||
$this->_template_rows = "\n\t<tr>\n\t\t".'<th style="text-align: left; border-bottom:1px solid #CCC;">{item}</th>'
|
||||
."\n\t\t".'<td style="border-bottom:1px solid #CCC;">{result}</td>'."\n\t</tr>";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse Template
|
||||
*
|
||||
* Harvests the data within the template {pseudo-variables}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _parse_template()
|
||||
{
|
||||
if ($this->_template_rows !== NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_template === NULL OR ! preg_match('/\{rows\}(.*?)\{\/rows\}/si', $this->_template, $match))
|
||||
{
|
||||
$this->_default_template();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_template_rows = $match[1];
|
||||
$this->_template = str_replace($match[0], '{rows}', $this->_template);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to test boolean TRUE
|
||||
*
|
||||
* @param mixed $test
|
||||
* @return bool
|
||||
*/
|
||||
function is_true($test)
|
||||
{
|
||||
return ($test === TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to test boolean FALSE
|
||||
*
|
||||
* @param mixed $test
|
||||
* @return bool
|
||||
*/
|
||||
function is_false($test)
|
||||
{
|
||||
return ($test === FALSE);
|
||||
}
|
1327
system/libraries/Upload.php
Normal file
1327
system/libraries/Upload.php
Normal file
File diff suppressed because it is too large
Load Diff
682
system/libraries/User_agent.php
Normal file
682
system/libraries/User_agent.php
Normal file
File diff suppressed because it is too large
Load Diff
1921
system/libraries/Xmlrpc.php
Normal file
1921
system/libraries/Xmlrpc.php
Normal file
File diff suppressed because it is too large
Load Diff
620
system/libraries/Xmlrpcs.php
Normal file
620
system/libraries/Xmlrpcs.php
Normal file
File diff suppressed because it is too large
Load Diff
534
system/libraries/Zip.php
Normal file
534
system/libraries/Zip.php
Normal file
File diff suppressed because it is too large
Load Diff
11
system/libraries/index.html
Normal file
11
system/libraries/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user