Skip to content
Browse files

Update README.md

1 parent a939ef8 commit 41e52c91b804637db5a6eb8722c42844c1e1dfcf @AutumnsWind committed
Sorry, we could not display the entire diff because it was too big.
View
255 README/Cache/Cache.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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
210 README/Cache/drivers/Cache_apc.php
@@ -0,0 +1,210 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 {
+
+ /**
+ * 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);
+
+ if ($success === TRUE)
+ {
+ return is_array($data)
+ ? unserialize($data[0])
+ : $data;
+ }
+
+ return FALSE;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Cache Save
+ *
+ * @param string $id Cache ID
+ * @param mixed $data Data to store
+ * @param int $ttol Length of time (in seconds) to cache the data
+ * @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)
+ {
+ $ttl = (int) $ttl;
+
+ return apc_store(
+ $id,
+ ($raw === TRUE ? $data : array(serialize($data), time(), $ttl)),
+ $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)
+ {
+ $success = FALSE;
+ $stored = apc_fetch($id, $success);
+
+ if ($success === FALSE OR count($stored) !== 3)
+ {
+ return FALSE;
+ }
+
+ list($data, $time, $ttl) = $stored;
+
+ return array(
+ 'expire' => $time + $ttl,
+ 'mtime' => $time,
+ 'data' => unserialize($data)
+ );
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * is_supported()
+ *
+ * Check to see if APC is available on this system, bail if it isn't.
+ *
+ * @return bool
+ */
+ public function is_supported()
+ {
+ if ( ! extension_loaded('apc') OR ! ini_get('apc.enabled'))
+ {
+ log_message('debug', 'The APC PHP extension must be loaded to use APC Cache.');
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+}
View
172 README/Cache/drivers/Cache_dummy.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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
286 README/Cache/drivers/Cache_file.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 file_exists($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 ( ! file_exists($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']))
+ {
+ return FALSE;
+ }
+
+ return array(
+ 'expire' => $mtime + $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
289 README/Cache/drivers/Cache_memcached.php
@@ -0,0 +1,289 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 $_memcache_conf = 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->_memcache_conf['default'];
+
+ if ($CI->config->load('memcached', TRUE, TRUE))
+ {
+ if (is_array($CI->config->config['memcached']))
+ {
+ $this->_memcache_conf = array();
+
+ foreach ($CI->config->config['memcached'] as $name => $conf)
+ {
+ $this->_memcache_conf[$name] = $conf;
+ }
+ }
+ }
+
+ 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?');
+ }
+
+ foreach ($this->_memcache_conf 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 (get_class($this->_memcached) === 'Memcache')
+ {
+ // Third parameter is persistance and defaults to TRUE.
+ $this->_memcached->addServer(
+ $cache_server['hostname'],
+ $cache_server['port'],
+ TRUE,
+ $cache_server['weight']
+ );
+ }
+ else
+ {
+ $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 (get_class($this->_memcached) === 'Memcached')
+ {
+ return $this->_memcached->set($id, $data, $ttl);
+ }
+ elseif (get_class($this->_memcached) === 'Memcache')
+ {
+ return $this->_memcached->set($id, $data, 0, $ttl);
+ }
+
+ return FALSE;
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Delete from Cache
+ *
+ * @param mixed 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)
+ {
+ return $this->_memcached->increment($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->_memcached->decrement($id, $offset);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * 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 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'));
+ }
+}
View
320 README/Cache/drivers/Cache_redis.php
@@ -0,0 +1,320 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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()
+ {
+ $config = array();
+ $CI =& get_instance();
+
+ if ($CI->config->load('redis', TRUE, TRUE))
+ {
+ $config = $CI->config->item('redis');
+ }
+
+ $config = array_merge(self::$_default_config, $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 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 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 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 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
206 README/Cache/drivers/Cache_wincache.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 {
+
+ /**
+ * 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()
+ {
+ if ( ! extension_loaded('wincache') OR ! ini_get('wincache.ucenabled'))
+ {
+ log_message('debug', 'The Wincache PHP extension must be loaded to use Wincache Cache.');
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+}
View
11 README/Cache/drivers/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
View
11 README/Cache/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
View
546 README/Calendar.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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
567 README/Cart.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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
342 README/Driver.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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;
+ }
+ }
+
+}
View
2,314 README/Email.php
2,314 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
480 README/Encrypt.php
@@ -0,0 +1,480 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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 ( ! 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 http://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 = 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 = strlen($string), $lh = 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_RAND);
+ 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 > strlen($data))
+ {
+ return FALSE;
+ }
+
+ $init_vect = substr($data, 0, $init_size);
+ $data = 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 = strlen($data), $lk = 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 = strlen($data), $lk = 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);
+ }
+
+}
View
926 README/Encryption.php
@@ -0,0 +1,926 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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_override flag
+ *
+ * @var bool
+ */
+ protected static $func_override;
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Class constructor
+ *
+ * @param array $params Configuration parameters
+ * @return void
+ */
+ public function __construct(array $params = array())
+ {
+ $this->_drivers = array(
+ 'mcrypt' => defined('MCRYPT_DEV_URANDOM'),
+ // While OpenSSL is available for PHP 5.3.0, an IV parameter
+ // for the encrypt/decrypt functions is only available since 5.3.3
+ 'openssl' => (is_php('5.3.3') && extension_loaded('openssl'))
+ );
+
+ if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl'])
+ {
+ show_error('Encryption: Unable to find an available encryption driver.');
+ }
+
+ isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override'));
+ $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)
+ {
+ return ($this->_driver === 'mcrypt')
+ ? mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)
+ : openssl_random_pseudo_bytes($length);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * 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)
+ ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM)
+ : 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']))
+ ? openssl_random_pseudo_bytes($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;
+ }
+ else
+ {
+ $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 integer
+ */
+ protected static function strlen($str)
+ {
+ return (self::$func_override)
+ ? 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_override)
+ {
+ // 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
1,595 README/Form_validation.php
1,595 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
667 README/Ftp.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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 probaly 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));
+ }
+
+}
View
1,825 README/Image_lib.php
1,825 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
856 README/Javascript.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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;
+ }
+ }
+
+}
View
1,076 README/Javascript/Jquery.php
@@ -0,0 +1,1076 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://codeigniter.com
+ * @since Version 1.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * Jquery Class
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Loader
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/libraries/javascript.html
+ */
+class CI_Jquery extends CI_Javascript {
+
+ /**
+ * JavaScript directory location
+ *
+ * @var string
+ */
+ protected $_javascript_folder = 'js';
+
+ /**
+ * JQuery code for load
+ *
+ * @var array
+ */
+ public $jquery_code_for_load = array();
+
+ /**
+ * JQuery code for compile
+ *
+ * @var array
+ */
+ public $jquery_code_for_compile = array();
+
+ /**
+ * JQuery corner active flag
+ *
+ * @var bool
+ */
+ public $jquery_corner_active = FALSE;
+
+ /**
+ * JQuery table sorter active flag
+ *
+ * @var bool
+ */
+ public $jquery_table_sorter_active = FALSE;
+
+ /**
+ * JQuery table sorter pager active
+ *
+ * @var bool
+ */
+ public $jquery_table_sorter_pager_active = FALSE;
+
+ /**
+ * JQuery AJAX image
+ *
+ * @var string
+ */
+ public $jquery_ajax_img = '';
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param array $params
+ * @return void
+ */
+ public function __construct($params)
+ {
+ $this->CI =& get_instance();
+ extract($params);
+
+ if ($autoload === TRUE)
+ {
+ $this->script();
+ }
+
+ log_message('info', 'Jquery Class Initialized');
+ }
+
+ // --------------------------------------------------------------------
+ // Event Code
+ // --------------------------------------------------------------------
+
+ /**
+ * Blur
+ *
+ * Outputs a jQuery blur event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _blur($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'blur');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Change
+ *
+ * Outputs a jQuery change event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _change($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'change');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Click
+ *
+ * Outputs a jQuery 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
+ */
+ protected function _click($element = 'this', $js = '', $ret_false = TRUE)
+ {
+ is_array($js) OR $js = array($js);
+
+ if ($ret_false)
+ {
+ $js[] = 'return false;';
+ }
+
+ return $this->_add_event($element, $js, 'click');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Double Click
+ *
+ * Outputs a jQuery dblclick event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _dblclick($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'dblclick');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Error
+ *
+ * Outputs a jQuery error event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _error($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'error');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Focus
+ *
+ * Outputs a jQuery focus event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _focus($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'focus');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Hover
+ *
+ * Outputs a jQuery hover event
+ *
+ * @param string - element
+ * @param string - Javascript code for mouse over
+ * @param string - Javascript code for mouse out
+ * @return string
+ */
+ protected function _hover($element = 'this', $over = '', $out = '')
+ {
+ $event = "\n\t$(".$this->_prep_element($element).").hover(\n\t\tfunction()\n\t\t{\n\t\t\t{$over}\n\t\t}, \n\t\tfunction()\n\t\t{\n\t\t\t{$out}\n\t\t});\n";
+
+ $this->jquery_code_for_compile[] = $event;
+
+ return $event;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Keydown
+ *
+ * Outputs a jQuery keydown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _keydown($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'keydown');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Keyup
+ *
+ * Outputs a jQuery keydown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _keyup($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'keyup');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Load
+ *
+ * Outputs a jQuery load event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _load($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'load');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mousedown
+ *
+ * Outputs a jQuery mousedown event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mousedown($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mousedown');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouse Out
+ *
+ * Outputs a jQuery mouseout event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mouseout($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mouseout');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouse Over
+ *
+ * Outputs a jQuery mouseover event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mouseover($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mouseover');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Mouseup
+ *
+ * Outputs a jQuery mouseup event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _mouseup($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'mouseup');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Output
+ *
+ * Outputs script directly
+ *
+ * @param array $array_js = array()
+ * @return void
+ */
+ protected function _output($array_js = array())
+ {
+ if ( ! is_array($array_js))
+ {
+ $array_js = array($array_js);
+ }
+
+ foreach ($array_js as $js)
+ {
+ $this->jquery_code_for_compile[] = "\t".$js."\n";
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Resize
+ *
+ * Outputs a jQuery resize event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _resize($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'resize');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Scroll
+ *
+ * Outputs a jQuery scroll event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _scroll($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'scroll');
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Unload
+ *
+ * Outputs a jQuery unload event
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @return string
+ */
+ protected function _unload($element = 'this', $js = '')
+ {
+ return $this->_add_event($element, $js, 'unload');
+ }
+
+ // --------------------------------------------------------------------
+ // Effects
+ // --------------------------------------------------------------------
+
+ /**
+ * Add Class
+ *
+ * Outputs a jQuery addClass event
+ *
+ * @param string $element
+ * @param string $class
+ * @return string
+ */
+ protected function _addClass($element = 'this', $class = '')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').addClass("'.$class.'");';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Animate
+ *
+ * Outputs a jQuery animate event
+ *
+ * @param string $element
+ * @param array $params
+ * @param string $speed 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string $extra
+ * @return string
+ */
+ protected function _animate($element = 'this', $params = array(), $speed = '', $extra = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ $animations = "\t\t\t";
+
+ foreach ($params as $param => $value)
+ {
+ $animations .= $param.": '".$value."', ";
+ }
+
+ $animations = substr($animations, 0, -2); // remove the last ", "
+
+ if ($speed !== '')
+ {
+ $speed = ', '.$speed;
+ }
+
+ if ($extra !== '')
+ {
+ $extra = ', '.$extra;
+ }
+
+ return "$({$element}).animate({\n$animations\n\t\t}".$speed.$extra.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fade In
+ *
+ * Outputs a jQuery hide event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _fadeIn($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return "$({$element}).fadeIn({$speed}{$callback});";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Fade Out
+ *
+ * Outputs a jQuery hide event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _fadeOut($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').fadeOut('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Hide
+ *
+ * Outputs a jQuery hide action
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _hide($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return "$({$element}).hide({$speed}{$callback});";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Remove Class
+ *
+ * Outputs a jQuery remove class event
+ *
+ * @param string $element
+ * @param string $class
+ * @return string
+ */
+ protected function _removeClass($element = 'this', $class = '')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').removeClass("'.$class.'");';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Up
+ *
+ * Outputs a jQuery slideUp event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _slideUp($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').slideUp('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Down
+ *
+ * Outputs a jQuery slideDown event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _slideDown($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').slideDown('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Slide Toggle
+ *
+ * Outputs a jQuery slideToggle event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _slideToggle($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').slideToggle('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Toggle
+ *
+ * Outputs a jQuery toggle event
+ *
+ * @param string - element
+ * @return string
+ */
+ protected function _toggle($element = 'this')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').toggle();';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Toggle Class
+ *
+ * Outputs a jQuery toggle class event
+ *
+ * @param string $element
+ * @param string $class
+ * @return string
+ */
+ protected function _toggleClass($element = 'this', $class = '')
+ {
+ $element = $this->_prep_element($element);
+ return '$('.$element.').toggleClass("'.$class.'");';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Show
+ *
+ * Outputs a jQuery show event
+ *
+ * @param string - element
+ * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds
+ * @param string - Javascript callback function
+ * @return string
+ */
+ protected function _show($element = 'this', $speed = '', $callback = '')
+ {
+ $element = $this->_prep_element($element);
+ $speed = $this->_validate_speed($speed);
+
+ if ($callback !== '')
+ {
+ $callback = ", function(){\n{$callback}\n}";
+ }
+
+ return '$('.$element.').show('.$speed.$callback.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Updater
+ *
+ * An Ajax call that populates the designated DOM node with
+ * returned content
+ *
+ * @param string The element to attach the event to
+ * @param string the controller to run the call against
+ * @param string optional parameters
+ * @return string
+ */
+
+ protected function _updater($container = 'this', $controller = '', $options = '')
+ {
+ $container = $this->_prep_element($container);
+ $controller = (strpos('://', $controller) === FALSE) ? $controller : $this->CI->config->site_url($controller);
+
+ // ajaxStart and ajaxStop are better choices here... but this is a stop gap
+ if ($this->CI->config->item('javascript_ajax_img') === '')
+ {
+ $loading_notifier = 'Loading...';
+ }
+ else
+ {
+ $loading_notifier = '<img src="'.$this->CI->config->slash_item('base_url').$this->CI->config->item('javascript_ajax_img').'" alt="Loading" />';
+ }
+
+ $updater = '$('.$container.").empty();\n" // anything that was in... get it out
+ ."\t\t$(".$container.').prepend("'.$loading_notifier."\");\n"; // to replace with an image
+
+ $request_options = '';
+ if ($options !== '')
+ {
+ $request_options .= ', {'
+ .(is_array($options) ? "'".implode("', '", $options)."'" : "'".str_replace(':', "':'", $options)."'")
+ .'}';
+ }
+
+ return $updater."\t\t$($container).load('$controller'$request_options);";
+ }
+
+ // --------------------------------------------------------------------
+ // Pre-written handy stuff
+ // --------------------------------------------------------------------
+
+ /**
+ * Zebra tables
+ *
+ * @param string $class
+ * @param string $odd
+ * @param string $hover
+ * @return string
+ */
+ protected function _zebraTables($class = '', $odd = 'odd', $hover = '')
+ {
+ $class = ($class !== '') ? '.'.$class : '';
+ $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");";
+
+ $this->jquery_code_for_compile[] = $zebra;
+
+ if ($hover !== '')
+ {
+ $hover = $this->hover("table{$class} tbody tr", "$(this).addClass('hover');", "$(this).removeClass('hover');");
+ }
+
+ return $zebra;
+ }
+
+ // --------------------------------------------------------------------
+ // Plugins
+ // --------------------------------------------------------------------
+
+ /**
+ * Corner Plugin
+ *
+ * @link http://www.malsup.com/jquery/corner/
+ * @param string $element
+ * @param string $corner_style
+ * @return string
+ */
+ public function corner($element = '', $corner_style = '')
+ {
+ // may want to make this configurable down the road
+ $corner_location = '/plugins/jquery.corner.js';
+
+ if ($corner_style !== '')
+ {
+ $corner_style = '"'.$corner_style.'"';
+ }
+
+ return '$('.$this->_prep_element($element).').corner('.$corner_style.');';
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Modal window
+ *
+ * Load a thickbox modal window
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function modal($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Effect
+ *
+ * Load an Effect library
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function effect($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Plugin
+ *
+ * Load a plugin library
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function plugin($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * UI
+ *
+ * Load a user interface library
+ *
+ * @param string $src
+ * @param bool $relative
+ * @return void
+ */
+ public function ui($src, $relative = FALSE)
+ {
+ $this->jquery_code_for_load[] = $this->external($src, $relative);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Sortable
+ *
+ * Creates a jQuery sortable
+ *
+ * @param string $element
+ * @param array $options
+ * @return string
+ */
+ public function sortable($element, $options = array())
+ {
+ if (count($options) > 0)
+ {
+ $sort_options = array();
+ foreach ($options as $k=>$v)
+ {
+ $sort_options[] = "\n\t\t".$k.': '.$v;
+ }
+ $sort_options = implode(',', $sort_options);
+ }
+ else
+ {
+ $sort_options = '';
+ }
+
+ return '$('.$this->_prep_element($element).').sortable({'.$sort_options."\n\t});";
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Table Sorter Plugin
+ *
+ * @param string table name
+ * @param string plugin location
+ * @return string
+ */
+ public function tablesorter($table = '', $options = '')
+ {
+ $this->jquery_code_for_compile[] = "\t$(".$this->_prep_element($table).').tablesorter('.$options.");\n";
+ }
+
+ // --------------------------------------------------------------------
+ // Class functions
+ // --------------------------------------------------------------------
+
+ /**
+ * Add Event
+ *
+ * Constructs the syntax for an event, and adds to into the array for compilation
+ *
+ * @param string The element to attach the event to
+ * @param string The code to execute
+ * @param string The event to pass
+ * @return string
+ */
+ protected function _add_event($element, $js, $event)
+ {
+ if (is_array($js))
+ {
+ $js = implode("\n\t\t", $js);
+ }
+
+ $event = "\n\t$(".$this->_prep_element($element).').'.$event."(function(){\n\t\t{$js}\n\t});\n";
+ $this->jquery_code_for_compile[] = $event;
+ return $event;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Compile
+ *
+ * As events are specified, they are stored in an array
+ * This function compiles them all for output on a page
+ *
+ * @param string $view_var
+ * @param bool $script_tags
+ * @return void
+ */
+ protected function _compile($view_var = 'script_foot', $script_tags = TRUE)
+ {
+ // External references
+ $external_scripts = implode('', $this->jquery_code_for_load);
+ $this->CI->load->vars(array('library_src' => $external_scripts));
+
+ if (count($this->jquery_code_for_compile) === 0)
+ {
+ // no inline references, let's just return
+ return;
+ }
+
+ // Inline references
+ $script = '$(document).ready(function() {'."\n"
+ .implode('', $this->jquery_code_for_compile)
+ .'});';
+
+ $output = ($script_tags === FALSE) ? $script : $this->inline($script);
+
+ $this->CI->load->vars(array($view_var => $output));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Clear Compile
+ *
+ * Clears the array of script events collected for output
+ *
+ * @return void
+ */
+ protected function _clear_compile()
+ {
+ $this->jquery_code_for_compile = array();
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Document Ready
+ *
+ * A wrapper for writing document.ready()
+ *
+ * @param array $js
+ * @return void
+ */
+ protected function _document_ready($js)
+ {
+ is_array($js) OR $js = array($js);
+
+ foreach ($js as $script)
+ {
+ $this->jquery_code_for_compile[] = $script;
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Script Tag
+ *
+ * Outputs the script tag that loads the jquery.js file into an HTML document
+ *
+ * @param string $library_src
+ * @param bool $relative
+ * @return string
+ */
+ public function script($library_src = '', $relative = FALSE)
+ {
+ $library_src = $this->external($library_src, $relative);
+ $this->jquery_code_for_load[] = $library_src;
+ return $library_src;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Prep Element
+ *
+ * Puts HTML element in quotes for use in jQuery code
+ * unless the supplied element is the Javascript 'this'
+ * object, in which case no quotes are added
+ *
+ * @param string
+ * @return string
+ */
+ protected function _prep_element($element)
+ {
+ if ($element !== 'this')
+ {
+ $element = '"'.$element.'"';
+ }
+
+ return $element;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Validate Speed
+ *
+ * Ensures the speed parameter is valid for jQuery
+ *
+ * @param string
+ * @return string
+ */
+ protected function _validate_speed($speed)
+ {
+ if (in_array($speed, array('slow', 'normal', 'fast')))
+ {
+ return '"'.$speed.'"';
+ }
+ elseif (preg_match('/[^0-9]/', $speed))
+ {
+ return '';
+ }
+
+ return $speed;
+ }
+
+}
View
11 README/Javascript/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
View
446 README/Migration.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 bool
+ */
+ protected $_migration_regex = NULL;
+
+ /**
+ * 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)
+ {
+ // Moving Up
+ $method = 'up';
+ }
+ else
+ {
+ // Moving Down, apply in reverse order
+ $method = 'down';
+ krsort($migrations);
+ }
+
+ if (empty($migrations))
+ {
+ return TRUE;
+ }
+
+ $previous = FALSE;
+
+ // Validate all available migrations, and run the ones within our target range
+ foreach ($migrations as $number => $file)
+ {
+ // Check for sequence gaps
+ if ($this->_migration_type === 'sequential' && $previous !== FALSE && abs($number - $previous) > 1)
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number);
+ return FALSE;
+ }
+
+ 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;
+ }
+
+ $previous = $number;
+
+ // Run migrations that are inside the target range
+ if (
+ ($method === 'up' && $number > $current_version && $number <= $target_version) OR
+ ($method === 'down' && $number <= $current_version && $number > $target_version)
+ )
+ {
+ $instance = new $class();
+ if ( ! is_callable(array($instance, $method)))
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class);
+ return FALSE;
+ }
+
+ log_message('debug', 'Migrating '.$method.' from version '.$current_version.' to version '.$number);
+ call_user_func(array($instance, $method));
+ $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
697 README/Pagination.php
@@ -0,0 +1,697 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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;
+ }
+ }
+
+ $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())
+ {
+ isset($params['attributes']) OR $params['attributes'] = array();
+ if (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 controll, 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);
+ }
+ else
+ {
+ // 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);
+ }
+ }
+
+ // 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
248 README/Parser.php
@@ -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 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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
570 README/Profiler.php
@@ -0,0 +1,570 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014 - 2015, 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. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://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 http://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 = "'".$key."'";
+
+ $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;">'
+ .((is_array($val) OR is_object($val)) ? '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>' : htmlspecialchars(stripslashes($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 = "'".$key."'";
+
+ $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;">';
+
+ if (is_array($val) OR is_object($val))
+ {
+ $output .= '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>';
+ }
+ else
+ {
+ $output .= htmlspecialchars(stripslashes($val));
+ }
+
+ $output .= "</td></tr>\n";
+ }
+
+ foreach ($_FILES as $key => $val)
+ {
+ is_int($key) OR $key = "'".$key."'";
+
+ $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;">';
+
+ if (is_array($val) OR is_object($val))
+ {
+ $output .= '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>';
+ }
+
+ $output .= "</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]) ? $_SERVER[$header] : '';
+ $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)
+ {
+ if (is_array($val) OR is_object($val))
+ {
+ $val = print_r($val, TRUE);
+ }
+
+ $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;">'.htmlspecialchars($val)."</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)
+ {
+ if (is_array($val) OR is_object($val))
+ {
+ $val = print_r($val, TRUE);
+ }
+
+ $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;">'.htmlspecialchars($val)."</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
0 README/README.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/Session.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/SessionHandlerInterface.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/Session_driver.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/drivers/Session_database_driver.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/drivers/Session_files_driver.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/drivers/Session_memcached_driver.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/drivers/Session_redis_driver.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/drivers/index.html
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Session/index.html
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Table.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Trackback.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Typography.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Unit_test.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Upload.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/User_agent.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Xmlrpc.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Xmlrpcs.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/Zip.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
View
0 README/index.html
Sorry, we could not display the changes to this file because there were too many other changes to display.

0 comments on commit 41e52c9

Please sign in to comment.
Something went wrong with that request. Please try again.