Initial commit

This commit is contained in:
2024-05-28 16:10:53 +02:00
commit eb32dbd5b2
253 changed files with 70017 additions and 0 deletions

View 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];
}
}

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

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

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

View 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();
}
}
}

View 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();
}
}
}

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

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

File diff suppressed because it is too large Load Diff

568
system/libraries/Cart.php Normal file

File diff suppressed because it is too large Load Diff

343
system/libraries/Driver.php Normal file
View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

668
system/libraries/Ftp.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

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

File diff suppressed because it is too large Load Diff

249
system/libraries/Parser.php Normal file
View 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;
}
}

File diff suppressed because it is too large Load Diff

View 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);
}

View 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);
}
}

View 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);
}
}

File diff suppressed because it is too large Load Diff

View 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);
}

View File

@@ -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);
}

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

View 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();
}
}

View 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);
}
}

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

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

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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
'#(&nbsp;\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>&nbsp;</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|$)/' => '&#8217;&#8221;$1',
'/(^|\s|<p>)\'"/' => '$1&#8216;&#8220;',
'/\'"(\W)/' => '&#8217;&#8221;$1',
'/(\W)\'"/' => '$1&#8216;&#8220;',
'/"\'(\s|$)/' => '&#8221;&#8217;$1',
'/(^|\s|<p>)"\'/' => '$1&#8220;&#8216;',
'/"\'(\W)/' => '&#8221;&#8217;$1',
'/(\W)"\'/' => '$1&#8220;&#8216;',
// single quote smart quotes
'/\'(\s|$)/' => '&#8217;$1',
'/(^|\s|<p>)\'/' => '$1&#8216;',
'/\'(\W)/' => '&#8217;$1',
'/(\W)\'/' => '$1&#8216;',
// double quote smart quotes
'/"(\s|$)/' => '&#8221;$1',
'/(^|\s|<p>)"/' => '$1&#8220;',
'/"(\W)/' => '&#8221;$1',
'/(\W)"/' => '$1&#8220;',
// apostrophes
"/(\w)'(\w)/" => '$1&#8217;$2',
// Em dash and ellipses dots
'/\s?\-\-\s?/' => '&#8212;',
'/(\w)\.{3}/' => '$1&#8230;',
// double space after sentences
'/(\W) /' => '$1&nbsp; ',
// ampersands, if not a character entity
'/&(?!#?[a-zA-Z0-9]{2,};)/' => '&amp;'
);
}
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;
}
}

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1921
system/libraries/Xmlrpc.php Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

534
system/libraries/Zip.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>403 Forbidden</title>
</head>
<body>
<p>Directory access is forbidden.</p>
</body>
</html>