Moved to PHP folder

This commit is contained in:
2019-06-30 22:04:19 -04:00
parent 6822968785
commit b198cd212f
433 changed files with 0 additions and 0 deletions

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

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

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

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

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

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

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

View File

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

View File

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

View 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).'&nbsp;'.$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}">&lt;&lt;</a></th>',
'heading_title_cell' => '<th colspan="{colspan}">{heading}</th>',
'heading_next_cell' => '<th><a href="{next_url}">&gt;&gt;</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' => '&nbsp;',
'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;
}
}

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

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

File diff suppressed because it is too large Load Diff

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

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,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;
}
}

View 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 = '&lsaquo; First';
/**
* Next link
*
* @var string
*/
protected $next_link = '&gt;';
/**
* Previous link
*
* @var string
*/
protected $prev_link = '&lt;';
/**
* Last link
*
* @var string
*/
protected $last_link = 'Last &rsaquo;';
/**
* 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) ? '?' : '&amp;';
// 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 '';
}
}

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

View 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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_benchmarks')."&nbsp;&nbsp;</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.'&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries').'&nbsp;&nbsp;</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&nbsp;JOIN', 'ORDER&nbsp;BY', 'GROUP&nbsp;BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR&nbsp;', 'HAVING', 'OFFSET', 'NOT&nbsp;IN', 'IN', 'LIKE', 'NOT&nbsp;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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_database')
.':&nbsp; '.$db->database.' ('.$name.')&nbsp;&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries')
.': '.count($db->queries).' ('.$total_time.')&nbsp;&nbsp;'.$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.'&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_get_data')."&nbsp;&nbsp;</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;">&#36;_GET['
.$key.']&nbsp;&nbsp; </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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_post_data')."&nbsp;&nbsp;</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;">&#36;_POST['
.$key.']&nbsp;&nbsp; </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;">&#36;_FILES['
.$key.']&nbsp;&nbsp; </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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_uri_string')."&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_controller_info')."&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_memory_usage')."&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_headers')
.'&nbsp;&nbsp;(<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.'&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_config').'&nbsp;&nbsp;(<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.'&nbsp;&nbsp;</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;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_session_data').'&nbsp;&nbsp;(<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.'&nbsp;&nbsp;</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>';
}
}

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

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

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

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

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

View File

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

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

View File

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

View File

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

View 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[] = '&nbsp;';
}
}
$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>'
);
}
}

View 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('&#45;', '-', $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('&amp;', '&lt;', '&gt;', '&quot;', '&#39;', '&#45;'),
$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 = '&#8230;')
{
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 : '';
}
}

View 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
'#(&nbsp;\s*)+<('.$this->block_elements.')#' => ' <$2',
// Replace the temporary markers we added earlier
'/\{@TAG\}/' => '<',
'/\{@DQ\}/' => '"',
'/\{@SQ\}/' => "'",
'/\{@DD\}/' => '--',
'/\{@NBS\}/' => ' ',
// An unintended consequence of the _format_newlines function is that
// some of the newlines get truncated, resulting in <p> tags
// starting immediately after <block> tags on the same line.
// This forces a newline after such occurrences, which looks much nicer.
"/><p>\n/" => ">\n<p>",
// Similarly, there might be cases where a closing </block> will follow
// a closing </p> tag, so we'll correct it by adding a newline in between
'#</p></#' => "</p>\n</"
);
// Do we need to reduce empty lines?
if ($reduce_linebreaks === TRUE)
{
$table['#<p>\n*</p>#'] = '';
}
else
{
// If we have empty paragraph tags we add a non-breaking space
// otherwise most browsers won't treat them as true paragraphs
$table['#<p></p>#'] = '<p>&nbsp;</p>';
}
return preg_replace(array_keys($table), $table, $str);
}
// --------------------------------------------------------------------
/**
* Format Characters
*
* This function mainly converts double and single quotes
* to curly entities, but it also converts em-dashes,
* double spaces, and ampersands
*
* @param string
* @return string
*/
public function format_characters($str)
{
static $table;
if ( ! isset($table))
{
$table = array(
// nested smart quotes, opening and closing
// note that rules for grammar (English) allow only for two levels deep
// and that single quotes are _supposed_ to always be on the outside
// but we'll accommodate both
// Note that in all cases, whitespace is the primary determining factor
// on which direction to curl, with non-word characters like punctuation
// being a secondary factor only after whitespace is addressed.
'/\'"(\s|$)/' => '&#8217;&#8221;$1',
'/(^|\s|<p>)\'"/' => '$1&#8216;&#8220;',
'/\'"(\W)/' => '&#8217;&#8221;$1',
'/(\W)\'"/' => '$1&#8216;&#8220;',
'/"\'(\s|$)/' => '&#8221;&#8217;$1',
'/(^|\s|<p>)"\'/' => '$1&#8220;&#8216;',
'/"\'(\W)/' => '&#8221;&#8217;$1',
'/(\W)"\'/' => '$1&#8220;&#8216;',
// single quote smart quotes
'/\'(\s|$)/' => '&#8217;$1',
'/(^|\s|<p>)\'/' => '$1&#8216;',
'/\'(\W)/' => '&#8217;$1',
'/(\W)\'/' => '$1&#8216;',
// double quote smart quotes
'/"(\s|$)/' => '&#8221;$1',
'/(^|\s|<p>)"/' => '$1&#8220;',
'/"(\W)/' => '&#8221;$1',
'/(\W)"/' => '$1&#8220;',
// apostrophes
"/(\w)'(\w)/" => '$1&#8217;$2',
// Em dash and ellipses dots
'/\s?\-\-\s?/' => '&#8212;',
'/(\w)\.{3}/' => '$1&#8230;',
// double space after sentences
'/(\W) /' => '$1&nbsp; ',
// ampersands, if not a character entity
'/&(?!#?[a-zA-Z0-9]{2,};)/' => '&amp;'
);
}
return preg_replace(array_keys($table), $table, $str);
}
// --------------------------------------------------------------------
/**
* Format Newlines
*
* Converts newline characters into either <p> tags or <br />
*
* @param string
* @return string
*/
protected function _format_newlines($str)
{
if ($str === '' OR (strpos($str, "\n") === FALSE && ! in_array($this->last_block_element, $this->inner_block_required)))
{
return $str;
}
// Convert two consecutive newlines to paragraphs
$str = str_replace("\n\n", "</p>\n\n<p>", $str);
// Convert single spaces to <br /> tags
$str = preg_replace("/([^\n])(\n)([^\n])/", '\\1<br />\\2\\3', $str);
// Wrap the whole enchilada in enclosing paragraphs
if ($str !== "\n")
{
// We trim off the right-side new line so that the closing </p> tag
// will be positioned immediately following the string, matching
// the behavior of the opening <p> tag
$str = '<p>'.rtrim($str).'</p>';
}
// Remove empty paragraphs if they are on the first line, as this
// is a potential unintended consequence of the previous code
return preg_replace('/<p><\/p>(.*)/', '\\1', $str, 1);
}
// ------------------------------------------------------------------------
/**
* Protect Characters
*
* Protects special characters from being formatted later
* We don't want quotes converted within tags so we'll temporarily convert them to {@DQ} and {@SQ}
* and we don't want double dashes converted to emdash entities, so they are marked with {@DD}
* likewise double spaces are converted to {@NBS} to prevent entity conversion
*
* @param array
* @return string
*/
protected function _protect_characters($match)
{
return str_replace(array("'",'"','--',' '), array('{@SQ}', '{@DQ}', '{@DD}', '{@NBS}'), $match[0]);
}
// --------------------------------------------------------------------
/**
* Convert newlines to HTML line breaks except within PRE tags
*
* @param string
* @return string
*/
public function nl2br_except_pre($str)
{
$newstr = '';
for ($ex = explode('pre>', $str), $ct = count($ex), $i = 0; $i < $ct; $i++)
{
$newstr .= (($i % 2) === 0) ? nl2br($ex[$i]) : $ex[$i];
if ($ct - 1 !== $i)
{
$newstr .= 'pre>';
}
}
return $newstr;
}
}

View File

@ -0,0 +1,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);
}

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

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

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

View File

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