Moved to PHP folder
This commit is contained in:
255
php/system/libraries/Cache/Cache.php
Normal file
255
php/system/libraries/Cache/Cache.php
Normal file
@ -0,0 +1,255 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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];
|
||||
}
|
||||
}
|
217
php/system/libraries/Cache/drivers/Cache_apc.php
Normal file
217
php/system/libraries/Cache/drivers/Cache_apc.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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'));
|
||||
}
|
||||
}
|
172
php/system/libraries/Cache/drivers/Cache_dummy.php
Normal file
172
php/system/libraries/Cache/drivers/Cache_dummy.php
Normal file
@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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;
|
||||
}
|
||||
|
||||
}
|
286
php/system/libraries/Cache/drivers/Cache_file.php
Normal file
286
php/system/libraries/Cache/drivers/Cache_file.php
Normal file
@ -0,0 +1,286 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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'])
|
||||
{
|
||||
unlink($this->_cache_path.$id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
313
php/system/libraries/Cache/drivers/Cache_memcached.php
Normal file
313
php/system/libraries/Cache/drivers/Cache_memcached.php
Normal file
@ -0,0 +1,313 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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();
|
||||
}
|
||||
}
|
||||
}
|
328
php/system/libraries/Cache/drivers/Cache_redis.php
Normal file
328
php/system/libraries/Cache/drivers/Cache_redis.php
Normal file
@ -0,0 +1,328 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter 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();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
$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().')');
|
||||
}
|
||||
|
||||
// Initialize the index of serialized values.
|
||||
$serialized = $this->_redis->sMembers('_ci_redis_serialized');
|
||||
empty($serialized) OR $this->_serialized = array_flip($serialized);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get cache
|
||||
*
|
||||
* @param string $key Cache ID
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$value = $this->_redis->get($key);
|
||||
|
||||
if ($value !== FALSE && isset($this->_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);
|
||||
}
|
||||
elseif (isset($this->_serialized[$id]))
|
||||
{
|
||||
$this->_serialized[$id] = NULL;
|
||||
$this->_redis->sRemove('_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->delete($key) !== 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (isset($this->_serialized[$key]))
|
||||
{
|
||||
$this->_serialized[$key] = NULL;
|
||||
$this->_redis->sRemove('_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->incr($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->decr($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();
|
||||
}
|
||||
}
|
||||
}
|
217
php/system/libraries/Cache/drivers/Cache_wincache.php
Normal file
217
php/system/libraries/Cache/drivers/Cache_wincache.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Wincache Caching Class
|
||||
*
|
||||
* Read more about Wincache functions here:
|
||||
* http://www.php.net/manual/en/ref.wincache.php
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Core
|
||||
* @author Mike Murkovic
|
||||
* @link
|
||||
*/
|
||||
class CI_Cache_wincache extends CI_Driver {
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Only present so that an error message is logged
|
||||
* if APC is not available.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ( ! $this->is_supported())
|
||||
{
|
||||
log_message('error', 'Cache: Failed to initialize Wincache; extension not loaded/enabled?');
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get
|
||||
*
|
||||
* Look for a value in the cache. If it exists, return the data,
|
||||
* if not, return FALSE
|
||||
*
|
||||
* @param string $id Cache Ide
|
||||
* @return mixed Value that is stored/FALSE on failure
|
||||
*/
|
||||
public function get($id)
|
||||
{
|
||||
$success = FALSE;
|
||||
$data = wincache_ucache_get($id, $success);
|
||||
|
||||
// Success returned by reference from wincache_ucache_get()
|
||||
return ($success) ? $data : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Save
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param mixed $data Data to store
|
||||
* @param int $ttl Time to live (in seconds)
|
||||
* @param bool $raw Whether to store the raw value (unused)
|
||||
* @return bool true on success/false on failure
|
||||
*/
|
||||
public function save($id, $data, $ttl = 60, $raw = FALSE)
|
||||
{
|
||||
return wincache_ucache_set($id, $data, $ttl);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete from Cache
|
||||
*
|
||||
* @param mixed unique identifier of the item in the cache
|
||||
* @return bool true on success/false on failure
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
return wincache_ucache_delete($id);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Increment a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to add
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function increment($id, $offset = 1)
|
||||
{
|
||||
$success = FALSE;
|
||||
$value = wincache_ucache_inc($id, $offset, $success);
|
||||
|
||||
return ($success === TRUE) ? $value : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrement a raw value
|
||||
*
|
||||
* @param string $id Cache ID
|
||||
* @param int $offset Step/value to reduce by
|
||||
* @return mixed New value on success or FALSE on failure
|
||||
*/
|
||||
public function decrement($id, $offset = 1)
|
||||
{
|
||||
$success = FALSE;
|
||||
$value = wincache_ucache_dec($id, $offset, $success);
|
||||
|
||||
return ($success === TRUE) ? $value : FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clean the cache
|
||||
*
|
||||
* @return bool false on failure/true on success
|
||||
*/
|
||||
public function clean()
|
||||
{
|
||||
return wincache_ucache_clear();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cache Info
|
||||
*
|
||||
* @return mixed array on success, false on failure
|
||||
*/
|
||||
public function cache_info()
|
||||
{
|
||||
return wincache_ucache_info(TRUE);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Cache Metadata
|
||||
*
|
||||
* @param mixed key to get cache metadata on
|
||||
* @return mixed array on success/false on failure
|
||||
*/
|
||||
public function get_metadata($id)
|
||||
{
|
||||
if ($stored = wincache_ucache_info(FALSE, $id))
|
||||
{
|
||||
$age = $stored['ucache_entries'][1]['age_seconds'];
|
||||
$ttl = $stored['ucache_entries'][1]['ttl_seconds'];
|
||||
$hitcount = $stored['ucache_entries'][1]['hitcount'];
|
||||
|
||||
return array(
|
||||
'expire' => $ttl - $age,
|
||||
'hitcount' => $hitcount,
|
||||
'age' => $age,
|
||||
'ttl' => $ttl
|
||||
);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* is_supported()
|
||||
*
|
||||
* Check to see if WinCache is available on this system, bail if it isn't.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_supported()
|
||||
{
|
||||
return (extension_loaded('wincache') && ini_get('wincache.ucenabled'));
|
||||
}
|
||||
}
|
11
php/system/libraries/Cache/drivers/index.html
Normal file
11
php/system/libraries/Cache/drivers/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
11
php/system/libraries/Cache/index.html
Normal file
11
php/system/libraries/Cache/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
546
php/system/libraries/Calendar.php
Normal file
546
php/system/libraries/Calendar.php
Normal file
@ -0,0 +1,546 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Calendar Class
|
||||
*
|
||||
* This class enables the creation of calendars
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/calendar.html
|
||||
*/
|
||||
class CI_Calendar {
|
||||
|
||||
/**
|
||||
* Calendar layout template
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $template = '';
|
||||
|
||||
/**
|
||||
* Replacements array for template
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $replacements = array();
|
||||
|
||||
/**
|
||||
* Day of the week to start the calendar on
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $start_day = 'sunday';
|
||||
|
||||
/**
|
||||
* How to display months
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $month_type = 'long';
|
||||
|
||||
/**
|
||||
* How to display names of days
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $day_type = 'abr';
|
||||
|
||||
/**
|
||||
* Whether to show next/prev month links
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $show_next_prev = FALSE;
|
||||
|
||||
/**
|
||||
* Url base to use for next/prev month links
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $next_prev_url = '';
|
||||
|
||||
/**
|
||||
* Show days of other months
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $show_other_days = FALSE;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CI Singleton
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Loads the calendar language file and sets the default time reference.
|
||||
*
|
||||
* @uses CI_Lang::$is_loaded
|
||||
*
|
||||
* @param array $config Calendar options
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
$this->CI =& get_instance();
|
||||
$this->CI->lang->load('calendar');
|
||||
|
||||
empty($config) OR $this->initialize($config);
|
||||
|
||||
log_message('info', 'Calendar Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize the user preferences
|
||||
*
|
||||
* Accepts an associative array as input, containing display preferences
|
||||
*
|
||||
* @param array config preferences
|
||||
* @return CI_Calendar
|
||||
*/
|
||||
public function initialize($config = array())
|
||||
{
|
||||
foreach ($config as $key => $val)
|
||||
{
|
||||
if (isset($this->$key))
|
||||
{
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the next_prev_url to the controller if required but not defined
|
||||
if ($this->show_next_prev === TRUE && empty($this->next_prev_url))
|
||||
{
|
||||
$this->next_prev_url = $this->CI->config->site_url($this->CI->router->class.'/'.$this->CI->router->method);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate the calendar
|
||||
*
|
||||
* @param int the year
|
||||
* @param int the month
|
||||
* @param array the data to be shown in the calendar cells
|
||||
* @return string
|
||||
*/
|
||||
public function generate($year = '', $month = '', $data = array())
|
||||
{
|
||||
$local_time = time();
|
||||
|
||||
// Set and validate the supplied month/year
|
||||
if (empty($year))
|
||||
{
|
||||
$year = date('Y', $local_time);
|
||||
}
|
||||
elseif (strlen($year) === 1)
|
||||
{
|
||||
$year = '200'.$year;
|
||||
}
|
||||
elseif (strlen($year) === 2)
|
||||
{
|
||||
$year = '20'.$year;
|
||||
}
|
||||
|
||||
if (empty($month))
|
||||
{
|
||||
$month = date('m', $local_time);
|
||||
}
|
||||
elseif (strlen($month) === 1)
|
||||
{
|
||||
$month = '0'.$month;
|
||||
}
|
||||
|
||||
$adjusted_date = $this->adjust_date($month, $year);
|
||||
|
||||
$month = $adjusted_date['month'];
|
||||
$year = $adjusted_date['year'];
|
||||
|
||||
// Determine the total days in the month
|
||||
$total_days = $this->get_total_days($month, $year);
|
||||
|
||||
// Set the starting day of the week
|
||||
$start_days = array('sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6);
|
||||
$start_day = isset($start_days[$this->start_day]) ? $start_days[$this->start_day] : 0;
|
||||
|
||||
// Set the starting day number
|
||||
$local_date = mktime(12, 0, 0, $month, 1, $year);
|
||||
$date = getdate($local_date);
|
||||
$day = $start_day + 1 - $date['wday'];
|
||||
|
||||
while ($day > 1)
|
||||
{
|
||||
$day -= 7;
|
||||
}
|
||||
|
||||
// Set the current month/year/day
|
||||
// We use this to determine the "today" date
|
||||
$cur_year = date('Y', $local_time);
|
||||
$cur_month = date('m', $local_time);
|
||||
$cur_day = date('j', $local_time);
|
||||
|
||||
$is_current_month = ($cur_year == $year && $cur_month == $month);
|
||||
|
||||
// Generate the template data array
|
||||
$this->parse_template();
|
||||
|
||||
// Begin building the calendar output
|
||||
$out = $this->replacements['table_open']."\n\n".$this->replacements['heading_row_start']."\n";
|
||||
|
||||
// "previous" month link
|
||||
if ($this->show_next_prev === TRUE)
|
||||
{
|
||||
// Add a trailing slash to the URL if needed
|
||||
$this->next_prev_url = preg_replace('/(.+?)\/*$/', '\\1/', $this->next_prev_url);
|
||||
|
||||
$adjusted_date = $this->adjust_date($month - 1, $year);
|
||||
$out .= str_replace('{previous_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->replacements['heading_previous_cell'])."\n";
|
||||
}
|
||||
|
||||
// Heading containing the month/year
|
||||
$colspan = ($this->show_next_prev === TRUE) ? 5 : 7;
|
||||
|
||||
$this->replacements['heading_title_cell'] = str_replace('{colspan}', $colspan,
|
||||
str_replace('{heading}', $this->get_month_name($month).' '.$year, $this->replacements['heading_title_cell']));
|
||||
|
||||
$out .= $this->replacements['heading_title_cell']."\n";
|
||||
|
||||
// "next" month link
|
||||
if ($this->show_next_prev === TRUE)
|
||||
{
|
||||
$adjusted_date = $this->adjust_date($month + 1, $year);
|
||||
$out .= str_replace('{next_url}', $this->next_prev_url.$adjusted_date['year'].'/'.$adjusted_date['month'], $this->replacements['heading_next_cell']);
|
||||
}
|
||||
|
||||
$out .= "\n".$this->replacements['heading_row_end']."\n\n"
|
||||
// Write the cells containing the days of the week
|
||||
.$this->replacements['week_row_start']."\n";
|
||||
|
||||
$day_names = $this->get_day_names();
|
||||
|
||||
for ($i = 0; $i < 7; $i ++)
|
||||
{
|
||||
$out .= str_replace('{week_day}', $day_names[($start_day + $i) %7], $this->replacements['week_day_cell']);
|
||||
}
|
||||
|
||||
$out .= "\n".$this->replacements['week_row_end']."\n";
|
||||
|
||||
// Build the main body of the calendar
|
||||
while ($day <= $total_days)
|
||||
{
|
||||
$out .= "\n".$this->replacements['cal_row_start']."\n";
|
||||
|
||||
for ($i = 0; $i < 7; $i++)
|
||||
{
|
||||
if ($day > 0 && $day <= $total_days)
|
||||
{
|
||||
$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->replacements['cal_cell_start_today'] : $this->replacements['cal_cell_start'];
|
||||
|
||||
if (isset($data[$day]))
|
||||
{
|
||||
// Cells with content
|
||||
$temp = ($is_current_month === TRUE && $day == $cur_day) ?
|
||||
$this->replacements['cal_cell_content_today'] : $this->replacements['cal_cell_content'];
|
||||
$out .= str_replace(array('{content}', '{day}'), array($data[$day], $day), $temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cells with no content
|
||||
$temp = ($is_current_month === TRUE && $day == $cur_day) ?
|
||||
$this->replacements['cal_cell_no_content_today'] : $this->replacements['cal_cell_no_content'];
|
||||
$out .= str_replace('{day}', $day, $temp);
|
||||
}
|
||||
|
||||
$out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->replacements['cal_cell_end_today'] : $this->replacements['cal_cell_end'];
|
||||
}
|
||||
elseif ($this->show_other_days === TRUE)
|
||||
{
|
||||
$out .= $this->replacements['cal_cell_start_other'];
|
||||
|
||||
if ($day <= 0)
|
||||
{
|
||||
// Day of previous month
|
||||
$prev_month = $this->adjust_date($month - 1, $year);
|
||||
$prev_month_days = $this->get_total_days($prev_month['month'], $prev_month['year']);
|
||||
$out .= str_replace('{day}', $prev_month_days + $day, $this->replacements['cal_cell_other']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Day of next month
|
||||
$out .= str_replace('{day}', $day - $total_days, $this->replacements['cal_cell_other']);
|
||||
}
|
||||
|
||||
$out .= $this->replacements['cal_cell_end_other'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blank cells
|
||||
$out .= $this->replacements['cal_cell_start'].$this->replacements['cal_cell_blank'].$this->replacements['cal_cell_end'];
|
||||
}
|
||||
|
||||
$day++;
|
||||
}
|
||||
|
||||
$out .= "\n".$this->replacements['cal_row_end']."\n";
|
||||
}
|
||||
|
||||
return $out .= "\n".$this->replacements['table_close'];
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Month Name
|
||||
*
|
||||
* Generates a textual month name based on the numeric
|
||||
* month provided.
|
||||
*
|
||||
* @param int the month
|
||||
* @return string
|
||||
*/
|
||||
public function get_month_name($month)
|
||||
{
|
||||
if ($this->month_type === 'short')
|
||||
{
|
||||
$month_names = array('01' => 'cal_jan', '02' => 'cal_feb', '03' => 'cal_mar', '04' => 'cal_apr', '05' => 'cal_may', '06' => 'cal_jun', '07' => 'cal_jul', '08' => 'cal_aug', '09' => 'cal_sep', '10' => 'cal_oct', '11' => 'cal_nov', '12' => 'cal_dec');
|
||||
}
|
||||
else
|
||||
{
|
||||
$month_names = array('01' => 'cal_january', '02' => 'cal_february', '03' => 'cal_march', '04' => 'cal_april', '05' => 'cal_mayl', '06' => 'cal_june', '07' => 'cal_july', '08' => 'cal_august', '09' => 'cal_september', '10' => 'cal_october', '11' => 'cal_november', '12' => 'cal_december');
|
||||
}
|
||||
|
||||
return ($this->CI->lang->line($month_names[$month]) === FALSE)
|
||||
? ucfirst(substr($month_names[$month], 4))
|
||||
: $this->CI->lang->line($month_names[$month]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Day Names
|
||||
*
|
||||
* Returns an array of day names (Sunday, Monday, etc.) based
|
||||
* on the type. Options: long, short, abr
|
||||
*
|
||||
* @param string
|
||||
* @return array
|
||||
*/
|
||||
public function get_day_names($day_type = '')
|
||||
{
|
||||
if ($day_type !== '')
|
||||
{
|
||||
$this->day_type = $day_type;
|
||||
}
|
||||
|
||||
if ($this->day_type === 'long')
|
||||
{
|
||||
$day_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
|
||||
}
|
||||
elseif ($this->day_type === 'short')
|
||||
{
|
||||
$day_names = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat');
|
||||
}
|
||||
else
|
||||
{
|
||||
$day_names = array('su', 'mo', 'tu', 'we', 'th', 'fr', 'sa');
|
||||
}
|
||||
|
||||
$days = array();
|
||||
for ($i = 0, $c = count($day_names); $i < $c; $i++)
|
||||
{
|
||||
$days[] = ($this->CI->lang->line('cal_'.$day_names[$i]) === FALSE) ? ucfirst($day_names[$i]) : $this->CI->lang->line('cal_'.$day_names[$i]);
|
||||
}
|
||||
|
||||
return $days;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Adjust Date
|
||||
*
|
||||
* This function makes sure that we have a valid month/year.
|
||||
* For example, if you submit 13 as the month, the year will
|
||||
* increment and the month will become January.
|
||||
*
|
||||
* @param int the month
|
||||
* @param int the year
|
||||
* @return array
|
||||
*/
|
||||
public function adjust_date($month, $year)
|
||||
{
|
||||
$date = array();
|
||||
|
||||
$date['month'] = $month;
|
||||
$date['year'] = $year;
|
||||
|
||||
while ($date['month'] > 12)
|
||||
{
|
||||
$date['month'] -= 12;
|
||||
$date['year']++;
|
||||
}
|
||||
|
||||
while ($date['month'] <= 0)
|
||||
{
|
||||
$date['month'] += 12;
|
||||
$date['year']--;
|
||||
}
|
||||
|
||||
if (strlen($date['month']) === 1)
|
||||
{
|
||||
$date['month'] = '0'.$date['month'];
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Total days in a given month
|
||||
*
|
||||
* @param int the month
|
||||
* @param int the year
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_days($month, $year)
|
||||
{
|
||||
$this->CI->load->helper('date');
|
||||
return days_in_month($month, $year);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set Default Template Data
|
||||
*
|
||||
* This is used in the event that the user has not created their own template
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function default_template()
|
||||
{
|
||||
return array(
|
||||
'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
|
||||
'heading_row_start' => '<tr>',
|
||||
'heading_previous_cell' => '<th><a href="{previous_url}"><<</a></th>',
|
||||
'heading_title_cell' => '<th colspan="{colspan}">{heading}</th>',
|
||||
'heading_next_cell' => '<th><a href="{next_url}">>></a></th>',
|
||||
'heading_row_end' => '</tr>',
|
||||
'week_row_start' => '<tr>',
|
||||
'week_day_cell' => '<td>{week_day}</td>',
|
||||
'week_row_end' => '</tr>',
|
||||
'cal_row_start' => '<tr>',
|
||||
'cal_cell_start' => '<td>',
|
||||
'cal_cell_start_today' => '<td>',
|
||||
'cal_cell_start_other' => '<td style="color: #666;">',
|
||||
'cal_cell_content' => '<a href="{content}">{day}</a>',
|
||||
'cal_cell_content_today' => '<a href="{content}"><strong>{day}</strong></a>',
|
||||
'cal_cell_no_content' => '{day}',
|
||||
'cal_cell_no_content_today' => '<strong>{day}</strong>',
|
||||
'cal_cell_blank' => ' ',
|
||||
'cal_cell_other' => '{day}',
|
||||
'cal_cell_end' => '</td>',
|
||||
'cal_cell_end_today' => '</td>',
|
||||
'cal_cell_end_other' => '</td>',
|
||||
'cal_row_end' => '</tr>',
|
||||
'table_close' => '</table>'
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse Template
|
||||
*
|
||||
* Harvests the data within the template {pseudo-variables}
|
||||
* used to display the calendar
|
||||
*
|
||||
* @return CI_Calendar
|
||||
*/
|
||||
public function parse_template()
|
||||
{
|
||||
$this->replacements = $this->default_template();
|
||||
|
||||
if (empty($this->template))
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (is_string($this->template))
|
||||
{
|
||||
$today = array('cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today');
|
||||
|
||||
foreach (array('table_open', 'table_close', 'heading_row_start', 'heading_previous_cell', 'heading_title_cell', 'heading_next_cell', 'heading_row_end', 'week_row_start', 'week_day_cell', 'week_row_end', 'cal_row_start', 'cal_cell_start', 'cal_cell_content', 'cal_cell_no_content', 'cal_cell_blank', 'cal_cell_end', 'cal_row_end', 'cal_cell_start_today', 'cal_cell_content_today', 'cal_cell_no_content_today', 'cal_cell_end_today', 'cal_cell_start_other', 'cal_cell_other', 'cal_cell_end_other') as $val)
|
||||
{
|
||||
if (preg_match('/\{'.$val.'\}(.*?)\{\/'.$val.'\}/si', $this->template, $match))
|
||||
{
|
||||
$this->replacements[$val] = $match[1];
|
||||
}
|
||||
elseif (in_array($val, $today, TRUE))
|
||||
{
|
||||
$this->replacements[$val] = $this->replacements[substr($val, 0, -6)];
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (is_array($this->template))
|
||||
{
|
||||
$this->replacements = array_merge($this->replacements, $this->template);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
567
php/system/libraries/Cart.php
Normal file
567
php/system/libraries/Cart.php
Normal file
@ -0,0 +1,567 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Shopping Cart Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Shopping Cart
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/cart.html
|
||||
* @deprecated 3.0.0 This class is too specific for CI.
|
||||
*/
|
||||
class CI_Cart {
|
||||
|
||||
/**
|
||||
* These are the regular expression rules that we use to validate the product ID and product name
|
||||
* alpha-numeric, dashes, underscores, or periods
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $product_id_rules = '\.a-z0-9_-';
|
||||
|
||||
/**
|
||||
* These are the regular expression rules that we use to validate the product ID and product name
|
||||
* alpha-numeric, dashes, underscores, colons or periods
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $product_name_rules = '\w \-\.\:';
|
||||
|
||||
/**
|
||||
* only allow safe product names
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $product_name_safe = TRUE;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reference to CodeIgniter instance
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
/**
|
||||
* Contents of the cart
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_cart_contents = array();
|
||||
|
||||
/**
|
||||
* Shopping Class Constructor
|
||||
*
|
||||
* The constructor loads the Session class, used to store the shopping cart contents.
|
||||
*
|
||||
* @param array
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($params = array())
|
||||
{
|
||||
// Set the super object to a local variable for use later
|
||||
$this->CI =& get_instance();
|
||||
|
||||
// Are any config settings being passed manually? If so, set them
|
||||
$config = is_array($params) ? $params : array();
|
||||
|
||||
// Load the Sessions class
|
||||
$this->CI->load->driver('session', $config);
|
||||
|
||||
// Grab the shopping cart array from the session table
|
||||
$this->_cart_contents = $this->CI->session->userdata('cart_contents');
|
||||
if ($this->_cart_contents === NULL)
|
||||
{
|
||||
// No cart exists so we'll set some base values
|
||||
$this->_cart_contents = array('cart_total' => 0, 'total_items' => 0);
|
||||
}
|
||||
|
||||
log_message('info', 'Cart Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Insert items into the cart and save it to the session table
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
public function insert($items = array())
|
||||
{
|
||||
// Was any cart data passed? No? Bah...
|
||||
if ( ! is_array($items) OR count($items) === 0)
|
||||
{
|
||||
log_message('error', 'The insert method must be passed an array containing data.');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// You can either insert a single product using a one-dimensional array,
|
||||
// or multiple products using a multi-dimensional one. The way we
|
||||
// determine the array type is by looking for a required array key named "id"
|
||||
// at the top level. If it's not found, we will assume it's a multi-dimensional array.
|
||||
|
||||
$save_cart = FALSE;
|
||||
if (isset($items['id']))
|
||||
{
|
||||
if (($rowid = $this->_insert($items)))
|
||||
{
|
||||
$save_cart = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($items as $val)
|
||||
{
|
||||
if (is_array($val) && isset($val['id']))
|
||||
{
|
||||
if ($this->_insert($val))
|
||||
{
|
||||
$save_cart = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the cart data if the insert was successful
|
||||
if ($save_cart === TRUE)
|
||||
{
|
||||
$this->_save_cart();
|
||||
return isset($rowid) ? $rowid : TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Insert
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
protected function _insert($items = array())
|
||||
{
|
||||
// Was any cart data passed? No? Bah...
|
||||
if ( ! is_array($items) OR count($items) === 0)
|
||||
{
|
||||
log_message('error', 'The insert method must be passed an array containing data.');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Does the $items array contain an id, quantity, price, and name? These are required
|
||||
if ( ! isset($items['id'], $items['qty'], $items['price'], $items['name']))
|
||||
{
|
||||
log_message('error', 'The cart array must contain a product ID, quantity, price, and name.');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Prep the quantity. It can only be a number. Duh... also trim any leading zeros
|
||||
$items['qty'] = (float) $items['qty'];
|
||||
|
||||
// If the quantity is zero or blank there's nothing for us to do
|
||||
if ($items['qty'] == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Validate the product ID. It can only be alpha-numeric, dashes, underscores or periods
|
||||
// Not totally sure we should impose this rule, but it seems prudent to standardize IDs.
|
||||
// Note: These can be user-specified by setting the $this->product_id_rules variable.
|
||||
if ( ! preg_match('/^['.$this->product_id_rules.']+$/i', $items['id']))
|
||||
{
|
||||
log_message('error', 'Invalid product ID. The product ID can only contain alpha-numeric characters, dashes, and underscores');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Validate the product name. It can only be alpha-numeric, dashes, underscores, colons or periods.
|
||||
// Note: These can be user-specified by setting the $this->product_name_rules variable.
|
||||
if ($this->product_name_safe && ! preg_match('/^['.$this->product_name_rules.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $items['name']))
|
||||
{
|
||||
log_message('error', 'An invalid name was submitted as the product name: '.$items['name'].' The name can only contain alpha-numeric characters, dashes, underscores, colons, and spaces');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Prep the price. Remove leading zeros and anything that isn't a number or decimal point.
|
||||
$items['price'] = (float) $items['price'];
|
||||
|
||||
// We now need to create a unique identifier for the item being inserted into the cart.
|
||||
// Every time something is added to the cart it is stored in the master cart array.
|
||||
// Each row in the cart array, however, must have a unique index that identifies not only
|
||||
// a particular product, but makes it possible to store identical products with different options.
|
||||
// For example, what if someone buys two identical t-shirts (same product ID), but in
|
||||
// different sizes? The product ID (and other attributes, like the name) will be identical for
|
||||
// both sizes because it's the same shirt. The only difference will be the size.
|
||||
// Internally, we need to treat identical submissions, but with different options, as a unique product.
|
||||
// Our solution is to convert the options array to a string and MD5 it along with the product ID.
|
||||
// This becomes the unique "row ID"
|
||||
if (isset($items['options']) && count($items['options']) > 0)
|
||||
{
|
||||
$rowid = md5($items['id'].serialize($items['options']));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No options were submitted so we simply MD5 the product ID.
|
||||
// Technically, we don't need to MD5 the ID in this case, but it makes
|
||||
// sense to standardize the format of array indexes for both conditions
|
||||
$rowid = md5($items['id']);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// Now that we have our unique "row ID", we'll add our cart items to the master array
|
||||
// grab quantity if it's already there and add it on
|
||||
$old_quantity = isset($this->_cart_contents[$rowid]['qty']) ? (int) $this->_cart_contents[$rowid]['qty'] : 0;
|
||||
|
||||
// Re-create the entry, just to make sure our index contains only the data from this submission
|
||||
$items['rowid'] = $rowid;
|
||||
$items['qty'] += $old_quantity;
|
||||
$this->_cart_contents[$rowid] = $items;
|
||||
|
||||
return $rowid;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update the cart
|
||||
*
|
||||
* This function permits the quantity of a given item to be changed.
|
||||
* Typically it is called from the "view cart" page if a user makes
|
||||
* changes to the quantity before checkout. That array must contain the
|
||||
* product ID and quantity for each item.
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
public function update($items = array())
|
||||
{
|
||||
// Was any cart data passed?
|
||||
if ( ! is_array($items) OR count($items) === 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// You can either update a single product using a one-dimensional array,
|
||||
// or multiple products using a multi-dimensional one. The way we
|
||||
// determine the array type is by looking for a required array key named "rowid".
|
||||
// If it's not found we assume it's a multi-dimensional array
|
||||
$save_cart = FALSE;
|
||||
if (isset($items['rowid']))
|
||||
{
|
||||
if ($this->_update($items) === TRUE)
|
||||
{
|
||||
$save_cart = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($items as $val)
|
||||
{
|
||||
if (is_array($val) && isset($val['rowid']))
|
||||
{
|
||||
if ($this->_update($val) === TRUE)
|
||||
{
|
||||
$save_cart = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the cart data if the insert was successful
|
||||
if ($save_cart === TRUE)
|
||||
{
|
||||
$this->_save_cart();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update the cart
|
||||
*
|
||||
* This function permits changing item properties.
|
||||
* Typically it is called from the "view cart" page if a user makes
|
||||
* changes to the quantity before checkout. That array must contain the
|
||||
* rowid and quantity for each item.
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
protected function _update($items = array())
|
||||
{
|
||||
// Without these array indexes there is nothing we can do
|
||||
if ( ! isset($items['rowid'], $this->_cart_contents[$items['rowid']]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Prep the quantity
|
||||
if (isset($items['qty']))
|
||||
{
|
||||
$items['qty'] = (float) $items['qty'];
|
||||
// Is the quantity zero? If so we will remove the item from the cart.
|
||||
// If the quantity is greater than zero we are updating
|
||||
if ($items['qty'] == 0)
|
||||
{
|
||||
unset($this->_cart_contents[$items['rowid']]);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// find updatable keys
|
||||
$keys = array_intersect(array_keys($this->_cart_contents[$items['rowid']]), array_keys($items));
|
||||
// if a price was passed, make sure it contains valid data
|
||||
if (isset($items['price']))
|
||||
{
|
||||
$items['price'] = (float) $items['price'];
|
||||
}
|
||||
|
||||
// product id & name shouldn't be changed
|
||||
foreach (array_diff($keys, array('id', 'name')) as $key)
|
||||
{
|
||||
$this->_cart_contents[$items['rowid']][$key] = $items[$key];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Save the cart array to the session DB
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _save_cart()
|
||||
{
|
||||
// Let's add up the individual prices and set the cart sub-total
|
||||
$this->_cart_contents['total_items'] = $this->_cart_contents['cart_total'] = 0;
|
||||
foreach ($this->_cart_contents as $key => $val)
|
||||
{
|
||||
// We make sure the array contains the proper indexes
|
||||
if ( ! is_array($val) OR ! isset($val['price'], $val['qty']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->_cart_contents['cart_total'] += ($val['price'] * $val['qty']);
|
||||
$this->_cart_contents['total_items'] += $val['qty'];
|
||||
$this->_cart_contents[$key]['subtotal'] = ($this->_cart_contents[$key]['price'] * $this->_cart_contents[$key]['qty']);
|
||||
}
|
||||
|
||||
// Is our cart empty? If so we delete it from the session
|
||||
if (count($this->_cart_contents) <= 2)
|
||||
{
|
||||
$this->CI->session->unset_userdata('cart_contents');
|
||||
|
||||
// Nothing more to do... coffee time!
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If we made it this far it means that our cart has data.
|
||||
// Let's pass it to the Session class so it can be stored
|
||||
$this->CI->session->set_userdata(array('cart_contents' => $this->_cart_contents));
|
||||
|
||||
// Woot!
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cart Total
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function total()
|
||||
{
|
||||
return $this->_cart_contents['cart_total'];
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Remove Item
|
||||
*
|
||||
* Removes an item from the cart
|
||||
*
|
||||
* @param int
|
||||
* @return bool
|
||||
*/
|
||||
public function remove($rowid)
|
||||
{
|
||||
// unset & save
|
||||
unset($this->_cart_contents[$rowid]);
|
||||
$this->_save_cart();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Total Items
|
||||
*
|
||||
* Returns the total item count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function total_items()
|
||||
{
|
||||
return $this->_cart_contents['total_items'];
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cart Contents
|
||||
*
|
||||
* Returns the entire cart array
|
||||
*
|
||||
* @param bool
|
||||
* @return array
|
||||
*/
|
||||
public function contents($newest_first = FALSE)
|
||||
{
|
||||
// do we want the newest first?
|
||||
$cart = ($newest_first) ? array_reverse($this->_cart_contents) : $this->_cart_contents;
|
||||
|
||||
// Remove these so they don't create a problem when showing the cart table
|
||||
unset($cart['total_items']);
|
||||
unset($cart['cart_total']);
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get cart item
|
||||
*
|
||||
* Returns the details of a specific item in the cart
|
||||
*
|
||||
* @param string $row_id
|
||||
* @return array
|
||||
*/
|
||||
public function get_item($row_id)
|
||||
{
|
||||
return (in_array($row_id, array('total_items', 'cart_total'), TRUE) OR ! isset($this->_cart_contents[$row_id]))
|
||||
? FALSE
|
||||
: $this->_cart_contents[$row_id];
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Has options
|
||||
*
|
||||
* Returns TRUE if the rowid passed to this function correlates to an item
|
||||
* that has options associated with it.
|
||||
*
|
||||
* @param string $row_id = ''
|
||||
* @return bool
|
||||
*/
|
||||
public function has_options($row_id = '')
|
||||
{
|
||||
return (isset($this->_cart_contents[$row_id]['options']) && count($this->_cart_contents[$row_id]['options']) !== 0);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Product options
|
||||
*
|
||||
* Returns the an array of options, for a particular product row ID
|
||||
*
|
||||
* @param string $row_id = ''
|
||||
* @return array
|
||||
*/
|
||||
public function product_options($row_id = '')
|
||||
{
|
||||
return isset($this->_cart_contents[$row_id]['options']) ? $this->_cart_contents[$row_id]['options'] : array();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Format Number
|
||||
*
|
||||
* Returns the supplied number with commas and a decimal point.
|
||||
*
|
||||
* @param float
|
||||
* @return string
|
||||
*/
|
||||
public function format_number($n = '')
|
||||
{
|
||||
return ($n === '') ? '' : number_format( (float) $n, 2, '.', ',');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroy the cart
|
||||
*
|
||||
* Empties the cart and kills the session
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
$this->_cart_contents = array('cart_total' => 0, 'total_items' => 0);
|
||||
$this->CI->session->unset_userdata('cart_contents');
|
||||
}
|
||||
|
||||
}
|
342
php/system/libraries/Driver.php
Normal file
342
php/system/libraries/Driver.php
Normal file
@ -0,0 +1,342 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
2490
php/system/libraries/Email.php
Normal file
2490
php/system/libraries/Email.php
Normal file
File diff suppressed because it is too large
Load Diff
521
php/system/libraries/Encrypt.php
Normal file
521
php/system/libraries/Encrypt.php
Normal file
@ -0,0 +1,521 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Encryption Class
|
||||
*
|
||||
* Provides two-way keyed encoding using Mcrypt
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/encryption.html
|
||||
*/
|
||||
class CI_Encrypt {
|
||||
|
||||
/**
|
||||
* Reference to the user's encryption key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $encryption_key = '';
|
||||
|
||||
/**
|
||||
* Type of hash operation
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_hash_type = 'sha1';
|
||||
|
||||
/**
|
||||
* Flag for the existence of mcrypt
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_mcrypt_exists = FALSE;
|
||||
|
||||
/**
|
||||
* Current cipher to be used with mcrypt
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_mcrypt_cipher;
|
||||
|
||||
/**
|
||||
* Method for encrypting/decrypting data
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_mcrypt_mode;
|
||||
|
||||
/**
|
||||
* Initialize Encryption class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (($this->_mcrypt_exists = function_exists('mcrypt_encrypt')) === FALSE)
|
||||
{
|
||||
show_error('The Encrypt library requires the Mcrypt extension.');
|
||||
}
|
||||
|
||||
log_message('info', 'Encrypt Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch the encryption key
|
||||
*
|
||||
* Returns it as MD5 in order to have an exact-length 128 bit key.
|
||||
* Mcrypt is sensitive to keys that are not the correct length
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function get_key($key = '')
|
||||
{
|
||||
if ($key === '')
|
||||
{
|
||||
if ($this->encryption_key !== '')
|
||||
{
|
||||
return $this->encryption_key;
|
||||
}
|
||||
|
||||
$key = config_item('encryption_key');
|
||||
|
||||
if ( ! self::strlen($key))
|
||||
{
|
||||
show_error('In order to use the encryption class requires that you set an encryption key in your config file.');
|
||||
}
|
||||
}
|
||||
|
||||
return md5($key);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the encryption key
|
||||
*
|
||||
* @param string
|
||||
* @return CI_Encrypt
|
||||
*/
|
||||
public function set_key($key = '')
|
||||
{
|
||||
$this->encryption_key = $key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encode
|
||||
*
|
||||
* Encodes the message string using bitwise XOR encoding.
|
||||
* The key is combined with a random hash, and then it
|
||||
* too gets converted using XOR. The whole thing is then run
|
||||
* through mcrypt using the randomized key. The end result
|
||||
* is a double-encrypted message string that is randomized
|
||||
* with each call to this function, even if the supplied
|
||||
* message and key are the same.
|
||||
*
|
||||
* @param string the string to encode
|
||||
* @param string the key
|
||||
* @return string
|
||||
*/
|
||||
public function encode($string, $key = '')
|
||||
{
|
||||
return base64_encode($this->mcrypt_encode($string, $this->get_key($key)));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decode
|
||||
*
|
||||
* Reverses the above process
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function decode($string, $key = '')
|
||||
{
|
||||
if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $this->mcrypt_decode(base64_decode($string), $this->get_key($key));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encode from Legacy
|
||||
*
|
||||
* Takes an encoded string from the original Encryption class algorithms and
|
||||
* returns a newly encoded string using the improved method added in 2.0.0
|
||||
* This allows for backwards compatibility and a method to transition to the
|
||||
* new encryption algorithms.
|
||||
*
|
||||
* For more details, see https://codeigniter.com/user_guide/installation/upgrade_200.html#encryption
|
||||
*
|
||||
* @param string
|
||||
* @param int (mcrypt mode constant)
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')
|
||||
{
|
||||
if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// decode it first
|
||||
// set mode temporarily to what it was when string was encoded with the legacy
|
||||
// algorithm - typically MCRYPT_MODE_ECB
|
||||
$current_mode = $this->_get_mode();
|
||||
$this->set_mode($legacy_mode);
|
||||
|
||||
$key = $this->get_key($key);
|
||||
$dec = base64_decode($string);
|
||||
if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)
|
||||
{
|
||||
$this->set_mode($current_mode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$dec = $this->_xor_decode($dec, $key);
|
||||
|
||||
// set the mcrypt mode back to what it should be, typically MCRYPT_MODE_CBC
|
||||
$this->set_mode($current_mode);
|
||||
|
||||
// and re-encode
|
||||
return base64_encode($this->mcrypt_encode($dec, $key));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* XOR Decode
|
||||
*
|
||||
* Takes an encoded string and key as input and generates the
|
||||
* plain-text original message
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _xor_decode($string, $key)
|
||||
{
|
||||
$string = $this->_xor_merge($string, $key);
|
||||
|
||||
$dec = '';
|
||||
for ($i = 0, $l = self::strlen($string); $i < $l; $i++)
|
||||
{
|
||||
$dec .= ($string[$i++] ^ $string[$i]);
|
||||
}
|
||||
|
||||
return $dec;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* XOR key + string Combiner
|
||||
*
|
||||
* Takes a string and key as input and computes the difference using XOR
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _xor_merge($string, $key)
|
||||
{
|
||||
$hash = $this->hash($key);
|
||||
$str = '';
|
||||
|
||||
for ($i = 0, $ls = self::strlen($string), $lh = self::strlen($hash); $i < $ls; $i++)
|
||||
{
|
||||
$str .= $string[$i] ^ $hash[($i % $lh)];
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encrypt using Mcrypt
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function mcrypt_encode($data, $key)
|
||||
{
|
||||
$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
|
||||
$init_vect = mcrypt_create_iv($init_size, MCRYPT_DEV_URANDOM);
|
||||
return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrypt using Mcrypt
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function mcrypt_decode($data, $key)
|
||||
{
|
||||
$data = $this->_remove_cipher_noise($data, $key);
|
||||
$init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
|
||||
|
||||
if ($init_size > self::strlen($data))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$init_vect = self::substr($data, 0, $init_size);
|
||||
$data = self::substr($data, $init_size);
|
||||
|
||||
return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Adds permuted noise to the IV + encrypted data to protect
|
||||
* against Man-in-the-middle attacks on CBC mode ciphers
|
||||
* http://www.ciphersbyritter.com/GLOSSARY.HTM#IV
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _add_cipher_noise($data, $key)
|
||||
{
|
||||
$key = $this->hash($key);
|
||||
$str = '';
|
||||
|
||||
for ($i = 0, $j = 0, $ld = self::strlen($data), $lk = self::strlen($key); $i < $ld; ++$i, ++$j)
|
||||
{
|
||||
if ($j >= $lk)
|
||||
{
|
||||
$j = 0;
|
||||
}
|
||||
|
||||
$str .= chr((ord($data[$i]) + ord($key[$j])) % 256);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Removes permuted noise from the IV + encrypted data, reversing
|
||||
* _add_cipher_noise()
|
||||
*
|
||||
* Function description
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function _remove_cipher_noise($data, $key)
|
||||
{
|
||||
$key = $this->hash($key);
|
||||
$str = '';
|
||||
|
||||
for ($i = 0, $j = 0, $ld = self::strlen($data), $lk = self::strlen($key); $i < $ld; ++$i, ++$j)
|
||||
{
|
||||
if ($j >= $lk)
|
||||
{
|
||||
$j = 0;
|
||||
}
|
||||
|
||||
$temp = ord($data[$i]) - ord($key[$j]);
|
||||
|
||||
if ($temp < 0)
|
||||
{
|
||||
$temp += 256;
|
||||
}
|
||||
|
||||
$str .= chr($temp);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Mcrypt Cipher
|
||||
*
|
||||
* @param int
|
||||
* @return CI_Encrypt
|
||||
*/
|
||||
public function set_cipher($cipher)
|
||||
{
|
||||
$this->_mcrypt_cipher = $cipher;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Mcrypt Mode
|
||||
*
|
||||
* @param int
|
||||
* @return CI_Encrypt
|
||||
*/
|
||||
public function set_mode($mode)
|
||||
{
|
||||
$this->_mcrypt_mode = $mode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Mcrypt cipher Value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function _get_cipher()
|
||||
{
|
||||
if ($this->_mcrypt_cipher === NULL)
|
||||
{
|
||||
return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;
|
||||
}
|
||||
|
||||
return $this->_mcrypt_cipher;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Mcrypt Mode Value
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function _get_mode()
|
||||
{
|
||||
if ($this->_mcrypt_mode === NULL)
|
||||
{
|
||||
return $this->_mcrypt_mode = MCRYPT_MODE_CBC;
|
||||
}
|
||||
|
||||
return $this->_mcrypt_mode;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Hash type
|
||||
*
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function set_hash($type = 'sha1')
|
||||
{
|
||||
$this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Hash encode a string
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function hash($str)
|
||||
{
|
||||
return hash($this->_hash_type, $str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe strlen()
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
protected static function strlen($str)
|
||||
{
|
||||
return defined('MB_OVERLOAD_STRING')
|
||||
? mb_strlen($str, '8bit')
|
||||
: strlen($str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe substr()
|
||||
*
|
||||
* @param string $str
|
||||
* @param int $start
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
protected static function substr($str, $start, $length = NULL)
|
||||
{
|
||||
if (defined('MB_OVERLOAD_STRING'))
|
||||
{
|
||||
// mb_substr($str, $start, null, '8bit') returns an empty
|
||||
// string on PHP 5.3
|
||||
isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
|
||||
return mb_substr($str, $start, $length, '8bit');
|
||||
}
|
||||
|
||||
return isset($length)
|
||||
? substr($str, $start, $length)
|
||||
: substr($str, $start);
|
||||
}
|
||||
}
|
941
php/system/libraries/Encryption.php
Normal file
941
php/system/libraries/Encryption.php
Normal file
@ -0,0 +1,941 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Encryption Class
|
||||
*
|
||||
* Provides two-way keyed encryption via PHP's MCrypt and/or OpenSSL extensions.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/encryption.html
|
||||
*/
|
||||
class CI_Encryption {
|
||||
|
||||
/**
|
||||
* Encryption cipher
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_cipher = 'aes-128';
|
||||
|
||||
/**
|
||||
* Cipher mode
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_mode = 'cbc';
|
||||
|
||||
/**
|
||||
* Cipher handle
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $_handle;
|
||||
|
||||
/**
|
||||
* Encryption key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_key;
|
||||
|
||||
/**
|
||||
* PHP extension to be used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_driver;
|
||||
|
||||
/**
|
||||
* List of usable drivers (PHP extensions)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_drivers = array();
|
||||
|
||||
/**
|
||||
* List of available modes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_modes = array(
|
||||
'mcrypt' => array(
|
||||
'cbc' => 'cbc',
|
||||
'ecb' => 'ecb',
|
||||
'ofb' => 'nofb',
|
||||
'ofb8' => 'ofb',
|
||||
'cfb' => 'ncfb',
|
||||
'cfb8' => 'cfb',
|
||||
'ctr' => 'ctr',
|
||||
'stream' => 'stream'
|
||||
),
|
||||
'openssl' => array(
|
||||
'cbc' => 'cbc',
|
||||
'ecb' => 'ecb',
|
||||
'ofb' => 'ofb',
|
||||
'cfb' => 'cfb',
|
||||
'cfb8' => 'cfb8',
|
||||
'ctr' => 'ctr',
|
||||
'stream' => '',
|
||||
'xts' => 'xts'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* List of supported HMAC algorithms
|
||||
*
|
||||
* name => digest size pairs
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_digests = array(
|
||||
'sha224' => 28,
|
||||
'sha256' => 32,
|
||||
'sha384' => 48,
|
||||
'sha512' => 64
|
||||
);
|
||||
|
||||
/**
|
||||
* mbstring.func_overload flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $func_overload;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $params = array())
|
||||
{
|
||||
$this->_drivers = array(
|
||||
'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
|
||||
'openssl' => extension_loaded('openssl')
|
||||
);
|
||||
|
||||
if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
|
||||
{
|
||||
show_error('Encryption: Unable to find an available encryption driver.');
|
||||
}
|
||||
|
||||
isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
|
||||
$this->initialize($params);
|
||||
|
||||
if ( ! isset($this->_key) && self::strlen($key = config_item('encryption_key')) > 0)
|
||||
{
|
||||
$this->_key = $key;
|
||||
}
|
||||
|
||||
log_message('info', 'Encryption Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return CI_Encryption
|
||||
*/
|
||||
public function initialize(array $params)
|
||||
{
|
||||
if ( ! empty($params['driver']))
|
||||
{
|
||||
if (isset($this->_drivers[$params['driver']]))
|
||||
{
|
||||
if ($this->_drivers[$params['driver']])
|
||||
{
|
||||
$this->_driver = $params['driver'];
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', "Encryption: Driver '".$params['driver']."' is not available.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', "Encryption: Unknown driver '".$params['driver']."' cannot be configured.");
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->_driver))
|
||||
{
|
||||
$this->_driver = ($this->_drivers['openssl'] === TRUE)
|
||||
? 'openssl'
|
||||
: 'mcrypt';
|
||||
|
||||
log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'.");
|
||||
}
|
||||
|
||||
empty($params['cipher']) && $params['cipher'] = $this->_cipher;
|
||||
empty($params['key']) OR $this->_key = $params['key'];
|
||||
$this->{'_'.$this->_driver.'_initialize'}($params);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize MCrypt
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
protected function _mcrypt_initialize($params)
|
||||
{
|
||||
if ( ! empty($params['cipher']))
|
||||
{
|
||||
$params['cipher'] = strtolower($params['cipher']);
|
||||
$this->_cipher_alias($params['cipher']);
|
||||
|
||||
if ( ! in_array($params['cipher'], mcrypt_list_algorithms(), TRUE))
|
||||
{
|
||||
log_message('error', 'Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_cipher = $params['cipher'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty($params['mode']))
|
||||
{
|
||||
$params['mode'] = strtolower($params['mode']);
|
||||
if ( ! isset($this->_modes['mcrypt'][$params['mode']]))
|
||||
{
|
||||
log_message('error', 'Encryption: MCrypt mode '.strtoupper($params['mode']).' is not available.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_mode = $this->_modes['mcrypt'][$params['mode']];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->_cipher, $this->_mode))
|
||||
{
|
||||
if (is_resource($this->_handle)
|
||||
&& (strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher
|
||||
OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode)
|
||||
)
|
||||
{
|
||||
mcrypt_module_close($this->_handle);
|
||||
}
|
||||
|
||||
if ($this->_handle = mcrypt_module_open($this->_cipher, '', $this->_mode, ''))
|
||||
{
|
||||
log_message('info', 'Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.');
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', 'Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize OpenSSL
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
protected function _openssl_initialize($params)
|
||||
{
|
||||
if ( ! empty($params['cipher']))
|
||||
{
|
||||
$params['cipher'] = strtolower($params['cipher']);
|
||||
$this->_cipher_alias($params['cipher']);
|
||||
$this->_cipher = $params['cipher'];
|
||||
}
|
||||
|
||||
if ( ! empty($params['mode']))
|
||||
{
|
||||
$params['mode'] = strtolower($params['mode']);
|
||||
if ( ! isset($this->_modes['openssl'][$params['mode']]))
|
||||
{
|
||||
log_message('error', 'Encryption: OpenSSL mode '.strtoupper($params['mode']).' is not available.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_mode = $this->_modes['openssl'][$params['mode']];
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->_cipher, $this->_mode))
|
||||
{
|
||||
// This is mostly for the stream mode, which doesn't get suffixed in OpenSSL
|
||||
$handle = empty($this->_mode)
|
||||
? $this->_cipher
|
||||
: $this->_cipher.'-'.$this->_mode;
|
||||
|
||||
if ( ! in_array($handle, openssl_get_cipher_methods(), TRUE))
|
||||
{
|
||||
$this->_handle = NULL;
|
||||
log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_handle = $handle;
|
||||
log_message('info', 'Encryption: OpenSSL initialized with method '.strtoupper($handle).'.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a random key
|
||||
*
|
||||
* @param int $length Output length
|
||||
* @return string
|
||||
*/
|
||||
public function create_key($length)
|
||||
{
|
||||
if (function_exists('random_bytes'))
|
||||
{
|
||||
try
|
||||
{
|
||||
return random_bytes((int) $length);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
log_message('error', $e->getMessage());
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
elseif (defined('MCRYPT_DEV_URANDOM'))
|
||||
{
|
||||
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
|
||||
}
|
||||
|
||||
$is_secure = NULL;
|
||||
$key = openssl_random_pseudo_bytes($length, $is_secure);
|
||||
return ($is_secure === TRUE)
|
||||
? $key
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encrypt
|
||||
*
|
||||
* @param string $data Input data
|
||||
* @param array $params Input parameters
|
||||
* @return string
|
||||
*/
|
||||
public function encrypt($data, array $params = NULL)
|
||||
{
|
||||
if (($params = $this->_get_params($params)) === FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption');
|
||||
|
||||
if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$params['base64'] && $data = base64_encode($data);
|
||||
|
||||
if (isset($params['hmac_digest']))
|
||||
{
|
||||
isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
|
||||
return hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']).$data;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encrypt via MCrypt
|
||||
*
|
||||
* @param string $data Input data
|
||||
* @param array $params Input parameters
|
||||
* @return string
|
||||
*/
|
||||
protected function _mcrypt_encrypt($data, $params)
|
||||
{
|
||||
if ( ! is_resource($params['handle']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// The greater-than-1 comparison is mostly a work-around for a bug,
|
||||
// where 1 is returned for ARCFour instead of 0.
|
||||
$iv = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
|
||||
? $this->create_key($iv_size)
|
||||
: NULL;
|
||||
|
||||
if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
|
||||
{
|
||||
if ($params['handle'] !== $this->_handle)
|
||||
{
|
||||
mcrypt_module_close($params['handle']);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Use PKCS#7 padding in order to ensure compatibility with OpenSSL
|
||||
// and other implementations outside of PHP.
|
||||
if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
|
||||
{
|
||||
$block_size = mcrypt_enc_get_block_size($params['handle']);
|
||||
$pad = $block_size - (self::strlen($data) % $block_size);
|
||||
$data .= str_repeat(chr($pad), $pad);
|
||||
}
|
||||
|
||||
// Work-around for yet another strange behavior in MCrypt.
|
||||
//
|
||||
// When encrypting in ECB mode, the IV is ignored. Yet
|
||||
// mcrypt_enc_get_iv_size() returns a value larger than 0
|
||||
// even if ECB is used AND mcrypt_generic_init() complains
|
||||
// if you don't pass an IV with length equal to the said
|
||||
// return value.
|
||||
//
|
||||
// This probably would've been fine (even though still wasteful),
|
||||
// but OpenSSL isn't that dumb and we need to make the process
|
||||
// portable, so ...
|
||||
$data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
|
||||
? $iv.mcrypt_generic($params['handle'], $data)
|
||||
: mcrypt_generic($params['handle'], $data);
|
||||
|
||||
mcrypt_generic_deinit($params['handle']);
|
||||
if ($params['handle'] !== $this->_handle)
|
||||
{
|
||||
mcrypt_module_close($params['handle']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Encrypt via OpenSSL
|
||||
*
|
||||
* @param string $data Input data
|
||||
* @param array $params Input parameters
|
||||
* @return string
|
||||
*/
|
||||
protected function _openssl_encrypt($data, $params)
|
||||
{
|
||||
if (empty($params['handle']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$iv = ($iv_size = openssl_cipher_iv_length($params['handle']))
|
||||
? $this->create_key($iv_size)
|
||||
: NULL;
|
||||
|
||||
$data = openssl_encrypt(
|
||||
$data,
|
||||
$params['handle'],
|
||||
$params['key'],
|
||||
1, // DO NOT TOUCH!
|
||||
$iv
|
||||
);
|
||||
|
||||
if ($data === FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $iv.$data;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrypt
|
||||
*
|
||||
* @param string $data Encrypted data
|
||||
* @param array $params Input parameters
|
||||
* @return string
|
||||
*/
|
||||
public function decrypt($data, array $params = NULL)
|
||||
{
|
||||
if (($params = $this->_get_params($params)) === FALSE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (isset($params['hmac_digest']))
|
||||
{
|
||||
// This might look illogical, but it is done during encryption as well ...
|
||||
// The 'base64' value is effectively an inverted "raw data" parameter
|
||||
$digest_size = ($params['base64'])
|
||||
? $this->_digests[$params['hmac_digest']] * 2
|
||||
: $this->_digests[$params['hmac_digest']];
|
||||
|
||||
if (self::strlen($data) <= $digest_size)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$hmac_input = self::substr($data, 0, $digest_size);
|
||||
$data = self::substr($data, $digest_size);
|
||||
|
||||
isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication');
|
||||
$hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']);
|
||||
|
||||
// Time-attack-safe comparison
|
||||
$diff = 0;
|
||||
for ($i = 0; $i < $digest_size; $i++)
|
||||
{
|
||||
$diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]);
|
||||
}
|
||||
|
||||
if ($diff !== 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($params['base64'])
|
||||
{
|
||||
$data = base64_decode($data);
|
||||
}
|
||||
|
||||
isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, self::strlen($this->_key), 'encryption');
|
||||
|
||||
return $this->{'_'.$this->_driver.'_decrypt'}($data, $params);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrypt via MCrypt
|
||||
*
|
||||
* @param string $data Encrypted data
|
||||
* @param array $params Input parameters
|
||||
* @return string
|
||||
*/
|
||||
protected function _mcrypt_decrypt($data, $params)
|
||||
{
|
||||
if ( ! is_resource($params['handle']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// The greater-than-1 comparison is mostly a work-around for a bug,
|
||||
// where 1 is returned for ARCFour instead of 0.
|
||||
if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1)
|
||||
{
|
||||
if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB')
|
||||
{
|
||||
$iv = self::substr($data, 0, $iv_size);
|
||||
$data = self::substr($data, $iv_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// MCrypt is dumb and this is ignored, only size matters
|
||||
$iv = str_repeat("\x0", $iv_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iv = NULL;
|
||||
}
|
||||
|
||||
if (mcrypt_generic_init($params['handle'], $params['key'], $iv) < 0)
|
||||
{
|
||||
if ($params['handle'] !== $this->_handle)
|
||||
{
|
||||
mcrypt_module_close($params['handle']);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$data = mdecrypt_generic($params['handle'], $data);
|
||||
// Remove PKCS#7 padding, if necessary
|
||||
if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE))
|
||||
{
|
||||
$data = self::substr($data, 0, -ord($data[self::strlen($data)-1]));
|
||||
}
|
||||
|
||||
mcrypt_generic_deinit($params['handle']);
|
||||
if ($params['handle'] !== $this->_handle)
|
||||
{
|
||||
mcrypt_module_close($params['handle']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Decrypt via OpenSSL
|
||||
*
|
||||
* @param string $data Encrypted data
|
||||
* @param array $params Input parameters
|
||||
* @return string
|
||||
*/
|
||||
protected function _openssl_decrypt($data, $params)
|
||||
{
|
||||
if ($iv_size = openssl_cipher_iv_length($params['handle']))
|
||||
{
|
||||
$iv = self::substr($data, 0, $iv_size);
|
||||
$data = self::substr($data, $iv_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iv = NULL;
|
||||
}
|
||||
|
||||
return empty($params['handle'])
|
||||
? FALSE
|
||||
: openssl_decrypt(
|
||||
$data,
|
||||
$params['handle'],
|
||||
$params['key'],
|
||||
1, // DO NOT TOUCH!
|
||||
$iv
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get params
|
||||
*
|
||||
* @param array $params Input parameters
|
||||
* @return array
|
||||
*/
|
||||
protected function _get_params($params)
|
||||
{
|
||||
if (empty($params))
|
||||
{
|
||||
return isset($this->_cipher, $this->_mode, $this->_key, $this->_handle)
|
||||
? array(
|
||||
'handle' => $this->_handle,
|
||||
'cipher' => $this->_cipher,
|
||||
'mode' => $this->_mode,
|
||||
'key' => NULL,
|
||||
'base64' => TRUE,
|
||||
'hmac_digest' => 'sha512',
|
||||
'hmac_key' => NULL
|
||||
)
|
||||
: FALSE;
|
||||
}
|
||||
elseif ( ! isset($params['cipher'], $params['mode'], $params['key']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (isset($params['mode']))
|
||||
{
|
||||
$params['mode'] = strtolower($params['mode']);
|
||||
if ( ! isset($this->_modes[$this->_driver][$params['mode']]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$params['mode'] = $this->_modes[$this->_driver][$params['mode']];
|
||||
}
|
||||
|
||||
if (isset($params['hmac']) && $params['hmac'] === FALSE)
|
||||
{
|
||||
$params['hmac_digest'] = $params['hmac_key'] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! isset($params['hmac_key']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
elseif (isset($params['hmac_digest']))
|
||||
{
|
||||
$params['hmac_digest'] = strtolower($params['hmac_digest']);
|
||||
if ( ! isset($this->_digests[$params['hmac_digest']]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$params['hmac_digest'] = 'sha512';
|
||||
}
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'handle' => NULL,
|
||||
'cipher' => $params['cipher'],
|
||||
'mode' => $params['mode'],
|
||||
'key' => $params['key'],
|
||||
'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE,
|
||||
'hmac_digest' => $params['hmac_digest'],
|
||||
'hmac_key' => $params['hmac_key']
|
||||
);
|
||||
|
||||
$this->_cipher_alias($params['cipher']);
|
||||
$params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode)
|
||||
? $this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode'])
|
||||
: $this->_handle;
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get MCrypt handle
|
||||
*
|
||||
* @param string $cipher Cipher name
|
||||
* @param string $mode Encryption mode
|
||||
* @return resource
|
||||
*/
|
||||
protected function _mcrypt_get_handle($cipher, $mode)
|
||||
{
|
||||
return mcrypt_module_open($cipher, '', $mode, '');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get OpenSSL handle
|
||||
*
|
||||
* @param string $cipher Cipher name
|
||||
* @param string $mode Encryption mode
|
||||
* @return string
|
||||
*/
|
||||
protected function _openssl_get_handle($cipher, $mode)
|
||||
{
|
||||
// OpenSSL methods aren't suffixed with '-stream' for this mode
|
||||
return ($mode === 'stream')
|
||||
? $cipher
|
||||
: $cipher.'-'.$mode;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Cipher alias
|
||||
*
|
||||
* Tries to translate cipher names between MCrypt and OpenSSL's "dialects".
|
||||
*
|
||||
* @param string $cipher Cipher name
|
||||
* @return void
|
||||
*/
|
||||
protected function _cipher_alias(&$cipher)
|
||||
{
|
||||
static $dictionary;
|
||||
|
||||
if (empty($dictionary))
|
||||
{
|
||||
$dictionary = array(
|
||||
'mcrypt' => array(
|
||||
'aes-128' => 'rijndael-128',
|
||||
'aes-192' => 'rijndael-128',
|
||||
'aes-256' => 'rijndael-128',
|
||||
'des3-ede3' => 'tripledes',
|
||||
'bf' => 'blowfish',
|
||||
'cast5' => 'cast-128',
|
||||
'rc4' => 'arcfour',
|
||||
'rc4-40' => 'arcfour'
|
||||
),
|
||||
'openssl' => array(
|
||||
'rijndael-128' => 'aes-128',
|
||||
'tripledes' => 'des-ede3',
|
||||
'blowfish' => 'bf',
|
||||
'cast-128' => 'cast5',
|
||||
'arcfour' => 'rc4-40',
|
||||
'rc4' => 'rc4-40'
|
||||
)
|
||||
);
|
||||
|
||||
// Notes:
|
||||
//
|
||||
// - Rijndael-128 is, at the same time all three of AES-128,
|
||||
// AES-192 and AES-256. The only difference between them is
|
||||
// the key size. Rijndael-192, Rijndael-256 on the other hand
|
||||
// also have different block sizes and are NOT AES-compatible.
|
||||
//
|
||||
// - Blowfish is said to be supporting key sizes between
|
||||
// 4 and 56 bytes, but it appears that between MCrypt and
|
||||
// OpenSSL, only those of 16 and more bytes are compatible.
|
||||
// Also, don't know what MCrypt's 'blowfish-compat' is.
|
||||
//
|
||||
// - CAST-128/CAST5 produces a longer cipher when encrypted via
|
||||
// OpenSSL, but (strangely enough) can be decrypted by either
|
||||
// extension anyway.
|
||||
// Also, it appears that OpenSSL uses 16 rounds regardless of
|
||||
// the key size, while RFC2144 says that for key sizes lower
|
||||
// than 11 bytes, only 12 rounds should be used. This makes
|
||||
// it portable only with keys of between 11 and 16 bytes.
|
||||
//
|
||||
// - RC4 (ARCFour) has a strange implementation under OpenSSL.
|
||||
// Its 'rc4-40' cipher method seems to work flawlessly, yet
|
||||
// there's another one, 'rc4' that only works with a 16-byte key.
|
||||
//
|
||||
// - DES is compatible, but doesn't need an alias.
|
||||
//
|
||||
// Other seemingly matching ciphers between MCrypt, OpenSSL:
|
||||
//
|
||||
// - RC2 is NOT compatible and only an obscure forum post
|
||||
// confirms that it is MCrypt's fault.
|
||||
}
|
||||
|
||||
if (isset($dictionary[$this->_driver][$cipher]))
|
||||
{
|
||||
$cipher = $dictionary[$this->_driver][$cipher];
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* HKDF
|
||||
*
|
||||
* @link https://tools.ietf.org/rfc/rfc5869.txt
|
||||
* @param $key Input key
|
||||
* @param $digest A SHA-2 hashing algorithm
|
||||
* @param $salt Optional salt
|
||||
* @param $length Output length (defaults to the selected digest size)
|
||||
* @param $info Optional context/application-specific info
|
||||
* @return string A pseudo-random key
|
||||
*/
|
||||
public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '')
|
||||
{
|
||||
if ( ! isset($this->_digests[$digest]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (empty($length) OR ! is_int($length))
|
||||
{
|
||||
$length = $this->_digests[$digest];
|
||||
}
|
||||
elseif ($length > (255 * $this->_digests[$digest]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
self::strlen($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]);
|
||||
|
||||
$prk = hash_hmac($digest, $key, $salt, TRUE);
|
||||
$key = '';
|
||||
for ($key_block = '', $block_index = 1; self::strlen($key) < $length; $block_index++)
|
||||
{
|
||||
$key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE);
|
||||
$key .= $key_block;
|
||||
}
|
||||
|
||||
return self::substr($key, 0, $length);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __get() magic
|
||||
*
|
||||
* @param string $key Property name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
// Because aliases
|
||||
if ($key === 'mode')
|
||||
{
|
||||
return array_search($this->_mode, $this->_modes[$this->_driver], TRUE);
|
||||
}
|
||||
elseif (in_array($key, array('cipher', 'driver', 'drivers', 'digests'), TRUE))
|
||||
{
|
||||
return $this->{'_'.$key};
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe strlen()
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
protected static function strlen($str)
|
||||
{
|
||||
return (self::$func_overload)
|
||||
? mb_strlen($str, '8bit')
|
||||
: strlen($str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe substr()
|
||||
*
|
||||
* @param string $str
|
||||
* @param int $start
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
protected static function substr($str, $start, $length = NULL)
|
||||
{
|
||||
if (self::$func_overload)
|
||||
{
|
||||
// mb_substr($str, $start, null, '8bit') returns an empty
|
||||
// string on PHP 5.3
|
||||
isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
|
||||
return mb_substr($str, $start, $length, '8bit');
|
||||
}
|
||||
|
||||
return isset($length)
|
||||
? substr($str, $start, $length)
|
||||
: substr($str, $start);
|
||||
}
|
||||
}
|
1591
php/system/libraries/Form_validation.php
Normal file
1591
php/system/libraries/Form_validation.php
Normal file
File diff suppressed because it is too large
Load Diff
667
php/system/libraries/Ftp.php
Normal file
667
php/system/libraries/Ftp.php
Normal file
@ -0,0 +1,667 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* FTP Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/ftp.html
|
||||
*/
|
||||
class CI_FTP {
|
||||
|
||||
/**
|
||||
* FTP Server hostname
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hostname = '';
|
||||
|
||||
/**
|
||||
* FTP Username
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $username = '';
|
||||
|
||||
/**
|
||||
* FTP Password
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $password = '';
|
||||
|
||||
/**
|
||||
* FTP Server port
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $port = 21;
|
||||
|
||||
/**
|
||||
* Passive mode flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $passive = TRUE;
|
||||
|
||||
/**
|
||||
* Debug flag
|
||||
*
|
||||
* Specifies whether to display error messages.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $debug = FALSE;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Connection ID
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $conn_id;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
empty($config) OR $this->initialize($config);
|
||||
log_message('info', 'FTP Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize preferences
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function initialize($config = array())
|
||||
{
|
||||
foreach ($config as $key => $val)
|
||||
{
|
||||
if (isset($this->$key))
|
||||
{
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// Prep the hostname
|
||||
$this->hostname = preg_replace('|.+?://|', '', $this->hostname);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* FTP Connect
|
||||
*
|
||||
* @param array $config Connection values
|
||||
* @return bool
|
||||
*/
|
||||
public function connect($config = array())
|
||||
{
|
||||
if (count($config) > 0)
|
||||
{
|
||||
$this->initialize($config);
|
||||
}
|
||||
|
||||
if (FALSE === ($this->conn_id = @ftp_connect($this->hostname, $this->port)))
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_connect');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! $this->_login())
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_login');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set passive mode if needed
|
||||
if ($this->passive === TRUE)
|
||||
{
|
||||
ftp_pasv($this->conn_id, TRUE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* FTP Login
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _login()
|
||||
{
|
||||
return @ftp_login($this->conn_id, $this->username, $this->password);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validates the connection ID
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _is_conn()
|
||||
{
|
||||
if ( ! is_resource($this->conn_id))
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_no_connection');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Change directory
|
||||
*
|
||||
* The second parameter lets us momentarily turn off debugging so that
|
||||
* this function can be used to test for the existence of a folder
|
||||
* without throwing an error. There's no FTP equivalent to is_dir()
|
||||
* so we do it by trying to change to a particular directory.
|
||||
* Internally, this parameter is only used by the "mirror" function below.
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $suppress_debug
|
||||
* @return bool
|
||||
*/
|
||||
public function changedir($path, $suppress_debug = FALSE)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$result = @ftp_chdir($this->conn_id, $path);
|
||||
|
||||
if ($result === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE && $suppress_debug === FALSE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_changedir');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a directory
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $permissions
|
||||
* @return bool
|
||||
*/
|
||||
public function mkdir($path, $permissions = NULL)
|
||||
{
|
||||
if ($path === '' OR ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$result = @ftp_mkdir($this->conn_id, $path);
|
||||
|
||||
if ($result === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_mkdir');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set file permissions if needed
|
||||
if ($permissions !== NULL)
|
||||
{
|
||||
$this->chmod($path, (int) $permissions);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Upload a file to the server
|
||||
*
|
||||
* @param string $locpath
|
||||
* @param string $rempath
|
||||
* @param string $mode
|
||||
* @param int $permissions
|
||||
* @return bool
|
||||
*/
|
||||
public function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( ! file_exists($locpath))
|
||||
{
|
||||
$this->_error('ftp_no_source_file');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set the mode if not specified
|
||||
if ($mode === 'auto')
|
||||
{
|
||||
// Get the file extension so we can set the upload type
|
||||
$ext = $this->_getext($locpath);
|
||||
$mode = $this->_settype($ext);
|
||||
}
|
||||
|
||||
$mode = ($mode === 'ascii') ? FTP_ASCII : FTP_BINARY;
|
||||
|
||||
$result = @ftp_put($this->conn_id, $rempath, $locpath, $mode);
|
||||
|
||||
if ($result === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_upload');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set file permissions if needed
|
||||
if ($permissions !== NULL)
|
||||
{
|
||||
$this->chmod($rempath, (int) $permissions);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Download a file from a remote server to the local server
|
||||
*
|
||||
* @param string $rempath
|
||||
* @param string $locpath
|
||||
* @param string $mode
|
||||
* @return bool
|
||||
*/
|
||||
public function download($rempath, $locpath, $mode = 'auto')
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set the mode if not specified
|
||||
if ($mode === 'auto')
|
||||
{
|
||||
// Get the file extension so we can set the upload type
|
||||
$ext = $this->_getext($rempath);
|
||||
$mode = $this->_settype($ext);
|
||||
}
|
||||
|
||||
$mode = ($mode === 'ascii') ? FTP_ASCII : FTP_BINARY;
|
||||
|
||||
$result = @ftp_get($this->conn_id, $locpath, $rempath, $mode);
|
||||
|
||||
if ($result === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_download');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Rename (or move) a file
|
||||
*
|
||||
* @param string $old_file
|
||||
* @param string $new_file
|
||||
* @param bool $move
|
||||
* @return bool
|
||||
*/
|
||||
public function rename($old_file, $new_file, $move = FALSE)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$result = @ftp_rename($this->conn_id, $old_file, $new_file);
|
||||
|
||||
if ($result === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_'.($move === FALSE ? 'rename' : 'move'));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Move a file
|
||||
*
|
||||
* @param string $old_file
|
||||
* @param string $new_file
|
||||
* @return bool
|
||||
*/
|
||||
public function move($old_file, $new_file)
|
||||
{
|
||||
return $this->rename($old_file, $new_file, TRUE);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Rename (or move) a file
|
||||
*
|
||||
* @param string $filepath
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_file($filepath)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$result = @ftp_delete($this->conn_id, $filepath);
|
||||
|
||||
if ($result === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_delete');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Delete a folder and recursively delete everything (including sub-folders)
|
||||
* contained within it.
|
||||
*
|
||||
* @param string $filepath
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_dir($filepath)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Add a trailing slash to the file path if needed
|
||||
$filepath = preg_replace('/(.+?)\/*$/', '\\1/', $filepath);
|
||||
|
||||
$list = $this->list_files($filepath);
|
||||
if ( ! empty($list))
|
||||
{
|
||||
for ($i = 0, $c = count($list); $i < $c; $i++)
|
||||
{
|
||||
// If we can't delete the item it's probably a directory,
|
||||
// so we'll recursively call delete_dir()
|
||||
if ( ! preg_match('#/\.\.?$#', $list[$i]) && ! @ftp_delete($this->conn_id, $list[$i]))
|
||||
{
|
||||
$this->delete_dir($filepath.$list[$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (@ftp_rmdir($this->conn_id, $filepath) === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_delete');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set file permissions
|
||||
*
|
||||
* @param string $path File path
|
||||
* @param int $perm Permissions
|
||||
* @return bool
|
||||
*/
|
||||
public function chmod($path, $perm)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (@ftp_chmod($this->conn_id, $perm, $path) === FALSE)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->_error('ftp_unable_to_chmod');
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* FTP List files in the specified directory
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*/
|
||||
public function list_files($path = '.')
|
||||
{
|
||||
return $this->_is_conn()
|
||||
? ftp_nlist($this->conn_id, $path)
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Read a directory and recreate it remotely
|
||||
*
|
||||
* This function recursively reads a folder and everything it contains
|
||||
* (including sub-folders) and creates a mirror via FTP based on it.
|
||||
* Whatever the directory structure of the original file path will be
|
||||
* recreated on the server.
|
||||
*
|
||||
* @param string $locpath Path to source with trailing slash
|
||||
* @param string $rempath Path to destination - include the base folder with trailing slash
|
||||
* @return bool
|
||||
*/
|
||||
public function mirror($locpath, $rempath)
|
||||
{
|
||||
if ( ! $this->_is_conn())
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Open the local file path
|
||||
if ($fp = @opendir($locpath))
|
||||
{
|
||||
// Attempt to open the remote file path and try to create it, if it doesn't exist
|
||||
if ( ! $this->changedir($rempath, TRUE) && ( ! $this->mkdir($rempath) OR ! $this->changedir($rempath)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Recursively read the local directory
|
||||
while (FALSE !== ($file = readdir($fp)))
|
||||
{
|
||||
if (is_dir($locpath.$file) && $file[0] !== '.')
|
||||
{
|
||||
$this->mirror($locpath.$file.'/', $rempath.$file.'/');
|
||||
}
|
||||
elseif ($file[0] !== '.')
|
||||
{
|
||||
// Get the file extension so we can se the upload type
|
||||
$ext = $this->_getext($file);
|
||||
$mode = $this->_settype($ext);
|
||||
|
||||
$this->upload($locpath.$file, $rempath.$file, $mode);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Extract the file extension
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function _getext($filename)
|
||||
{
|
||||
return (($dot = strrpos($filename, '.')) === FALSE)
|
||||
? 'txt'
|
||||
: substr($filename, $dot + 1);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the upload type
|
||||
*
|
||||
* @param string $ext Filename extension
|
||||
* @return string
|
||||
*/
|
||||
protected function _settype($ext)
|
||||
{
|
||||
return in_array($ext, array('txt', 'text', 'php', 'phps', 'php4', 'js', 'css', 'htm', 'html', 'phtml', 'shtml', 'log', 'xml'), TRUE)
|
||||
? 'ascii'
|
||||
: 'binary';
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close the connection
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
return $this->_is_conn()
|
||||
? @ftp_close($this->conn_id)
|
||||
: FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Display error message
|
||||
*
|
||||
* @param string $line
|
||||
* @return void
|
||||
*/
|
||||
protected function _error($line)
|
||||
{
|
||||
$CI =& get_instance();
|
||||
$CI->lang->load('ftp');
|
||||
show_error($CI->lang->line($line));
|
||||
}
|
||||
|
||||
}
|
1842
php/system/libraries/Image_lib.php
Normal file
1842
php/system/libraries/Image_lib.php
Normal file
File diff suppressed because it is too large
Load Diff
856
php/system/libraries/Javascript.php
Normal file
856
php/system/libraries/Javascript.php
Normal file
@ -0,0 +1,856 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Javascript Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Javascript
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/javascript.html
|
||||
* @deprecated 3.0.0 This was never a good idea in the first place.
|
||||
*/
|
||||
class CI_Javascript {
|
||||
|
||||
/**
|
||||
* JavaScript location
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_javascript_location = 'js';
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $params
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($params = array())
|
||||
{
|
||||
$defaults = array('js_library_driver' => 'jquery', 'autoload' => TRUE);
|
||||
|
||||
foreach ($defaults as $key => $val)
|
||||
{
|
||||
if (isset($params[$key]) && $params[$key] !== '')
|
||||
{
|
||||
$defaults[$key] = $params[$key];
|
||||
}
|
||||
}
|
||||
|
||||
extract($defaults);
|
||||
|
||||
$this->CI =& get_instance();
|
||||
|
||||
// load the requested js library
|
||||
$this->CI->load->library('Javascript/'.$js_library_driver, array('autoload' => $autoload));
|
||||
// make js to refer to current library
|
||||
$this->js =& $this->CI->$js_library_driver;
|
||||
|
||||
log_message('info', 'Javascript Class Initialized and loaded. Driver used: '.$js_library_driver);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Event Code
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Blur
|
||||
*
|
||||
* Outputs a javascript library blur event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function blur($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_blur($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Change
|
||||
*
|
||||
* Outputs a javascript library change event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function change($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_change($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Click
|
||||
*
|
||||
* Outputs a javascript library click event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @param bool whether or not to return false
|
||||
* @return string
|
||||
*/
|
||||
public function click($element = 'this', $js = '', $ret_false = TRUE)
|
||||
{
|
||||
return $this->js->_click($element, $js, $ret_false);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Double Click
|
||||
*
|
||||
* Outputs a javascript library dblclick event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function dblclick($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_dblclick($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Error
|
||||
*
|
||||
* Outputs a javascript library error event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function error($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_error($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Focus
|
||||
*
|
||||
* Outputs a javascript library focus event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function focus($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_focus($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Hover
|
||||
*
|
||||
* Outputs a javascript library hover event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - Javascript code for mouse over
|
||||
* @param string - Javascript code for mouse out
|
||||
* @return string
|
||||
*/
|
||||
public function hover($element = 'this', $over = '', $out = '')
|
||||
{
|
||||
return $this->js->_hover($element, $over, $out);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Keydown
|
||||
*
|
||||
* Outputs a javascript library keydown event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function keydown($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_keydown($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Keyup
|
||||
*
|
||||
* Outputs a javascript library keydown event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function keyup($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_keyup($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Load
|
||||
*
|
||||
* Outputs a javascript library load event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function load($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_load($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mousedown
|
||||
*
|
||||
* Outputs a javascript library mousedown event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function mousedown($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_mousedown($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mouse Out
|
||||
*
|
||||
* Outputs a javascript library mouseout event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function mouseout($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_mouseout($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mouse Over
|
||||
*
|
||||
* Outputs a javascript library mouseover event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function mouseover($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_mouseover($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mouseup
|
||||
*
|
||||
* Outputs a javascript library mouseup event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function mouseup($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_mouseup($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Output
|
||||
*
|
||||
* Outputs the called javascript to the screen
|
||||
*
|
||||
* @param string The code to output
|
||||
* @return string
|
||||
*/
|
||||
public function output($js)
|
||||
{
|
||||
return $this->js->_output($js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Ready
|
||||
*
|
||||
* Outputs a javascript library mouseup event
|
||||
*
|
||||
* @param string $js Code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function ready($js)
|
||||
{
|
||||
return $this->js->_document_ready($js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resize
|
||||
*
|
||||
* Outputs a javascript library resize event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function resize($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_resize($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Scroll
|
||||
*
|
||||
* Outputs a javascript library scroll event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function scroll($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_scroll($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Unload
|
||||
*
|
||||
* Outputs a javascript library unload event
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param string The code to execute
|
||||
* @return string
|
||||
*/
|
||||
public function unload($element = 'this', $js = '')
|
||||
{
|
||||
return $this->js->_unload($element, $js);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Effects
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add Class
|
||||
*
|
||||
* Outputs a javascript library addClass event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - Class to add
|
||||
* @return string
|
||||
*/
|
||||
public function addClass($element = 'this', $class = '')
|
||||
{
|
||||
return $this->js->_addClass($element, $class);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Animate
|
||||
*
|
||||
* Outputs a javascript library animate event
|
||||
*
|
||||
* @param string $element = 'this'
|
||||
* @param array $params = array()
|
||||
* @param mixed $speed 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string $extra
|
||||
* @return string
|
||||
*/
|
||||
public function animate($element = 'this', $params = array(), $speed = '', $extra = '')
|
||||
{
|
||||
return $this->js->_animate($element, $params, $speed, $extra);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fade In
|
||||
*
|
||||
* Outputs a javascript library hide event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function fadeIn($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_fadeIn($element, $speed, $callback);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fade Out
|
||||
*
|
||||
* Outputs a javascript library hide event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function fadeOut($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_fadeOut($element, $speed, $callback);
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Slide Up
|
||||
*
|
||||
* Outputs a javascript library slideUp event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function slideUp($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_slideUp($element, $speed, $callback);
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Remove Class
|
||||
*
|
||||
* Outputs a javascript library removeClass event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - Class to add
|
||||
* @return string
|
||||
*/
|
||||
public function removeClass($element = 'this', $class = '')
|
||||
{
|
||||
return $this->js->_removeClass($element, $class);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Slide Down
|
||||
*
|
||||
* Outputs a javascript library slideDown event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function slideDown($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_slideDown($element, $speed, $callback);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Slide Toggle
|
||||
*
|
||||
* Outputs a javascript library slideToggle event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function slideToggle($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_slideToggle($element, $speed, $callback);
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Hide
|
||||
*
|
||||
* Outputs a javascript library hide action
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function hide($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_hide($element, $speed, $callback);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Toggle
|
||||
*
|
||||
* Outputs a javascript library toggle event
|
||||
*
|
||||
* @param string - element
|
||||
* @return string
|
||||
*/
|
||||
public function toggle($element = 'this')
|
||||
{
|
||||
return $this->js->_toggle($element);
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Toggle Class
|
||||
*
|
||||
* Outputs a javascript library toggle class event
|
||||
*
|
||||
* @param string $element = 'this'
|
||||
* @param string $class = ''
|
||||
* @return string
|
||||
*/
|
||||
public function toggleClass($element = 'this', $class = '')
|
||||
{
|
||||
return $this->js->_toggleClass($element, $class);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Show
|
||||
*
|
||||
* Outputs a javascript library show event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function show($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_show($element, $speed, $callback);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile
|
||||
*
|
||||
* gather together all script needing to be output
|
||||
*
|
||||
* @param string $view_var
|
||||
* @param bool $script_tags
|
||||
* @return string
|
||||
*/
|
||||
public function compile($view_var = 'script_foot', $script_tags = TRUE)
|
||||
{
|
||||
$this->js->_compile($view_var, $script_tags);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clear Compile
|
||||
*
|
||||
* Clears any previous javascript collected for output
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function clear_compile()
|
||||
{
|
||||
$this->js->_clear_compile();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* External
|
||||
*
|
||||
* Outputs a <script> tag with the source as an external js file
|
||||
*
|
||||
* @param string $external_file
|
||||
* @param bool $relative
|
||||
* @return string
|
||||
*/
|
||||
public function external($external_file = '', $relative = FALSE)
|
||||
{
|
||||
if ($external_file !== '')
|
||||
{
|
||||
$this->_javascript_location = $external_file;
|
||||
}
|
||||
elseif ($this->CI->config->item('javascript_location') !== '')
|
||||
{
|
||||
$this->_javascript_location = $this->CI->config->item('javascript_location');
|
||||
}
|
||||
|
||||
if ($relative === TRUE OR strpos($external_file, 'http://') === 0 OR strpos($external_file, 'https://') === 0)
|
||||
{
|
||||
$str = $this->_open_script($external_file);
|
||||
}
|
||||
elseif (strpos($this->_javascript_location, 'http://') !== FALSE)
|
||||
{
|
||||
$str = $this->_open_script($this->_javascript_location.$external_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
$str = $this->_open_script($this->CI->config->slash_item('base_url').$this->_javascript_location.$external_file);
|
||||
}
|
||||
|
||||
return $str.$this->_close_script();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Inline
|
||||
*
|
||||
* Outputs a <script> tag
|
||||
*
|
||||
* @param string The element to attach the event to
|
||||
* @param bool If a CDATA section should be added
|
||||
* @return string
|
||||
*/
|
||||
public function inline($script, $cdata = TRUE)
|
||||
{
|
||||
return $this->_open_script()
|
||||
. ($cdata ? "\n// <![CDATA[\n".$script."\n// ]]>\n" : "\n".$script."\n")
|
||||
. $this->_close_script();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open Script
|
||||
*
|
||||
* Outputs an opening <script>
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _open_script($src = '')
|
||||
{
|
||||
return '<script type="text/javascript" charset="'.strtolower($this->CI->config->item('charset')).'"'
|
||||
.($src === '' ? '>' : ' src="'.$src.'">');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close Script
|
||||
*
|
||||
* Outputs an closing </script>
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _close_script($extra = "\n")
|
||||
{
|
||||
return '</script>'.$extra;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// AJAX-Y STUFF - still a testbed
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Update
|
||||
*
|
||||
* Outputs a javascript library slideDown event
|
||||
*
|
||||
* @param string - element
|
||||
* @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
|
||||
* @param string - Javascript callback function
|
||||
* @return string
|
||||
*/
|
||||
public function update($element = 'this', $speed = '', $callback = '')
|
||||
{
|
||||
return $this->js->_updater($element, $speed, $callback);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate JSON
|
||||
*
|
||||
* Can be passed a database result or associative array and returns a JSON formatted string
|
||||
*
|
||||
* @param mixed result set or array
|
||||
* @param bool match array types (defaults to objects)
|
||||
* @return string a json formatted string
|
||||
*/
|
||||
public function generate_json($result = NULL, $match_array_type = FALSE)
|
||||
{
|
||||
// JSON data can optionally be passed to this function
|
||||
// either as a database result object or an array, or a user supplied array
|
||||
if ($result !== NULL)
|
||||
{
|
||||
if (is_object($result))
|
||||
{
|
||||
$json_result = is_callable(array($result, 'result_array')) ? $result->result_array() : (array) $result;
|
||||
}
|
||||
elseif (is_array($result))
|
||||
{
|
||||
$json_result = $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->_prep_args($result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 'null';
|
||||
}
|
||||
|
||||
$json = array();
|
||||
$_is_assoc = TRUE;
|
||||
|
||||
if ( ! is_array($json_result) && empty($json_result))
|
||||
{
|
||||
show_error('Generate JSON Failed - Illegal key, value pair.');
|
||||
}
|
||||
elseif ($match_array_type)
|
||||
{
|
||||
$_is_assoc = $this->_is_associative_array($json_result);
|
||||
}
|
||||
|
||||
foreach ($json_result as $k => $v)
|
||||
{
|
||||
if ($_is_assoc)
|
||||
{
|
||||
$json[] = $this->_prep_args($k, TRUE).':'.$this->generate_json($v, $match_array_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
$json[] = $this->generate_json($v, $match_array_type);
|
||||
}
|
||||
}
|
||||
|
||||
$json = implode(',', $json);
|
||||
|
||||
return $_is_assoc ? '{'.$json.'}' : '['.$json.']';
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is associative array
|
||||
*
|
||||
* Checks for an associative array
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
protected function _is_associative_array($arr)
|
||||
{
|
||||
foreach (array_keys($arr) as $key => $val)
|
||||
{
|
||||
if ($key !== $val)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prep Args
|
||||
*
|
||||
* Ensures a standard json value and escapes values
|
||||
*
|
||||
* @param mixed $result
|
||||
* @param bool $is_key = FALSE
|
||||
* @return string
|
||||
*/
|
||||
protected function _prep_args($result, $is_key = FALSE)
|
||||
{
|
||||
if ($result === NULL)
|
||||
{
|
||||
return 'null';
|
||||
}
|
||||
elseif (is_bool($result))
|
||||
{
|
||||
return ($result === TRUE) ? 'true' : 'false';
|
||||
}
|
||||
elseif (is_string($result) OR $is_key)
|
||||
{
|
||||
return '"'.str_replace(array('\\', "\t", "\n", "\r", '"', '/'), array('\\\\', '\\t', '\\n', "\\r", '\"', '\/'), $result).'"';
|
||||
}
|
||||
elseif (is_scalar($result))
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1076
php/system/libraries/Javascript/Jquery.php
Normal file
1076
php/system/libraries/Javascript/Jquery.php
Normal file
File diff suppressed because it is too large
Load Diff
11
php/system/libraries/Javascript/index.html
Normal file
11
php/system/libraries/Javascript/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
477
php/system/libraries/Migration.php
Normal file
477
php/system/libraries/Migration.php
Normal file
@ -0,0 +1,477 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* 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 ( ! is_callable(array($class, $method)))
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
}
|
704
php/system/libraries/Pagination.php
Normal file
704
php/system/libraries/Pagination.php
Normal file
@ -0,0 +1,704 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Pagination Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Pagination
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/pagination.html
|
||||
*/
|
||||
class CI_Pagination {
|
||||
|
||||
/**
|
||||
* Base URL
|
||||
*
|
||||
* The page that we're linking to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $base_url = '';
|
||||
|
||||
/**
|
||||
* Prefix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = '';
|
||||
|
||||
/**
|
||||
* Suffix
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $suffix = '';
|
||||
|
||||
/**
|
||||
* Total number of items
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $total_rows = 0;
|
||||
|
||||
/**
|
||||
* Number of links to show
|
||||
*
|
||||
* Relates to "digit" type links shown before/after
|
||||
* the currently viewed page.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $num_links = 2;
|
||||
|
||||
/**
|
||||
* Items per page
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $per_page = 10;
|
||||
|
||||
/**
|
||||
* Current page
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $cur_page = 0;
|
||||
|
||||
/**
|
||||
* Use page numbers flag
|
||||
*
|
||||
* Whether to use actual page numbers instead of an offset
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $use_page_numbers = FALSE;
|
||||
|
||||
/**
|
||||
* First link
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $first_link = '‹ First';
|
||||
|
||||
/**
|
||||
* Next link
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $next_link = '>';
|
||||
|
||||
/**
|
||||
* Previous link
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prev_link = '<';
|
||||
|
||||
/**
|
||||
* Last link
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $last_link = 'Last ›';
|
||||
|
||||
/**
|
||||
* URI Segment
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uri_segment = 0;
|
||||
|
||||
/**
|
||||
* Full tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $full_tag_open = '';
|
||||
|
||||
/**
|
||||
* Full tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $full_tag_close = '';
|
||||
|
||||
/**
|
||||
* First tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $first_tag_open = '';
|
||||
|
||||
/**
|
||||
* First tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $first_tag_close = '';
|
||||
|
||||
/**
|
||||
* Last tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $last_tag_open = '';
|
||||
|
||||
/**
|
||||
* Last tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $last_tag_close = '';
|
||||
|
||||
/**
|
||||
* First URL
|
||||
*
|
||||
* An alternative URL for the first page
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $first_url = '';
|
||||
|
||||
/**
|
||||
* Current tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $cur_tag_open = '<strong>';
|
||||
|
||||
/**
|
||||
* Current tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $cur_tag_close = '</strong>';
|
||||
|
||||
/**
|
||||
* Next tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $next_tag_open = '';
|
||||
|
||||
/**
|
||||
* Next tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $next_tag_close = '';
|
||||
|
||||
/**
|
||||
* Previous tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prev_tag_open = '';
|
||||
|
||||
/**
|
||||
* Previous tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prev_tag_close = '';
|
||||
|
||||
/**
|
||||
* Number tag open
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $num_tag_open = '';
|
||||
|
||||
/**
|
||||
* Number tag close
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $num_tag_close = '';
|
||||
|
||||
/**
|
||||
* Page query string flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $page_query_string = FALSE;
|
||||
|
||||
/**
|
||||
* Query string segment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $query_string_segment = 'per_page';
|
||||
|
||||
/**
|
||||
* Display pages flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $display_pages = TRUE;
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_attributes = '';
|
||||
|
||||
/**
|
||||
* Link types
|
||||
*
|
||||
* "rel" attribute
|
||||
*
|
||||
* @see CI_Pagination::_attr_rel()
|
||||
* @var array
|
||||
*/
|
||||
protected $_link_types = array();
|
||||
|
||||
/**
|
||||
* Reuse query string flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $reuse_query_string = FALSE;
|
||||
|
||||
/**
|
||||
* Use global URL suffix flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $use_global_url_suffix = FALSE;
|
||||
|
||||
/**
|
||||
* Data page attribute
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $data_page_attr = 'data-ci-pagination-page';
|
||||
|
||||
/**
|
||||
* CI Singleton
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $params Initialization parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($params = array())
|
||||
{
|
||||
$this->CI =& get_instance();
|
||||
$this->CI->load->language('pagination');
|
||||
foreach (array('first_link', 'next_link', 'prev_link', 'last_link') as $key)
|
||||
{
|
||||
if (($val = $this->CI->lang->line('pagination_'.$key)) !== FALSE)
|
||||
{
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// _parse_attributes(), called by initialize(), needs to run at least once
|
||||
// in order to enable "rel" attributes, and this triggers it.
|
||||
isset($params['attributes']) OR $params['attributes'] = array();
|
||||
|
||||
$this->initialize($params);
|
||||
log_message('info', 'Pagination Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize Preferences
|
||||
*
|
||||
* @param array $params Initialization parameters
|
||||
* @return CI_Pagination
|
||||
*/
|
||||
public function initialize(array $params = array())
|
||||
{
|
||||
if (isset($params['attributes']) && is_array($params['attributes']))
|
||||
{
|
||||
$this->_parse_attributes($params['attributes']);
|
||||
unset($params['attributes']);
|
||||
}
|
||||
|
||||
// Deprecated legacy support for the anchor_class option
|
||||
// Should be removed in CI 3.1+
|
||||
if (isset($params['anchor_class']))
|
||||
{
|
||||
empty($params['anchor_class']) OR $attributes['class'] = $params['anchor_class'];
|
||||
unset($params['anchor_class']);
|
||||
}
|
||||
|
||||
foreach ($params as $key => $val)
|
||||
{
|
||||
if (property_exists($this, $key))
|
||||
{
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->CI->config->item('enable_query_strings') === TRUE)
|
||||
{
|
||||
$this->page_query_string = TRUE;
|
||||
}
|
||||
|
||||
if ($this->use_global_url_suffix === TRUE)
|
||||
{
|
||||
$this->suffix = $this->CI->config->item('url_suffix');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate the pagination links
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function create_links()
|
||||
{
|
||||
// If our item count or per-page total is zero there is no need to continue.
|
||||
// Note: DO NOT change the operator to === here!
|
||||
if ($this->total_rows == 0 OR $this->per_page == 0)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
// Calculate the total number of pages
|
||||
$num_pages = (int) ceil($this->total_rows / $this->per_page);
|
||||
|
||||
// Is there only one page? Hm... nothing more to do here then.
|
||||
if ($num_pages === 1)
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
// Check the user defined number of links.
|
||||
$this->num_links = (int) $this->num_links;
|
||||
|
||||
if ($this->num_links < 0)
|
||||
{
|
||||
show_error('Your number of links must be a non-negative number.');
|
||||
}
|
||||
|
||||
// Keep any existing query string items.
|
||||
// Note: Has nothing to do with any other query string option.
|
||||
if ($this->reuse_query_string === TRUE)
|
||||
{
|
||||
$get = $this->CI->input->get();
|
||||
|
||||
// Unset the control, method, old-school routing options
|
||||
unset($get['c'], $get['m'], $get[$this->query_string_segment]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$get = array();
|
||||
}
|
||||
|
||||
// Put together our base and first URLs.
|
||||
// Note: DO NOT append to the properties as that would break successive calls
|
||||
$base_url = trim($this->base_url);
|
||||
$first_url = $this->first_url;
|
||||
|
||||
$query_string = '';
|
||||
$query_string_sep = (strpos($base_url, '?') === FALSE) ? '?' : '&';
|
||||
|
||||
// Are we using query strings?
|
||||
if ($this->page_query_string === TRUE)
|
||||
{
|
||||
// If a custom first_url hasn't been specified, we'll create one from
|
||||
// the base_url, but without the page item.
|
||||
if ($first_url === '')
|
||||
{
|
||||
$first_url = $base_url;
|
||||
|
||||
// If we saved any GET items earlier, make sure they're appended.
|
||||
if ( ! empty($get))
|
||||
{
|
||||
$first_url .= $query_string_sep.http_build_query($get);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the page segment to the end of the query string, where the
|
||||
// page number will be appended.
|
||||
$base_url .= $query_string_sep.http_build_query(array_merge($get, array($this->query_string_segment => '')));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Standard segment mode.
|
||||
// Generate our saved query string to append later after the page number.
|
||||
if ( ! empty($get))
|
||||
{
|
||||
$query_string = $query_string_sep.http_build_query($get);
|
||||
$this->suffix .= $query_string;
|
||||
}
|
||||
|
||||
// Does the base_url have the query string in it?
|
||||
// If we're supposed to save it, remove it so we can append it later.
|
||||
if ($this->reuse_query_string === TRUE && ($base_query_pos = strpos($base_url, '?')) !== FALSE)
|
||||
{
|
||||
$base_url = substr($base_url, 0, $base_query_pos);
|
||||
}
|
||||
|
||||
if ($first_url === '')
|
||||
{
|
||||
$first_url = $base_url.$query_string;
|
||||
}
|
||||
|
||||
$base_url = rtrim($base_url, '/').'/';
|
||||
}
|
||||
|
||||
// Determine the current page number.
|
||||
$base_page = ($this->use_page_numbers) ? 1 : 0;
|
||||
|
||||
// Are we using query strings?
|
||||
if ($this->page_query_string === TRUE)
|
||||
{
|
||||
$this->cur_page = $this->CI->input->get($this->query_string_segment);
|
||||
}
|
||||
elseif (empty($this->cur_page))
|
||||
{
|
||||
// Default to the last segment number if one hasn't been defined.
|
||||
if ($this->uri_segment === 0)
|
||||
{
|
||||
$this->uri_segment = count($this->CI->uri->segment_array());
|
||||
}
|
||||
|
||||
$this->cur_page = $this->CI->uri->segment($this->uri_segment);
|
||||
|
||||
// Remove any specified prefix/suffix from the segment.
|
||||
if ($this->prefix !== '' OR $this->suffix !== '')
|
||||
{
|
||||
$this->cur_page = str_replace(array($this->prefix, $this->suffix), '', $this->cur_page);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->cur_page = (string) $this->cur_page;
|
||||
}
|
||||
|
||||
// If something isn't quite right, back to the default base page.
|
||||
if ( ! ctype_digit($this->cur_page) OR ($this->use_page_numbers && (int) $this->cur_page === 0))
|
||||
{
|
||||
$this->cur_page = $base_page;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure we're using integers for comparisons later.
|
||||
$this->cur_page = (int) $this->cur_page;
|
||||
}
|
||||
|
||||
// Is the page number beyond the result range?
|
||||
// If so, we show the last page.
|
||||
if ($this->use_page_numbers)
|
||||
{
|
||||
if ($this->cur_page > $num_pages)
|
||||
{
|
||||
$this->cur_page = $num_pages;
|
||||
}
|
||||
}
|
||||
elseif ($this->cur_page > $this->total_rows)
|
||||
{
|
||||
$this->cur_page = ($num_pages - 1) * $this->per_page;
|
||||
}
|
||||
|
||||
$uri_page_number = $this->cur_page;
|
||||
|
||||
// If we're using offset instead of page numbers, convert it
|
||||
// to a page number, so we can generate the surrounding number links.
|
||||
if ( ! $this->use_page_numbers)
|
||||
{
|
||||
$this->cur_page = (int) floor(($this->cur_page/$this->per_page) + 1);
|
||||
}
|
||||
|
||||
// Calculate the start and end numbers. These determine
|
||||
// which number to start and end the digit links with.
|
||||
$start = (($this->cur_page - $this->num_links) > 0) ? $this->cur_page - ($this->num_links - 1) : 1;
|
||||
$end = (($this->cur_page + $this->num_links) < $num_pages) ? $this->cur_page + $this->num_links : $num_pages;
|
||||
|
||||
// And here we go...
|
||||
$output = '';
|
||||
|
||||
// Render the "First" link.
|
||||
if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1 + ! $this->num_links))
|
||||
{
|
||||
// Take the general parameters, and squeeze this pagination-page attr in for JS frameworks.
|
||||
$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1);
|
||||
|
||||
$output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
|
||||
.$this->first_link.'</a>'.$this->first_tag_close;
|
||||
}
|
||||
|
||||
// Render the "Previous" link.
|
||||
if ($this->prev_link !== FALSE && $this->cur_page !== 1)
|
||||
{
|
||||
$i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page;
|
||||
|
||||
$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, ($this->cur_page - 1));
|
||||
|
||||
if ($i === $base_page)
|
||||
{
|
||||
// First page
|
||||
$output .= $this->prev_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('prev').'>'
|
||||
.$this->prev_link.'</a>'.$this->prev_tag_close;
|
||||
}
|
||||
else
|
||||
{
|
||||
$append = $this->prefix.$i.$this->suffix;
|
||||
$output .= $this->prev_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>'
|
||||
.$this->prev_link.'</a>'.$this->prev_tag_close;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Render the pages
|
||||
if ($this->display_pages !== FALSE)
|
||||
{
|
||||
// Write the digit links
|
||||
for ($loop = $start - 1; $loop <= $end; $loop++)
|
||||
{
|
||||
$i = ($this->use_page_numbers) ? $loop : ($loop * $this->per_page) - $this->per_page;
|
||||
|
||||
$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $loop);
|
||||
|
||||
if ($i >= $base_page)
|
||||
{
|
||||
if ($this->cur_page === $loop)
|
||||
{
|
||||
// Current page
|
||||
$output .= $this->cur_tag_open.$loop.$this->cur_tag_close;
|
||||
}
|
||||
elseif ($i === $base_page)
|
||||
{
|
||||
// First page
|
||||
$output .= $this->num_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>'
|
||||
.$loop.'</a>'.$this->num_tag_close;
|
||||
}
|
||||
else
|
||||
{
|
||||
$append = $this->prefix.$i.$this->suffix;
|
||||
$output .= $this->num_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.'>'
|
||||
.$loop.'</a>'.$this->num_tag_close;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render the "next" link
|
||||
if ($this->next_link !== FALSE && $this->cur_page < $num_pages)
|
||||
{
|
||||
$i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page;
|
||||
|
||||
$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $this->cur_page + 1);
|
||||
|
||||
$output .= $this->next_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes
|
||||
.$this->_attr_rel('next').'>'.$this->next_link.'</a>'.$this->next_tag_close;
|
||||
}
|
||||
|
||||
// Render the "Last" link
|
||||
if ($this->last_link !== FALSE && ($this->cur_page + $this->num_links + ! $this->num_links) < $num_pages)
|
||||
{
|
||||
$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
|
||||
|
||||
$attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, $num_pages);
|
||||
|
||||
$output .= $this->last_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>'
|
||||
.$this->last_link.'</a>'.$this->last_tag_close;
|
||||
}
|
||||
|
||||
// Kill double slashes. Note: Sometimes we can end up with a double slash
|
||||
// in the penultimate link so we'll kill all double slashes.
|
||||
$output = preg_replace('#([^:"])//+#', '\\1/', $output);
|
||||
|
||||
// Add the wrapper HTML if exists
|
||||
return $this->full_tag_open.$output.$this->full_tag_close;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse attributes
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return void
|
||||
*/
|
||||
protected function _parse_attributes($attributes)
|
||||
{
|
||||
isset($attributes['rel']) OR $attributes['rel'] = TRUE;
|
||||
$this->_link_types = ($attributes['rel'])
|
||||
? array('start' => 'start', 'prev' => 'prev', 'next' => 'next')
|
||||
: array();
|
||||
unset($attributes['rel']);
|
||||
|
||||
$this->_attributes = '';
|
||||
foreach ($attributes as $key => $value)
|
||||
{
|
||||
$this->_attributes .= ' '.$key.'="'.$value.'"';
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add "rel" attribute
|
||||
*
|
||||
* @link http://www.w3.org/TR/html5/links.html#linkTypes
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
protected function _attr_rel($type)
|
||||
{
|
||||
if (isset($this->_link_types[$type]))
|
||||
{
|
||||
unset($this->_link_types[$type]);
|
||||
return ' rel="'.$type.'"';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
248
php/system/libraries/Parser.php
Normal file
248
php/system/libraries/Parser.php
Normal file
@ -0,0 +1,248 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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/user_guide/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;
|
||||
}
|
||||
|
||||
}
|
574
php/system/libraries/Profiler.php
Normal file
574
php/system/libraries/Profiler.php
Normal file
@ -0,0 +1,574 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Profiler Class
|
||||
*
|
||||
* This class enables you to display benchmark, query, and other data
|
||||
* in order to help with debugging and optimization.
|
||||
*
|
||||
* Note: At some point it would be good to move all the HTML in this class
|
||||
* into a set of template files in order to allow customization.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Libraries
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/general/profiling.html
|
||||
*/
|
||||
class CI_Profiler {
|
||||
|
||||
/**
|
||||
* List of profiler sections available to show
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_available_sections = array(
|
||||
'benchmarks',
|
||||
'get',
|
||||
'memory_usage',
|
||||
'post',
|
||||
'uri_string',
|
||||
'controller_info',
|
||||
'queries',
|
||||
'http_headers',
|
||||
'session_data',
|
||||
'config'
|
||||
);
|
||||
|
||||
/**
|
||||
* Number of queries to show before making the additional queries togglable
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_query_toggle_count = 25;
|
||||
|
||||
/**
|
||||
* Reference to the CodeIgniter singleton
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $CI;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* Initialize Profiler
|
||||
*
|
||||
* @param array $config Parameters
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
$this->CI =& get_instance();
|
||||
$this->CI->load->language('profiler');
|
||||
|
||||
// default all sections to display
|
||||
foreach ($this->_available_sections as $section)
|
||||
{
|
||||
if ( ! isset($config[$section]))
|
||||
{
|
||||
$this->_compile_{$section} = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
$this->set_sections($config);
|
||||
log_message('info', 'Profiler Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set Sections
|
||||
*
|
||||
* Sets the private _compile_* properties to enable/disable Profiler sections
|
||||
*
|
||||
* @param mixed $config
|
||||
* @return void
|
||||
*/
|
||||
public function set_sections($config)
|
||||
{
|
||||
if (isset($config['query_toggle_count']))
|
||||
{
|
||||
$this->_query_toggle_count = (int) $config['query_toggle_count'];
|
||||
unset($config['query_toggle_count']);
|
||||
}
|
||||
|
||||
foreach ($config as $method => $enable)
|
||||
{
|
||||
if (in_array($method, $this->_available_sections))
|
||||
{
|
||||
$this->_compile_{$method} = ($enable !== FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Auto Profiler
|
||||
*
|
||||
* This function cycles through the entire array of mark points and
|
||||
* matches any two points that are named identically (ending in "_start"
|
||||
* and "_end" respectively). It then compiles the execution times for
|
||||
* all points and returns it as an array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _compile_benchmarks()
|
||||
{
|
||||
$profile = array();
|
||||
foreach ($this->CI->benchmark->marker as $key => $val)
|
||||
{
|
||||
// We match the "end" marker so that the list ends
|
||||
// up in the order that it was defined
|
||||
if (preg_match('/(.+?)_end$/i', $key, $match)
|
||||
&& isset($this->CI->benchmark->marker[$match[1].'_end'], $this->CI->benchmark->marker[$match[1].'_start']))
|
||||
{
|
||||
$profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a table containing the profile data.
|
||||
// Note: At some point we should turn this into a template that can
|
||||
// be modified. We also might want to make this data available to be logged
|
||||
|
||||
$output = "\n\n"
|
||||
.'<fieldset id="ci_profiler_benchmarks" style="border:1px solid #900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#900;"> '.$this->CI->lang->line('profiler_benchmarks')." </legend>"
|
||||
."\n\n\n<table style=\"width:100%;\">\n";
|
||||
|
||||
foreach ($profile as $key => $val)
|
||||
{
|
||||
$key = ucwords(str_replace(array('_', '-'), ' ', $key));
|
||||
$output .= '<tr><td style="padding:5px;width:50%;color:#000;font-weight:bold;background-color:#ddd;">'
|
||||
.$key.' </td><td style="padding:5px;width:50%;color:#900;font-weight:normal;background-color:#ddd;">'
|
||||
.$val."</td></tr>\n";
|
||||
}
|
||||
|
||||
return $output."</table>\n</fieldset>";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile Queries
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_queries()
|
||||
{
|
||||
$dbs = array();
|
||||
|
||||
// Let's determine which databases are currently connected to
|
||||
foreach (get_object_vars($this->CI) as $name => $cobject)
|
||||
{
|
||||
if (is_object($cobject))
|
||||
{
|
||||
if ($cobject instanceof CI_DB)
|
||||
{
|
||||
$dbs[get_class($this->CI).':$'.$name] = $cobject;
|
||||
}
|
||||
elseif ($cobject instanceof CI_Model)
|
||||
{
|
||||
foreach (get_object_vars($cobject) as $mname => $mobject)
|
||||
{
|
||||
if ($mobject instanceof CI_DB)
|
||||
{
|
||||
$dbs[get_class($cobject).':$'.$mname] = $mobject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($dbs) === 0)
|
||||
{
|
||||
return "\n\n"
|
||||
.'<fieldset id="ci_profiler_queries" style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#0000FF;"> '.$this->CI->lang->line('profiler_queries').' </legend>'
|
||||
."\n\n\n<table style=\"border:none; width:100%;\">\n"
|
||||
.'<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
|
||||
.$this->CI->lang->line('profiler_no_db')
|
||||
."</td></tr>\n</table>\n</fieldset>";
|
||||
}
|
||||
|
||||
// Load the text helper so we can highlight the SQL
|
||||
$this->CI->load->helper('text');
|
||||
|
||||
// Key words we want bolded
|
||||
$highlight = array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'AND', 'LEFT JOIN', 'ORDER BY', 'GROUP BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR ', 'HAVING', 'OFFSET', 'NOT IN', 'IN', 'LIKE', 'NOT LIKE', 'COUNT', 'MAX', 'MIN', 'ON', 'AS', 'AVG', 'SUM', '(', ')');
|
||||
|
||||
$output = "\n\n";
|
||||
$count = 0;
|
||||
|
||||
foreach ($dbs as $name => $db)
|
||||
{
|
||||
$hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : '';
|
||||
$total_time = number_format(array_sum($db->query_times), 4).' '.$this->CI->lang->line('profiler_seconds');
|
||||
|
||||
$show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_hide').'\'?\''.$this->CI->lang->line('profiler_section_show').'\':\''.$this->CI->lang->line('profiler_section_hide').'\';">'.$this->CI->lang->line('profiler_section_hide').'</span>)';
|
||||
|
||||
if ($hide_queries !== '')
|
||||
{
|
||||
$show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)';
|
||||
}
|
||||
|
||||
$output .= '<fieldset style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#0000FF;"> '.$this->CI->lang->line('profiler_database')
|
||||
.': '.$db->database.' ('.$name.') '.$this->CI->lang->line('profiler_queries')
|
||||
.': '.count($db->queries).' ('.$total_time.') '.$show_hide_js."</legend>\n\n\n"
|
||||
.'<table style="width:100%;'.$hide_queries.'" id="ci_profiler_queries_db_'.$count."\">\n";
|
||||
|
||||
if (count($db->queries) === 0)
|
||||
{
|
||||
$output .= '<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
|
||||
.$this->CI->lang->line('profiler_no_queries')."</td></tr>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($db->queries as $key => $val)
|
||||
{
|
||||
$time = number_format($db->query_times[$key], 4);
|
||||
$val = highlight_code($val);
|
||||
|
||||
foreach ($highlight as $bold)
|
||||
{
|
||||
$val = str_replace($bold, '<strong>'.$bold.'</strong>', $val);
|
||||
}
|
||||
|
||||
$output .= '<tr><td style="padding:5px;vertical-align:top;width:1%;color:#900;font-weight:normal;background-color:#ddd;">'
|
||||
.$time.' </td><td style="padding:5px;color:#000;font-weight:normal;background-color:#ddd;">'
|
||||
.$val."</td></tr>\n";
|
||||
}
|
||||
}
|
||||
|
||||
$output .= "</table>\n</fieldset>";
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile $_GET Data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_get()
|
||||
{
|
||||
$output = "\n\n"
|
||||
.'<fieldset id="ci_profiler_get" style="border:1px solid #cd6e00;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#cd6e00;"> '.$this->CI->lang->line('profiler_get_data')." </legend>\n";
|
||||
|
||||
if (count($_GET) === 0)
|
||||
{
|
||||
$output .= '<div style="color:#cd6e00;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_get').'</div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= "\n\n<table style=\"width:100%;border:none;\">\n";
|
||||
|
||||
foreach ($_GET as $key => $val)
|
||||
{
|
||||
is_int($key) OR $key = "'".htmlspecialchars($key, ENT_QUOTES, config_item('charset'))."'";
|
||||
$val = (is_array($val) OR is_object($val))
|
||||
? '<pre>'.htmlspecialchars(print_r($val, TRUE), ENT_QUOTES, config_item('charset')).'</pre>'
|
||||
: htmlspecialchars($val, ENT_QUOTES, config_item('charset'));
|
||||
|
||||
$output .= '<tr><td style="width:50%;color:#000;background-color:#ddd;padding:5px;">$_GET['
|
||||
.$key.'] </td><td style="width:50%;padding:5px;color:#cd6e00;font-weight:normal;background-color:#ddd;">'
|
||||
.$val."</td></tr>\n";
|
||||
}
|
||||
|
||||
$output .= "</table>\n";
|
||||
}
|
||||
|
||||
return $output.'</fieldset>';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile $_POST Data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_post()
|
||||
{
|
||||
$output = "\n\n"
|
||||
.'<fieldset id="ci_profiler_post" style="border:1px solid #009900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#009900;"> '.$this->CI->lang->line('profiler_post_data')." </legend>\n";
|
||||
|
||||
if (count($_POST) === 0 && count($_FILES) === 0)
|
||||
{
|
||||
$output .= '<div style="color:#009900;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_post').'</div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= "\n\n<table style=\"width:100%;\">\n";
|
||||
|
||||
foreach ($_POST as $key => $val)
|
||||
{
|
||||
is_int($key) OR $key = "'".htmlspecialchars($key, ENT_QUOTES, config_item('charset'))."'";
|
||||
$val = (is_array($val) OR is_object($val))
|
||||
? '<pre>'.htmlspecialchars(print_r($val, TRUE), ENT_QUOTES, config_item('charset')).'</pre>'
|
||||
: htmlspecialchars($val, ENT_QUOTES, config_item('charset'));
|
||||
|
||||
$output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">$_POST['
|
||||
.$key.'] </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">'
|
||||
.$val."</td></tr>\n";
|
||||
}
|
||||
|
||||
foreach ($_FILES as $key => $val)
|
||||
{
|
||||
is_int($key) OR $key = "'".htmlspecialchars($key, ENT_QUOTES, config_item('charset'))."'";
|
||||
$val = (is_array($val) OR is_object($val))
|
||||
? '<pre>'.htmlspecialchars(print_r($val, TRUE), ENT_QUOTES, config_item('charset')).'</pre>'
|
||||
: htmlspecialchars($val, ENT_QUOTES, config_item('charset'));
|
||||
|
||||
$output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">$_FILES['
|
||||
.$key.'] </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">'
|
||||
.$val."</td></tr>\n";
|
||||
}
|
||||
|
||||
$output .= "</table>\n";
|
||||
}
|
||||
|
||||
return $output.'</fieldset>';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Show query string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_uri_string()
|
||||
{
|
||||
return "\n\n"
|
||||
.'<fieldset id="ci_profiler_uri_string" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#000;"> '.$this->CI->lang->line('profiler_uri_string')." </legend>\n"
|
||||
.'<div style="color:#000;font-weight:normal;padding:4px 0 4px 0;">'
|
||||
.($this->CI->uri->uri_string === '' ? $this->CI->lang->line('profiler_no_uri') : $this->CI->uri->uri_string)
|
||||
.'</div></fieldset>';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Show the controller and function that were called
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_controller_info()
|
||||
{
|
||||
return "\n\n"
|
||||
.'<fieldset id="ci_profiler_controller_info" style="border:1px solid #995300;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#995300;"> '.$this->CI->lang->line('profiler_controller_info')." </legend>\n"
|
||||
.'<div style="color:#995300;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->router->class.'/'.$this->CI->router->method
|
||||
.'</div></fieldset>';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile memory usage
|
||||
*
|
||||
* Display total used memory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_memory_usage()
|
||||
{
|
||||
return "\n\n"
|
||||
.'<fieldset id="ci_profiler_memory_usage" style="border:1px solid #5a0099;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#5a0099;"> '.$this->CI->lang->line('profiler_memory_usage')." </legend>\n"
|
||||
.'<div style="color:#5a0099;font-weight:normal;padding:4px 0 4px 0;">'
|
||||
.(($usage = memory_get_usage()) != '' ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
|
||||
.'</div></fieldset>';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile header information
|
||||
*
|
||||
* Lists HTTP headers
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_http_headers()
|
||||
{
|
||||
$output = "\n\n"
|
||||
.'<fieldset id="ci_profiler_http_headers" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#000;"> '.$this->CI->lang->line('profiler_headers')
|
||||
.' (<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_httpheaders_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show')."</span>)</legend>\n\n\n"
|
||||
.'<table style="width:100%;display:none;" id="ci_profiler_httpheaders_table">'."\n";
|
||||
|
||||
foreach (array('HTTP_ACCEPT', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_PORT', 'SERVER_NAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'HTTP_ACCEPT_LANGUAGE', 'SCRIPT_NAME', 'REQUEST_METHOD',' HTTP_HOST', 'REMOTE_HOST', 'CONTENT_TYPE', 'SERVER_PROTOCOL', 'QUERY_STRING', 'HTTP_ACCEPT_ENCODING', 'HTTP_X_FORWARDED_FOR', 'HTTP_DNT') as $header)
|
||||
{
|
||||
$val = isset($_SERVER[$header]) ? htmlspecialchars($_SERVER[$header], ENT_QUOTES, config_item('charset')) : '';
|
||||
$output .= '<tr><td style="vertical-align:top;width:50%;padding:5px;color:#900;background-color:#ddd;">'
|
||||
.$header.' </td><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">'.$val."</td></tr>\n";
|
||||
}
|
||||
|
||||
return $output."</table>\n</fieldset>";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile config information
|
||||
*
|
||||
* Lists developer config variables
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_config()
|
||||
{
|
||||
$output = "\n\n"
|
||||
.'<fieldset id="ci_profiler_config" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
."\n"
|
||||
.'<legend style="color:#000;"> '.$this->CI->lang->line('profiler_config').' (<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_config_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show')."</span>)</legend>\n\n\n"
|
||||
.'<table style="width:100%;display:none;" id="ci_profiler_config_table">'."\n";
|
||||
|
||||
foreach ($this->CI->config->config as $config => $val)
|
||||
{
|
||||
$pre = '';
|
||||
$pre_close = '';
|
||||
|
||||
if (is_array($val) OR is_object($val))
|
||||
{
|
||||
$val = print_r($val, TRUE);
|
||||
|
||||
$pre = '<pre>' ;
|
||||
$pre_close = '</pre>';
|
||||
}
|
||||
|
||||
$output .= '<tr><td style="padding:5px;vertical-align:top;color:#900;background-color:#ddd;">'
|
||||
.$config.' </td><td style="padding:5px;color:#000;background-color:#ddd;">'.$pre.htmlspecialchars($val, ENT_QUOTES, config_item('charset')).$pre_close."</td></tr>\n";
|
||||
}
|
||||
|
||||
return $output."</table>\n</fieldset>";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile session userdata
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _compile_session_data()
|
||||
{
|
||||
if ( ! isset($this->CI->session))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$output = '<fieldset id="ci_profiler_csession" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
|
||||
.'<legend style="color:#000;"> '.$this->CI->lang->line('profiler_session_data').' (<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_session_data\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
|
||||
.'<table style="width:100%;display:none;" id="ci_profiler_session_data">';
|
||||
|
||||
foreach ($this->CI->session->userdata() as $key => $val)
|
||||
{
|
||||
$pre = '';
|
||||
$pre_close = '';
|
||||
|
||||
if (is_array($val) OR is_object($val))
|
||||
{
|
||||
$val = print_r($val, TRUE);
|
||||
|
||||
$pre = '<pre>' ;
|
||||
$pre_close = '</pre>';
|
||||
}
|
||||
|
||||
$output .= '<tr><td style="padding:5px;vertical-align:top;color:#900;background-color:#ddd;">'
|
||||
.$key.' </td><td style="padding:5px;color:#000;background-color:#ddd;">'.$pre.htmlspecialchars($val, ENT_QUOTES, config_item('charset')).$pre_close."</td></tr>\n";
|
||||
}
|
||||
|
||||
return $output."</table>\n</fieldset>";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Run the Profiler
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$output = '<div id="codeigniter_profiler" style="clear:both;background-color:#fff;padding:10px;">';
|
||||
$fields_displayed = 0;
|
||||
|
||||
foreach ($this->_available_sections as $section)
|
||||
{
|
||||
if ($this->_compile_{$section} !== FALSE)
|
||||
{
|
||||
$func = '_compile_'.$section;
|
||||
$output .= $this->{$func}();
|
||||
$fields_displayed++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fields_displayed === 0)
|
||||
{
|
||||
$output .= '<p style="border:1px solid #5a0099;padding:10px;margin:20px 0;background-color:#eee;">'
|
||||
.$this->CI->lang->line('profiler_no_profiles').'</p>';
|
||||
}
|
||||
|
||||
return $output.'</div>';
|
||||
}
|
||||
|
||||
}
|
983
php/system/libraries/Session/Session.php
Normal file
983
php/system/libraries/Session/Session.php
Normal file
@ -0,0 +1,983 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 2.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Session Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session {
|
||||
|
||||
/**
|
||||
* Userdata array
|
||||
*
|
||||
* Just a reference to $_SESSION, for BC purposes.
|
||||
*/
|
||||
public $userdata;
|
||||
|
||||
protected $_driver = 'files';
|
||||
protected $_config;
|
||||
protected $_sid_regexp;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(array $params = array())
|
||||
{
|
||||
// No sessions under CLI
|
||||
if (is_cli())
|
||||
{
|
||||
log_message('debug', 'Session: Initialization under CLI aborted.');
|
||||
return;
|
||||
}
|
||||
elseif ((bool) ini_get('session.auto_start'))
|
||||
{
|
||||
log_message('error', 'Session: session.auto_start is enabled in php.ini. Aborting.');
|
||||
return;
|
||||
}
|
||||
elseif ( ! empty($params['driver']))
|
||||
{
|
||||
$this->_driver = $params['driver'];
|
||||
unset($params['driver']);
|
||||
}
|
||||
elseif ($driver = config_item('sess_driver'))
|
||||
{
|
||||
$this->_driver = $driver;
|
||||
}
|
||||
// Note: BC workaround
|
||||
elseif (config_item('sess_use_database'))
|
||||
{
|
||||
log_message('debug', 'Session: "sess_driver" is empty; using BC fallback to "sess_use_database".');
|
||||
$this->_driver = 'database';
|
||||
}
|
||||
|
||||
$class = $this->_ci_load_classes($this->_driver);
|
||||
|
||||
// Configuration ...
|
||||
$this->_configure($params);
|
||||
$this->_config['_sid_regexp'] = $this->_sid_regexp;
|
||||
|
||||
$class = new $class($this->_config);
|
||||
if ($class instanceof SessionHandlerInterface)
|
||||
{
|
||||
if (is_php('5.4'))
|
||||
{
|
||||
session_set_save_handler($class, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
session_set_save_handler(
|
||||
array($class, 'open'),
|
||||
array($class, 'close'),
|
||||
array($class, 'read'),
|
||||
array($class, 'write'),
|
||||
array($class, 'destroy'),
|
||||
array($class, 'gc')
|
||||
);
|
||||
|
||||
register_shutdown_function('session_write_close');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_message('error', "Session: Driver '".$this->_driver."' doesn't implement SessionHandlerInterface. Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize the cookie, because apparently PHP doesn't do that for userspace handlers
|
||||
if (isset($_COOKIE[$this->_config['cookie_name']])
|
||||
&& (
|
||||
! is_string($_COOKIE[$this->_config['cookie_name']])
|
||||
OR ! preg_match('#\A'.$this->_sid_regexp.'\z#', $_COOKIE[$this->_config['cookie_name']])
|
||||
)
|
||||
)
|
||||
{
|
||||
unset($_COOKIE[$this->_config['cookie_name']]);
|
||||
}
|
||||
|
||||
session_start();
|
||||
|
||||
// Is session ID auto-regeneration configured? (ignoring ajax requests)
|
||||
if ((empty($_SERVER['HTTP_X_REQUESTED_WITH']) OR strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest')
|
||||
&& ($regenerate_time = config_item('sess_time_to_update')) > 0
|
||||
)
|
||||
{
|
||||
if ( ! isset($_SESSION['__ci_last_regenerate']))
|
||||
{
|
||||
$_SESSION['__ci_last_regenerate'] = time();
|
||||
}
|
||||
elseif ($_SESSION['__ci_last_regenerate'] < (time() - $regenerate_time))
|
||||
{
|
||||
$this->sess_regenerate((bool) config_item('sess_regenerate_destroy'));
|
||||
}
|
||||
}
|
||||
// Another work-around ... PHP doesn't seem to send the session cookie
|
||||
// unless it is being currently created or regenerated
|
||||
elseif (isset($_COOKIE[$this->_config['cookie_name']]) && $_COOKIE[$this->_config['cookie_name']] === session_id())
|
||||
{
|
||||
setcookie(
|
||||
$this->_config['cookie_name'],
|
||||
session_id(),
|
||||
(empty($this->_config['cookie_lifetime']) ? 0 : time() + $this->_config['cookie_lifetime']),
|
||||
$this->_config['cookie_path'],
|
||||
$this->_config['cookie_domain'],
|
||||
$this->_config['cookie_secure'],
|
||||
TRUE
|
||||
);
|
||||
}
|
||||
|
||||
$this->_ci_init_vars();
|
||||
|
||||
log_message('info', "Session: Class initialized using '".$this->_driver."' driver.");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CI Load Classes
|
||||
*
|
||||
* An internal method to load all possible dependency and extension
|
||||
* classes. It kind of emulates the CI_Driver library, but is
|
||||
* self-sufficient.
|
||||
*
|
||||
* @param string $driver Driver name
|
||||
* @return string Driver class name
|
||||
*/
|
||||
protected function _ci_load_classes($driver)
|
||||
{
|
||||
// PHP 5.4 compatibility
|
||||
interface_exists('SessionHandlerInterface', FALSE) OR require_once(BASEPATH.'libraries/Session/SessionHandlerInterface.php');
|
||||
|
||||
$prefix = config_item('subclass_prefix');
|
||||
|
||||
if ( ! class_exists('CI_Session_driver', FALSE))
|
||||
{
|
||||
require_once(
|
||||
file_exists(APPPATH.'libraries/Session/Session_driver.php')
|
||||
? APPPATH.'libraries/Session/Session_driver.php'
|
||||
: BASEPATH.'libraries/Session/Session_driver.php'
|
||||
);
|
||||
|
||||
if (file_exists($file_path = APPPATH.'libraries/Session/'.$prefix.'Session_driver.php'))
|
||||
{
|
||||
require_once($file_path);
|
||||
}
|
||||
}
|
||||
|
||||
$class = 'Session_'.$driver.'_driver';
|
||||
|
||||
// Allow custom drivers without the CI_ or MY_ prefix
|
||||
if ( ! class_exists($class, FALSE) && file_exists($file_path = APPPATH.'libraries/Session/drivers/'.$class.'.php'))
|
||||
{
|
||||
require_once($file_path);
|
||||
if (class_exists($class, FALSE))
|
||||
{
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! class_exists('CI_'.$class, FALSE))
|
||||
{
|
||||
if (file_exists($file_path = APPPATH.'libraries/Session/drivers/'.$class.'.php') OR file_exists($file_path = BASEPATH.'libraries/Session/drivers/'.$class.'.php'))
|
||||
{
|
||||
require_once($file_path);
|
||||
}
|
||||
|
||||
if ( ! class_exists('CI_'.$class, FALSE) && ! class_exists($class, FALSE))
|
||||
{
|
||||
throw new UnexpectedValueException("Session: Configured driver '".$driver."' was not found. Aborting.");
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! class_exists($prefix.$class, FALSE) && file_exists($file_path = APPPATH.'libraries/Session/drivers/'.$prefix.$class.'.php'))
|
||||
{
|
||||
require_once($file_path);
|
||||
if (class_exists($prefix.$class, FALSE))
|
||||
{
|
||||
return $prefix.$class;
|
||||
}
|
||||
|
||||
log_message('debug', 'Session: '.$prefix.$class.".php found but it doesn't declare class ".$prefix.$class.'.');
|
||||
}
|
||||
|
||||
return 'CI_'.$class;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Configuration
|
||||
*
|
||||
* Handle input parameters and configuration defaults
|
||||
*
|
||||
* @param array &$params Input parameters
|
||||
* @return void
|
||||
*/
|
||||
protected function _configure(&$params)
|
||||
{
|
||||
$expiration = config_item('sess_expiration');
|
||||
|
||||
if (isset($params['cookie_lifetime']))
|
||||
{
|
||||
$params['cookie_lifetime'] = (int) $params['cookie_lifetime'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$params['cookie_lifetime'] = ( ! isset($expiration) && config_item('sess_expire_on_close'))
|
||||
? 0 : (int) $expiration;
|
||||
}
|
||||
|
||||
isset($params['cookie_name']) OR $params['cookie_name'] = config_item('sess_cookie_name');
|
||||
if (empty($params['cookie_name']))
|
||||
{
|
||||
$params['cookie_name'] = ini_get('session.name');
|
||||
}
|
||||
else
|
||||
{
|
||||
ini_set('session.name', $params['cookie_name']);
|
||||
}
|
||||
|
||||
isset($params['cookie_path']) OR $params['cookie_path'] = config_item('cookie_path');
|
||||
isset($params['cookie_domain']) OR $params['cookie_domain'] = config_item('cookie_domain');
|
||||
isset($params['cookie_secure']) OR $params['cookie_secure'] = (bool) config_item('cookie_secure');
|
||||
|
||||
session_set_cookie_params(
|
||||
$params['cookie_lifetime'],
|
||||
$params['cookie_path'],
|
||||
$params['cookie_domain'],
|
||||
$params['cookie_secure'],
|
||||
TRUE // HttpOnly; Yes, this is intentional and not configurable for security reasons
|
||||
);
|
||||
|
||||
if (empty($expiration))
|
||||
{
|
||||
$params['expiration'] = (int) ini_get('session.gc_maxlifetime');
|
||||
}
|
||||
else
|
||||
{
|
||||
$params['expiration'] = (int) $expiration;
|
||||
ini_set('session.gc_maxlifetime', $expiration);
|
||||
}
|
||||
|
||||
$params['match_ip'] = (bool) (isset($params['match_ip']) ? $params['match_ip'] : config_item('sess_match_ip'));
|
||||
|
||||
isset($params['save_path']) OR $params['save_path'] = config_item('sess_save_path');
|
||||
|
||||
$this->_config = $params;
|
||||
|
||||
// Security is king
|
||||
ini_set('session.use_trans_sid', 0);
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
ini_set('session.use_cookies', 1);
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
|
||||
$this->_configure_sid_length();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Configure session ID length
|
||||
*
|
||||
* To make life easier, we used to force SHA-1 and 4 bits per
|
||||
* character on everyone. And of course, someone was unhappy.
|
||||
*
|
||||
* Then PHP 7.1 broke backwards-compatibility because ext/session
|
||||
* is such a mess that nobody wants to touch it with a pole stick,
|
||||
* and the one guy who does, nobody has the energy to argue with.
|
||||
*
|
||||
* So we were forced to make changes, and OF COURSE something was
|
||||
* going to break and now we have this pile of shit. -- Narf
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _configure_sid_length()
|
||||
{
|
||||
if (PHP_VERSION_ID < 70100)
|
||||
{
|
||||
$hash_function = ini_get('session.hash_function');
|
||||
if (ctype_digit($hash_function))
|
||||
{
|
||||
if ($hash_function !== '1')
|
||||
{
|
||||
ini_set('session.hash_function', 1);
|
||||
}
|
||||
|
||||
$bits = 160;
|
||||
}
|
||||
elseif ( ! in_array($hash_function, hash_algos(), TRUE))
|
||||
{
|
||||
ini_set('session.hash_function', 1);
|
||||
$bits = 160;
|
||||
}
|
||||
elseif (($bits = strlen(hash($hash_function, 'dummy', false)) * 4) < 160)
|
||||
{
|
||||
ini_set('session.hash_function', 1);
|
||||
$bits = 160;
|
||||
}
|
||||
|
||||
$bits_per_character = (int) ini_get('session.hash_bits_per_character');
|
||||
$sid_length = (int) ceil($bits / $bits_per_character);
|
||||
}
|
||||
else
|
||||
{
|
||||
$bits_per_character = (int) ini_get('session.sid_bits_per_character');
|
||||
$sid_length = (int) ini_get('session.sid_length');
|
||||
if (($bits = $sid_length * $bits_per_character) < 160)
|
||||
{
|
||||
// Add as many more characters as necessary to reach at least 160 bits
|
||||
$sid_length += (int) ceil((160 % $bits) / $bits_per_character);
|
||||
ini_set('session.sid_length', $sid_length);
|
||||
}
|
||||
}
|
||||
|
||||
// Yes, 4,5,6 are the only known possible values as of 2016-10-27
|
||||
switch ($bits_per_character)
|
||||
{
|
||||
case 4:
|
||||
$this->_sid_regexp = '[0-9a-f]';
|
||||
break;
|
||||
case 5:
|
||||
$this->_sid_regexp = '[0-9a-v]';
|
||||
break;
|
||||
case 6:
|
||||
$this->_sid_regexp = '[0-9a-zA-Z,-]';
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_sid_regexp .= '{'.$sid_length.'}';
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handle temporary variables
|
||||
*
|
||||
* Clears old "flash" data, marks the new one for deletion and handles
|
||||
* "temp" data deletion.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _ci_init_vars()
|
||||
{
|
||||
if ( ! empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
$current_time = time();
|
||||
|
||||
foreach ($_SESSION['__ci_vars'] as $key => &$value)
|
||||
{
|
||||
if ($value === 'new')
|
||||
{
|
||||
$_SESSION['__ci_vars'][$key] = 'old';
|
||||
}
|
||||
// Hacky, but 'old' will (implicitly) always be less than time() ;)
|
||||
// DO NOT move this above the 'new' check!
|
||||
elseif ($value < $current_time)
|
||||
{
|
||||
unset($_SESSION[$key], $_SESSION['__ci_vars'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
unset($_SESSION['__ci_vars']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->userdata =& $_SESSION;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mark as flash
|
||||
*
|
||||
* @param mixed $key Session data key(s)
|
||||
* @return bool
|
||||
*/
|
||||
public function mark_as_flash($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
for ($i = 0, $c = count($key); $i < $c; $i++)
|
||||
{
|
||||
if ( ! isset($_SESSION[$key[$i]]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
$new = array_fill_keys($key, 'new');
|
||||
|
||||
$_SESSION['__ci_vars'] = isset($_SESSION['__ci_vars'])
|
||||
? array_merge($_SESSION['__ci_vars'], $new)
|
||||
: $new;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( ! isset($_SESSION[$key]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$_SESSION['__ci_vars'][$key] = 'new';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get flash keys
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_flash_keys()
|
||||
{
|
||||
if ( ! isset($_SESSION['__ci_vars']))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$keys = array();
|
||||
foreach (array_keys($_SESSION['__ci_vars']) as $key)
|
||||
{
|
||||
is_int($_SESSION['__ci_vars'][$key]) OR $keys[] = $key;
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Unmark flash
|
||||
*
|
||||
* @param mixed $key Session data key(s)
|
||||
* @return void
|
||||
*/
|
||||
public function unmark_flash($key)
|
||||
{
|
||||
if (empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
is_array($key) OR $key = array($key);
|
||||
|
||||
foreach ($key as $k)
|
||||
{
|
||||
if (isset($_SESSION['__ci_vars'][$k]) && ! is_int($_SESSION['__ci_vars'][$k]))
|
||||
{
|
||||
unset($_SESSION['__ci_vars'][$k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
unset($_SESSION['__ci_vars']);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Mark as temp
|
||||
*
|
||||
* @param mixed $key Session data key(s)
|
||||
* @param int $ttl Time-to-live in seconds
|
||||
* @return bool
|
||||
*/
|
||||
public function mark_as_temp($key, $ttl = 300)
|
||||
{
|
||||
$ttl += time();
|
||||
|
||||
if (is_array($key))
|
||||
{
|
||||
$temp = array();
|
||||
|
||||
foreach ($key as $k => $v)
|
||||
{
|
||||
// Do we have a key => ttl pair, or just a key?
|
||||
if (is_int($k))
|
||||
{
|
||||
$k = $v;
|
||||
$v = $ttl;
|
||||
}
|
||||
else
|
||||
{
|
||||
$v += time();
|
||||
}
|
||||
|
||||
if ( ! isset($_SESSION[$k]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$temp[$k] = $v;
|
||||
}
|
||||
|
||||
$_SESSION['__ci_vars'] = isset($_SESSION['__ci_vars'])
|
||||
? array_merge($_SESSION['__ci_vars'], $temp)
|
||||
: $temp;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ( ! isset($_SESSION[$key]))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$_SESSION['__ci_vars'][$key] = $ttl;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get temp keys
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_temp_keys()
|
||||
{
|
||||
if ( ! isset($_SESSION['__ci_vars']))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$keys = array();
|
||||
foreach (array_keys($_SESSION['__ci_vars']) as $key)
|
||||
{
|
||||
is_int($_SESSION['__ci_vars'][$key]) && $keys[] = $key;
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Unmark temp
|
||||
*
|
||||
* @param mixed $key Session data key(s)
|
||||
* @return void
|
||||
*/
|
||||
public function unmark_temp($key)
|
||||
{
|
||||
if (empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
is_array($key) OR $key = array($key);
|
||||
|
||||
foreach ($key as $k)
|
||||
{
|
||||
if (isset($_SESSION['__ci_vars'][$k]) && is_int($_SESSION['__ci_vars'][$k]))
|
||||
{
|
||||
unset($_SESSION['__ci_vars'][$k]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
unset($_SESSION['__ci_vars']);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __get()
|
||||
*
|
||||
* @param string $key 'session_id' or a session data key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key)
|
||||
{
|
||||
// Note: Keep this order the same, just in case somebody wants to
|
||||
// use 'session_id' as a session data key, for whatever reason
|
||||
if (isset($_SESSION[$key]))
|
||||
{
|
||||
return $_SESSION[$key];
|
||||
}
|
||||
elseif ($key === 'session_id')
|
||||
{
|
||||
return session_id();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __isset()
|
||||
*
|
||||
* @param string $key 'session_id' or a session data key
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($key)
|
||||
{
|
||||
if ($key === 'session_id')
|
||||
{
|
||||
return (session_status() === PHP_SESSION_ACTIVE);
|
||||
}
|
||||
|
||||
return isset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* __set()
|
||||
*
|
||||
* @param string $key Session data key
|
||||
* @param mixed $value Session data value
|
||||
* @return void
|
||||
*/
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Session destroy
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function sess_destroy()
|
||||
{
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Session regenerate
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param bool $destroy Destroy old session data flag
|
||||
* @return void
|
||||
*/
|
||||
public function sess_regenerate($destroy = FALSE)
|
||||
{
|
||||
$_SESSION['__ci_last_regenerate'] = time();
|
||||
session_regenerate_id($destroy);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get userdata reference
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @returns array
|
||||
*/
|
||||
public function &get_userdata()
|
||||
{
|
||||
return $_SESSION;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Userdata (fetch)
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param string $key Session data key
|
||||
* @return mixed Session data value or NULL if not found
|
||||
*/
|
||||
public function userdata($key = NULL)
|
||||
{
|
||||
if (isset($key))
|
||||
{
|
||||
return isset($_SESSION[$key]) ? $_SESSION[$key] : NULL;
|
||||
}
|
||||
elseif (empty($_SESSION))
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$userdata = array();
|
||||
$_exclude = array_merge(
|
||||
array('__ci_vars'),
|
||||
$this->get_flash_keys(),
|
||||
$this->get_temp_keys()
|
||||
);
|
||||
|
||||
foreach (array_keys($_SESSION) as $key)
|
||||
{
|
||||
if ( ! in_array($key, $_exclude, TRUE))
|
||||
{
|
||||
$userdata[$key] = $_SESSION[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $userdata;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set userdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $data Session data key or an associative array
|
||||
* @param mixed $value Value to store
|
||||
* @return void
|
||||
*/
|
||||
public function set_userdata($data, $value = NULL)
|
||||
{
|
||||
if (is_array($data))
|
||||
{
|
||||
foreach ($data as $key => &$value)
|
||||
{
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$_SESSION[$data] = $value;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Unset userdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $key Session data key(s)
|
||||
* @return void
|
||||
*/
|
||||
public function unset_userdata($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
foreach ($key as $k)
|
||||
{
|
||||
unset($_SESSION[$k]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* All userdata (fetch)
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @return array $_SESSION, excluding flash data items
|
||||
*/
|
||||
public function all_userdata()
|
||||
{
|
||||
return $this->userdata();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Has userdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param string $key Session data key
|
||||
* @return bool
|
||||
*/
|
||||
public function has_userdata($key)
|
||||
{
|
||||
return isset($_SESSION[$key]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flashdata (fetch)
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param string $key Session data key
|
||||
* @return mixed Session data value or NULL if not found
|
||||
*/
|
||||
public function flashdata($key = NULL)
|
||||
{
|
||||
if (isset($key))
|
||||
{
|
||||
return (isset($_SESSION['__ci_vars'], $_SESSION['__ci_vars'][$key], $_SESSION[$key]) && ! is_int($_SESSION['__ci_vars'][$key]))
|
||||
? $_SESSION[$key]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
$flashdata = array();
|
||||
|
||||
if ( ! empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
foreach ($_SESSION['__ci_vars'] as $key => &$value)
|
||||
{
|
||||
is_int($value) OR $flashdata[$key] = $_SESSION[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $flashdata;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set flashdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $data Session data key or an associative array
|
||||
* @param mixed $value Value to store
|
||||
* @return void
|
||||
*/
|
||||
public function set_flashdata($data, $value = NULL)
|
||||
{
|
||||
$this->set_userdata($data, $value);
|
||||
$this->mark_as_flash(is_array($data) ? array_keys($data) : $data);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Keep flashdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $key Session data key(s)
|
||||
* @return void
|
||||
*/
|
||||
public function keep_flashdata($key)
|
||||
{
|
||||
$this->mark_as_flash($key);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Temp data (fetch)
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param string $key Session data key
|
||||
* @return mixed Session data value or NULL if not found
|
||||
*/
|
||||
public function tempdata($key = NULL)
|
||||
{
|
||||
if (isset($key))
|
||||
{
|
||||
return (isset($_SESSION['__ci_vars'], $_SESSION['__ci_vars'][$key], $_SESSION[$key]) && is_int($_SESSION['__ci_vars'][$key]))
|
||||
? $_SESSION[$key]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
$tempdata = array();
|
||||
|
||||
if ( ! empty($_SESSION['__ci_vars']))
|
||||
{
|
||||
foreach ($_SESSION['__ci_vars'] as $key => &$value)
|
||||
{
|
||||
is_int($value) && $tempdata[$key] = $_SESSION[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $tempdata;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set tempdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $data Session data key or an associative array of items
|
||||
* @param mixed $value Value to store
|
||||
* @param int $ttl Time-to-live in seconds
|
||||
* @return void
|
||||
*/
|
||||
public function set_tempdata($data, $value = NULL, $ttl = 300)
|
||||
{
|
||||
$this->set_userdata($data, $value);
|
||||
$this->mark_as_temp(is_array($data) ? array_keys($data) : $data, $ttl);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Unset tempdata
|
||||
*
|
||||
* Legacy CI_Session compatibility method
|
||||
*
|
||||
* @param mixed $data Session data key(s)
|
||||
* @return void
|
||||
*/
|
||||
public function unset_tempdata($key)
|
||||
{
|
||||
$this->unmark_temp($key);
|
||||
}
|
||||
|
||||
}
|
59
php/system/libraries/Session/SessionHandlerInterface.php
Normal file
59
php/system/libraries/Session/SessionHandlerInterface.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* SessionHandlerInterface
|
||||
*
|
||||
* PHP 5.4 compatibility interface
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/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);
|
||||
}
|
208
php/system/libraries/Session/Session_driver.php
Normal file
208
php/system/libraries/Session/Session_driver.php
Normal file
@ -0,0 +1,208 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Session Driver Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/sessions.html
|
||||
*/
|
||||
abstract class CI_Session_driver implements SessionHandlerInterface {
|
||||
|
||||
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 on PHP 5.x (7+ does it by itself)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function php5_validate_id()
|
||||
{
|
||||
if (PHP_VERSION_ID < 70000 && 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()
|
||||
{
|
||||
return setcookie(
|
||||
$this->_config['cookie_name'],
|
||||
NULL,
|
||||
1,
|
||||
$this->_config['cookie_path'],
|
||||
$this->_config['cookie_domain'],
|
||||
$this->_config['cookie_secure'],
|
||||
TRUE
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fail
|
||||
*
|
||||
* Drivers other than the 'files' one don't (need to) use the
|
||||
* session.save_path INI setting, but that leads to confusing
|
||||
* error messages emitted by PHP when open() or write() fail,
|
||||
* as the message contains session.save_path ...
|
||||
* To work around the problem, the drivers will call this method
|
||||
* so that the INI is set just in time for the error message to
|
||||
* be properly generated.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _fail()
|
||||
{
|
||||
ini_set('session.save_path', config_item('sess_save_path'));
|
||||
return $this->_failure;
|
||||
}
|
||||
}
|
446
php/system/libraries/Session/drivers/Session_database_driver.php
Normal file
446
php/system/libraries/Session/drivers/Session_database_driver.php
Normal file
@ -0,0 +1,446 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Session Database Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_database_driver extends CI_Session_driver implements SessionHandlerInterface {
|
||||
|
||||
/**
|
||||
* DB object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $_db;
|
||||
|
||||
/**
|
||||
* Row exists flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_row_exists = FALSE;
|
||||
|
||||
/**
|
||||
* Lock "driver" flag
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_platform;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param array $params Configuration parameters
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(&$params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
$CI =& get_instance();
|
||||
isset($CI->db) OR $CI->load->database();
|
||||
$this->_db = $CI->db;
|
||||
|
||||
if ( ! $this->_db instanceof CI_DB_query_builder)
|
||||
{
|
||||
throw new Exception('Query Builder not enabled for the configured database. Aborting.');
|
||||
}
|
||||
elseif ($this->_db->pconnect)
|
||||
{
|
||||
throw new Exception('Configured database connection is persistent. Aborting.');
|
||||
}
|
||||
elseif ($this->_db->cache_on)
|
||||
{
|
||||
throw new Exception('Configured database connection has cache enabled. Aborting.');
|
||||
}
|
||||
|
||||
$db_driver = $this->_db->dbdriver.(empty($this->_db->subdriver) ? '' : '_'.$this->_db->subdriver);
|
||||
if (strpos($db_driver, 'mysql') !== FALSE)
|
||||
{
|
||||
$this->_platform = 'mysql';
|
||||
}
|
||||
elseif (in_array($db_driver, array('postgre', 'pdo_pgsql'), TRUE))
|
||||
{
|
||||
$this->_platform = 'postgre';
|
||||
}
|
||||
|
||||
// Note: BC work-around for the old 'sess_table_name' setting, should be removed in the future.
|
||||
if ( ! isset($this->_config['save_path']) && ($this->_config['save_path'] = config_item('sess_table_name')))
|
||||
{
|
||||
log_message('debug', 'Session: "sess_save_path" is empty; using BC fallback to "sess_table_name".');
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Open
|
||||
*
|
||||
* Initializes the database connection
|
||||
*
|
||||
* @param string $save_path Table name
|
||||
* @param string $name Session cookie name, unused
|
||||
* @return bool
|
||||
*/
|
||||
public function open($save_path, $name)
|
||||
{
|
||||
if (empty($this->_db->conn_id) && ! $this->_db->db_connect())
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
$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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
$this->_fingerprint = md5('');
|
||||
return '';
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Write
|
||||
*
|
||||
* Writes (create / update) session data
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @param string $session_data Serialized session data
|
||||
* @return bool
|
||||
*/
|
||||
public function write($session_id, $session_data)
|
||||
{
|
||||
// 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->_fail();
|
||||
}
|
||||
|
||||
$this->_row_exists = FALSE;
|
||||
$this->_session_id = $session_id;
|
||||
}
|
||||
elseif ($this->_lock === FALSE)
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
if ($this->_row_exists === FALSE)
|
||||
{
|
||||
$insert_data = array(
|
||||
'id' => $session_id,
|
||||
'ip_address' => $_SERVER['REMOTE_ADDR'],
|
||||
'timestamp' => time(),
|
||||
'data' => ($this->_platform === 'postgre' ? base64_encode($session_data) : $session_data)
|
||||
);
|
||||
|
||||
if ($this->_db->insert($this->_config['save_path'], $insert_data))
|
||||
{
|
||||
$this->_fingerprint = md5($session_data);
|
||||
$this->_row_exists = TRUE;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
$this->_db->where('id', $session_id);
|
||||
if ($this->_config['match_ip'])
|
||||
{
|
||||
$this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
|
||||
}
|
||||
|
||||
$update_data = array('timestamp' => time());
|
||||
if ($this->_fingerprint !== md5($session_data))
|
||||
{
|
||||
$update_data['data'] = ($this->_platform === 'postgre')
|
||||
? base64_encode($session_data)
|
||||
: $session_data;
|
||||
}
|
||||
|
||||
if ($this->_db->update($this->_config['save_path'], $update_data))
|
||||
{
|
||||
$this->_fingerprint = md5($session_data);
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
return ($this->_lock && ! $this->_release_lock())
|
||||
? $this->_fail()
|
||||
: $this->_success;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Destroy
|
||||
*
|
||||
* Destroys the current session.
|
||||
*
|
||||
* @param string $session_id Session ID
|
||||
* @return bool
|
||||
*/
|
||||
public function destroy($session_id)
|
||||
{
|
||||
if ($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->_fail();
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->close() === $this->_success)
|
||||
{
|
||||
$this->_cookie_destroy();
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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->_fail();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $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();
|
||||
}
|
||||
}
|
424
php/system/libraries/Session/drivers/Session_files_driver.php
Normal file
424
php/system/libraries/Session/drivers/Session_files_driver.php
Normal file
@ -0,0 +1,424 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Session Files Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_files_driver extends CI_Session_driver implements SessionHandlerInterface {
|
||||
|
||||
/**
|
||||
* 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 = (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))
|
||||
{
|
||||
throw new Exception("Session: Configured save path '".$this->_config['save_path']."' is not a directory, doesn't exist or cannot be created.");
|
||||
}
|
||||
}
|
||||
elseif ( ! is_writable($save_path))
|
||||
{
|
||||
throw new Exception("Session: Configured save path '".$this->_config['save_path']."' is not writable by the PHP process.");
|
||||
}
|
||||
|
||||
$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 '';
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $id
|
||||
* @return bool
|
||||
*/
|
||||
public function validateId($id)
|
||||
{
|
||||
return is_file($this->_file_path.$id);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe strlen()
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
protected static function strlen($str)
|
||||
{
|
||||
return (self::$func_overload)
|
||||
? mb_strlen($str, '8bit')
|
||||
: strlen($str);
|
||||
}
|
||||
}
|
@ -0,0 +1,397 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Session Memcached Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_memcached_driver extends CI_Session_driver implements SessionHandlerInterface {
|
||||
|
||||
/**
|
||||
* 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->_fail();
|
||||
}
|
||||
|
||||
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->_fail();
|
||||
}
|
||||
|
||||
$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->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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->_fail();
|
||||
}
|
||||
// Was the ID regenerated?
|
||||
elseif ($session_id !== $this->_session_id)
|
||||
{
|
||||
if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
$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->_fail();
|
||||
}
|
||||
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->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks and closes connection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (isset($this->_memcached))
|
||||
{
|
||||
$this->_release_lock();
|
||||
if ( ! $this->_memcached->quit())
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
$this->_memcached = NULL;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $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;
|
||||
}
|
||||
}
|
417
php/system/libraries/Session/drivers/Session_redis_driver.php
Normal file
417
php/system/libraries/Session/drivers/Session_redis_driver.php
Normal file
@ -0,0 +1,417 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 3.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* CodeIgniter Session Redis Driver
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Sessions
|
||||
* @author Andrey Andreev
|
||||
* @link https://codeigniter.com/user_guide/libraries/sessions.html
|
||||
*/
|
||||
class CI_Session_redis_driver extends CI_Session_driver implements SessionHandlerInterface {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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 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->_fail();
|
||||
}
|
||||
|
||||
$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;
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
$this->php5_validate_id();
|
||||
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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->_fail();
|
||||
}
|
||||
// Was the ID regenerated?
|
||||
elseif ($session_id !== $this->_session_id)
|
||||
{
|
||||
if ( ! $this->_release_lock() OR ! $this->_get_lock($session_id))
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
$this->_key_exists = FALSE;
|
||||
$this->_session_id = $session_id;
|
||||
}
|
||||
|
||||
$this->_redis->setTimeout($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->_fail();
|
||||
}
|
||||
|
||||
return ($this->_redis->setTimeout($this->_key_prefix.$session_id, $this->_config['expiration']))
|
||||
? $this->_success
|
||||
: $this->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Close
|
||||
*
|
||||
* Releases locks and closes connection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if (isset($this->_redis))
|
||||
{
|
||||
try {
|
||||
if ($this->_redis->ping() === '+PONG')
|
||||
{
|
||||
$this->_release_lock();
|
||||
if ($this->_redis->close() === FALSE)
|
||||
{
|
||||
return $this->_fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
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->delete($this->_key_prefix.$session_id)) !== 1)
|
||||
{
|
||||
log_message('debug', 'Session: Redis::delete() expected to return 1, got '.var_export($result, TRUE).' instead.');
|
||||
}
|
||||
|
||||
$this->_cookie_destroy();
|
||||
return $this->_success;
|
||||
}
|
||||
|
||||
return $this->_fail();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate ID
|
||||
*
|
||||
* Checks whether a session ID record exists server-side,
|
||||
* to enforce session.use_strict_mode.
|
||||
*
|
||||
* @param string $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->setTimeout($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;
|
||||
}
|
||||
|
||||
$result = ($ttl === -2)
|
||||
? $this->_redis->set($lock_key, time(), array('nx', 'ex' => 300))
|
||||
: $this->_redis->setex($lock_key, 300, time());
|
||||
|
||||
if ( ! $result)
|
||||
{
|
||||
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->delete($this->_lock_key))
|
||||
{
|
||||
log_message('error', 'Session: Error while trying to free lock for '.$this->_lock_key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->_lock_key = NULL;
|
||||
$this->_lock = FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
11
php/system/libraries/Session/drivers/index.html
Normal file
11
php/system/libraries/Session/drivers/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
11
php/system/libraries/Session/index.html
Normal file
11
php/system/libraries/Session/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
538
php/system/libraries/Table.php
Normal file
538
php/system/libraries/Table.php
Normal file
@ -0,0 +1,538 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.3.1
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* HTML Table Generating Class
|
||||
*
|
||||
* Lets you create tables manually or from database result objects, or arrays.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category HTML Tables
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/table.html
|
||||
*/
|
||||
class CI_Table {
|
||||
|
||||
/**
|
||||
* Data for table rows
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $rows = array();
|
||||
|
||||
/**
|
||||
* Data for table heading
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $heading = array();
|
||||
|
||||
/**
|
||||
* Whether or not to automatically create the table header
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $auto_heading = TRUE;
|
||||
|
||||
/**
|
||||
* Table caption
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $caption = NULL;
|
||||
|
||||
/**
|
||||
* Table layout template
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $template = NULL;
|
||||
|
||||
/**
|
||||
* Newline setting
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $newline = "\n";
|
||||
|
||||
/**
|
||||
* Contents of empty cells
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $empty_cells = '';
|
||||
|
||||
/**
|
||||
* Callback for custom table layout
|
||||
*
|
||||
* @var function
|
||||
*/
|
||||
public $function = NULL;
|
||||
|
||||
/**
|
||||
* Set the template from the table config file if it exists
|
||||
*
|
||||
* @param array $config (default: array())
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
// initialize config
|
||||
foreach ($config as $key => $val)
|
||||
{
|
||||
$this->template[$key] = $val;
|
||||
}
|
||||
|
||||
log_message('info', 'Table Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the template
|
||||
*
|
||||
* @param array $template
|
||||
* @return bool
|
||||
*/
|
||||
public function set_template($template)
|
||||
{
|
||||
if ( ! is_array($template))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->template = $template;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the table heading
|
||||
*
|
||||
* Can be passed as an array or discreet params
|
||||
*
|
||||
* @param mixed
|
||||
* @return CI_Table
|
||||
*/
|
||||
public function set_heading($args = array())
|
||||
{
|
||||
$this->heading = $this->_prep_args(func_get_args());
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set columns. Takes a one-dimensional array as input and creates
|
||||
* a multi-dimensional array with a depth equal to the number of
|
||||
* columns. This allows a single array with many elements to be
|
||||
* displayed in a table that has a fixed column count.
|
||||
*
|
||||
* @param array $array
|
||||
* @param int $col_limit
|
||||
* @return array
|
||||
*/
|
||||
public function make_columns($array = array(), $col_limit = 0)
|
||||
{
|
||||
if ( ! is_array($array) OR count($array) === 0 OR ! is_int($col_limit))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Turn off the auto-heading feature since it's doubtful we
|
||||
// will want headings from a one-dimensional array
|
||||
$this->auto_heading = FALSE;
|
||||
|
||||
if ($col_limit === 0)
|
||||
{
|
||||
return $array;
|
||||
}
|
||||
|
||||
$new = array();
|
||||
do
|
||||
{
|
||||
$temp = array_splice($array, 0, $col_limit);
|
||||
|
||||
if (count($temp) < $col_limit)
|
||||
{
|
||||
for ($i = count($temp); $i < $col_limit; $i++)
|
||||
{
|
||||
$temp[] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
$new[] = $temp;
|
||||
}
|
||||
while (count($array) > 0);
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set "empty" cells
|
||||
*
|
||||
* Can be passed as an array or discreet params
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return CI_Table
|
||||
*/
|
||||
public function set_empty($value)
|
||||
{
|
||||
$this->empty_cells = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add a table row
|
||||
*
|
||||
* Can be passed as an array or discreet params
|
||||
*
|
||||
* @param mixed
|
||||
* @return CI_Table
|
||||
*/
|
||||
public function add_row($args = array())
|
||||
{
|
||||
$this->rows[] = $this->_prep_args(func_get_args());
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Prep Args
|
||||
*
|
||||
* Ensures a standard associative array format for all cell data
|
||||
*
|
||||
* @param array
|
||||
* @return array
|
||||
*/
|
||||
protected function _prep_args($args)
|
||||
{
|
||||
// If there is no $args[0], skip this and treat as an associative array
|
||||
// This can happen if there is only a single key, for example this is passed to table->generate
|
||||
// array(array('foo'=>'bar'))
|
||||
if (isset($args[0]) && count($args) === 1 && is_array($args[0]) && ! isset($args[0]['data']))
|
||||
{
|
||||
$args = $args[0];
|
||||
}
|
||||
|
||||
foreach ($args as $key => $val)
|
||||
{
|
||||
is_array($val) OR $args[$key] = array('data' => $val);
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add a table caption
|
||||
*
|
||||
* @param string $caption
|
||||
* @return CI_Table
|
||||
*/
|
||||
public function set_caption($caption)
|
||||
{
|
||||
$this->caption = $caption;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generate the table
|
||||
*
|
||||
* @param mixed $table_data
|
||||
* @return string
|
||||
*/
|
||||
public function generate($table_data = NULL)
|
||||
{
|
||||
// The table data can optionally be passed to this function
|
||||
// either as a database result object or an array
|
||||
if ( ! empty($table_data))
|
||||
{
|
||||
if ($table_data instanceof CI_DB_result)
|
||||
{
|
||||
$this->_set_from_db_result($table_data);
|
||||
}
|
||||
elseif (is_array($table_data))
|
||||
{
|
||||
$this->_set_from_array($table_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Is there anything to display? No? Smite them!
|
||||
if (empty($this->heading) && empty($this->rows))
|
||||
{
|
||||
return 'Undefined table data';
|
||||
}
|
||||
|
||||
// Compile and validate the template date
|
||||
$this->_compile_template();
|
||||
|
||||
// Validate a possibly existing custom cell manipulation function
|
||||
if (isset($this->function) && ! is_callable($this->function))
|
||||
{
|
||||
$this->function = NULL;
|
||||
}
|
||||
|
||||
// Build the table!
|
||||
|
||||
$out = $this->template['table_open'].$this->newline;
|
||||
|
||||
// Add any caption here
|
||||
if ($this->caption)
|
||||
{
|
||||
$out .= '<caption>'.$this->caption.'</caption>'.$this->newline;
|
||||
}
|
||||
|
||||
// Is there a table heading to display?
|
||||
if ( ! empty($this->heading))
|
||||
{
|
||||
$out .= $this->template['thead_open'].$this->newline.$this->template['heading_row_start'].$this->newline;
|
||||
|
||||
foreach ($this->heading as $heading)
|
||||
{
|
||||
$temp = $this->template['heading_cell_start'];
|
||||
|
||||
foreach ($heading as $key => $val)
|
||||
{
|
||||
if ($key !== 'data')
|
||||
{
|
||||
$temp = str_replace('<th', '<th '.$key.'="'.$val.'"', $temp);
|
||||
}
|
||||
}
|
||||
|
||||
$out .= $temp.(isset($heading['data']) ? $heading['data'] : '').$this->template['heading_cell_end'];
|
||||
}
|
||||
|
||||
$out .= $this->template['heading_row_end'].$this->newline.$this->template['thead_close'].$this->newline;
|
||||
}
|
||||
|
||||
// Build the table rows
|
||||
if ( ! empty($this->rows))
|
||||
{
|
||||
$out .= $this->template['tbody_open'].$this->newline;
|
||||
|
||||
$i = 1;
|
||||
foreach ($this->rows as $row)
|
||||
{
|
||||
if ( ! is_array($row))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// We use modulus to alternate the row colors
|
||||
$name = fmod($i++, 2) ? '' : 'alt_';
|
||||
|
||||
$out .= $this->template['row_'.$name.'start'].$this->newline;
|
||||
|
||||
foreach ($row as $cell)
|
||||
{
|
||||
$temp = $this->template['cell_'.$name.'start'];
|
||||
|
||||
foreach ($cell as $key => $val)
|
||||
{
|
||||
if ($key !== 'data')
|
||||
{
|
||||
$temp = str_replace('<td', '<td '.$key.'="'.$val.'"', $temp);
|
||||
}
|
||||
}
|
||||
|
||||
$cell = isset($cell['data']) ? $cell['data'] : '';
|
||||
$out .= $temp;
|
||||
|
||||
if ($cell === '' OR $cell === NULL)
|
||||
{
|
||||
$out .= $this->empty_cells;
|
||||
}
|
||||
elseif (isset($this->function))
|
||||
{
|
||||
$out .= call_user_func($this->function, $cell);
|
||||
}
|
||||
else
|
||||
{
|
||||
$out .= $cell;
|
||||
}
|
||||
|
||||
$out .= $this->template['cell_'.$name.'end'];
|
||||
}
|
||||
|
||||
$out .= $this->template['row_'.$name.'end'].$this->newline;
|
||||
}
|
||||
|
||||
$out .= $this->template['tbody_close'].$this->newline;
|
||||
}
|
||||
|
||||
$out .= $this->template['table_close'];
|
||||
|
||||
// Clear table class properties before generating the table
|
||||
$this->clear();
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Clears the table arrays. Useful if multiple tables are being generated
|
||||
*
|
||||
* @return CI_Table
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
$this->rows = array();
|
||||
$this->heading = array();
|
||||
$this->auto_heading = TRUE;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set table data from a database result object
|
||||
*
|
||||
* @param CI_DB_result $object Database result object
|
||||
* @return void
|
||||
*/
|
||||
protected function _set_from_db_result($object)
|
||||
{
|
||||
// First generate the headings from the table column names
|
||||
if ($this->auto_heading === TRUE && empty($this->heading))
|
||||
{
|
||||
$this->heading = $this->_prep_args($object->list_fields());
|
||||
}
|
||||
|
||||
foreach ($object->result_array() as $row)
|
||||
{
|
||||
$this->rows[] = $this->_prep_args($row);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set table data from an array
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
protected function _set_from_array($data)
|
||||
{
|
||||
if ($this->auto_heading === TRUE && empty($this->heading))
|
||||
{
|
||||
$this->heading = $this->_prep_args(array_shift($data));
|
||||
}
|
||||
|
||||
foreach ($data as &$row)
|
||||
{
|
||||
$this->rows[] = $this->_prep_args($row);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile Template
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _compile_template()
|
||||
{
|
||||
if ($this->template === NULL)
|
||||
{
|
||||
$this->template = $this->_default_template();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->temp = $this->_default_template();
|
||||
foreach (array('table_open', 'thead_open', 'thead_close', 'heading_row_start', 'heading_row_end', 'heading_cell_start', 'heading_cell_end', 'tbody_open', 'tbody_close', 'row_start', 'row_end', 'cell_start', 'cell_end', 'row_alt_start', 'row_alt_end', 'cell_alt_start', 'cell_alt_end', 'table_close') as $val)
|
||||
{
|
||||
if ( ! isset($this->template[$val]))
|
||||
{
|
||||
$this->template[$val] = $this->temp[$val];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default Template
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _default_template()
|
||||
{
|
||||
return array(
|
||||
'table_open' => '<table border="0" cellpadding="4" cellspacing="0">',
|
||||
|
||||
'thead_open' => '<thead>',
|
||||
'thead_close' => '</thead>',
|
||||
|
||||
'heading_row_start' => '<tr>',
|
||||
'heading_row_end' => '</tr>',
|
||||
'heading_cell_start' => '<th>',
|
||||
'heading_cell_end' => '</th>',
|
||||
|
||||
'tbody_open' => '<tbody>',
|
||||
'tbody_close' => '</tbody>',
|
||||
|
||||
'row_start' => '<tr>',
|
||||
'row_end' => '</tr>',
|
||||
'cell_start' => '<td>',
|
||||
'cell_end' => '</td>',
|
||||
|
||||
'row_alt_start' => '<tr>',
|
||||
'row_alt_end' => '</tr>',
|
||||
'cell_alt_start' => '<td>',
|
||||
'cell_alt_end' => '</td>',
|
||||
|
||||
'table_close' => '</table>'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
556
php/system/libraries/Trackback.php
Normal file
556
php/system/libraries/Trackback.php
Normal file
@ -0,0 +1,556 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Trackback Class
|
||||
*
|
||||
* Trackback Sending/Receiving Class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Trackbacks
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/trackback.html
|
||||
*/
|
||||
class CI_Trackback {
|
||||
|
||||
/**
|
||||
* Character set
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* Trackback data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $data = array(
|
||||
'url' => '',
|
||||
'title' => '',
|
||||
'excerpt' => '',
|
||||
'blog_name' => '',
|
||||
'charset' => ''
|
||||
);
|
||||
|
||||
/**
|
||||
* Convert ASCII flag
|
||||
*
|
||||
* Whether to convert high-ASCII and MS Word
|
||||
* characters to HTML entities.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $convert_ascii = TRUE;
|
||||
|
||||
/**
|
||||
* Response
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $response = '';
|
||||
|
||||
/**
|
||||
* Error messages list
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $error_msg = array();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
log_message('info', 'Trackback Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Send Trackback
|
||||
*
|
||||
* @param array
|
||||
* @return bool
|
||||
*/
|
||||
public function send($tb_data)
|
||||
{
|
||||
if ( ! is_array($tb_data))
|
||||
{
|
||||
$this->set_error('The send() method must be passed an array');
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Pre-process the Trackback Data
|
||||
foreach (array('url', 'title', 'excerpt', 'blog_name', 'ping_url') as $item)
|
||||
{
|
||||
if ( ! isset($tb_data[$item]))
|
||||
{
|
||||
$this->set_error('Required item missing: '.$item);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch ($item)
|
||||
{
|
||||
case 'ping_url':
|
||||
$$item = $this->extract_urls($tb_data[$item]);
|
||||
break;
|
||||
case 'excerpt':
|
||||
$$item = $this->limit_characters($this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
|
||||
break;
|
||||
case 'url':
|
||||
$$item = str_replace('-', '-', $this->convert_xml(strip_tags(stripslashes($tb_data[$item]))));
|
||||
break;
|
||||
default:
|
||||
$$item = $this->convert_xml(strip_tags(stripslashes($tb_data[$item])));
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert High ASCII Characters
|
||||
if ($this->convert_ascii === TRUE && in_array($item, array('excerpt', 'title', 'blog_name'), TRUE))
|
||||
{
|
||||
$$item = $this->convert_ascii($$item);
|
||||
}
|
||||
}
|
||||
|
||||
// Build the Trackback data string
|
||||
$charset = isset($tb_data['charset']) ? $tb_data['charset'] : $this->charset;
|
||||
|
||||
$data = 'url='.rawurlencode($url).'&title='.rawurlencode($title).'&blog_name='.rawurlencode($blog_name)
|
||||
.'&excerpt='.rawurlencode($excerpt).'&charset='.rawurlencode($charset);
|
||||
|
||||
// Send Trackback(s)
|
||||
$return = TRUE;
|
||||
if (count($ping_url) > 0)
|
||||
{
|
||||
foreach ($ping_url as $url)
|
||||
{
|
||||
if ($this->process($url, $data) === FALSE)
|
||||
{
|
||||
$return = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Receive Trackback Data
|
||||
*
|
||||
* This function simply validates the incoming TB data.
|
||||
* It returns FALSE on failure and TRUE on success.
|
||||
* If the data is valid it is set to the $this->data array
|
||||
* so that it can be inserted into a database.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function receive()
|
||||
{
|
||||
foreach (array('url', 'title', 'blog_name', 'excerpt') as $val)
|
||||
{
|
||||
if (empty($_POST[$val]))
|
||||
{
|
||||
$this->set_error('The following required POST variable is missing: '.$val);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$this->data['charset'] = isset($_POST['charset']) ? strtoupper(trim($_POST['charset'])) : 'auto';
|
||||
|
||||
if ($val !== 'url' && MB_ENABLED === TRUE)
|
||||
{
|
||||
if (MB_ENABLED === TRUE)
|
||||
{
|
||||
$_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']);
|
||||
}
|
||||
elseif (ICONV_ENABLED === TRUE)
|
||||
{
|
||||
$_POST[$val] = @iconv($this->data['charset'], $this->charset.'//IGNORE', $_POST[$val]);
|
||||
}
|
||||
}
|
||||
|
||||
$_POST[$val] = ($val !== 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]);
|
||||
|
||||
if ($val === 'excerpt')
|
||||
{
|
||||
$_POST['excerpt'] = $this->limit_characters($_POST['excerpt']);
|
||||
}
|
||||
|
||||
$this->data[$val] = $_POST[$val];
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Send Trackback Error Message
|
||||
*
|
||||
* Allows custom errors to be set. By default it
|
||||
* sends the "incomplete information" error, as that's
|
||||
* the most common one.
|
||||
*
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function send_error($message = 'Incomplete Information')
|
||||
{
|
||||
exit('<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>1</error>\n<message>".$message."</message>\n</response>");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Send Trackback Success Message
|
||||
*
|
||||
* This should be called when a trackback has been
|
||||
* successfully received and inserted.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function send_success()
|
||||
{
|
||||
exit('<?xml version="1.0" encoding="utf-8"?'.">\n<response>\n<error>0</error>\n</response>");
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Fetch a particular item
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function data($item)
|
||||
{
|
||||
return isset($this->data[$item]) ? $this->data[$item] : '';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Process Trackback
|
||||
*
|
||||
* Opens a socket connection and passes the data to
|
||||
* the server. Returns TRUE on success, FALSE on failure
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return bool
|
||||
*/
|
||||
public function process($url, $data)
|
||||
{
|
||||
$target = parse_url($url);
|
||||
|
||||
// Open the socket
|
||||
if ( ! $fp = @fsockopen($target['host'], 80))
|
||||
{
|
||||
$this->set_error('Invalid Connection: '.$url);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Build the path
|
||||
$path = isset($target['path']) ? $target['path'] : $url;
|
||||
empty($target['query']) OR $path .= '?'.$target['query'];
|
||||
|
||||
// Add the Trackback ID to the data string
|
||||
if ($id = $this->get_id($url))
|
||||
{
|
||||
$data = 'tb_id='.$id.'&'.$data;
|
||||
}
|
||||
|
||||
// Transfer the data
|
||||
fputs($fp, 'POST '.$path." HTTP/1.0\r\n");
|
||||
fputs($fp, 'Host: '.$target['host']."\r\n");
|
||||
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
|
||||
fputs($fp, 'Content-length: '.strlen($data)."\r\n");
|
||||
fputs($fp, "Connection: close\r\n\r\n");
|
||||
fputs($fp, $data);
|
||||
|
||||
// Was it successful?
|
||||
|
||||
$this->response = '';
|
||||
while ( ! feof($fp))
|
||||
{
|
||||
$this->response .= fgets($fp, 128);
|
||||
}
|
||||
@fclose($fp);
|
||||
|
||||
if (stripos($this->response, '<error>0</error>') === FALSE)
|
||||
{
|
||||
$message = preg_match('/<message>(.*?)<\/message>/is', $this->response, $match)
|
||||
? trim($match[1])
|
||||
: 'An unknown error was encountered';
|
||||
$this->set_error($message);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Extract Trackback URLs
|
||||
*
|
||||
* This function lets multiple trackbacks be sent.
|
||||
* It takes a string of URLs (separated by comma or
|
||||
* space) and puts each URL into an array
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function extract_urls($urls)
|
||||
{
|
||||
// Remove the pesky white space and replace with a comma, then replace doubles.
|
||||
$urls = str_replace(',,', ',', preg_replace('/\s*(\S+)\s*/', '\\1,', $urls));
|
||||
|
||||
// Break into an array via commas and remove duplicates
|
||||
$urls = array_unique(preg_split('/[,]/', rtrim($urls, ',')));
|
||||
|
||||
array_walk($urls, array($this, 'validate_url'));
|
||||
return $urls;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Validate URL
|
||||
*
|
||||
* Simply adds "http://" if missing
|
||||
*
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function validate_url(&$url)
|
||||
{
|
||||
$url = trim($url);
|
||||
|
||||
if (stripos($url, 'http') !== 0)
|
||||
{
|
||||
$url = 'http://'.$url;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find the Trackback URL's ID
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function get_id($url)
|
||||
{
|
||||
$tb_id = '';
|
||||
|
||||
if (strpos($url, '?') !== FALSE)
|
||||
{
|
||||
$tb_array = explode('/', $url);
|
||||
$tb_end = $tb_array[count($tb_array)-1];
|
||||
|
||||
if ( ! is_numeric($tb_end))
|
||||
{
|
||||
$tb_end = $tb_array[count($tb_array)-2];
|
||||
}
|
||||
|
||||
$tb_array = explode('=', $tb_end);
|
||||
$tb_id = $tb_array[count($tb_array)-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = rtrim($url, '/');
|
||||
|
||||
$tb_array = explode('/', $url);
|
||||
$tb_id = $tb_array[count($tb_array)-1];
|
||||
|
||||
if ( ! is_numeric($tb_id))
|
||||
{
|
||||
$tb_id = $tb_array[count($tb_array)-2];
|
||||
}
|
||||
}
|
||||
|
||||
return ctype_digit((string) $tb_id) ? $tb_id : FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Convert Reserved XML characters to Entities
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function convert_xml($str)
|
||||
{
|
||||
$temp = '__TEMP_AMPERSANDS__';
|
||||
|
||||
$str = preg_replace(array('/&#(\d+);/', '/&(\w+);/'), $temp.'\\1;', $str);
|
||||
|
||||
$str = str_replace(array('&', '<', '>', '"', "'", '-'),
|
||||
array('&', '<', '>', '"', ''', '-'),
|
||||
$str);
|
||||
|
||||
return preg_replace(array('/'.$temp.'(\d+);/', '/'.$temp.'(\w+);/'), array('&#\\1;', '&\\1;'), $str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Character limiter
|
||||
*
|
||||
* Limits the string based on the character count. Will preserve complete words.
|
||||
*
|
||||
* @param string
|
||||
* @param int
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function limit_characters($str, $n = 500, $end_char = '…')
|
||||
{
|
||||
if (strlen($str) < $n)
|
||||
{
|
||||
return $str;
|
||||
}
|
||||
|
||||
$str = preg_replace('/\s+/', ' ', str_replace(array("\r\n", "\r", "\n"), ' ', $str));
|
||||
|
||||
if (strlen($str) <= $n)
|
||||
{
|
||||
return $str;
|
||||
}
|
||||
|
||||
$out = '';
|
||||
foreach (explode(' ', trim($str)) as $val)
|
||||
{
|
||||
$out .= $val.' ';
|
||||
if (strlen($out) >= $n)
|
||||
{
|
||||
return rtrim($out).$end_char;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* High ASCII to Entities
|
||||
*
|
||||
* Converts Hight ascii text and MS Word special chars
|
||||
* to character entities
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function convert_ascii($str)
|
||||
{
|
||||
$count = 1;
|
||||
$out = '';
|
||||
$temp = array();
|
||||
|
||||
for ($i = 0, $s = strlen($str); $i < $s; $i++)
|
||||
{
|
||||
$ordinal = ord($str[$i]);
|
||||
|
||||
if ($ordinal < 128)
|
||||
{
|
||||
$out .= $str[$i];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (count($temp) === 0)
|
||||
{
|
||||
$count = ($ordinal < 224) ? 2 : 3;
|
||||
}
|
||||
|
||||
$temp[] = $ordinal;
|
||||
|
||||
if (count($temp) === $count)
|
||||
{
|
||||
$number = ($count === 3)
|
||||
? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64)
|
||||
: (($temp[0] % 32) * 64) + ($temp[1] % 64);
|
||||
|
||||
$out .= '&#'.$number.';';
|
||||
$count = 1;
|
||||
$temp = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set error message
|
||||
*
|
||||
* @param string
|
||||
* @return void
|
||||
*/
|
||||
public function set_error($msg)
|
||||
{
|
||||
log_message('error', $msg);
|
||||
$this->error_msg[] = $msg;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Show error messages
|
||||
*
|
||||
* @param string
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function display_errors($open = '<p>', $close = '</p>')
|
||||
{
|
||||
return (count($this->error_msg) > 0) ? $open.implode($close.$open, $this->error_msg).$close : '';
|
||||
}
|
||||
|
||||
}
|
424
php/system/libraries/Typography.php
Normal file
424
php/system/libraries/Typography.php
Normal file
@ -0,0 +1,424 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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/user_guide/libraries/typography.html
|
||||
*/
|
||||
class CI_Typography {
|
||||
|
||||
/**
|
||||
* Block level elements that should not be wrapped inside <p> tags
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $block_elements = 'address|blockquote|div|dl|fieldset|form|h\d|hr|noscript|object|ol|p|pre|script|table|ul';
|
||||
|
||||
/**
|
||||
* Elements that should not have <p> and <br /> tags within them.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $skip_elements = 'p|pre|ol|ul|dl|object|table|h\d';
|
||||
|
||||
/**
|
||||
* Tags we want the parser to completely ignore when splitting the string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $inline_elements = 'a|abbr|acronym|b|bdo|big|br|button|cite|code|del|dfn|em|i|img|ins|input|label|map|kbd|q|samp|select|small|span|strong|sub|sup|textarea|tt|var';
|
||||
|
||||
/**
|
||||
* array of block level elements that require inner content to be within another block level element
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $inner_block_required = array('blockquote');
|
||||
|
||||
/**
|
||||
* the last block element parsed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $last_block_element = '';
|
||||
|
||||
/**
|
||||
* whether or not to protect quotes within { curly braces }
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $protect_braced_quotes = FALSE;
|
||||
|
||||
/**
|
||||
* Auto Typography
|
||||
*
|
||||
* This function converts text, making it typographically correct:
|
||||
* - Converts double spaces into paragraphs.
|
||||
* - Converts single line breaks into <br /> tags
|
||||
* - Converts single and double quotes into correctly facing curly quote entities.
|
||||
* - Converts three dots into ellipsis.
|
||||
* - Converts double dashes into em-dashes.
|
||||
* - Converts two spaces into entities
|
||||
*
|
||||
* @param string
|
||||
* @param bool whether to reduce more then two consecutive newlines to two
|
||||
* @return string
|
||||
*/
|
||||
public function auto_typography($str, $reduce_linebreaks = FALSE)
|
||||
{
|
||||
if ($str === '')
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
// Standardize Newlines to make matching easier
|
||||
if (strpos($str, "\r") !== FALSE)
|
||||
{
|
||||
$str = str_replace(array("\r\n", "\r"), "\n", $str);
|
||||
}
|
||||
|
||||
// Reduce line breaks. If there are more than two consecutive linebreaks
|
||||
// we'll compress them down to a maximum of two since there's no benefit to more.
|
||||
if ($reduce_linebreaks === TRUE)
|
||||
{
|
||||
$str = preg_replace("/\n\n+/", "\n\n", $str);
|
||||
}
|
||||
|
||||
// HTML comment tags don't conform to patterns of normal tags, so pull them out separately, only if needed
|
||||
$html_comments = array();
|
||||
if (strpos($str, '<!--') !== FALSE && preg_match_all('#(<!\-\-.*?\-\->)#s', $str, $matches))
|
||||
{
|
||||
for ($i = 0, $total = count($matches[0]); $i < $total; $i++)
|
||||
{
|
||||
$html_comments[] = $matches[0][$i];
|
||||
$str = str_replace($matches[0][$i], '{@HC'.$i.'}', $str);
|
||||
}
|
||||
}
|
||||
|
||||
// match and yank <pre> tags if they exist. It's cheaper to do this separately since most content will
|
||||
// not contain <pre> tags, and it keeps the PCRE patterns below simpler and faster
|
||||
if (strpos($str, '<pre') !== FALSE)
|
||||
{
|
||||
$str = preg_replace_callback('#<pre.*?>.*?</pre>#si', array($this, '_protect_characters'), $str);
|
||||
}
|
||||
|
||||
// Convert quotes within tags to temporary markers.
|
||||
$str = preg_replace_callback('#<.+?>#si', array($this, '_protect_characters'), $str);
|
||||
|
||||
// Do the same with braces if necessary
|
||||
if ($this->protect_braced_quotes === TRUE)
|
||||
{
|
||||
$str = preg_replace_callback('#\{.+?\}#si', array($this, '_protect_characters'), $str);
|
||||
}
|
||||
|
||||
// Convert "ignore" tags to temporary marker. The parser splits out the string at every tag
|
||||
// it encounters. Certain inline tags, like image tags, links, span tags, etc. will be
|
||||
// adversely affected if they are split out so we'll convert the opening bracket < temporarily to: {@TAG}
|
||||
$str = preg_replace('#<(/*)('.$this->inline_elements.')([ >])#i', '{@TAG}\\1\\2\\3', $str);
|
||||
|
||||
/* Split the string at every tag. This expression creates an array with this prototype:
|
||||
*
|
||||
* [array]
|
||||
* {
|
||||
* [0] = <opening tag>
|
||||
* [1] = Content...
|
||||
* [2] = <closing tag>
|
||||
* Etc...
|
||||
* }
|
||||
*/
|
||||
$chunks = preg_split('/(<(?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+>)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
// Build our finalized string. We cycle through the array, skipping tags, and processing the contained text
|
||||
$str = '';
|
||||
$process = TRUE;
|
||||
|
||||
for ($i = 0, $c = count($chunks) - 1; $i <= $c; $i++)
|
||||
{
|
||||
// Are we dealing with a tag? If so, we'll skip the processing for this cycle.
|
||||
// Well also set the "process" flag which allows us to skip <pre> tags and a few other things.
|
||||
if (preg_match('#<(/*)('.$this->block_elements.').*?>#', $chunks[$i], $match))
|
||||
{
|
||||
if (preg_match('#'.$this->skip_elements.'#', $match[2]))
|
||||
{
|
||||
$process = ($match[1] === '/');
|
||||
}
|
||||
|
||||
if ($match[1] === '')
|
||||
{
|
||||
$this->last_block_element = $match[2];
|
||||
}
|
||||
|
||||
$str .= $chunks[$i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($process === FALSE)
|
||||
{
|
||||
$str .= $chunks[$i];
|
||||
continue;
|
||||
}
|
||||
|
||||
// Force a newline to make sure end tags get processed by _format_newlines()
|
||||
if ($i === $c)
|
||||
{
|
||||
$chunks[$i] .= "\n";
|
||||
}
|
||||
|
||||
// Convert Newlines into <p> and <br /> tags
|
||||
$str .= $this->_format_newlines($chunks[$i]);
|
||||
}
|
||||
|
||||
// No opening block level tag? Add it if needed.
|
||||
if ( ! preg_match('/^\s*<(?:'.$this->block_elements.')/i', $str))
|
||||
{
|
||||
$str = preg_replace('/^(.*?)<('.$this->block_elements.')/i', '<p>$1</p><$2', $str);
|
||||
}
|
||||
|
||||
// Convert quotes, elipsis, em-dashes, non-breaking spaces, and ampersands
|
||||
$str = $this->format_characters($str);
|
||||
|
||||
// restore HTML comments
|
||||
for ($i = 0, $total = count($html_comments); $i < $total; $i++)
|
||||
{
|
||||
// remove surrounding paragraph tags, but only if there's an opening paragraph tag
|
||||
// otherwise HTML comments at the ends of paragraphs will have the closing tag removed
|
||||
// if '<p>{@HC1}' then replace <p>{@HC1}</p> with the comment, else replace only {@HC1} with the comment
|
||||
$str = preg_replace('#(?(?=<p>\{@HC'.$i.'\})<p>\{@HC'.$i.'\}(\s*</p>)|\{@HC'.$i.'\})#s', $html_comments[$i], $str);
|
||||
}
|
||||
|
||||
// Final clean up
|
||||
$table = array(
|
||||
|
||||
// If the user submitted their own paragraph tags within the text
|
||||
// we will retain them instead of using our tags.
|
||||
'/(<p[^>*?]>)<p>/' => '$1', // <?php BBEdit syntax coloring bug fix
|
||||
|
||||
// Reduce multiple instances of opening/closing paragraph tags to a single one
|
||||
'#(</p>)+#' => '</p>',
|
||||
'/(<p>\W*<p>)+/' => '<p>',
|
||||
|
||||
// Clean up stray paragraph tags that appear before block level elements
|
||||
'#<p></p><('.$this->block_elements.')#' => '<$1',
|
||||
|
||||
// Clean up stray non-breaking spaces preceding block elements
|
||||
'#( \s*)+<('.$this->block_elements.')#' => ' <$2',
|
||||
|
||||
// Replace the temporary markers we added earlier
|
||||
'/\{@TAG\}/' => '<',
|
||||
'/\{@DQ\}/' => '"',
|
||||
'/\{@SQ\}/' => "'",
|
||||
'/\{@DD\}/' => '--',
|
||||
'/\{@NBS\}/' => ' ',
|
||||
|
||||
// An unintended consequence of the _format_newlines function is that
|
||||
// some of the newlines get truncated, resulting in <p> tags
|
||||
// starting immediately after <block> tags on the same line.
|
||||
// This forces a newline after such occurrences, which looks much nicer.
|
||||
"/><p>\n/" => ">\n<p>",
|
||||
|
||||
// Similarly, there might be cases where a closing </block> will follow
|
||||
// a closing </p> tag, so we'll correct it by adding a newline in between
|
||||
'#</p></#' => "</p>\n</"
|
||||
);
|
||||
|
||||
// Do we need to reduce empty lines?
|
||||
if ($reduce_linebreaks === TRUE)
|
||||
{
|
||||
$table['#<p>\n*</p>#'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we have empty paragraph tags we add a non-breaking space
|
||||
// otherwise most browsers won't treat them as true paragraphs
|
||||
$table['#<p></p>#'] = '<p> </p>';
|
||||
}
|
||||
|
||||
return preg_replace(array_keys($table), $table, $str);
|
||||
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Format Characters
|
||||
*
|
||||
* This function mainly converts double and single quotes
|
||||
* to curly entities, but it also converts em-dashes,
|
||||
* double spaces, and ampersands
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function format_characters($str)
|
||||
{
|
||||
static $table;
|
||||
|
||||
if ( ! isset($table))
|
||||
{
|
||||
$table = array(
|
||||
// nested smart quotes, opening and closing
|
||||
// note that rules for grammar (English) allow only for two levels deep
|
||||
// and that single quotes are _supposed_ to always be on the outside
|
||||
// but we'll accommodate both
|
||||
// Note that in all cases, whitespace is the primary determining factor
|
||||
// on which direction to curl, with non-word characters like punctuation
|
||||
// being a secondary factor only after whitespace is addressed.
|
||||
'/\'"(\s|$)/' => '’”$1',
|
||||
'/(^|\s|<p>)\'"/' => '$1‘“',
|
||||
'/\'"(\W)/' => '’”$1',
|
||||
'/(\W)\'"/' => '$1‘“',
|
||||
'/"\'(\s|$)/' => '”’$1',
|
||||
'/(^|\s|<p>)"\'/' => '$1“‘',
|
||||
'/"\'(\W)/' => '”’$1',
|
||||
'/(\W)"\'/' => '$1“‘',
|
||||
|
||||
// single quote smart quotes
|
||||
'/\'(\s|$)/' => '’$1',
|
||||
'/(^|\s|<p>)\'/' => '$1‘',
|
||||
'/\'(\W)/' => '’$1',
|
||||
'/(\W)\'/' => '$1‘',
|
||||
|
||||
// double quote smart quotes
|
||||
'/"(\s|$)/' => '”$1',
|
||||
'/(^|\s|<p>)"/' => '$1“',
|
||||
'/"(\W)/' => '”$1',
|
||||
'/(\W)"/' => '$1“',
|
||||
|
||||
// apostrophes
|
||||
"/(\w)'(\w)/" => '$1’$2',
|
||||
|
||||
// Em dash and ellipses dots
|
||||
'/\s?\-\-\s?/' => '—',
|
||||
'/(\w)\.{3}/' => '$1…',
|
||||
|
||||
// double space after sentences
|
||||
'/(\W) /' => '$1 ',
|
||||
|
||||
// ampersands, if not a character entity
|
||||
'/&(?!#?[a-zA-Z0-9]{2,};)/' => '&'
|
||||
);
|
||||
}
|
||||
|
||||
return preg_replace(array_keys($table), $table, $str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Format Newlines
|
||||
*
|
||||
* Converts newline characters into either <p> tags or <br />
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
protected function _format_newlines($str)
|
||||
{
|
||||
if ($str === '' OR (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required)))
|
||||
{
|
||||
return $str;
|
||||
}
|
||||
|
||||
// Convert two consecutive newlines to paragraphs
|
||||
$str = str_replace("\n\n", "</p>\n\n<p>", $str);
|
||||
|
||||
// Convert single spaces to <br /> tags
|
||||
$str = preg_replace("/([^\n])(\n)([^\n])/", '\\1<br />\\2\\3', $str);
|
||||
|
||||
// Wrap the whole enchilada in enclosing paragraphs
|
||||
if ($str !== "\n")
|
||||
{
|
||||
// We trim off the right-side new line so that the closing </p> tag
|
||||
// will be positioned immediately following the string, matching
|
||||
// the behavior of the opening <p> tag
|
||||
$str = '<p>'.rtrim($str).'</p>';
|
||||
}
|
||||
|
||||
// Remove empty paragraphs if they are on the first line, as this
|
||||
// is a potential unintended consequence of the previous code
|
||||
return preg_replace('/<p><\/p>(.*)/', '\\1', $str, 1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Protect Characters
|
||||
*
|
||||
* Protects special characters from being formatted later
|
||||
* We don't want quotes converted within tags so we'll temporarily convert them to {@DQ} and {@SQ}
|
||||
* and we don't want double dashes converted to emdash entities, so they are marked with {@DD}
|
||||
* likewise double spaces are converted to {@NBS} to prevent entity conversion
|
||||
*
|
||||
* @param array
|
||||
* @return string
|
||||
*/
|
||||
protected function _protect_characters($match)
|
||||
{
|
||||
return str_replace(array("'",'"','--',' '), array('{@SQ}', '{@DQ}', '{@DD}', '{@NBS}'), $match[0]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Convert newlines to HTML line breaks except within PRE tags
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
public function nl2br_except_pre($str)
|
||||
{
|
||||
$newstr = '';
|
||||
for ($ex = explode('pre>', $str), $ct = count($ex), $i = 0; $i < $ct; $i++)
|
||||
{
|
||||
$newstr .= (($i % 2) === 0) ? nl2br($ex[$i]) : $ex[$i];
|
||||
if ($ct - 1 !== $i)
|
||||
{
|
||||
$newstr .= 'pre>';
|
||||
}
|
||||
}
|
||||
|
||||
return $newstr;
|
||||
}
|
||||
|
||||
}
|
406
php/system/libraries/Unit_test.php
Normal file
406
php/system/libraries/Unit_test.php
Normal file
@ -0,0 +1,406 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 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/user_guide/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);
|
||||
}
|
1326
php/system/libraries/Upload.php
Normal file
1326
php/system/libraries/Upload.php
Normal file
File diff suppressed because it is too large
Load Diff
681
php/system/libraries/User_agent.php
Normal file
681
php/system/libraries/User_agent.php
Normal file
@ -0,0 +1,681 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* User Agent Class
|
||||
*
|
||||
* Identifies the platform, browser, robot, or mobile device of the browsing agent
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category User Agent
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/user_agent.html
|
||||
*/
|
||||
class CI_User_agent {
|
||||
|
||||
/**
|
||||
* Current user-agent
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $agent = NULL;
|
||||
|
||||
/**
|
||||
* Flag for if the user-agent belongs to a browser
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $is_browser = FALSE;
|
||||
|
||||
/**
|
||||
* Flag for if the user-agent is a robot
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $is_robot = FALSE;
|
||||
|
||||
/**
|
||||
* Flag for if the user-agent is a mobile browser
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $is_mobile = FALSE;
|
||||
|
||||
/**
|
||||
* Languages accepted by the current user agent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $languages = array();
|
||||
|
||||
/**
|
||||
* Character sets accepted by the current user agent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $charsets = array();
|
||||
|
||||
/**
|
||||
* List of platforms to compare against current user agent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $platforms = array();
|
||||
|
||||
/**
|
||||
* List of browsers to compare against current user agent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $browsers = array();
|
||||
|
||||
/**
|
||||
* List of mobile browsers to compare against current user agent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $mobiles = array();
|
||||
|
||||
/**
|
||||
* List of robots to compare against current user agent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $robots = array();
|
||||
|
||||
/**
|
||||
* Current user-agent platform
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $platform = '';
|
||||
|
||||
/**
|
||||
* Current user-agent browser
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $browser = '';
|
||||
|
||||
/**
|
||||
* Current user-agent version
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $version = '';
|
||||
|
||||
/**
|
||||
* Current user-agent mobile name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mobile = '';
|
||||
|
||||
/**
|
||||
* Current user-agent robot name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $robot = '';
|
||||
|
||||
/**
|
||||
* HTTP Referer
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $referer;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Sets the User Agent and runs the compilation routine
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->_load_agent_file();
|
||||
|
||||
if (isset($_SERVER['HTTP_USER_AGENT']))
|
||||
{
|
||||
$this->agent = trim($_SERVER['HTTP_USER_AGENT']);
|
||||
$this->_compile_data();
|
||||
}
|
||||
|
||||
log_message('info', 'User Agent Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile the User Agent Data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _load_agent_file()
|
||||
{
|
||||
if (($found = file_exists(APPPATH.'config/user_agents.php')))
|
||||
{
|
||||
include(APPPATH.'config/user_agents.php');
|
||||
}
|
||||
|
||||
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php'))
|
||||
{
|
||||
include(APPPATH.'config/'.ENVIRONMENT.'/user_agents.php');
|
||||
$found = TRUE;
|
||||
}
|
||||
|
||||
if ($found !== TRUE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$return = FALSE;
|
||||
|
||||
if (isset($platforms))
|
||||
{
|
||||
$this->platforms = $platforms;
|
||||
unset($platforms);
|
||||
$return = TRUE;
|
||||
}
|
||||
|
||||
if (isset($browsers))
|
||||
{
|
||||
$this->browsers = $browsers;
|
||||
unset($browsers);
|
||||
$return = TRUE;
|
||||
}
|
||||
|
||||
if (isset($mobiles))
|
||||
{
|
||||
$this->mobiles = $mobiles;
|
||||
unset($mobiles);
|
||||
$return = TRUE;
|
||||
}
|
||||
|
||||
if (isset($robots))
|
||||
{
|
||||
$this->robots = $robots;
|
||||
unset($robots);
|
||||
$return = TRUE;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Compile the User Agent Data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _compile_data()
|
||||
{
|
||||
$this->_set_platform();
|
||||
|
||||
foreach (array('_set_robot', '_set_browser', '_set_mobile') as $function)
|
||||
{
|
||||
if ($this->$function() === TRUE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Platform
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set_platform()
|
||||
{
|
||||
if (is_array($this->platforms) && count($this->platforms) > 0)
|
||||
{
|
||||
foreach ($this->platforms as $key => $val)
|
||||
{
|
||||
if (preg_match('|'.preg_quote($key).'|i', $this->agent))
|
||||
{
|
||||
$this->platform = $val;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->platform = 'Unknown Platform';
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Browser
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set_browser()
|
||||
{
|
||||
if (is_array($this->browsers) && count($this->browsers) > 0)
|
||||
{
|
||||
foreach ($this->browsers as $key => $val)
|
||||
{
|
||||
if (preg_match('|'.$key.'.*?([0-9\.]+)|i', $this->agent, $match))
|
||||
{
|
||||
$this->is_browser = TRUE;
|
||||
$this->version = $match[1];
|
||||
$this->browser = $val;
|
||||
$this->_set_mobile();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Robot
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set_robot()
|
||||
{
|
||||
if (is_array($this->robots) && count($this->robots) > 0)
|
||||
{
|
||||
foreach ($this->robots as $key => $val)
|
||||
{
|
||||
if (preg_match('|'.preg_quote($key).'|i', $this->agent))
|
||||
{
|
||||
$this->is_robot = TRUE;
|
||||
$this->robot = $val;
|
||||
$this->_set_mobile();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the Mobile Device
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function _set_mobile()
|
||||
{
|
||||
if (is_array($this->mobiles) && count($this->mobiles) > 0)
|
||||
{
|
||||
foreach ($this->mobiles as $key => $val)
|
||||
{
|
||||
if (FALSE !== (stripos($this->agent, $key)))
|
||||
{
|
||||
$this->is_mobile = TRUE;
|
||||
$this->mobile = $val;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the accepted languages
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _set_languages()
|
||||
{
|
||||
if ((count($this->languages) === 0) && ! empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
|
||||
{
|
||||
$this->languages = explode(',', preg_replace('/(;\s?q=[0-9\.]+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE']))));
|
||||
}
|
||||
|
||||
if (count($this->languages) === 0)
|
||||
{
|
||||
$this->languages = array('Undefined');
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Set the accepted character sets
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _set_charsets()
|
||||
{
|
||||
if ((count($this->charsets) === 0) && ! empty($_SERVER['HTTP_ACCEPT_CHARSET']))
|
||||
{
|
||||
$this->charsets = explode(',', preg_replace('/(;\s?q=.+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET']))));
|
||||
}
|
||||
|
||||
if (count($this->charsets) === 0)
|
||||
{
|
||||
$this->charsets = array('Undefined');
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is Browser
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function is_browser($key = NULL)
|
||||
{
|
||||
if ( ! $this->is_browser)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// No need to be specific, it's a browser
|
||||
if ($key === NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check for a specific browser
|
||||
return (isset($this->browsers[$key]) && $this->browser === $this->browsers[$key]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is Robot
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function is_robot($key = NULL)
|
||||
{
|
||||
if ( ! $this->is_robot)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// No need to be specific, it's a robot
|
||||
if ($key === NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check for a specific robot
|
||||
return (isset($this->robots[$key]) && $this->robot === $this->robots[$key]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is Mobile
|
||||
*
|
||||
* @param string $key
|
||||
* @return bool
|
||||
*/
|
||||
public function is_mobile($key = NULL)
|
||||
{
|
||||
if ( ! $this->is_mobile)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// No need to be specific, it's a mobile
|
||||
if ($key === NULL)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Check for a specific robot
|
||||
return (isset($this->mobiles[$key]) && $this->mobile === $this->mobiles[$key]);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Is this a referral from another site?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_referral()
|
||||
{
|
||||
if ( ! isset($this->referer))
|
||||
{
|
||||
if (empty($_SERVER['HTTP_REFERER']))
|
||||
{
|
||||
$this->referer = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$referer_host = @parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
|
||||
$own_host = parse_url(config_item('base_url'), PHP_URL_HOST);
|
||||
|
||||
$this->referer = ($referer_host && $referer_host !== $own_host);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->referer;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Agent String
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function agent_string()
|
||||
{
|
||||
return $this->agent;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Platform
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function platform()
|
||||
{
|
||||
return $this->platform;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Browser Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function browser()
|
||||
{
|
||||
return $this->browser;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the Browser Version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function version()
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get The Robot Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function robot()
|
||||
{
|
||||
return $this->robot;
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the Mobile Device
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mobile()
|
||||
{
|
||||
return $this->mobile;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the referrer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function referrer()
|
||||
{
|
||||
return empty($_SERVER['HTTP_REFERER']) ? '' : trim($_SERVER['HTTP_REFERER']);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the accepted languages
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function languages()
|
||||
{
|
||||
if (count($this->languages) === 0)
|
||||
{
|
||||
$this->_set_languages();
|
||||
}
|
||||
|
||||
return $this->languages;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the accepted Character Sets
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function charsets()
|
||||
{
|
||||
if (count($this->charsets) === 0)
|
||||
{
|
||||
$this->_set_charsets();
|
||||
}
|
||||
|
||||
return $this->charsets;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Test for a particular language
|
||||
*
|
||||
* @param string $lang
|
||||
* @return bool
|
||||
*/
|
||||
public function accept_lang($lang = 'en')
|
||||
{
|
||||
return in_array(strtolower($lang), $this->languages(), TRUE);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Test for a particular character set
|
||||
*
|
||||
* @param string $charset
|
||||
* @return bool
|
||||
*/
|
||||
public function accept_charset($charset = 'utf-8')
|
||||
{
|
||||
return in_array(strtolower($charset), $this->charsets(), TRUE);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a custom user-agent string
|
||||
*
|
||||
* @param string $string
|
||||
* @return void
|
||||
*/
|
||||
public function parse($string)
|
||||
{
|
||||
// Reset values
|
||||
$this->is_browser = FALSE;
|
||||
$this->is_robot = FALSE;
|
||||
$this->is_mobile = FALSE;
|
||||
$this->browser = '';
|
||||
$this->version = '';
|
||||
$this->mobile = '';
|
||||
$this->robot = '';
|
||||
|
||||
// Set the new user-agent string and parse it, unless empty
|
||||
$this->agent = $string;
|
||||
|
||||
if ( ! empty($string))
|
||||
{
|
||||
$this->_compile_data();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1920
php/system/libraries/Xmlrpc.php
Normal file
1920
php/system/libraries/Xmlrpc.php
Normal file
File diff suppressed because it is too large
Load Diff
619
php/system/libraries/Xmlrpcs.php
Normal file
619
php/system/libraries/Xmlrpcs.php
Normal file
@ -0,0 +1,619 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
if ( ! function_exists('xml_parser_create'))
|
||||
{
|
||||
show_error('Your PHP installation does not support XML');
|
||||
}
|
||||
|
||||
if ( ! class_exists('CI_Xmlrpc', FALSE))
|
||||
{
|
||||
show_error('You must load the Xmlrpc class before loading the Xmlrpcs class in order to create a server.');
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* XML-RPC server class
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category XML-RPC
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/xmlrpc.html
|
||||
*/
|
||||
class CI_Xmlrpcs extends CI_Xmlrpc {
|
||||
|
||||
/**
|
||||
* Array of methods mapped to function names and signatures
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $methods = array();
|
||||
|
||||
/**
|
||||
* Debug Message
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $debug_msg = '';
|
||||
|
||||
/**
|
||||
* XML RPC Server methods
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $system_methods = array();
|
||||
|
||||
/**
|
||||
* Configuration object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public $object = FALSE;
|
||||
|
||||
/**
|
||||
* Initialize XMLRPC class
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
parent::__construct();
|
||||
$this->set_system_methods();
|
||||
|
||||
if (isset($config['functions']) && is_array($config['functions']))
|
||||
{
|
||||
$this->methods = array_merge($this->methods, $config['functions']);
|
||||
}
|
||||
|
||||
log_message('info', 'XML-RPC Server Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize Prefs and Serve
|
||||
*
|
||||
* @param mixed
|
||||
* @return void
|
||||
*/
|
||||
public function initialize($config = array())
|
||||
{
|
||||
if (isset($config['functions']) && is_array($config['functions']))
|
||||
{
|
||||
$this->methods = array_merge($this->methods, $config['functions']);
|
||||
}
|
||||
|
||||
if (isset($config['debug']))
|
||||
{
|
||||
$this->debug = $config['debug'];
|
||||
}
|
||||
|
||||
if (isset($config['object']) && is_object($config['object']))
|
||||
{
|
||||
$this->object = $config['object'];
|
||||
}
|
||||
|
||||
if (isset($config['xss_clean']))
|
||||
{
|
||||
$this->xss_clean = $config['xss_clean'];
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Setting of System Methods
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_system_methods()
|
||||
{
|
||||
$this->methods = array(
|
||||
'system.listMethods' => array(
|
||||
'function' => 'this.listMethods',
|
||||
'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString), array($this->xmlrpcArray)),
|
||||
'docstring' => 'Returns an array of available methods on this server'),
|
||||
'system.methodHelp' => array(
|
||||
'function' => 'this.methodHelp',
|
||||
'signature' => array(array($this->xmlrpcString, $this->xmlrpcString)),
|
||||
'docstring' => 'Returns a documentation string for the specified method'),
|
||||
'system.methodSignature' => array(
|
||||
'function' => 'this.methodSignature',
|
||||
'signature' => array(array($this->xmlrpcArray, $this->xmlrpcString)),
|
||||
'docstring' => 'Returns an array describing the return type and required parameters of a method'),
|
||||
'system.multicall' => array(
|
||||
'function' => 'this.multicall',
|
||||
'signature' => array(array($this->xmlrpcArray, $this->xmlrpcArray)),
|
||||
'docstring' => 'Combine multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details')
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Main Server Function
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function serve()
|
||||
{
|
||||
$r = $this->parseRequest();
|
||||
$payload = '<?xml version="1.0" encoding="'.$this->xmlrpc_defencoding.'"?'.'>'."\n".$this->debug_msg.$r->prepare_response();
|
||||
|
||||
header('Content-Type: text/xml');
|
||||
header('Content-Length: '.strlen($payload));
|
||||
exit($payload);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add Method to Class
|
||||
*
|
||||
* @param string method name
|
||||
* @param string function
|
||||
* @param string signature
|
||||
* @param string docstring
|
||||
* @return void
|
||||
*/
|
||||
public function add_to_map($methodname, $function, $sig, $doc)
|
||||
{
|
||||
$this->methods[$methodname] = array(
|
||||
'function' => $function,
|
||||
'signature' => $sig,
|
||||
'docstring' => $doc
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse Server Request
|
||||
*
|
||||
* @param string data
|
||||
* @return object xmlrpc response
|
||||
*/
|
||||
public function parseRequest($data = '')
|
||||
{
|
||||
//-------------------------------------
|
||||
// Get Data
|
||||
//-------------------------------------
|
||||
|
||||
if ($data === '')
|
||||
{
|
||||
$CI =& get_instance();
|
||||
if ($CI->input->method() === 'post')
|
||||
{
|
||||
$data = $CI->input->raw_input_stream;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
// Set up XML Parser
|
||||
//-------------------------------------
|
||||
|
||||
$parser = xml_parser_create($this->xmlrpc_defencoding);
|
||||
$parser_object = new XML_RPC_Message('filler');
|
||||
$pname = (string) $parser;
|
||||
|
||||
$parser_object->xh[$pname] = array(
|
||||
'isf' => 0,
|
||||
'isf_reason' => '',
|
||||
'params' => array(),
|
||||
'stack' => array(),
|
||||
'valuestack' => array(),
|
||||
'method' => ''
|
||||
);
|
||||
|
||||
xml_set_object($parser, $parser_object);
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE);
|
||||
xml_set_element_handler($parser, 'open_tag', 'closing_tag');
|
||||
xml_set_character_data_handler($parser, 'character_data');
|
||||
//xml_set_default_handler($parser, 'default_handler');
|
||||
|
||||
//-------------------------------------
|
||||
// PARSE + PROCESS XML DATA
|
||||
//-------------------------------------
|
||||
|
||||
if ( ! xml_parse($parser, $data, 1))
|
||||
{
|
||||
// Return XML error as a faultCode
|
||||
$r = new XML_RPC_Response(0,
|
||||
$this->xmlrpcerrxml + xml_get_error_code($parser),
|
||||
sprintf('XML error: %s at line %d',
|
||||
xml_error_string(xml_get_error_code($parser)),
|
||||
xml_get_current_line_number($parser)));
|
||||
xml_parser_free($parser);
|
||||
}
|
||||
elseif ($parser_object->xh[$pname]['isf'])
|
||||
{
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']);
|
||||
}
|
||||
else
|
||||
{
|
||||
xml_parser_free($parser);
|
||||
|
||||
$m = new XML_RPC_Message($parser_object->xh[$pname]['method']);
|
||||
$plist = '';
|
||||
|
||||
for ($i = 0, $c = count($parser_object->xh[$pname]['params']); $i < $c; $i++)
|
||||
{
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$plist .= $i.' - '.print_r(get_object_vars($parser_object->xh[$pname]['params'][$i]), TRUE).";\n";
|
||||
}
|
||||
|
||||
$m->addParam($parser_object->xh[$pname]['params'][$i]);
|
||||
}
|
||||
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
echo "<pre>---PLIST---\n".$plist."\n---PLIST END---\n\n</pre>";
|
||||
}
|
||||
|
||||
$r = $this->_execute($m);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
// SET DEBUGGING MESSAGE
|
||||
//-------------------------------------
|
||||
|
||||
if ($this->debug === TRUE)
|
||||
{
|
||||
$this->debug_msg = "<!-- DEBUG INFO:\n\n".$plist."\n END DEBUG-->\n";
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Executes the Method
|
||||
*
|
||||
* @param object
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _execute($m)
|
||||
{
|
||||
$methName = $m->method_name;
|
||||
|
||||
// Check to see if it is a system call
|
||||
$system_call = (strpos($methName, 'system') === 0);
|
||||
|
||||
if ($this->xss_clean === FALSE)
|
||||
{
|
||||
$m->xss_clean = FALSE;
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
// Valid Method
|
||||
//-------------------------------------
|
||||
|
||||
if ( ! isset($this->methods[$methName]['function']))
|
||||
{
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
// Check for Method (and Object)
|
||||
//-------------------------------------
|
||||
|
||||
$method_parts = explode('.', $this->methods[$methName]['function']);
|
||||
$objectCall = ! empty($method_parts[1]);
|
||||
|
||||
if ($system_call === TRUE)
|
||||
{
|
||||
if ( ! is_callable(array($this, $method_parts[1])))
|
||||
{
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
|
||||
}
|
||||
}
|
||||
elseif (($objectCall && ! is_callable(array($method_parts[0], $method_parts[1])))
|
||||
OR ( ! $objectCall && ! is_callable($this->methods[$methName]['function']))
|
||||
)
|
||||
{
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
// Checking Methods Signature
|
||||
//-------------------------------------
|
||||
|
||||
if (isset($this->methods[$methName]['signature']))
|
||||
{
|
||||
$sig = $this->methods[$methName]['signature'];
|
||||
for ($i = 0, $c = count($sig); $i < $c; $i++)
|
||||
{
|
||||
$current_sig = $sig[$i];
|
||||
|
||||
if (count($current_sig) === count($m->params)+1)
|
||||
{
|
||||
for ($n = 0, $mc = count($m->params); $n < $mc; $n++)
|
||||
{
|
||||
$p = $m->params[$n];
|
||||
$pt = ($p->kindOf() === 'scalar') ? $p->scalarval() : $p->kindOf();
|
||||
|
||||
if ($pt !== $current_sig[$n+1])
|
||||
{
|
||||
$pno = $n+1;
|
||||
$wanted = $current_sig[$n+1];
|
||||
|
||||
return new XML_RPC_Response(0,
|
||||
$this->xmlrpcerr['incorrect_params'],
|
||||
$this->xmlrpcstr['incorrect_params'] .
|
||||
': Wanted '.$wanted.', got '.$pt.' at param '.$pno.')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
// Calls the Function
|
||||
//-------------------------------------
|
||||
|
||||
if ($objectCall === TRUE)
|
||||
{
|
||||
if ($method_parts[0] === 'this' && $system_call === TRUE)
|
||||
{
|
||||
return call_user_func(array($this, $method_parts[1]), $m);
|
||||
}
|
||||
elseif ($this->object === FALSE)
|
||||
{
|
||||
return get_instance()->{$method_parts[1]}($m);
|
||||
}
|
||||
|
||||
return $this->object->{$method_parts[1]}($m);
|
||||
}
|
||||
|
||||
return call_user_func($this->methods[$methName]['function'], $m);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Server Function: List Methods
|
||||
*
|
||||
* @param mixed
|
||||
* @return object
|
||||
*/
|
||||
public function listMethods($m)
|
||||
{
|
||||
$v = new XML_RPC_Values();
|
||||
$output = array();
|
||||
|
||||
foreach ($this->methods as $key => $value)
|
||||
{
|
||||
$output[] = new XML_RPC_Values($key, 'string');
|
||||
}
|
||||
|
||||
foreach ($this->system_methods as $key => $value)
|
||||
{
|
||||
$output[] = new XML_RPC_Values($key, 'string');
|
||||
}
|
||||
|
||||
$v->addArray($output);
|
||||
return new XML_RPC_Response($v);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Server Function: Return Signature for Method
|
||||
*
|
||||
* @param mixed
|
||||
* @return object
|
||||
*/
|
||||
public function methodSignature($m)
|
||||
{
|
||||
$parameters = $m->output_parameters();
|
||||
$method_name = $parameters[0];
|
||||
|
||||
if (isset($this->methods[$method_name]))
|
||||
{
|
||||
if ($this->methods[$method_name]['signature'])
|
||||
{
|
||||
$sigs = array();
|
||||
$signature = $this->methods[$method_name]['signature'];
|
||||
|
||||
for ($i = 0, $c = count($signature); $i < $c; $i++)
|
||||
{
|
||||
$cursig = array();
|
||||
$inSig = $signature[$i];
|
||||
for ($j = 0, $jc = count($inSig); $j < $jc; $j++)
|
||||
{
|
||||
$cursig[]= new XML_RPC_Values($inSig[$j], 'string');
|
||||
}
|
||||
$sigs[] = new XML_RPC_Values($cursig, 'array');
|
||||
}
|
||||
|
||||
return new XML_RPC_Response(new XML_RPC_Values($sigs, 'array'));
|
||||
}
|
||||
|
||||
return new XML_RPC_Response(new XML_RPC_Values('undef', 'string'));
|
||||
}
|
||||
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Server Function: Doc String for Method
|
||||
*
|
||||
* @param mixed
|
||||
* @return object
|
||||
*/
|
||||
public function methodHelp($m)
|
||||
{
|
||||
$parameters = $m->output_parameters();
|
||||
$method_name = $parameters[0];
|
||||
|
||||
if (isset($this->methods[$method_name]))
|
||||
{
|
||||
$docstring = isset($this->methods[$method_name]['docstring']) ? $this->methods[$method_name]['docstring'] : '';
|
||||
|
||||
return new XML_RPC_Response(new XML_RPC_Values($docstring, 'string'));
|
||||
}
|
||||
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Server Function: Multi-call
|
||||
*
|
||||
* @param mixed
|
||||
* @return object
|
||||
*/
|
||||
public function multicall($m)
|
||||
{
|
||||
// Disabled
|
||||
return new XML_RPC_Response(0, $this->xmlrpcerr['unknown_method'], $this->xmlrpcstr['unknown_method']);
|
||||
|
||||
$parameters = $m->output_parameters();
|
||||
$calls = $parameters[0];
|
||||
|
||||
$result = array();
|
||||
|
||||
foreach ($calls as $value)
|
||||
{
|
||||
$m = new XML_RPC_Message($value[0]);
|
||||
$plist = '';
|
||||
|
||||
for ($i = 0, $c = count($value[1]); $i < $c; $i++)
|
||||
{
|
||||
$m->addParam(new XML_RPC_Values($value[1][$i], 'string'));
|
||||
}
|
||||
|
||||
$attempt = $this->_execute($m);
|
||||
|
||||
if ($attempt->faultCode() !== 0)
|
||||
{
|
||||
return $attempt;
|
||||
}
|
||||
|
||||
$result[] = new XML_RPC_Values(array($attempt->value()), 'array');
|
||||
}
|
||||
|
||||
return new XML_RPC_Response(new XML_RPC_Values($result, 'array'));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Multi-call Function: Error Handling
|
||||
*
|
||||
* @param mixed
|
||||
* @return object
|
||||
*/
|
||||
public function multicall_error($err)
|
||||
{
|
||||
$str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString();
|
||||
$code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode();
|
||||
|
||||
$struct['faultCode'] = new XML_RPC_Values($code, 'int');
|
||||
$struct['faultString'] = new XML_RPC_Values($str, 'string');
|
||||
|
||||
return new XML_RPC_Values($struct, 'struct');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Multi-call Function: Processes method
|
||||
*
|
||||
* @param mixed
|
||||
* @return object
|
||||
*/
|
||||
public function do_multicall($call)
|
||||
{
|
||||
if ($call->kindOf() !== 'struct')
|
||||
{
|
||||
return $this->multicall_error('notstruct');
|
||||
}
|
||||
elseif ( ! $methName = $call->me['struct']['methodName'])
|
||||
{
|
||||
return $this->multicall_error('nomethod');
|
||||
}
|
||||
|
||||
list($scalar_value, $scalar_type) = array(reset($methName->me), key($methName->me));
|
||||
$scalar_type = $scalar_type === $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type;
|
||||
|
||||
if ($methName->kindOf() !== 'scalar' OR $scalar_type !== 'string')
|
||||
{
|
||||
return $this->multicall_error('notstring');
|
||||
}
|
||||
elseif ($scalar_value === 'system.multicall')
|
||||
{
|
||||
return $this->multicall_error('recursion');
|
||||
}
|
||||
elseif ( ! $params = $call->me['struct']['params'])
|
||||
{
|
||||
return $this->multicall_error('noparams');
|
||||
}
|
||||
elseif ($params->kindOf() !== 'array')
|
||||
{
|
||||
return $this->multicall_error('notarray');
|
||||
}
|
||||
|
||||
list($b, $a) = array(reset($params->me), key($params->me));
|
||||
|
||||
$msg = new XML_RPC_Message($scalar_value);
|
||||
for ($i = 0, $numParams = count($b); $i < $numParams; $i++)
|
||||
{
|
||||
$msg->params[] = $params->me['array'][$i];
|
||||
}
|
||||
|
||||
$result = $this->_execute($msg);
|
||||
|
||||
if ($result->faultCode() !== 0)
|
||||
{
|
||||
return $this->multicall_error($result);
|
||||
}
|
||||
|
||||
return new XML_RPC_Values(array($result->value()), 'array');
|
||||
}
|
||||
|
||||
}
|
532
php/system/libraries/Zip.php
Normal file
532
php/system/libraries/Zip.php
Normal file
@ -0,0 +1,532 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 - 2018, British Columbia Institute of Technology
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author EllisLab Dev Team
|
||||
* @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
|
||||
* @copyright Copyright (c) 2014 - 2018, British Columbia Institute of Technology (http://bcit.ca/)
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 1.0.0
|
||||
* @filesource
|
||||
*/
|
||||
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* Zip Compression Class
|
||||
*
|
||||
* This class is based on a library I found at Zend:
|
||||
* http://www.zend.com/codex.php?id=696&single=1
|
||||
*
|
||||
* The original library is a little rough around the edges so I
|
||||
* refactored it and added several additional methods -- Rick Ellis
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @subpackage Libraries
|
||||
* @category Encryption
|
||||
* @author EllisLab Dev Team
|
||||
* @link https://codeigniter.com/user_guide/libraries/zip.html
|
||||
*/
|
||||
class CI_Zip {
|
||||
|
||||
/**
|
||||
* Zip data in string form
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $zipdata = '';
|
||||
|
||||
/**
|
||||
* Zip data for a directory in string form
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $directory = '';
|
||||
|
||||
/**
|
||||
* Number of files/folder in zip file
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $entries = 0;
|
||||
|
||||
/**
|
||||
* Number of files in zip
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $file_num = 0;
|
||||
|
||||
/**
|
||||
* relative offset of local header
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $offset = 0;
|
||||
|
||||
/**
|
||||
* Reference to time at init
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $now;
|
||||
|
||||
/**
|
||||
* The level of compression
|
||||
*
|
||||
* Ranges from 0 to 9, with 9 being the highest level.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $compression_level = 2;
|
||||
|
||||
/**
|
||||
* mbstring.func_overload flag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $func_overload;
|
||||
|
||||
/**
|
||||
* Initialize zip compression class
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
|
||||
|
||||
$this->now = time();
|
||||
log_message('info', 'Zip Compression Class Initialized');
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add Directory
|
||||
*
|
||||
* Lets you add a virtual directory into which you can place files.
|
||||
*
|
||||
* @param mixed $directory the directory name. Can be string or array
|
||||
* @return void
|
||||
*/
|
||||
public function add_dir($directory)
|
||||
{
|
||||
foreach ((array) $directory as $dir)
|
||||
{
|
||||
if ( ! preg_match('|.+/$|', $dir))
|
||||
{
|
||||
$dir .= '/';
|
||||
}
|
||||
|
||||
$dir_time = $this->_get_mod_time($dir);
|
||||
$this->_add_dir($dir, $dir_time['file_mtime'], $dir_time['file_mdate']);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get file/directory modification time
|
||||
*
|
||||
* If this is a newly created file/dir, we will set the time to 'now'
|
||||
*
|
||||
* @param string $dir path to file
|
||||
* @return array filemtime/filemdate
|
||||
*/
|
||||
protected function _get_mod_time($dir)
|
||||
{
|
||||
// filemtime() may return false, but raises an error for non-existing files
|
||||
$date = file_exists($dir) ? getdate(filemtime($dir)) : getdate($this->now);
|
||||
|
||||
return array(
|
||||
'file_mtime' => ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2,
|
||||
'file_mdate' => (($date['year'] - 1980) << 9) + ($date['mon'] << 5) + $date['mday']
|
||||
);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add Directory
|
||||
*
|
||||
* @param string $dir the directory name
|
||||
* @param int $file_mtime
|
||||
* @param int $file_mdate
|
||||
* @return void
|
||||
*/
|
||||
protected function _add_dir($dir, $file_mtime, $file_mdate)
|
||||
{
|
||||
$dir = str_replace('\\', '/', $dir);
|
||||
|
||||
$this->zipdata .=
|
||||
"\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00"
|
||||
.pack('v', $file_mtime)
|
||||
.pack('v', $file_mdate)
|
||||
.pack('V', 0) // crc32
|
||||
.pack('V', 0) // compressed filesize
|
||||
.pack('V', 0) // uncompressed filesize
|
||||
.pack('v', self::strlen($dir)) // length of pathname
|
||||
.pack('v', 0) // extra field length
|
||||
.$dir
|
||||
// below is "data descriptor" segment
|
||||
.pack('V', 0) // crc32
|
||||
.pack('V', 0) // compressed filesize
|
||||
.pack('V', 0); // uncompressed filesize
|
||||
|
||||
$this->directory .=
|
||||
"\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00"
|
||||
.pack('v', $file_mtime)
|
||||
.pack('v', $file_mdate)
|
||||
.pack('V',0) // crc32
|
||||
.pack('V',0) // compressed filesize
|
||||
.pack('V',0) // uncompressed filesize
|
||||
.pack('v', self::strlen($dir)) // length of pathname
|
||||
.pack('v', 0) // extra field length
|
||||
.pack('v', 0) // file comment length
|
||||
.pack('v', 0) // disk number start
|
||||
.pack('v', 0) // internal file attributes
|
||||
.pack('V', 16) // external file attributes - 'directory' bit set
|
||||
.pack('V', $this->offset) // relative offset of local header
|
||||
.$dir;
|
||||
|
||||
$this->offset = self::strlen($this->zipdata);
|
||||
$this->entries++;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add Data to Zip
|
||||
*
|
||||
* Lets you add files to the archive. If the path is included
|
||||
* in the filename it will be placed within a directory. Make
|
||||
* sure you use add_dir() first to create the folder.
|
||||
*
|
||||
* @param mixed $filepath A single filepath or an array of file => data pairs
|
||||
* @param string $data Single file contents
|
||||
* @return void
|
||||
*/
|
||||
public function add_data($filepath, $data = NULL)
|
||||
{
|
||||
if (is_array($filepath))
|
||||
{
|
||||
foreach ($filepath as $path => $data)
|
||||
{
|
||||
$file_data = $this->_get_mod_time($path);
|
||||
$this->_add_data($path, $data, $file_data['file_mtime'], $file_data['file_mdate']);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$file_data = $this->_get_mod_time($filepath);
|
||||
$this->_add_data($filepath, $data, $file_data['file_mtime'], $file_data['file_mdate']);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add Data to Zip
|
||||
*
|
||||
* @param string $filepath the file name/path
|
||||
* @param string $data the data to be encoded
|
||||
* @param int $file_mtime
|
||||
* @param int $file_mdate
|
||||
* @return void
|
||||
*/
|
||||
protected function _add_data($filepath, $data, $file_mtime, $file_mdate)
|
||||
{
|
||||
$filepath = str_replace('\\', '/', $filepath);
|
||||
|
||||
$uncompressed_size = self::strlen($data);
|
||||
$crc32 = crc32($data);
|
||||
$gzdata = self::substr(gzcompress($data, $this->compression_level), 2, -4);
|
||||
$compressed_size = self::strlen($gzdata);
|
||||
|
||||
$this->zipdata .=
|
||||
"\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00"
|
||||
.pack('v', $file_mtime)
|
||||
.pack('v', $file_mdate)
|
||||
.pack('V', $crc32)
|
||||
.pack('V', $compressed_size)
|
||||
.pack('V', $uncompressed_size)
|
||||
.pack('v', self::strlen($filepath)) // length of filename
|
||||
.pack('v', 0) // extra field length
|
||||
.$filepath
|
||||
.$gzdata; // "file data" segment
|
||||
|
||||
$this->directory .=
|
||||
"\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00"
|
||||
.pack('v', $file_mtime)
|
||||
.pack('v', $file_mdate)
|
||||
.pack('V', $crc32)
|
||||
.pack('V', $compressed_size)
|
||||
.pack('V', $uncompressed_size)
|
||||
.pack('v', self::strlen($filepath)) // length of filename
|
||||
.pack('v', 0) // extra field length
|
||||
.pack('v', 0) // file comment length
|
||||
.pack('v', 0) // disk number start
|
||||
.pack('v', 0) // internal file attributes
|
||||
.pack('V', 32) // external file attributes - 'archive' bit set
|
||||
.pack('V', $this->offset) // relative offset of local header
|
||||
.$filepath;
|
||||
|
||||
$this->offset = self::strlen($this->zipdata);
|
||||
$this->entries++;
|
||||
$this->file_num++;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Read the contents of a file and add it to the zip
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $archive_filepath
|
||||
* @return bool
|
||||
*/
|
||||
public function read_file($path, $archive_filepath = FALSE)
|
||||
{
|
||||
if (file_exists($path) && FALSE !== ($data = file_get_contents($path)))
|
||||
{
|
||||
if (is_string($archive_filepath))
|
||||
{
|
||||
$name = str_replace('\\', '/', $archive_filepath);
|
||||
}
|
||||
else
|
||||
{
|
||||
$name = str_replace('\\', '/', $path);
|
||||
|
||||
if ($archive_filepath === FALSE)
|
||||
{
|
||||
$name = preg_replace('|.*/(.+)|', '\\1', $name);
|
||||
}
|
||||
}
|
||||
|
||||
$this->add_data($name, $data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Read a directory and add it to the zip.
|
||||
*
|
||||
* This function recursively reads a folder and everything it contains (including
|
||||
* sub-folders) and creates a zip based on it. Whatever directory structure
|
||||
* is in the original file path will be recreated in the zip file.
|
||||
*
|
||||
* @param string $path path to source directory
|
||||
* @param bool $preserve_filepath
|
||||
* @param string $root_path
|
||||
* @return bool
|
||||
*/
|
||||
public function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL)
|
||||
{
|
||||
$path = rtrim($path, '/\\').DIRECTORY_SEPARATOR;
|
||||
if ( ! $fp = @opendir($path))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Set the original directory root for child dir's to use as relative
|
||||
if ($root_path === NULL)
|
||||
{
|
||||
$root_path = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, dirname($path)).DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
while (FALSE !== ($file = readdir($fp)))
|
||||
{
|
||||
if ($file[0] === '.')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_dir($path.$file))
|
||||
{
|
||||
$this->read_dir($path.$file.DIRECTORY_SEPARATOR, $preserve_filepath, $root_path);
|
||||
}
|
||||
elseif (FALSE !== ($data = file_get_contents($path.$file)))
|
||||
{
|
||||
$name = str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $path);
|
||||
if ($preserve_filepath === FALSE)
|
||||
{
|
||||
$name = str_replace($root_path, '', $name);
|
||||
}
|
||||
|
||||
$this->add_data($name.$file, $data);
|
||||
}
|
||||
}
|
||||
|
||||
closedir($fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the Zip file
|
||||
*
|
||||
* @return string (binary encoded)
|
||||
*/
|
||||
public function get_zip()
|
||||
{
|
||||
// Is there any data to return?
|
||||
if ($this->entries === 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return $this->zipdata
|
||||
.$this->directory."\x50\x4b\x05\x06\x00\x00\x00\x00"
|
||||
.pack('v', $this->entries) // total # of entries "on this disk"
|
||||
.pack('v', $this->entries) // total # of entries overall
|
||||
.pack('V', self::strlen($this->directory)) // size of central dir
|
||||
.pack('V', self::strlen($this->zipdata)) // offset to start of central dir
|
||||
."\x00\x00"; // .zip file comment length
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Write File to the specified directory
|
||||
*
|
||||
* Lets you write a file
|
||||
*
|
||||
* @param string $filepath the file name
|
||||
* @return bool
|
||||
*/
|
||||
public function archive($filepath)
|
||||
{
|
||||
if ( ! ($fp = @fopen($filepath, 'w+b')))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
flock($fp, LOCK_EX);
|
||||
|
||||
for ($result = $written = 0, $data = $this->get_zip(), $length = self::strlen($data); $written < $length; $written += $result)
|
||||
{
|
||||
if (($result = fwrite($fp, self::substr($data, $written))) === FALSE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
flock($fp, LOCK_UN);
|
||||
fclose($fp);
|
||||
|
||||
return is_int($result);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Download
|
||||
*
|
||||
* @param string $filename the file name
|
||||
* @return void
|
||||
*/
|
||||
public function download($filename = 'backup.zip')
|
||||
{
|
||||
if ( ! preg_match('|.+?\.zip$|', $filename))
|
||||
{
|
||||
$filename .= '.zip';
|
||||
}
|
||||
|
||||
get_instance()->load->helper('download');
|
||||
$get_zip = $this->get_zip();
|
||||
$zip_content =& $get_zip;
|
||||
|
||||
force_download($filename, $zip_content);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Initialize Data
|
||||
*
|
||||
* Lets you clear current zip data. Useful if you need to create
|
||||
* multiple zips with different data.
|
||||
*
|
||||
* @return CI_Zip
|
||||
*/
|
||||
public function clear_data()
|
||||
{
|
||||
$this->zipdata = '';
|
||||
$this->directory = '';
|
||||
$this->entries = 0;
|
||||
$this->file_num = 0;
|
||||
$this->offset = 0;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe strlen()
|
||||
*
|
||||
* @param string $str
|
||||
* @return int
|
||||
*/
|
||||
protected static function strlen($str)
|
||||
{
|
||||
return (self::$func_overload)
|
||||
? mb_strlen($str, '8bit')
|
||||
: strlen($str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Byte-safe substr()
|
||||
*
|
||||
* @param string $str
|
||||
* @param int $start
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
protected static function substr($str, $start, $length = NULL)
|
||||
{
|
||||
if (self::$func_overload)
|
||||
{
|
||||
// mb_substr($str, $start, null, '8bit') returns an empty
|
||||
// string on PHP 5.3
|
||||
isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
|
||||
return mb_substr($str, $start, $length, '8bit');
|
||||
}
|
||||
|
||||
return isset($length)
|
||||
? substr($str, $start, $length)
|
||||
: substr($str, $start);
|
||||
}
|
||||
}
|
11
php/system/libraries/index.html
Normal file
11
php/system/libraries/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<p>Directory access is forbidden.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user