diff options
Diffstat (limited to 'system/libraries')
40 files changed, 4222 insertions, 1907 deletions
diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php index 4395cf411..48bd9581a 100644 --- a/system/libraries/Cache/Cache.php +++ b/system/libraries/Cache/Cache.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Caching Class @@ -41,13 +42,13 @@ class CI_Cache extends CI_Driver_Library { * * @var array */ - protected $valid_drivers = array( - 'cache_apc', - 'cache_dummy', - 'cache_file', - 'cache_memcached', - 'cache_redis', - 'cache_wincache' + protected $valid_drivers = array( + 'apc', + 'dummy', + 'file', + 'memcached', + 'redis', + 'wincache' ); /** @@ -67,16 +68,23 @@ class CI_Cache extends CI_Driver_Library { /** * Fallback driver * - * @param string + * @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 + * @param array $config = array() * @return void */ public function __construct($config = array()) @@ -96,12 +104,11 @@ class CI_Cache extends CI_Driver_Library { } } - if (isset($config['backup'])) + isset($config['key_prefix']) && $this->key_prefix = $config['key_prefix']; + + if (isset($config['backup']) && in_array('cache_'.$config['backup'], $this->valid_drivers)) { - if (in_array('cache_'.$config['backup'], $this->valid_drivers)) - { - $this->_backup_driver = $config['backup']; - } + $this->_backup_driver = $config['backup']; } // If the specified adapter isn't available, check the backup. @@ -129,12 +136,12 @@ class CI_Cache extends CI_Driver_Library { * 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 + * @param string $id + * @return mixed value matching $id or FALSE on failure */ public function get($id) { - return $this->{$this->_adapter}->get($id); + return $this->{$this->_adapter}->get($this->key_prefix.$id); } // ------------------------------------------------------------------------ @@ -142,14 +149,14 @@ class CI_Cache extends CI_Driver_Library { /** * Cache Save * - * @param string Unique Key - * @param mixed Data to store - * @param int Length of time (in seconds) to cache the data - * @return bool true on success/false on failure + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl = 60 Cache TTL (in seconds) + * @return bool TRUE on success, FALSE on failure */ public function save($id, $data, $ttl = 60) { - return $this->{$this->_adapter}->save($id, $data, $ttl); + return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl); } // ------------------------------------------------------------------------ @@ -157,12 +164,12 @@ class CI_Cache extends CI_Driver_Library { /** * Delete from Cache * - * @param mixed unique identifier of the item in the cache - * @return bool true on success/false on failure + * @param string $id Cache ID + * @return bool TRUE on success, FALSE on failure */ public function delete($id) { - return $this->{$this->_adapter}->delete($id); + return $this->{$this->_adapter}->delete($this->key_prefix.$id); } // ------------------------------------------------------------------------ @@ -170,7 +177,7 @@ class CI_Cache extends CI_Driver_Library { /** * Clean the cache * - * @return bool false on failure/true on success + * @return bool TRUE on success, FALSE on failure */ public function clean() { @@ -182,8 +189,8 @@ class CI_Cache extends CI_Driver_Library { /** * Cache Info * - * @param string user/filehits - * @return mixed array on success, false on failure + * @param string $type = 'user' user/filehits + * @return mixed array containing cache info on success OR FALSE on failure */ public function cache_info($type = 'user') { @@ -195,12 +202,12 @@ class CI_Cache extends CI_Driver_Library { /** * Get Cache Metadata * - * @param mixed key to get cache metadata on - * @return mixed return value from child method + * @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($id); + return $this->{$this->_adapter}->get_metadata($this->key_prefix.$id); } // ------------------------------------------------------------------------ @@ -208,7 +215,7 @@ class CI_Cache extends CI_Driver_Library { /** * Is the requested driver supported in this environment? * - * @param string The driver to test. + * @param string $driver The driver to test * @return array */ public function is_supported($driver) diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php index c85034f95..a9ad6ed19 100644 --- a/system/libraries/Cache/drivers/Cache_apc.php +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter APC Caching Class @@ -47,9 +48,11 @@ class CI_Cache_apc extends CI_Driver { */ public function get($id) { - $data = apc_fetch($id); + $success = FALSE; + $data = apc_fetch($id, $success); - return is_array($data) ? $data[0] : FALSE; + return ($success === TRUE && is_array($data)) + ? unserialize($data[0]) : FALSE; } // ------------------------------------------------------------------------ @@ -66,7 +69,7 @@ class CI_Cache_apc extends CI_Driver { public function save($id, $data, $ttl = 60) { $ttl = (int) $ttl; - return apc_store($id, array($data, time(), $ttl), $ttl); + return apc_store($id, array(serialize($data), time(), $ttl), $ttl); } // ------------------------------------------------------------------------ @@ -117,9 +120,10 @@ class CI_Cache_apc extends CI_Driver { */ public function get_metadata($id) { - $stored = apc_fetch($id); + $success = FALSE; + $stored = apc_fetch($id, $success); - if (count($stored) !== 3) + if ($success === FALSE OR count($stored) !== 3) { return FALSE; } @@ -129,7 +133,7 @@ class CI_Cache_apc extends CI_Driver { return array( 'expire' => $time + $ttl, 'mtime' => $time, - 'data' => $data + 'data' => unserialize($data) ); } diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php index 3f2b4b956..a3bdc3c80 100644 --- a/system/libraries/Cache/drivers/Cache_dummy.php +++ b/system/libraries/Cache/drivers/Cache_dummy.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Dummy Caching Class diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php index 37d77c268..9fd053362 100644 --- a/system/libraries/Cache/drivers/Cache_file.php +++ b/system/libraries/Cache/drivers/Cache_file.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter File Caching Class @@ -73,7 +74,7 @@ class CI_Cache_file extends CI_Driver { $data = unserialize(file_get_contents($this->_cache_path.$id)); - if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) + if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) { unlink($this->_cache_path.$id); return FALSE; diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php index bf90f6197..fae002347 100644 --- a/system/libraries/Cache/drivers/Cache_memcached.php +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 2.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Memcached Caching Class diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php index e4a26b5f0..60033344b 100644 --- a/system/libraries/Cache/drivers/Cache_redis.php +++ b/system/libraries/Cache/drivers/Cache_redis.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Redis Caching Class diff --git a/system/libraries/Cache/drivers/Cache_wincache.php b/system/libraries/Cache/drivers/Cache_wincache.php index 74048d564..9154f3fce 100644 --- a/system/libraries/Cache/drivers/Cache_wincache.php +++ b/system/libraries/Cache/drivers/Cache_wincache.php @@ -1,8 +1,8 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * - * An open source application development framework for PHP 5.1.6 or newer + * An open source application development framework for PHP 5.2.4 or newer * * NOTICE OF LICENSE * @@ -18,12 +18,13 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2012 EllisLab, Inc. + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * @link http://codeigniter.com * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Wincache Caching Class @@ -126,10 +127,10 @@ class CI_Cache_wincache extends CI_Driver { $hitcount = $stored['ucache_entries'][1]['hitcount']; return array( - 'expire' => $ttl - $age, - 'hitcount' => $hitcount, - 'age' => $age, - 'ttl' => $ttl + 'expire' => $ttl - $age, + 'hitcount' => $hitcount, + 'age' => $age, + 'ttl' => $ttl ); } diff --git a/system/libraries/Cache/drivers/index.html b/system/libraries/Cache/drivers/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/system/libraries/Cache/drivers/index.html @@ -0,0 +1,10 @@ +<html> +<head> + <title>403 Forbidden</title> +</head> +<body> + +<p>Directory access is forbidden.</p> + +</body> +</html>
\ No newline at end of file diff --git a/system/libraries/Cache/index.html b/system/libraries/Cache/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/system/libraries/Cache/index.html @@ -0,0 +1,10 @@ +<html> +<head> + <title>403 Forbidden</title> +</head> +<body> + +<p>Directory access is forbidden.</p> + +</body> +</html>
\ No newline at end of file diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php index a49f171b9..ec2b7bcc1 100644 --- a/system/libraries/Calendar.php +++ b/system/libraries/Calendar.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Calendar Class @@ -95,11 +96,13 @@ class CI_Calendar { public $next_prev_url = ''; /** - * Constructor + * Class constructor * - * Loads the calendar language file and sets the default time reference + * Loads the calendar language file and sets the default time reference. * - * @param array + * @uses CI_Lang::$is_loaded + * + * @param array $config Calendar options * @return void */ public function __construct($config = array()) @@ -157,7 +160,7 @@ class CI_Calendar { // Set and validate the supplied month/year if (empty($year)) { - $year = date('Y', $this->local_time); + $year = date('Y', $this->local_time); } elseif (strlen($year) === 1) { @@ -216,8 +219,8 @@ class CI_Calendar { // "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); + // 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->temp['heading_previous_cell'])."\n"; @@ -441,7 +444,7 @@ class CI_Calendar { */ public function default_template() { - return array( + return array( 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', 'heading_row_start' => '<tr>', 'heading_previous_cell' => '<th><a href="{previous_url}"><<</a></th>', @@ -487,7 +490,7 @@ class CI_Calendar { $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') as $val) + 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') as $val) { if (preg_match('/\{'.$val.'\}(.*?)\{\/'.$val.'\}/si', $this->template, $match)) { diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php index c442f88da..79c2b8cdc 100644 --- a/system/libraries/Cart.php +++ b/system/libraries/Cart.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Shopping Cart Class @@ -98,7 +99,7 @@ class CI_Cart { // Grab the shopping cart array from the session table $this->_cart_contents = $this->CI->session->userdata('cart_contents'); - if ($this->_cart_contents === FALSE) + 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); @@ -193,7 +194,7 @@ class CI_Cart { $items['qty'] = (float) $items['qty']; // If the quantity is zero or blank there's nothing for us to do - if ( ! is_numeric($items['qty']) OR $items['qty'] == 0) + if ($items['qty'] == 0) { return FALSE; } @@ -224,15 +225,6 @@ class CI_Cart { // Prep the price. Remove leading zeros and anything that isn't a number or decimal point. $items['price'] = (float) $items['price']; - // Is the price a valid number? - if ( ! is_numeric($items['price'])) - { - log_message('error', 'An invalid price was submitted for product ID: '.$items['id']); - return FALSE; - } - - // -------------------------------------------------------------------- - // 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 @@ -350,12 +342,6 @@ class CI_Cart { // Prep the quantity $items['qty'] = (float) $items['qty']; - // Is the quantity a number? - if ( ! is_numeric($items['qty'])) - { - return FALSE; - } - // 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) @@ -480,17 +466,34 @@ class CI_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 mixed + * @param string $row_id = '' * @return bool */ - public function has_options($rowid = '') + public function has_options($row_id = '') { - return (isset($this->_cart_contents[$rowid]['options']) && count($this->_cart_contents[$rowid]['options']) !== 0); + return (isset($this->_cart_contents[$row_id]['options']) && count($this->_cart_contents[$row_id]['options']) !== 0); } // -------------------------------------------------------------------- @@ -500,12 +503,12 @@ class CI_Cart { * * Returns the an array of options, for a particular product row ID * - * @param int + * @param string $row_id = '' * @return array */ - public function product_options($rowid = '') + public function product_options($row_id = '') { - return isset($this->_cart_contents[$rowid]['options']) ? $this->_cart_contents[$rowid]['options'] : array(); + return isset($this->_cart_contents[$row_id]['options']) ? $this->_cart_contents[$row_id]['options'] : array(); } // -------------------------------------------------------------------- diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index d67ee2549..8323e8f01 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Driver Library Class @@ -54,64 +55,128 @@ class CI_Driver_Library { 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 mixed $child - * @return mixed + * @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 + $CI = get_instance(); + $prefix = (string) $CI->config->item('subclass_prefix'); + if ( ! isset($this->lib_name)) { - $this->lib_name = get_class($this); + // Get library name without any prefix + $this->lib_name = str_replace(array('CI_', $prefix), '', get_class($this)); } - // The class will be prefixed with the parent lib - $child_class = $this->lib_name.'_'.$child; + // The child will be prefixed with the parent lib + $child_name = $this->lib_name.'_'.$child; - // Remove the CI_ prefix and lowercase - $lib_name = ucfirst(strtolower(str_replace('CI_', '', $this->lib_name))); - $driver_name = strtolower(str_replace('CI_', '', $child_class)); + // 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 + $paths = $CI->load->get_package_paths(TRUE); - if (in_array($driver_name, array_map('strtolower', $this->valid_drivers))) + // Is there an extension? + $class_name = $prefix.$child_name; + $found = class_exists($class_name); + if ( ! $found) { - // check and see if the driver is in a separate file - if ( ! class_exists($child_class)) + // Check for subclass file + foreach ($paths as $path) { - // check application path first - foreach (get_instance()->load->get_package_paths(TRUE) as $path) + // Does the file exist? + $file = $path.'libraries/'.$this->lib_name.'/drivers/'.$prefix.$child_name.'.php'; + if (file_exists($file)) { - // loves me some nesting! - foreach (array(ucfirst($driver_name), $driver_name) as $class) + // Yes - require base class from BASEPATH + $basepath = BASEPATH.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php'; + if ( ! file_exists($basepath)) { - $filepath = $path.'libraries/'.$lib_name.'/drivers/'.$class.'.php'; - - if (file_exists($filepath)) - { - include_once $filepath; - break 2; - } + $msg = 'Unable to load the requested class: CI_'.$child_name; + log_message('error', $msg); + show_error($msg); } + + // Include both sources and mark found + include($basepath); + include($file); + $found = TRUE; + break; } + } + } - // it's a valid driver, but the file simply can't be found - if ( ! class_exists($child_class)) + // Do we need to search for the class? + if ( ! $found) + { + // Use standard class name + $class_name = 'CI_'.$child_name; + $found = class_exists($class_name); + if ( ! $found) + { + // Check package paths + foreach ($paths as $path) { - log_message('error', 'Unable to load the requested driver: '.$child_class); - show_error('Unable to load the requested driver: '.$child_class); + // Does the file exist? + $file = $path.'libraries/'.$this->lib_name.'/drivers/'.$child_name.'.php'; + if (file_exists($file)) + { + // Include source + include($file); + break; + } } } + } - $obj = new $child_class; - $obj->decorate($this); - $this->$child = $obj; - return $this->$child; + // Did we finally find the class? + if ( ! class_exists($class_name)) + { + if (class_exists($child_name)) + { + $class_name = $child_name; + } + else + { + $msg = 'Unable to load the requested driver: '.$class_name; + log_message('error', $msg); + show_error($msg); + } } - // The requested driver isn't valid! - log_message('error', 'Invalid driver requested: '.$child_class); - show_error('Invalid driver requested: '.$child_class); + // Instantiate, decorate and add child + $obj = new $class_name(); + $obj->decorate($this); + $this->$child = $obj; + return $this->$child; } } @@ -156,7 +221,8 @@ class CI_Driver { /** * Array of methods and properties for the parent class(es) * - * @var array + * @static + * @var array */ protected static $_reflections = array(); diff --git a/system/libraries/Email.php b/system/libraries/Email.php index fdb9be4da..5d8fc8aea 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Email Class @@ -38,66 +39,352 @@ */ class CI_Email { + /** + * Used as the User-Agent and X-Mailer headers' value. + * + * @var string + */ public $useragent = 'CodeIgniter'; + + /** + * Path to the Sendmail binary. + * + * @var string + */ public $mailpath = '/usr/sbin/sendmail'; // Sendmail path + + /** + * Which method to use for sending e-mails. + * + * @var string 'mail', 'sendmail' or 'smtp' + */ public $protocol = 'mail'; // mail/sendmail/smtp - public $smtp_host = ''; // SMTP Server. Example: mail.earthlink.net - public $smtp_user = ''; // SMTP Username - public $smtp_pass = ''; // SMTP Password - public $smtp_port = 25; // SMTP Port - public $smtp_timeout = 5; // SMTP Timeout in seconds - public $smtp_crypto = ''; // SMTP Encryption. Can be null, tls or ssl. - public $wordwrap = TRUE; // TRUE/FALSE Turns word-wrap on/off - public $wrapchars = 76; // Number of characters to wrap at. - public $mailtype = 'text'; // text/html Defines email formatting - public $charset = 'utf-8'; // Default char set: iso-8859-1 or us-ascii + + /** + * STMP Server host + * + * @var string + */ + public $smtp_host = ''; + + /** + * SMTP Username + * + * @var string + */ + public $smtp_user = ''; + + /** + * SMTP Password + * + * @var string + */ + public $smtp_pass = ''; + + /** + * SMTP Server port + * + * @var int + */ + public $smtp_port = 25; + + /** + * SMTP connection timeout in seconds + * + * @var int + */ + public $smtp_timeout = 5; + + /** + * SMTP Encryption + * + * @var string NULL, 'tls' or 'ssl' + */ + public $smtp_crypto = NULL; + + /** + * Whether to apply word-wrapping to the message body. + * + * @var bool + */ + public $wordwrap = TRUE; + + /** + * Number of characters to wrap at. + * + * @see CI_Email::$wordwrap + * @var int + */ + public $wrapchars = 76; + + /** + * Message format. + * + * @var string 'text' or 'html' + */ + public $mailtype = 'text'; + + /** + * Character set (default: utf-8) + * + * @var string + */ + public $charset = 'utf-8'; + + /** + * Multipart message + * + * @var string 'mixed' (in the body) or 'related' (separate) + */ public $multipart = 'mixed'; // "mixed" (in the body) or "related" (separate) - public $alt_message = ''; // Alternative message for HTML emails - public $validate = FALSE; // TRUE/FALSE. Enables email validation + + /** + * Alternative message (for HTML messages only) + * + * @var string + */ + public $alt_message = ''; + + /** + * Whether to validate e-mail addresses. + * + * @var bool + */ + public $validate = FALSE; + + /** + * X-Priority header value. + * + * @var int 1-5 + */ public $priority = 3; // Default priority (1 - 5) + + /** + * Newline character sequence. + * Use "\r\n" to comply with RFC 822. + * + * @link http://www.ietf.org/rfc/rfc822.txt + * @var string "\r\n" or "\n" + */ public $newline = "\n"; // Default newline. "\r\n" or "\n" (Use "\r\n" to comply with RFC 822) - public $crlf = "\n"; // The RFC 2045 compliant CRLF for quoted-printable is "\r\n". Apparently some servers, - // even on the receiving end think they need to muck with CRLFs, so using "\n", while - // distasteful, is the only thing that seems to work for all environments. - public $dsn = FALSE; // Delivery Status Notification - public $send_multipart = TRUE; // TRUE/FALSE - Yahoo does not like multipart alternative, so this is an override. Set to FALSE for Yahoo. - public $bcc_batch_mode = FALSE; // TRUE/FALSE - Turns on/off Bcc batch feature - public $bcc_batch_size = 200; // If bcc_batch_mode = TRUE, sets max number of Bccs in each batch + /** + * CRLF character sequence + * + * RFC 2045 specifies that for 'quoted-printable' encoding, + * "\r\n" must be used. However, it appears that some servers + * (even on the receiving end) don't handle it properly and + * switching to "\n", while improper, is the only solution + * that seems to work for all environments. + * + * @link http://www.ietf.org/rfc/rfc822.txt + * @var string + */ + public $crlf = "\n"; + + /** + * Whether to use Delivery Status Notification. + * + * @var bool + */ + public $dsn = FALSE; + + /** + * Whether to send multipart alternatives. + * Yahoo! doesn't seem to like these. + * + * @var bool + */ + public $send_multipart = TRUE; + + /** + * Whether to send messages to BCC recipients in batches. + * + * @var bool + */ + public $bcc_batch_mode = FALSE; + + /** + * BCC Batch max number size. + * + * @see CI_Email::$bcc_batch_mode + * @var int + */ + public $bcc_batch_size = 200; + + // -------------------------------------------------------------------- + + /** + * Whether PHP is running in safe mode. Initialized by the class constructor. + * + * @var bool + */ protected $_safe_mode = FALSE; + + /** + * Subject header + * + * @var string + */ protected $_subject = ''; + + /** + * Message body + * + * @var string + */ protected $_body = ''; + + /** + * Final message body to be sent. + * + * @var string + */ protected $_finalbody = ''; + + /** + * multipart/alternative boundary + * + * @var string + */ protected $_alt_boundary = ''; + + /** + * Attachment boundary + * + * @var string + */ protected $_atc_boundary = ''; + + /** + * Final headers to send + * + * @var string + */ protected $_header_str = ''; + + /** + * SMTP Connection socket placeholder + * + * @var resource + */ protected $_smtp_connect = ''; + + /** + * Mail encoding + * + * @var string '8bit' or '7bit' + */ protected $_encoding = '8bit'; - protected $_IP = FALSE; + + /** + * Whether to perform SMTP authentication + * + * @var bool + */ protected $_smtp_auth = FALSE; + + /** + * Whether to send a Reply-To header + * + * @var bool + */ protected $_replyto_flag = FALSE; + + /** + * Debug messages + * + * @see CI_Email::print_debugger() + * @var string + */ protected $_debug_msg = array(); + + /** + * Recipients + * + * @var string[] + */ protected $_recipients = array(); + + /** + * CC Recipients + * + * @var string[] + */ protected $_cc_array = array(); + + /** + * BCC Recipients + * + * @var string[] + */ protected $_bcc_array = array(); + + /** + * Message headers + * + * @var string[] + */ protected $_headers = array(); - protected $_attach_name = array(); - protected $_attach_type = array(); - protected $_attach_disp = array(); + + /** + * Attachment data + * + * @var array + */ + protected $_attachments = array(); + + /** + * Valid $protocol values + * + * @see CI_Email::$protocol + * @var string[] + */ protected $_protocols = array('mail', 'sendmail', 'smtp'); - protected $_base_charsets = array('us-ascii', 'iso-2022-'); // 7-bit charsets (excluding language suffix) + + /** + * Base charsets + * + * Character sets valid for 7-bit encoding, + * excluding language suffix. + * + * @var string[] + */ + protected $_base_charsets = array('us-ascii', 'iso-2022-'); + + /** + * Bit depths + * + * Valid mail encodings + * + * @see CI_Email::$_encoding + * @var string[] + */ protected $_bit_depths = array('7bit', '8bit'); + + /** + * $priority translations + * + * Actual values to send with the X-Priority header + * + * @var string[] + */ protected $_priorities = array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)'); + // -------------------------------------------------------------------- + /** * Constructor - Sets Email Preferences * * The constructor can be passed an array of config values * + * @param array $config = array() * @return void */ public function __construct($config = array()) { + $this->charset = config_item('charset'); + if (count($config) > 0) { $this->initialize($config); @@ -108,6 +395,8 @@ class CI_Email { $this->_safe_mode = (bool) @ini_get('safe_mode'); } + $this->charset = strtoupper($this->charset); + log_message('debug', 'Email Class Initialized'); } @@ -171,9 +460,7 @@ class CI_Email { if ($clear_attachments !== FALSE) { - $this->_attach_name = array(); - $this->_attach_type = array(); - $this->_attach_disp = array(); + $this->_attachments = array(); } return $this; @@ -184,11 +471,12 @@ class CI_Email { /** * Set FROM * - * @param string - * @param string + * @param string $from + * @param string $name + * @param string $return_path = NULL Return-Path * @return object */ - public function from($from, $name = '') + public function from($from, $name = '', $return_path = NULL) { if (preg_match('/\<(.*)\>/', $from, $match)) { @@ -198,6 +486,10 @@ class CI_Email { if ($this->validate) { $this->validate_email($this->_str_to_array($from)); + if ($return_path) + { + $this->validate_email($this->_str_to_array($return_path)); + } } // prepare the display name @@ -211,12 +503,14 @@ class CI_Email { } else { - $name = $this->_prep_q_encoding($name, TRUE); + $name = $this->_prep_q_encoding($name); } } $this->set_header('From', $name.' <'.$from.'>'); - $this->set_header('Return-Path', '<'.$from.'>'); + + isset($return_path) OR $return_path = $from; + $this->set_header('Return-Path', '<'.$return_path.'>'); return $this; } @@ -281,16 +575,7 @@ class CI_Email { $this->set_header('To', implode(', ', $to)); } - switch ($this->_get_protocol()) - { - case 'smtp': - $this->_recipients = $to; - break; - case 'sendmail': - case 'mail': - $this->_recipients = implode(', ', $to); - break; - } + $this->_recipients = $to; return $this; } @@ -404,14 +689,20 @@ class CI_Email { /** * Assign file attachments * - * @param string + * @param string $filename + * @param string $disposition = 'attachment' + * @param string $newname = NULL + * @param string $mime = '' * @return object */ public function attach($filename, $disposition = '', $newname = NULL, $mime = '') { - $this->_attach_name[] = array($filename, $newname); - $this->_attach_disp[] = empty($disposition) ? 'attachment' : $disposition; // Can also be 'inline' Not sure if it matters - $this->_attach_type[] = $mime; + $this->_attachments[] = array( + 'name' => array($filename, $newname), + 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters + 'type' => $mime + ); + return $this; } @@ -629,9 +920,9 @@ class CI_Email { { if ($this->mailtype === 'html') { - return (count($this->_attach_name) === 0) ? 'html' : 'html-attach'; + return (count($this->_attachments) === 0) ? 'html' : 'html-attach'; } - elseif ($this->mailtype === 'text' && count($this->_attach_name) > 0) + elseif ($this->mailtype === 'text' && count($this->_attachments) > 0) { return 'plain-attach'; } @@ -741,8 +1032,8 @@ class CI_Email { /** * Build alternative plain text message * - * This public function provides the raw message for use - * in plain-text headers of HTML-formatted emails. + * Provides the raw message for use in plain-text headers of + * HTML-formatted emails. * If the user hasn't specified his own alternative message * it creates one by stripping the HTML * @@ -750,9 +1041,11 @@ class CI_Email { */ protected function _get_alt_message() { - if ($this->alt_message !== '') + if ( ! empty($this->alt_message)) { - return $this->word_wrap($this->alt_message, '76'); + return ($this->wordwrap) + ? $this->word_wrap($this->alt_message, 76) + : $this->alt_message; } $body = preg_match('/\<body.*?\>(.*)\<\/body\>/si', $this->_body, $match) ? $match[1] : $this->_body; @@ -763,7 +1056,12 @@ class CI_Email { $body = str_replace(str_repeat("\n", $i), "\n\n", $body); } - return $this->word_wrap($body, 76); + // Reduce multiple spaces + $body = preg_replace('| +|', ' ', $body); + + return ($this->wordwrap) + ? $this->word_wrap($body, 76) + : $body; } // -------------------------------------------------------------------- @@ -772,26 +1070,26 @@ class CI_Email { * Word Wrap * * @param string - * @param int + * @param int line-length limit * @return string */ - public function word_wrap($str, $charlim = '') + public function word_wrap($str, $charlim = NULL) { - // Se the character limit - if ($charlim === '') + // Set the character limit, if not already present + if (empty($charlim)) { - $charlim = ($this->wrapchars === '') ? 76 : $this->wrapchars; + $charlim = empty($this->wrapchars) ? 76 : $this->wrapchars; } - // Reduce multiple spaces - $str = preg_replace('| +|', ' ', $str); - // Standardize newlines if (strpos($str, "\r") !== FALSE) { $str = str_replace(array("\r\n", "\r"), "\n", $str); } + // Reduce multiple spaces at end of line + $str = preg_replace('| +\n|', "\n", $str); + // If the current word is surrounded by {unwrap} tags we'll // strip the entire chunk and replace it with a marker. $unwrap = array(); @@ -971,7 +1269,6 @@ class CI_Email { $this->_finalbody = $body.$this->_prep_quoted_printable($this->_body).$this->newline.$this->newline; - if ($this->_get_protocol() === 'mail') { $this->_header_str .= $hdr; @@ -981,7 +1278,6 @@ class CI_Email { $this->_finalbody = $hdr.$this->_finalbody; } - if ($this->send_multipart !== FALSE) { $this->_finalbody .= '--'.$this->_alt_boundary.'--'; @@ -1036,14 +1332,15 @@ class CI_Email { } $attachment = array(); - for ($i = 0, $c = count($this->_attach_name), $z = 0; $i < $c; $i++) + for ($i = 0, $c = count($this->_attachments), $z = 0; $i < $c; $i++) { - $filename = $this->_attach_name[$i][0]; - $basename = is_null($this->_attach_name[$i][1]) ? basename($filename) : $this->_attach_name[$i][1]; - $ctype = $this->_attach_type[$i]; + $filename = $this->_attachments[$i]['name'][0]; + $basename = is_null($this->_attachments[$i]['name'][1]) + ? basename($filename) : $this->_attachments[$i]['name'][1]; + $ctype = $this->_attachments[$i]['type']; $file_content = ''; - if ($this->_attach_type[$i] === '') + if ($ctype === '') { if ( ! file_exists($filename)) { @@ -1065,13 +1362,13 @@ class CI_Email { } else { - $file_content =& $this->_attach_content[$i]; + $file_content =& $this->_attachments[$i]['name'][0]; } $attachment[$z++] = '--'.$this->_atc_boundary.$this->newline .'Content-type: '.$ctype.'; ' .'name="'.$basename.'"'.$this->newline - .'Content-Disposition: '.$this->_attach_disp[$i].';'.$this->newline + .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline .'Content-Transfer-Encoding: base64'.$this->newline; $attachment[$z++] = chunk_split(base64_encode($file_content)); @@ -1091,17 +1388,28 @@ class CI_Email { * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt * * @param string - * @param int * @return string */ - protected function _prep_quoted_printable($str, $charlim = '') + protected function _prep_quoted_printable($str) { - // Set the character limit - // Don't allow over 76, as that will make servers and MUAs barf - // all over quoted-printable data - if ($charlim === '' OR $charlim > 76) + // We are intentionally wrapping so mail servers will encode characters + // properly and MUAs will behave, so {unwrap} must go! + $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); + + // RFC 2045 specifies CRLF as "\r\n". + // However, many developers choose to override that and violate + // the RFC rules due to (apparently) a bug in MS Exchange, + // which only works with "\n". + if ($this->crlf === "\r\n") { - $charlim = 76; + if (is_php('5.3')) + { + return quoted_printable_encode($str); + } + elseif (function_exists('imap_8bit')) + { + return imap_8bit($str); + } } // Reduce multiple spaces & remove nulls @@ -1113,10 +1421,6 @@ class CI_Email { $str = str_replace(array("\r\n", "\r"), "\n", $str); } - // We are intentionally wrapping so mail servers will encode characters - // properly and MUAs will behave, so {unwrap} must go! - $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); - $escape = '='; $output = ''; @@ -1146,7 +1450,7 @@ class CI_Email { // If we're at the character limit, add the line to the output, // reset our temp variable, and keep on chuggin' - if ((strlen($temp) + strlen($char)) >= $charlim) + if ((strlen($temp) + strlen($char)) >= 76) { $output .= $temp.$escape.$this->crlf; $temp = ''; @@ -1169,66 +1473,75 @@ class CI_Email { /** * Prep Q Encoding * - * Performs "Q Encoding" on a string for use in email headers. It's related - * but not identical to quoted-printable, so it has its own method + * Performs "Q Encoding" on a string for use in email headers. + * It's related but not identical to quoted-printable, so it has its + * own method. * * @param string - * @param bool set to TRUE for processing From: headers * @return string */ - protected function _prep_q_encoding($str, $from = FALSE) + protected function _prep_q_encoding($str) { - $str = str_replace(array("\r", "\n"), array('', ''), $str); - - // Line length must not exceed 76 characters, so we adjust for - // a space, 7 extra characters =??Q??=, and the charset that we will add to each line - $limit = 75 - 7 - strlen($this->charset); + $str = str_replace(array("\r", "\n"), '', $str); - // these special characters must be converted too - $convert = array('_', '=', '?'); - - if ($from === TRUE) + if ($this->charset === 'UTF-8') { - $convert[] = ','; - $convert[] = ';'; + if (MB_ENABLED === TRUE) + { + return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf); + } + elseif (extension_loaded('iconv')) + { + $output = @iconv_mime_encode('', $str, + array( + 'scheme' => 'Q', + 'line-length' => 76, + 'input-charset' => $this->charset, + 'output-charset' => $this->charset, + 'line-break-chars' => $this->crlf + ) + ); + + // There are reports that iconv_mime_encode() might fail and return FALSE + if ($output !== FALSE) + { + // iconv_mime_encode() will always put a header field name. + // We've passed it an empty one, but it still prepends our + // encoded string with ': ', so we need to strip it. + return substr($output, 2); + } + + $chars = iconv_strlen($str, 'UTF-8'); + } } - $output = ''; - $temp = ''; + // We might already have this set for UTF-8 + isset($chars) OR $chars = strlen($str); - for ($i = 0, $length = strlen($str); $i < $length; $i++) + $output = '=?'.$this->charset.'?Q?'; + for ($i = 0, $length = strlen($output), $iconv = extension_loaded('iconv'); $i < $chars; $i++) { - // Grab the next character - $char = $str[$i]; - $ascii = ord($char); + $chr = ($this->charset === 'UTF-8' && $iconv === TRUE) + ? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2)) + : '='.strtoupper(bin2hex($str[$i])); - // convert ALL non-printable ASCII characters and our specials - if ($ascii < 32 OR $ascii > 126 OR in_array($char, $convert)) + // RFC 2045 sets a limit of 76 characters per line. + // We'll append ?= to the end of each line though. + if ($length + ($l = strlen($chr)) > 74) { - $char = '='.dechex($ascii); + $output .= '?='.$this->crlf // EOL + .' =?'.$this->charset.'?Q?'.$chr; // New line + $length = 6 + strlen($this->charset) + $l; // Reset the length for the new line } - - // handle regular spaces a bit more compactly than =20 - if ($ascii === 32) - { - $char = '_'; - } - - // If we're at the character limit, add the line to the output, - // reset our temp variable, and keep on chuggin' - if ((strlen($temp) + strlen($char)) >= $limit) + else { - $output .= $temp.$this->crlf; - $temp = ''; + $output .= $chr; + $length += $l; } - - // Add the character to our temporary line - $temp .= $char; } - // wrap each line with the shebang, charset, and transfer encoding - // the preceding space on successive lines is required for header "folding" - return trim(preg_replace('/^(.*)$/m', ' =?'.$this->charset.'?Q?$1?=', $output.$temp)); + // End the header + return $output.'?='; } // -------------------------------------------------------------------- @@ -1236,9 +1549,10 @@ class CI_Email { /** * Send Email * + * @param bool $auto_clear = TRUE * @return bool */ - public function send() + public function send($auto_clear = TRUE) { if ($this->_replyto_flag === FALSE) { @@ -1257,11 +1571,25 @@ class CI_Email { if ($this->bcc_batch_mode && count($this->_bcc_array) > $this->bcc_batch_size) { - return $this->batch_bcc_send(); + $result = $this->batch_bcc_send(); + + if ($result && $auto_clear) + { + $this->clear(); + } + + return $result; } $this->_build_message(); - return $this->_spool_email(); + $result = $this->_spool_email(); + + if ($result && $auto_clear) + { + $this->clear(); + } + + return $result; } // -------------------------------------------------------------------- @@ -1334,6 +1662,7 @@ class CI_Email { /** * Strip line-breaks via callback * + * @param string $matches * @return string */ protected function _remove_nl_callback($matches) @@ -1377,6 +1706,11 @@ class CI_Email { */ protected function _send_with_mail() { + if (is_array($this->_recipients)) + { + $this->_recipients = implode(', ', $this->_recipients); + } + if ($this->_safe_mode === TRUE) { return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str); @@ -1385,7 +1719,7 @@ class CI_Email { { // most documentation of sendmail using the "-f" flag lacks a space after it, however // we've encountered servers that seem to require it to be in place. - return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['From'])); + return mail($this->_recipients, $this->_subject, $this->_finalbody, $this->_header_str, '-f '.$this->clean_email($this->_headers['Return-Path'])); } } @@ -1398,11 +1732,14 @@ class CI_Email { */ protected function _send_with_sendmail() { - $fp = @popen($this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']).' -t', 'w'); - - if ($fp === FALSE OR $fp === NULL) + // is popen() enabled? + if ( ! function_usable('popen') + OR FALSE === ($fp = @popen( + $this->mailpath.' -oi -f '.$this->clean_email($this->_headers['From']) + .' -t -r '.$this->clean_email($this->_headers['Return-Path']) + , 'w')) + ) // server probably has popen disabled, so nothing we can do to get a verbose error. { - // server probably has popen disabled, so nothing we can do to get a verbose error. return FALSE; } @@ -1496,7 +1833,6 @@ class CI_Email { /** * SMTP Connect * - * @param string * @return string */ protected function _smtp_connect() @@ -1599,7 +1935,7 @@ class CI_Email { $this->_debug_msg[] = '<pre>'.$cmd.': '.$reply.'</pre>'; - if ( (int) substr($reply, 0, 3) !== $resp) + if ((int) substr($reply, 0, 3) !== $resp) { $this->_set_error_message('lang:email_smtp_error', $reply); return FALSE; @@ -1616,7 +1952,7 @@ class CI_Email { // -------------------------------------------------------------------- /** - * SMTP Authenticate + * SMTP Authenticate * * @return bool */ @@ -1671,11 +2007,12 @@ class CI_Email { /** * Send SMTP data * + * @param string $data * @return bool */ protected function _send_data($data) { - if ( ! fwrite($this->_smtp_connect, $data . $this->newline)) + if ( ! fwrite($this->_smtp_connect, $data.$this->newline)) { $this->_set_error_message('lang:email_smtp_data_failure', $data); return FALSE; @@ -1723,64 +2060,44 @@ class CI_Email { // -------------------------------------------------------------------- /** - * Get IP + * Get Debug Message * + * @param array $include List of raw data chunks to include in the output + * Valid options are: 'headers', 'subject', 'body' * @return string */ - protected function _get_ip() + public function print_debugger($include = array('headers', 'subject', 'body')) { - if ($this->_IP !== FALSE) - { - return $this->_IP; - } + $msg = ''; - $cip = ( ! empty($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : FALSE; - $rip = ( ! empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : FALSE; - if ($cip) $this->_IP = $cip; - elseif ($rip) $this->_IP = $rip; - else + if (count($this->_debug_msg) > 0) { - $fip = ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE; - if ($fip) + foreach ($this->_debug_msg as $val) { - $this->_IP = $fip; + $msg .= $val; } } - if (strpos($this->_IP, ',') !== FALSE) + // Determine which parts of our raw data needs to be printed + $raw_data = ''; + is_array($include) OR $include = array($include); + + if (in_array('headers', $include, TRUE)) { - $x = explode(',', $this->_IP); - $this->_IP = end($x); + $raw_data = $this->_header_str."\n"; } - if ( ! preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->_IP)) + if (in_array('subject', $include, TRUE)) { - $this->_IP = '0.0.0.0'; + $raw_data .= htmlspecialchars($this->_subject)."\n"; } - return $this->_IP; - } - - // -------------------------------------------------------------------- - - /** - * Get Debug Message - * - * @return string - */ - public function print_debugger() - { - $msg = ''; - - if (count($this->_debug_msg) > 0) + if (in_array('body', $include, TRUE)) { - foreach ($this->_debug_msg as $val) - { - $msg .= $val; - } + $raw_data .= htmlspecialchars($this->_finalbody); } - return $msg.'<pre>'.$this->_header_str."\n".htmlspecialchars($this->_subject)."\n".htmlspecialchars($this->_finalbody).'</pre>'; + return $msg.($raw_data === '' ? '' : '<pre>'.$raw_data.'</pre>'); } // -------------------------------------------------------------------- @@ -1788,7 +2105,8 @@ class CI_Email { /** * Set Message * - * @param string + * @param string $msg + * @param string $val = '' * @return void */ protected function _set_error_message($msg, $val = '') @@ -1796,7 +2114,7 @@ class CI_Email { $CI =& get_instance(); $CI->lang->load('email'); - if (substr($msg, 0, 5) !== 'lang:' OR FALSE === ($line = $CI->lang->line(substr($msg, 5)))) + if (sscanf($msg, 'lang:%s', $line) !== 1 OR FALSE === ($line = $CI->lang->line($line))) { $this->_debug_msg[] = str_replace('%s', $val, $msg).'<br />'; } diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php index 8ffd93aea..cdb0a6452 100644 --- a/system/libraries/Encrypt.php +++ b/system/libraries/Encrypt.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Encryption Class @@ -165,7 +166,7 @@ class CI_Encrypt { */ public function decode($string, $key = '') { - if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string)) + if (preg_match('/[^a-zA-Z0-9\/\+=]/', $string) OR base64_encode(base64_decode($string)) !== $string) { return FALSE; } @@ -484,7 +485,7 @@ class CI_Encrypt { */ public function set_hash($type = 'sha1') { - $this->_hash_type = ($type !== 'sha1' && $type !== 'md5') ? 'sha1' : $type; + $this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1'; } // -------------------------------------------------------------------- @@ -497,7 +498,7 @@ class CI_Encrypt { */ public function hash($str) { - return ($this->_hash_type === 'sha1') ? sha1($str) : md5($str); + return hash($this->_hash_type, $str); } } diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 353624100..68534251b 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Form Validation Class @@ -104,7 +105,7 @@ class CI_Form_validation { * * @var array */ - protected $validation_data = array(); + public $validation_data = array(); /** * Initialize Form_Validation class @@ -134,12 +135,6 @@ class CI_Form_validation { // Automatically load the form helper $this->CI->load->helper('form'); - // Set the character encoding in MB. - if (MB_ENABLED === TRUE) - { - mb_internal_encoding($this->CI->config->item('charset')); - } - log_message('debug', 'Form Validation Class Initialized'); } @@ -204,12 +199,10 @@ class CI_Form_validation { // Is the field name an array? If it is an array, we break it apart // into its components so that we can fetch the corresponding POST data later + $indexes = array(); if (preg_match_all('/\[(.*?)\]/', $field, $matches)) { - // Note: Due to a bug in current() that affects some versions - // of PHP we can not pass function call directly into it - $x = explode('[', $field); - $indexes[] = current($x); + sscanf($field, '%[^[][', $indexes[0]); for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { @@ -223,7 +216,6 @@ class CI_Form_validation { } else { - $indexes = array(); $is_array = FALSE; } @@ -445,11 +437,10 @@ class CI_Form_validation { // Load the language file containing error messages $this->CI->lang->load('form_validation'); - // Cycle through the rules for each field, match the - // corresponding $_POST item and test for errors + // Cycle through the rules for each field and match the corresponding $validation_data item foreach ($this->_field_data as $field => $row) { - // Fetch the data from the corresponding $_POST or validation array and cache it in the _field_data array. + // Fetch the data from the validation_data array item and cache it in the _field_data array. // Depending on whether the field name is an array or a string will determine where we get it from. if ($row['is_array'] === TRUE) { @@ -459,6 +450,18 @@ class CI_Form_validation { { $this->_field_data[$field]['postdata'] = $validation_array[$field]; } + } + + // Execute validation rules + // Note: A second foreach (for now) is required in order to avoid false-positives + // for rules like 'matches', which correlate to other validation fields. + foreach ($this->_field_data as $field => $row) + { + // Don't try to validate if we have no rules set + if (empty($row['rules'])) + { + continue; + } $this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']); } @@ -493,7 +496,8 @@ class CI_Form_validation { return isset($array[$keys[$i]]) ? $this->_reduce_array($array[$keys[$i]], $keys, ($i+1)) : NULL; } - return $array; + // NULL must be returned for empty fields + return ($array === '') ? NULL : $array; } // -------------------------------------------------------------------- @@ -605,13 +609,15 @@ class CI_Form_validation { { $line = $this->_error_messages[$type]; } - elseif (FALSE === ($line = $this->CI->lang->line($type))) + elseif (FALSE === ($line = $this->CI->lang->line('form_validation_'.$type)) + // DEPRECATED support for non-prefixed keys + && FALSE === ($line = $this->CI->lang->line($type, FALSE))) { $line = 'The field was not set'; } // Build the error message - $message = sprintf($line, $this->_translate_fieldname($row['label'])); + $message = $this->_build_error_msg($line, $this->_translate_fieldname($row['label'])); // Save the error message $this->_field_data[$row['field']]['error'] = $message; @@ -669,8 +675,8 @@ class CI_Form_validation { $param = FALSE; if (preg_match('/(.*?)\[(.*)\]/', $rule, $match)) { - $rule = $match[1]; - $param = $match[2]; + $rule = $match[1]; + $param = $match[2]; } // Call the function that corresponds to the rule @@ -745,7 +751,9 @@ class CI_Form_validation { { if ( ! isset($this->_error_messages[$rule])) { - if (FALSE === ($line = $this->CI->lang->line($rule))) + if (FALSE === ($line = $this->CI->lang->line('form_validation_'.$rule)) + // DEPRECATED support for non-prefixed keys + && FALSE === ($line = $this->CI->lang->line($rule, FALSE))) { $line = 'Unable to access an error message corresponding to your field name.'; } @@ -763,7 +771,7 @@ class CI_Form_validation { } // Build the error message - $message = sprintf($line, $this->_translate_fieldname($row['label']), $param); + $message = $this->_build_error_msg($line, $this->_translate_fieldname($row['label']), $param); // Save the error message $this->_field_data[$row['field']]['error'] = $message; @@ -790,13 +798,12 @@ class CI_Form_validation { { // Do we need to translate the field name? // We look for the prefix lang: to determine this - if (strpos($fieldname, 'lang:') === 0) + if (sscanf($fieldname, 'lang:%s', $line) === 1) { - // Grab the variable - $line = substr($fieldname, 5); - // Were we able to translate the field name? If not we use $line - if (FALSE === ($fieldname = $this->CI->lang->line($line))) + if (FALSE === ($fieldname = $this->CI->lang->line('form_validation_'.$line)) + // DEPRECATED support for non-prefixed keys + && FALSE === ($fieldname = $this->CI->lang->line($line, FALSE))) { return $line; } @@ -808,6 +815,27 @@ class CI_Form_validation { // -------------------------------------------------------------------- /** + * Build an error message using the field and param. + * + * @param string The error message line + * @param string A field's human name + * @param mixed A rule's optional parameter + * @return string + */ + protected function _build_error_msg($line, $field = '', $param = '') + { + // Check for %s in the string for legacy support. + if (strpos($line, '%s') !== FALSE) + { + return sprintf($line, $field, $param); + } + + return str_replace(array('{field}', '{param}'), array($field, $param), $line); + } + + // -------------------------------------------------------------------- + + /** * Get the value from a form * * Permits you to repopulate a form field with the value it was submitted @@ -957,15 +985,29 @@ class CI_Form_validation { /** * Match one field to another * - * @param string - * @param string field + * @param string $str string to compare against + * @param string $field * @return bool */ public function matches($str, $field) { - $validation_array = empty($this->validation_data) ? $_POST : $this->validation_data; + return isset($this->_field_data[$field], $this->_field_data[$field]['postdata']) + ? ($str === $this->_field_data[$field]['postdata']) + : FALSE; + } - return isset($validation_array[$field]) ? ($str === $validation_array[$field]) : FALSE; + // -------------------------------------------------------------------- + + /** + * Differs from another field + * + * @param string + * @param string field + * @return bool + */ + public function differs($str, $field) + { + return ! (isset($this->_field_data[$field]) && $this->_field_data[$field]['postdata'] === $str); } // -------------------------------------------------------------------- @@ -982,7 +1024,7 @@ class CI_Form_validation { */ public function is_unique($str, $field) { - list($table, $field) = explode('.', $field); + sscanf($field, '%[^.].%[^.]', $table, $field); if (isset($this->CI->db)) { $query = $this->CI->db->limit(1)->get_where($table, array($field => $str)); @@ -1069,6 +1111,48 @@ class CI_Form_validation { // -------------------------------------------------------------------- /** + * Valid URL + * + * @param string $str + * @return bool + */ + public function valid_url($str) + { + if (empty($str)) + { + return FALSE; + } + elseif (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $str, $matches)) + { + if (empty($matches[2])) + { + return FALSE; + } + elseif ( ! in_array($matches[1], array('http', 'https'), TRUE)) + { + return FALSE; + } + + $str = $matches[2]; + } + + $str = 'http://'.$str; + + // There's a bug affecting PHP 5.2.13, 5.3.2 that considers the + // underscore to be a valid hostname character instead of a dash. + // Reference: https://bugs.php.net/bug.php?id=51192 + if (version_compare(PHP_VERSION, '5.2.13', '==') === 0 OR version_compare(PHP_VERSION, '5.3.2', '==') === 0) + { + sscanf($str, 'http://%[^/]', $host); + $str = substr_replace($str, strtr($host, array('_' => '-', '-' => '_')), 7, strlen($host)); + } + + return (filter_var($str, FILTER_VALIDATE_URL) !== FALSE); + } + + // -------------------------------------------------------------------- + + /** * Valid Email * * @param string @@ -1309,6 +1393,11 @@ class CI_Form_validation { */ public function prep_for_form($data = '') { + if ($this->_safe_form_data === FALSE OR empty($data)) + { + return $data; + } + if (is_array($data)) { foreach ($data as $key => $val) @@ -1319,11 +1408,6 @@ class CI_Form_validation { return $data; } - if ($this->_safe_form_data === FALSE OR $data === '') - { - return $data; - } - return str_replace(array("'", '"', '<', '>'), array(''', '"', '<', '>'), stripslashes($data)); } @@ -1386,7 +1470,7 @@ class CI_Form_validation { */ public function encode_php_tags($str) { - return str_replace(array('<?', '?>'), array('<?', '?>'), $str); + return str_replace(array('<?', '?>'), array('<?', '?>'), $str); } // -------------------------------------------------------------------- diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index 76f5e151a..7f58fee7b 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * FTP Class @@ -36,14 +37,65 @@ */ 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 + * + * @var resource + */ public $conn_id = FALSE; + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @param array $config + * @return void + */ public function __construct($config = array()) { if (count($config) > 0) @@ -59,7 +111,7 @@ class CI_FTP { /** * Initialize preferences * - * @param array + * @param array $config * @return void */ public function initialize($config = array()) @@ -81,7 +133,7 @@ class CI_FTP { /** * FTP Connect * - * @param array the connection values + * @param array $config Connection values * @return bool */ public function connect($config = array()) @@ -161,8 +213,8 @@ class CI_FTP { * 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 - * @param bool + * @param string $path + * @param bool $supress_debug * @return bool */ public function changedir($path = '', $supress_debug = FALSE) @@ -191,8 +243,8 @@ class CI_FTP { /** * Create a directory * - * @param string - * @param int + * @param string $path + * @param int $permissions * @return bool */ public function mkdir($path = '', $permissions = NULL) @@ -227,10 +279,10 @@ class CI_FTP { /** * Upload a file to the server * - * @param string - * @param string - * @param string - * @param int + * @param string $locpath + * @param string $rempath + * @param string $mode + * @param int $permissions * @return bool */ public function upload($locpath, $rempath, $mode = 'auto', $permissions = NULL) @@ -281,9 +333,9 @@ class CI_FTP { /** * Download a file from a remote server to the local server * - * @param string - * @param string - * @param string + * @param string $rempath + * @param string $locpath + * @param string $mode * @return bool */ public function download($rempath, $locpath, $mode = 'auto') @@ -322,9 +374,9 @@ class CI_FTP { /** * Rename (or move) a file * - * @param string - * @param string - * @param bool + * @param string $old_file + * @param string $new_file + * @param bool $move * @return bool */ public function rename($old_file, $new_file, $move = FALSE) @@ -353,8 +405,8 @@ class CI_FTP { /** * Move a file * - * @param string - * @param string + * @param string $old_file + * @param string $new_file * @return bool */ public function move($old_file, $new_file) @@ -367,7 +419,7 @@ class CI_FTP { /** * Rename (or move) a file * - * @param string + * @param string $filepath * @return bool */ public function delete_file($filepath) @@ -397,7 +449,7 @@ class CI_FTP { * Delete a folder and recursively delete everything (including sub-folders) * containted within it. * - * @param string + * @param string $filepath * @return bool */ public function delete_dir($filepath) @@ -408,7 +460,7 @@ class CI_FTP { } // Add a trailing slash to the file path if needed - $filepath = preg_replace('/(.+?)\/*$/', '\\1/', $filepath); + $filepath = preg_replace('/(.+?)\/*$/', '\\1/', $filepath); $list = $this->list_files($filepath); @@ -444,8 +496,8 @@ class CI_FTP { /** * Set file permissions * - * @param string the file path - * @param int the permissions + * @param string $path File path + * @param int $perm Permissions * @return bool */ public function chmod($path, $perm) @@ -474,6 +526,7 @@ class CI_FTP { /** * FTP List files in the specified directory * + * @param string $path * @return array */ public function list_files($path = '.') @@ -496,8 +549,8 @@ class CI_FTP { * Whatever the directory structure of the original file path will be * recreated on the server. * - * @param string path to source with trailing slash - * @param string path to destination - include the base folder with trailing slash + * @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) @@ -543,7 +596,7 @@ class CI_FTP { /** * Extract the file extension * - * @param string + * @param string $filename * @return string */ protected function _getext($filename) @@ -562,7 +615,7 @@ class CI_FTP { /** * Set the upload type * - * @param string + * @param string $ext Filename extension * @return string */ protected function _settype($ext) @@ -583,7 +636,6 @@ class CI_FTP { 'xml' ); - return in_array($ext, $text_types) ? 'ascii' : 'binary'; } @@ -609,7 +661,7 @@ class CI_FTP { /** * Display error message * - * @param string + * @param string $line * @return void */ protected function _error($line) diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index 899b995d4..46a9c120f 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Image Manipulation class @@ -604,7 +605,7 @@ class CI_Image_lib { // Set the quality $this->quality = trim(str_replace('%', '', $this->quality)); - if ($this->quality === '' OR $this->quality === 0 OR ! preg_match('/^[0-9]+$/', $this->quality)) + if ($this->quality === '' OR $this->quality === 0 OR ! ctype_digit($this->quality)) { $this->quality = 90; } @@ -866,7 +867,11 @@ class CI_Image_lib { } $retval = 1; - @exec($cmd, $output, $retval); + // exec() might be disabled + if (function_usable('exec')) + { + @exec($cmd, $output, $retval); + } // Did it work? if ($retval > 0) @@ -946,7 +951,11 @@ class CI_Image_lib { $cmd = $this->library_path.$cmd_in.' '.$this->full_src_path.' | '.$cmd_inner.' | '.$cmd_out.' > '.$this->dest_folder.'netpbm.tmp'; $retval = 1; - @exec($cmd, $output, $retval); + // exec() might be disabled + if (function_usable('exec')) + { + @exec($cmd, $output, $retval); + } // Did it work? if ($retval > 0) @@ -958,7 +967,7 @@ class CI_Image_lib { // With NetPBM we have to create a temporary image. // If you try manipulating the original it fails so // we have to rename the temp file. - copy ($this->dest_folder.'netpbm.tmp', $this->full_dst_path); + copy($this->dest_folder.'netpbm.tmp', $this->full_dst_path); unlink($this->dest_folder.'netpbm.tmp'); @chmod($this->full_dst_path, FILE_WRITE_MODE); @@ -1268,8 +1277,8 @@ class CI_Image_lib { if ($this->wm_use_drop_shadow === FALSE) $this->wm_shadow_distance = 0; - $this->wm_vrt_alignment = strtoupper(substr($this->wm_vrt_alignment, 0, 1)); - $this->wm_hor_alignment = strtoupper(substr($this->wm_hor_alignment, 0, 1)); + $this->wm_vrt_alignment = strtoupper($this->wm_vrt_alignment[0]); + $this->wm_hor_alignment = strtoupper($this->wm_hor_alignment[0]); // Set verticle alignment if ($this->wm_vrt_alignment === 'M') @@ -1320,6 +1329,13 @@ class CI_Image_lib { imagestring($src_img, $this->wm_font_size, $x_shad, $y_shad, $this->wm_text, $drp_color); imagestring($src_img, $this->wm_font_size, $x_axis, $y_axis, $this->wm_text, $txt_color); } + + // We can preserve transparency for PNG images + if ($this->image_type === 3) + { + imagealphablending($src_img, FALSE); + imagesavealpha($src_img, TRUE); + } } // Output the final image @@ -1357,7 +1373,6 @@ class CI_Image_lib { if ($image_type === '') $image_type = $this->image_type; - switch ($image_type) { case 1 : @@ -1502,13 +1517,13 @@ class CI_Image_lib { public function image_reproportion() { if (($this->width === 0 && $this->height === 0) OR $this->orig_width === 0 OR $this->orig_height === 0 - OR ( ! preg_match('/^[0-9]+$/', $this->width) && ! preg_match('/^[0-9]+$/', $this->height)) - OR ! preg_match('/^[0-9]+$/', $this->orig_width) OR ! preg_match('/^[0-9]+$/', $this->orig_height)) + OR ( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) + OR ! ctype_digit((string) $this->orig_width) OR ! ctype_digit((string) $this->orig_height)) { return; } - // Sanitize so we don't call preg_match() anymore + // Sanitize $this->width = (int) $this->width; $this->height = (int) $this->height; diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php index 5c8b09217..420b623ee 100644 --- a/system/libraries/Javascript.php +++ b/system/libraries/Javascript.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Javascript Class @@ -36,8 +37,21 @@ */ 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); @@ -312,8 +326,7 @@ class CI_Javascript { * * Outputs a javascript library mouseup event * - * @param string The element to attach the event to - * @param string The code to execute + * @param string $js Code to execute * @return string */ public function ready($js) @@ -394,9 +407,10 @@ class CI_Javascript { * * Outputs a javascript library animate event * - * @param string - element - * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds - * @param string - Javascript callback function + * @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 = '') @@ -546,10 +560,11 @@ class CI_Javascript { * * Outputs a javascript library toggle class event * - * @param string - element + * @param string $element = 'this' + * @param string $class = '' * @return string */ - public function toggleClass($element = 'this', $class='') + public function toggleClass($element = 'this', $class = '') { return $this->js->_toggleClass($element, $class); } @@ -571,7 +586,6 @@ class CI_Javascript { return $this->js->_show($element, $speed, $callback); } - // -------------------------------------------------------------------- /** @@ -579,7 +593,8 @@ class CI_Javascript { * * gather together all script needing to be output * - * @param string The element to attach the event to + * @param string $view_var + * @param bool $script_tags * @return string */ public function compile($view_var = 'script_foot', $script_tags = TRUE) @@ -587,6 +602,8 @@ class CI_Javascript { $this->js->_compile($view_var, $script_tags); } + // -------------------------------------------------------------------- + /** * Clear Compile * @@ -606,7 +623,8 @@ class CI_Javascript { * * Outputs a <script> tag with the source as an external js file * - * @param string The element to attach the event to + * @param string $external_file + * @param bool $relative * @return string */ public function external($external_file = '', $relative = FALSE) @@ -799,7 +817,8 @@ class CI_Javascript { * * Ensures a standard json value and escapes values * - * @param mixed + * @param mixed $result + * @param bool $is_key = FALSE * @return string */ protected function _prep_args($result, $is_key = FALSE) diff --git a/system/libraries/Log.php b/system/libraries/Log.php deleted file mode 100644 index baac80121..000000000 --- a/system/libraries/Log.php +++ /dev/null @@ -1,180 +0,0 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); -/** - * CodeIgniter - * - * An open source application development framework for PHP 5.2.4 or newer - * - * NOTICE OF LICENSE - * - * Licensed under the Open Software License version 3.0 - * - * This source file is subject to the Open Software License (OSL 3.0) that is - * bundled with this package in the files license.txt / license.rst. It is - * also available through the world wide web at this URL: - * http://opensource.org/licenses/OSL-3.0 - * If you did not receive a copy of the license and are unable to obtain it - * through the world wide web, please send an email to - * licensing@ellislab.com so we can send you a copy immediately. - * - * @package CodeIgniter - * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) - * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) - * @link http://codeigniter.com - * @since Version 1.0 - * @filesource - */ - -/** - * Logging Class - * - * @package CodeIgniter - * @subpackage Libraries - * @category Logging - * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/general/errors.html - */ -class CI_Log { - - /** - * Path to save log files - * - * @var string - */ - protected $_log_path; - - /** - * Level of logging - * - * @var int - */ - protected $_threshold = 1; - - /** - * Highest level of logging - * - * @var int - */ - protected $_threshold_max = 0; - - /** - * Array of threshold levels to log - * - * @var array - */ - protected $_threshold_array = array(); - - /** - * Format of timestamp for log files - * - * @var string - */ - protected $_date_fmt = 'Y-m-d H:i:s'; - - /** - * Whether or not the logger can write to the log files - * - * @var bool - */ - protected $_enabled = TRUE; - - /** - * Predefined logging levels - * - * @var array - */ - protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4); - - /** - * Initialize Logging class - * - * @return void - */ - public function __construct() - { - $config =& get_config(); - - $this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/'; - - if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path)) - { - $this->_enabled = FALSE; - } - - if (is_numeric($config['log_threshold'])) - { - $this->_threshold = (int) $config['log_threshold']; - } - elseif (is_array($config['log_threshold'])) - { - $this->_threshold = $this->_threshold_max; - $this->_threshold_array = array_flip($config['log_threshold']); - } - - if ($config['log_date_format'] !== '') - { - $this->_date_fmt = $config['log_date_format']; - } - } - - // -------------------------------------------------------------------- - - /** - * Write Log File - * - * Generally this function will be called using the global log_message() function - * - * @param string the error level - * @param string the error message - * @param bool whether the error is a native PHP error - * @return bool - */ - public function write_log($level = 'error', $msg, $php_error = FALSE) - { - if ($this->_enabled === FALSE) - { - return FALSE; - } - - $level = strtoupper($level); - - if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold)) - && ! isset($this->_threshold_array[$this->_levels[$level]])) - { - return FALSE; - } - - - $filepath = $this->_log_path.'log-'.date('Y-m-d').'.php'; - $message = ''; - - if ( ! file_exists($filepath)) - { - $newfile = TRUE; - $message .= '<'."?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); ?".">\n\n"; - } - - if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE)) - { - return FALSE; - } - - $message .= $level.' '.($level === 'INFO' ? ' -' : '-').' '.date($this->_date_fmt).' --> '.$msg."\n"; - - flock($fp, LOCK_EX); - fwrite($fp, $message); - flock($fp, LOCK_UN); - fclose($fp); - - if (isset($newfile) && $newfile === TRUE) - { - @chmod($filepath, FILE_WRITE_MODE); - } - - return TRUE; - } - -} - -/* End of file Log.php */ -/* Location: ./system/libraries/Log.php */
\ No newline at end of file diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php index c786703ca..e591ab64a 100644 --- a/system/libraries/Migration.php +++ b/system/libraries/Migration.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 3.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Migration Class @@ -47,6 +48,13 @@ class CI_Migration { protected $_migration_enabled = FALSE; /** + * Migration numbering type + * + * @var bool + */ + protected $_migration_type = 'sequential'; + + /** * Path to migration classes * * @var string @@ -70,11 +78,18 @@ class CI_Migration { /** * Whether to automatically run migrations * - * @var bool + * @var bool */ protected $_migration_auto_latest = FALSE; /** + * Migration basename regex + * + * @var bool + */ + protected $_migration_regex = NULL; + + /** * Error message * * @var string @@ -84,7 +99,7 @@ class CI_Migration { /** * Initialize Migration Class * - * @param array + * @param array $config * @return void */ public function __construct($config = array()) @@ -126,11 +141,22 @@ class CI_Migration { 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' => 'INT', 'constraint' => 3), + 'version' => array('type' => 'BIGINT', 'constraint' => 20), )); $this->dbforge->create_table($this->_migration_table, TRUE); @@ -153,118 +179,88 @@ class CI_Migration { * Calls each migration step required to get to the schema version of * choice * - * @param int Target schema version + * @param int $target_version Target schema version * @return mixed TRUE if already latest, FALSE if failed, int if upgraded */ public function version($target_version) { - $start = $current_version = $this->_get_version(); - $stop = $target_version; + $current_version = (int) $this->_get_version(); + $target_version = (int) $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 - ++$start; - ++$stop; - $step = 1; + $method = 'up'; } else { - // Moving Down - $step = -1; + // Moving Down, apply in reverse order + $method = 'down'; + krsort($migrations); } - $method = $step === 1 ? 'up' : 'down'; - $migrations = array(); - - // We now prepare to actually DO the migrations - // But first let's make sure that everything is the way it should be - for ($i = $start; $i != $stop; $i += $step) + if (empty($migrations)) { - $f = glob(sprintf($this->_migration_path.'%03d_*.php', $i)); + return TRUE; + } - // Only one migration per step is permitted - if (count($f) > 1) + $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_multiple_version'), $i); + $this->_error_string = sprintf($this->lang->line('migration_sequence_gap'), $number); return FALSE; } - // Migration step not found - if (count($f) === 0) - { - // If trying to migrate up to a version greater than the last - // existing one, migrate to the last one. - if ($step === 1) - { - break; - } + include $file; + $class = 'Migration_'.ucfirst(strtolower($this->_get_migration_name(basename($file, '.php')))); - // If trying to migrate down but we're missing a step, - // something must definitely be wrong. - $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i); + // Validate the migration file structure + if ( ! class_exists($class)) + { + $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); return FALSE; } - $file = basename($f[0]); - $name = basename($f[0], '.php'); + $previous = $number; - // Filename validations - if (preg_match('/^\d{3}_(\w+)$/', $name, $match)) + // 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) + ) { - $match[1] = strtolower($match[1]); - - // Cannot repeat a migration at different steps - if (in_array($match[1], $migrations)) - { - $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]); - return FALSE; - } - - include $f[0]; - $class = 'Migration_'.ucfirst($match[1]); - - if ( ! class_exists($class)) - { - $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); - return FALSE; - } - - if ( ! is_callable(array($class, $method))) + $instance = new $class(); + if ( ! is_callable(array($instance, $method))) { $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); return FALSE; } - $migrations[] = $match[1]; + 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); } - else - { - $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file); - return FALSE; - } - } - - log_message('debug', 'Current migration: '.$current_version); - - $version = $i + ($step === 1 ? -1 : 0); - - // If there is nothing to do so quit - if ($migrations === array()) - { - return TRUE; } - log_message('debug', 'Migrating from '.$method.' to version '.$version); - - // Loop through the migrations - foreach ($migrations AS $migration) + // 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) { - // Run the migration class - $class = 'Migration_'.ucfirst(strtolower($migration)); - call_user_func(array(new $class, $method)); - - $current_version += $step; + $current_version = $target_version; $this->_update_version($current_version); } @@ -278,21 +274,23 @@ class CI_Migration { /** * Set's the schema to the latest migration * - * @return mixed true if already latest, false if failed, int if upgraded + * @return mixed TRUE if already latest, FALSE if failed, int if upgraded */ public function latest() { - if ( ! $migrations = $this->find_migrations()) + $migrations = $this->find_migrations(); + + if (empty($migrations)) { $this->_error_string = $this->lang->line('migration_none_found'); - return false; + return FALSE; } $last_migration = basename(end($migrations)); // Calculate the last migration step from existing migration // filenames and procceed to the standard version migration - return $this->version((int) $last_migration); + return $this->version($this->_get_migration_number($last_migration)); } // -------------------------------------------------------------------- @@ -300,7 +298,7 @@ class CI_Migration { /** * Set's the schema to the migration version set in config * - * @return mixed true if already current, false if failed, int if upgraded + * @return mixed TRUE if already current, FALSE if failed, int if upgraded */ public function current() { @@ -326,22 +324,62 @@ class CI_Migration { * * @return array list of migration file paths sorted by version */ - protected function find_migrations() + public function find_migrations() { - // Load all *_*.php files in the migrations path - $files = glob($this->_migration_path.'*_*.php'); + $migrations = array(); - for ($i = 0, $c = count($files); $i < $c; $i++) + // Load all *_*.php files in the migrations path + foreach (glob($this->_migration_path.'*_*.php') as $file) { - // Mark wrongly formatted files as false for later filtering - if ( ! preg_match('/^\d{3}_(\w+)$/', basename($files[$i], '.php'))) + $name = basename($file, '.php'); + + // Filter out non-migration files + if (preg_match($this->_migration_regex, $name)) { - $files[$i] = FALSE; + $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; } } - sort($files); - return $files; + ksort($migrations); + return $migrations; + } + + // -------------------------------------------------------------------- + + /** + * Extracts the migration number from a filename + * + * @param string $migration + * @return int Numeric portion of a migration filename + */ + protected function _get_migration_number($migration) + { + return sscanf($migration, '%d', $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); } // -------------------------------------------------------------------- @@ -362,13 +400,13 @@ class CI_Migration { /** * Stores the current schema version * - * @param int Migration reached + * @param int $migration Migration reached * @return void Outputs a report of the migration */ - protected function _update_version($migrations) + protected function _update_version($migration) { return $this->db->update($this->_migration_table, array( - 'version' => $migrations + 'version' => $migration )); } @@ -377,7 +415,7 @@ class CI_Migration { /** * Enable the use of CI super-global * - * @param $var + * @param string $var * @return mixed */ public function __get($var) diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index 75745dd48..66b341760 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Pagination Class @@ -36,45 +37,269 @@ */ class CI_Pagination { - protected $base_url = ''; // The page we are linking to - protected $prefix = ''; // A custom prefix added to the path. - protected $suffix = ''; // A custom suffix added to the path. - protected $total_rows = 0; // Total number of items (database results) - protected $per_page = 10; // Max number of items you want shown per page - protected $num_links = 2; // Number of "digit" links to show before/after the currently viewed page - protected $cur_page = 0; // The current page being viewed - protected $use_page_numbers = FALSE; // Use page number for segment instead of offset - protected $first_link = '‹ First'; - protected $next_link = '>'; - protected $prev_link = '<'; - protected $last_link = 'Last ›'; - protected $uri_segment = 3; - protected $full_tag_open = ''; - protected $full_tag_close = ''; - protected $first_tag_open = ''; - protected $first_tag_close = ' '; - protected $last_tag_open = ' '; - protected $last_tag_close = ''; - protected $first_url = ''; // Alternative URL for the First Page. - protected $cur_tag_open = ' <strong>'; - protected $cur_tag_close = '</strong>'; - protected $next_tag_open = ' '; - protected $next_tag_close = ' '; - protected $prev_tag_open = ' '; - protected $prev_tag_close = ''; - protected $num_tag_open = ' '; - protected $num_tag_close = ''; + /** + * 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; + + /** + * Items per page + * + * @var int + */ + protected $per_page = 10; + + /** + * Number of links to show + * + * Relates to "digit" type links shown before/after + * the currently viewed page. + * + * @var int + */ + protected $num_links = 2; + + /** + * Current page + * + * @var int + */ + protected $cur_page = 0; + + /** + * Use page numbers flag + * + * Whether to use actual page numbers instead of an offset + * + * @var bool + */ + protected $use_page_numbers = FALSE; + + /** + * First link + * + * @var string + */ + protected $first_link = '‹ First'; + + /** + * Next link + * + * @var string + */ + protected $next_link = '>'; + + /** + * Previous link + * + * @var string + */ + protected $prev_link = '<'; + + /** + * Last link + * + * @var string + */ + protected $last_link = 'Last ›'; + + /** + * URI Segment + * + * @var int + */ + protected $uri_segment = 3; + + /** + * 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; - protected $query_string_segment = 'per_page'; - protected $display_pages = TRUE; - protected $_attributes = ''; - protected $_link_types = array(); + + /** + * 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; /** + * Data page attribute + * + * @var string + */ + protected $data_page_attr = 'data-ci-pagination-page'; + + // -------------------------------------------------------------------- + + /** * Constructor * - * @param array initialization parameters + * @param array $params Initialization parameters * @return void */ public function __construct($params = array()) @@ -88,7 +313,7 @@ class CI_Pagination { /** * Initialize Preferences * - * @param array initialization parameters + * @param array $params Initialization parameters * @return void */ public function initialize($params = array()) @@ -156,7 +381,7 @@ class CI_Pagination { // See if we are using a prefix or suffix on links if ($this->prefix !== '' OR $this->suffix !== '') { - $this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->segment($this->uri_segment)); + $this->cur_page = (int) str_replace(array($this->prefix, $this->suffix), '', $CI->uri->rsegment($this->uri_segment)); } if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) @@ -168,7 +393,7 @@ class CI_Pagination { } elseif ( ! $this->cur_page && $CI->uri->segment($this->uri_segment) !== $base_page) { - $this->cur_page = (int) $CI->uri->segment($this->uri_segment); + $this->cur_page = (int) $CI->uri->rsegment($this->uri_segment); } // Set current page to 1 if it's not valid or if using page numbers instead of offset @@ -202,7 +427,7 @@ class CI_Pagination { if ( ! $this->use_page_numbers) { - $this->cur_page = floor(($this->cur_page/$this->per_page) + 1); + $this->cur_page = (int) floor(($this->cur_page/$this->per_page) + 1); } // Calculate the start and end numbers. These determine @@ -214,7 +439,8 @@ class CI_Pagination { // string. If post, add a trailing slash to the base URL if needed if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) { - $this->base_url = rtrim($this->base_url).'&'.$this->query_string_segment.'='; + $segment = (strpos($this->base_url, '?')) ? '&' : '?'; + $this->base_url = rtrim($this->base_url).$segment.$this->query_string_segment.'='; } else { @@ -230,22 +456,30 @@ class CI_Pagination { if ($this->reuse_query_string === TRUE) { $get = $CI->input->get(); - + // Unset the controll, method, old-school routing options unset($get['c'], $get['m'], $get[$this->query_string_segment]); - // Put everything else onto the end - $query_string = (strpos($this->base_url, '&') !== FALSE ? '&' : '?') . http_build_query($get, '', '&'); + if ( ! empty($get)) + { + // Put everything else onto the end + $query_string = (strpos($this->base_url, '?') !== FALSE ? '&' : '?') + .http_build_query($get, '', '&'); - // Add this after the suffix to put it into more links easily - $this->suffix .= $query_string; + // Add this after the suffix to put it into more links easily + $this->suffix .= $query_string; + } } // Render the "First" link if ($this->first_link !== FALSE && $this->cur_page > ($this->num_links + 1)) { $first_url = ($this->first_url === '') ? $this->base_url : $this->first_url; - $output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$this->_attributes.$this->_attr_rel('start').'>' + + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $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; } @@ -254,15 +488,18 @@ class CI_Pagination { { $i = ($this->use_page_numbers) ? $uri_page_number - 1 : $uri_page_number - $this->per_page; + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + if ($i === $base_page && $this->first_url !== '') { - $output .= $this->prev_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$this->_attributes.$this->_attr_rel('prev').'>' + $output .= $this->prev_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$attributes.$this->_attr_rel('prev').'>' .$this->prev_link.'</a>'.$this->prev_tag_close; } else { $append = ($i === $base_page) ? $query_string : $this->prefix.$i.$this->suffix; - $output .= $this->prev_tag_open.'<a href="'.$this->base_url.$append.'"'.$this->_attributes.$this->_attr_rel('prev').'>' + $output .= $this->prev_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>' .$this->prev_link.'</a>'.$this->prev_tag_close; } @@ -275,6 +512,10 @@ class CI_Pagination { for ($loop = $start -1; $loop <= $end; $loop++) { $i = ($this->use_page_numbers) ? $loop : ($loop * $this->per_page) - $this->per_page; + + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + if ($i >= $base_page) { if ($this->cur_page === $loop) @@ -286,13 +527,13 @@ class CI_Pagination { $n = ($i === $base_page) ? '' : $i; if ($n === '' && ! empty($this->first_url)) { - $output .= $this->num_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$this->_attributes.$this->_attr_rel('start').'>' + $output .= $this->num_tag_open.'<a href="'.$this->first_url.$query_string.'"'.$attributes.$this->_attr_rel('start').'>' .$loop.'</a>'.$this->num_tag_close; } else { $append = ($n === '') ? $query_string : $this->prefix.$n.$this->suffix; - $output .= $this->num_tag_open.'<a href="'.$this->base_url.$append.'"'.$this->_attributes.$this->_attr_rel('start').'>' + $output .= $this->num_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('start').'>' .$loop.'</a>'.$this->num_tag_close; } } @@ -305,7 +546,10 @@ class CI_Pagination { { $i = ($this->use_page_numbers) ? $this->cur_page + 1 : $this->cur_page * $this->per_page; - $output .= $this->next_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$this->_attributes + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + + $output .= $this->next_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$attributes .$this->_attr_rel('next').'>'.$this->next_link.'</a>'.$this->next_tag_close; } @@ -314,7 +558,10 @@ class CI_Pagination { { $i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page; - $output .= $this->last_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$this->_attributes.'>' + // Take the general parameters, and squeeze this pagination-page attr in there for JS fw's + $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, (int) $i); + + $output .= $this->last_tag_open.'<a href="'.$this->base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>' .$this->last_link.'</a>'.$this->last_tag_close; } @@ -331,7 +578,7 @@ class CI_Pagination { /** * Parse attributes * - * @param array + * @param array $attributes * @return void */ protected function _parse_attributes($attributes) @@ -355,7 +602,7 @@ class CI_Pagination { * Add "rel" attribute * * @link http://www.w3.org/TR/html5/links.html#linkTypes - * @param string + * @param string $type * @return string */ protected function _attr_rel($type) diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php index b64c78254..faa94b7c9 100644 --- a/system/libraries/Parser.php +++ b/system/libraries/Parser.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Parser Class @@ -57,6 +58,20 @@ class CI_Parser { */ protected $CI; + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @return void + */ + public function __construct() + { + $this->CI =& get_instance(); + } + + // -------------------------------------------------------------------- + /** * Parse a template * @@ -70,7 +85,6 @@ class CI_Parser { */ public function parse($template, $data, $return = FALSE) { - $this->CI =& get_instance(); $template = $this->CI->load->view($template, $data, TRUE); return $this->_parse($template, $data, $return); diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php index 1e961f6df..1c97e3481 100644 --- a/system/libraries/Profiler.php +++ b/system/libraries/Profiler.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * CodeIgniter Profiler Class @@ -74,12 +75,14 @@ class CI_Profiler { */ protected $CI; + // -------------------------------------------------------------------- + /** - * Constructor + * Class constructor * * Initialize Profiler * - * @param array $config + * @param array $config Parameters */ public function __construct($config = array()) { @@ -111,7 +114,7 @@ class CI_Profiler { * * Sets the private _compile_* properties to enable/disable Profiler sections * - * @param mixed + * @param mixed $config * @return void */ public function set_sections($config) @@ -190,11 +193,24 @@ class CI_Profiler { $dbs = array(); // Let's determine which databases are currently connected to - foreach (get_object_vars($this->CI) as $CI_object) + foreach (get_object_vars($this->CI) as $name => $cobject) { - if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB')) + if (is_object($cobject)) { - $dbs[] = $CI_object; + 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; + } + } + } } } @@ -219,7 +235,7 @@ class CI_Profiler { $output = "\n\n"; $count = 0; - foreach ($dbs as $db) + foreach ($dbs as $name => $db) { $hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : ''; @@ -233,7 +249,7 @@ class CI_Profiler { $output .= '<fieldset style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">' ."\n" .'<legend style="color:#0000FF;"> '.$this->CI->lang->line('profiler_database') - .': '.$db->database.' '.$this->CI->lang->line('profiler_queries') + .': '.$db->database.' ('.$name.') '.$this->CI->lang->line('profiler_queries') .': '.count($db->queries).' '.$show_hide_js."</legend>\n\n\n" .'<table style="width:100%;'.$hide_queries.'" id="ci_profiler_queries_db_'.$count."\">\n"; diff --git a/system/libraries/Session.php b/system/libraries/Session.php deleted file mode 100644 index af38dc366..000000000 --- a/system/libraries/Session.php +++ /dev/null @@ -1,955 +0,0 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); -/** - * CodeIgniter - * - * An open source application development framework for PHP 5.2.4 or newer - * - * NOTICE OF LICENSE - * - * Licensed under the Open Software License version 3.0 - * - * This source file is subject to the Open Software License (OSL 3.0) that is - * bundled with this package in the files license.txt / license.rst. It is - * also available through the world wide web at this URL: - * http://opensource.org/licenses/OSL-3.0 - * If you did not receive a copy of the license and are unable to obtain it - * through the world wide web, please send an email to - * licensing@ellislab.com so we can send you a copy immediately. - * - * @package CodeIgniter - * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) - * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) - * @link http://codeigniter.com - * @since Version 1.0 - * @filesource - */ - -/** - * Session Class - * - * @package CodeIgniter - * @subpackage Libraries - * @category Sessions - * @author EllisLab Dev Team - * @link http://codeigniter.com/user_guide/libraries/sessions.html - */ -class CI_Session { - - /** - * Whether to encrypt the session cookie - * - * @var bool - */ - public $sess_encrypt_cookie = FALSE; - - /** - * Whether to use to the database for session storage - * - * @var bool - */ - public $sess_use_database = FALSE; - - /** - * Name of the database table in which to store sessions - * - * @var string - */ - public $sess_table_name = ''; - - /** - * Length of time (in seconds) for sessions to expire - * - * @var int - */ - public $sess_expiration = 7200; - - /** - * Whether to kill session on close of browser window - * - * @var bool - */ - public $sess_expire_on_close = FALSE; - - /** - * Whether to match session on ip address - * - * @var bool - */ - public $sess_match_ip = FALSE; - - /** - * Whether to match session on user-agent - * - * @var bool - */ - public $sess_match_useragent = TRUE; - - /** - * Name of session cookie - * - * @var string - */ - public $sess_cookie_name = 'ci_session'; - - /** - * Session cookie prefix - * - * @var string - */ - public $cookie_prefix = ''; - - /** - * Session cookie path - * - * @var string - */ - public $cookie_path = ''; - - /** - * Session cookie domain - * - * @var string - */ - public $cookie_domain = ''; - - /** - * Whether to set the cookie only on HTTPS connections - * - * @var bool - */ - public $cookie_secure = FALSE; - - /** - * Whether cookie should be allowed only to be sent by the server - * - * @var bool - */ - public $cookie_httponly = FALSE; - - /** - * Interval at which to update session - * - * @var int - */ - public $sess_time_to_update = 300; - - /** - * Key with which to encrypt the session cookie - * - * @var string - */ - public $encryption_key = ''; - - /** - * String to indicate flash data cookies - * - * @var string - */ - public $flashdata_key = 'flash'; - - /** - * Timezone to use for the current time - * - * @var string - */ - public $time_reference = 'local'; - - - /** - * Session data - * - * @var array - */ - public $userdata = array(); - - /** - * Reference to CodeIgniter instance - * - * @var object - */ - public $CI; - - /** - * Current time - * - * @var int - */ - public $now; - - /** - * Session Constructor - * - * The constructor runs the session routines automatically - * whenever the class is instantiated. - * - * @param array - * @return void - */ - public function __construct($params = array()) - { - log_message('debug', 'Session Class Initialized'); - - // Set the super object to a local variable for use throughout the class - $this->CI =& get_instance(); - - // Set all the session preferences, which can either be set - // manually via the $params array above or via the config file - foreach (array('sess_encrypt_cookie', 'sess_use_database', 'sess_table_name', 'sess_expiration', 'sess_expire_on_close', 'sess_match_ip', 'sess_match_useragent', 'sess_cookie_name', 'cookie_path', 'cookie_domain', 'cookie_secure', 'cookie_httponly', 'sess_time_to_update', 'time_reference', 'cookie_prefix', 'encryption_key') as $key) - { - $this->$key = isset($params[$key]) ? $params[$key] : $this->CI->config->item($key); - } - - if ($this->encryption_key === '') - { - show_error('In order to use the Session class you are required to set an encryption key in your config file.'); - } - - // Load the string helper so we can use the strip_slashes() function - $this->CI->load->helper('string'); - - // Do we need encryption? If so, load the encryption class - if ($this->sess_encrypt_cookie === TRUE) - { - $this->CI->load->library('encrypt'); - } - - // Are we using a database? If so, load it - if ($this->sess_use_database === TRUE && $this->sess_table_name !== '') - { - $this->CI->load->database(); - } - - // Set the "now" time. Can either be GMT or server time, based on the - // config prefs. We use this to set the "last activity" time - $this->now = $this->_get_time(); - - // Set the session length. If the session expiration is - // set to zero we'll set the expiration two years from now. - if ($this->sess_expiration === 0) - { - $this->sess_expiration = (60*60*24*365*2); - } - - // Set the cookie name - $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; - - // Run the Session routine. If a session doesn't exist we'll - // create a new one. If it does, we'll update it. - if ( ! $this->sess_read()) - { - $this->sess_create(); - } - else - { - $this->sess_update(); - } - - // Delete 'old' flashdata (from last request) - $this->_flashdata_sweep(); - - // Mark all new flashdata as old (data will be deleted before next request) - $this->_flashdata_mark(); - - // Delete expired sessions if necessary - $this->_sess_gc(); - - log_message('debug', 'Session routines successfully run'); - } - - // -------------------------------------------------------------------- - - /** - * Fetch the current session data if it exists - * - * @return bool - */ - public function sess_read() - { - // Fetch the cookie - $session = $this->CI->input->cookie($this->sess_cookie_name); - - // No cookie? Goodbye cruel world!... - if ($session === NULL) - { - log_message('debug', 'A session cookie was not found.'); - return FALSE; - } - - // Decrypt the cookie data - if ($this->sess_encrypt_cookie === TRUE) - { - $session = $this->CI->encrypt->decode($session); - } - else - { - // encryption was not used, so we need to check the md5 hash - $hash = substr($session, strlen($session)-32); // get last 32 chars - $session = substr($session, 0, strlen($session)-32); - - // Does the md5 hash match? This is to prevent manipulation of session data in userspace - if ($hash !== md5($session.$this->encryption_key)) - { - log_message('error', 'The session cookie data did not match what was expected. This could be a possible hacking attempt.'); - $this->sess_destroy(); - return FALSE; - } - } - - // Unserialize the session array - $session = $this->_unserialize($session); - - // Is the session data we unserialized an array with the correct format? - if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity'])) - { - $this->sess_destroy(); - return FALSE; - } - - // Is the session current? - if (($session['last_activity'] + $this->sess_expiration) < $this->now) - { - $this->sess_destroy(); - return FALSE; - } - - // Does the IP match? - if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address()) - { - $this->sess_destroy(); - return FALSE; - } - - // Does the User Agent Match? - if ($this->sess_match_useragent === TRUE && trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120))) - { - $this->sess_destroy(); - return FALSE; - } - - // Is there a corresponding session in the DB? - if ($this->sess_use_database === TRUE) - { - $this->CI->db->where('session_id', $session['session_id']); - - if ($this->sess_match_ip === TRUE) - { - $this->CI->db->where('ip_address', $session['ip_address']); - } - - if ($this->sess_match_useragent === TRUE) - { - $this->CI->db->where('user_agent', $session['user_agent']); - } - - $query = $this->CI->db->limit(1)->get($this->sess_table_name); - - // No result? Kill it! - if ($query->num_rows() === 0) - { - $this->sess_destroy(); - return FALSE; - } - - // Is there custom data? If so, add it to the main session array - $row = $query->row(); - if ( ! empty($row->user_data)) - { - $custom_data = $this->_unserialize($row->user_data); - - if (is_array($custom_data)) - { - foreach ($custom_data as $key => $val) - { - $session[$key] = $val; - } - } - } - } - - // Session is valid! - $this->userdata = $session; - unset($session); - - return TRUE; - } - - // -------------------------------------------------------------------- - - /** - * Write the session data - * - * @return void - */ - public function sess_write() - { - // Are we saving custom data to the DB? If not, all we do is update the cookie - if ($this->sess_use_database === FALSE) - { - $this->_set_cookie(); - return; - } - - // set the custom userdata, the session data we will set in a second - $custom_userdata = $this->userdata; - $cookie_userdata = array(); - - // Before continuing, we need to determine if there is any custom data to deal with. - // Let's determine this by removing the default indexes to see if there's anything left in the array - // and set the session data while we're at it - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - unset($custom_userdata[$val]); - $cookie_userdata[$val] = $this->userdata[$val]; - } - - // Did we find any custom data? If not, we turn the empty array into a string - // since there's no reason to serialize and store an empty array in the DB - if (count($custom_userdata) === 0) - { - $custom_userdata = ''; - } - else - { - // Serialize the custom data array so we can store it - $custom_userdata = $this->_serialize($custom_userdata); - } - - // Run the update query - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->update($this->sess_table_name, array('last_activity' => $this->userdata['last_activity'], 'user_data' => $custom_userdata)); - - // Write the cookie. Notice that we manually pass the cookie data array to the - // _set_cookie() function. Normally that function will store $this->userdata, but - // in this case that array contains custom data, which we do not want in the cookie. - $this->_set_cookie($cookie_userdata); - } - - // -------------------------------------------------------------------- - - /** - * Create a new session - * - * @return void - */ - public function sess_create() - { - $sessid = ''; - do - { - $sessid .= mt_rand(0, mt_getrandmax()); - } - while (strlen($sessid) < 32); - - // To make the session ID even more secure we'll combine it with the user's IP - $sessid .= $this->CI->input->ip_address(); - - $this->userdata = array( - 'session_id' => md5(uniqid($sessid, TRUE)), - 'ip_address' => $this->CI->input->ip_address(), - 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), - 'last_activity' => $this->now, - 'user_data' => '' - ); - - // Save the data to the DB if needed - if ($this->sess_use_database === TRUE) - { - $this->CI->db->query($this->CI->db->insert_string($this->sess_table_name, $this->userdata)); - } - - // Write the cookie - $this->_set_cookie(); - } - - // -------------------------------------------------------------------- - - /** - * Update an existing session - * - * @return void - */ - public function sess_update() - { - // We only update the session every five minutes by default - if (($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) - { - return; - } - - // _set_cookie() will handle this for us if we aren't using database sessions - // by pushing all userdata to the cookie. - $cookie_data = NULL; - - /* Changing the session ID during an AJAX call causes problems, - * so we'll only update our last_activity - */ - if ($this->CI->input->is_ajax_request()) - { - $this->userdata['last_activity'] = $this->now; - - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } - - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, - array('last_activity' => $this->userdata['last_activity']), - array('session_id' => $this->userdata['session_id']))); - } - - return $this->_set_cookie($cookie_data); - } - - // Save the old session id so we know which record to - // update in the database if we need it - $old_sessid = $this->userdata['session_id']; - $new_sessid = ''; - do - { - $new_sessid .= mt_rand(0, mt_getrandmax()); - } - while (strlen($new_sessid) < 32); - - // To make the session ID even more secure we'll combine it with the user's IP - $new_sessid .= $this->CI->input->ip_address(); - - // Turn it into a hash and update the session data array - $this->userdata['session_id'] = $new_sessid = md5(uniqid($new_sessid, TRUE)); - $this->userdata['last_activity'] = $this->now; - - // Update the session ID and last_activity field in the DB if needed - if ($this->sess_use_database === TRUE) - { - // set cookie explicitly to only have our session data - $cookie_data = array(); - foreach (array('session_id','ip_address','user_agent','last_activity') as $val) - { - $cookie_data[$val] = $this->userdata[$val]; - } - - $this->CI->db->query($this->CI->db->update_string($this->sess_table_name, array('last_activity' => $this->now, 'session_id' => $new_sessid), array('session_id' => $old_sessid))); - } - - // Write the cookie - $this->_set_cookie($cookie_data); - } - - // -------------------------------------------------------------------- - - /** - * Destroy the current session - * - * @return void - */ - public function sess_destroy() - { - // Kill the session DB row - if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) - { - $this->CI->db->where('session_id', $this->userdata['session_id']); - $this->CI->db->delete($this->sess_table_name); - } - - // Kill the cookie - setcookie( - $this->sess_cookie_name, - addslashes(serialize(array())), - ($this->now - 31500000), - $this->cookie_path, - $this->cookie_domain, - 0 - ); - - // Kill session data - $this->userdata = array(); - } - - // -------------------------------------------------------------------- - - /** - * Fetch a specific item from the session array - * - * @param string - * @return string - */ - public function userdata($item) - { - return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL; - } - - // -------------------------------------------------------------------- - - /** - * Fetch all session data - * - * @return array - */ - public function all_userdata() - { - return $this->userdata; - } - - // -------------------------------------------------------------------------- - - /** - * Fetch all flashdata - * - * @return array - */ - public function all_flashdata() - { - $out = array(); - - // loop through all userdata - foreach ($this->all_userdata() as $key => $val) - { - // if it contains flashdata, add it - if (strpos($key, 'flash:old:') !== FALSE) - { - $out[$key] = $val; - } - } - return $out; - } - - // -------------------------------------------------------------------- - - /** - * Add or change data in the "userdata" array - * - * @param mixed - * @param string - * @return void - */ - public function set_userdata($newdata = array(), $newval = '') - { - if (is_string($newdata)) - { - $newdata = array($newdata => $newval); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - $this->userdata[$key] = $val; - } - } - - $this->sess_write(); - } - - // -------------------------------------------------------------------- - - /** - * Delete a session variable from the "userdata" array - * - * @param array - * @return void - */ - public function unset_userdata($newdata = array()) - { - if (is_string($newdata)) - { - $newdata = array($newdata => ''); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - unset($this->userdata[$key]); - } - } - - $this->sess_write(); - } - - // ------------------------------------------------------------------------ - - /** - * Add or change flashdata, only available - * until the next request - * - * @param mixed - * @param string - * @return void - */ - public function set_flashdata($newdata = array(), $newval = '') - { - if (is_string($newdata)) - { - $newdata = array($newdata => $newval); - } - - if (count($newdata) > 0) - { - foreach ($newdata as $key => $val) - { - $this->set_userdata($this->flashdata_key.':new:'.$key, $val); - } - } - } - - // ------------------------------------------------------------------------ - - /** - * Keeps existing flashdata available to next request. - * - * @param string - * @return void - */ - public function keep_flashdata($key) - { - // 'old' flashdata gets removed. Here we mark all - // flashdata as 'new' to preserve it from _flashdata_sweep() - // Note the function will return NULL if the $key - // provided cannot be found - $value = $this->userdata($this->flashdata_key.':old:'.$key); - - $this->set_userdata($this->flashdata_key.':new:'.$key, $value); - } - - // ------------------------------------------------------------------------ - - /** - * Fetch a specific flashdata item from the session array - * - * @param string - * @return string - */ - public function flashdata($key) - { - return $this->userdata($this->flashdata_key.':old:'.$key); - } - - // ------------------------------------------------------------------------ - - /** - * Identifies flashdata as 'old' for removal - * when _flashdata_sweep() runs. - * - * @return void - */ - protected function _flashdata_mark() - { - $userdata = $this->all_userdata(); - foreach ($userdata as $name => $value) - { - $parts = explode(':new:', $name); - if (is_array($parts) && count($parts) === 2) - { - $this->set_userdata($this->flashdata_key.':old:'.$parts[1], $value); - $this->unset_userdata($name); - } - } - } - - // ------------------------------------------------------------------------ - - /** - * Removes all flashdata marked as 'old' - * - * @return void - */ - protected function _flashdata_sweep() - { - $userdata = $this->all_userdata(); - foreach ($userdata as $key => $value) - { - if (strpos($key, ':old:')) - { - $this->unset_userdata($key); - } - } - - } - - // -------------------------------------------------------------------- - - /** - * Get the "now" time - * - * @return string - */ - protected function _get_time() - { - if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get()) - { - return time(); - } - - $datetime = new DateTime('now', new DateTimeZone($this->time_reference)); - sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second); - - return mktime($hour, $minute, $second, $month, $day, $year); - } - - // -------------------------------------------------------------------- - - /** - * Write the session cookie - * - * @param mixed - * @return void - */ - protected function _set_cookie($cookie_data = NULL) - { - if (is_null($cookie_data)) - { - $cookie_data = $this->userdata; - } - - // Serialize the userdata for the cookie - $cookie_data = $this->_serialize($cookie_data); - - if ($this->sess_encrypt_cookie === TRUE) - { - $cookie_data = $this->CI->encrypt->encode($cookie_data); - } - else - { - // if encryption is not used, we provide an md5 hash to prevent userside tampering - $cookie_data = $cookie_data.md5($cookie_data.$this->encryption_key); - } - - $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); - - // Set the cookie - setcookie( - $this->sess_cookie_name, - $cookie_data, - $expire, - $this->cookie_path, - $this->cookie_domain, - $this->cookie_secure, - $this->cookie_httponly - ); - } - - // -------------------------------------------------------------------- - - /** - * Serialize an array - * - * This function first converts any slashes found in the array to a temporary - * marker, so when it gets unserialized the slashes will be preserved - * - * @param array - * @return string - */ - protected function _serialize($data) - { - if (is_array($data)) - { - array_walk_recursive($data, array(&$this, '_escape_slashes')); - } - elseif (is_string($data)) - { - $data = str_replace('\\', '{{slash}}', $data); - } - return serialize($data); - } - - /** - * Escape slashes - * - * This function converts any slashes found into a temporary marker - * - * @param string - * @param string - * @return void - */ - protected function _escape_slashes(&$val, $key) - { - if (is_string($val)) - { - $val = str_replace('\\', '{{slash}}', $val); - } - } - - // -------------------------------------------------------------------- - - /** - * Unserialize - * - * This function unserializes a data string, then converts any - * temporary slash markers back to actual slashes - * - * @param array - * @return string - */ - protected function _unserialize($data) - { - $data = @unserialize(strip_slashes(trim($data))); - - if (is_array($data)) - { - array_walk_recursive($data, array(&$this, '_unescape_slashes')); - return $data; - } - - return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data; - } - - // -------------------------------------------------------------------- - - /** - * Unescape slashes - * - * This function converts any slash markers back into actual slashes - * - * @param string - * @param string - * @return void - */ - protected function _unescape_slashes(&$val, $key) - { - if (is_string($val)) - { - $val= str_replace('{{slash}}', '\\', $val); - } - } - - // -------------------------------------------------------------------- - - /** - * Garbage collection - * - * This deletes expired session rows from database - * if the probability percentage is met - * - * @return void - */ - protected function _sess_gc() - { - if ($this->sess_use_database !== TRUE) - { - return; - } - - $probability = ini_get('session.gc_probability'); - $divisor = ini_get('session.gc_divisor'); - - srand(time()); - if ((mt_rand(0, $divisor) / $divisor) < $probability) - { - $expire = $this->now - $this->sess_expiration; - - $this->CI->db->where('last_activity < '.$expire); - $this->CI->db->delete($this->sess_table_name); - - log_message('debug', 'Session garbage collection performed.'); - } - } - -} - -/* End of file Session.php */ -/* Location: ./system/libraries/Session.php */
\ No newline at end of file diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php new file mode 100644 index 000000000..85a483592 --- /dev/null +++ b/system/libraries/Session/Session.php @@ -0,0 +1,753 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 2.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * CodeIgniter Session Class + * + * The user interface defined by EllisLabs, now with puggable drivers to manage different storage mechanisms. + * By default, the cookie session driver will load, but the 'sess_driver' config/param item (see above) can be + * used to specify the 'native' driver, or any other you might create. + * Once loaded, this driver setup is a drop-in replacement for the former CI_Session library, taking its place as the + * 'session' member of the global controller framework (e.g.: $CI->session or $this->session). + * In keeping with the CI_Driver methodology, multiple drivers may be loaded, although this might be a bit confusing. + * The CI_Session library class keeps track of the most recently loaded driver as "current" to call for driver methods. + * Ideally, one driver is loaded and all calls go directly through the main library interface. However, any methods + * called through the specific driver will switch the "current" driver to itself before invoking the library method + * (which will then call back into the driver for low-level operations). So, alternation between two drivers can be + * achieved by specifying which driver to use for each call (e.g.: $this->session->native->set_userdata('foo', 'bar'); + * $this->session->cookie->userdata('foo'); $this->session->native->unset_userdata('foo');). Notice in the previous + * example that the _native_ userdata value 'foo' would be set to 'bar', which would NOT be returned by the call for + * the _cookie_ userdata 'foo', nor would the _cookie_ value be unset by the call to unset the _native_ 'foo' value. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/libraries/sessions.html + */ +class CI_Session extends CI_Driver_Library { + + /** + * Initialization parameters + * + * @var array + */ + public $params = array(); + + /** + * Current driver in use + * + * @var string + */ + protected $current = NULL; + + /** + * User data + * + * @var array + */ + protected $userdata = array(); + + // ------------------------------------------------------------------------ + + const FLASHDATA_KEY = 'flash'; + const FLASHDATA_NEW = ':new:'; + const FLASHDATA_OLD = ':old:'; + const FLASHDATA_EXP = ':exp:'; + const EXPIRATION_KEY = '__expirations'; + const TEMP_EXP_DEF = 300; + + // ------------------------------------------------------------------------ + + /** + * CI_Session constructor + * + * The constructor loads the configured driver ('sess_driver' in config.php or as a parameter), running + * routines in its constructor, and manages flashdata aging. + * + * @param array Configuration parameters + * @return void + */ + public function __construct(array $params = array()) + { + $CI =& get_instance(); + + // No sessions under CLI + if ($CI->input->is_cli_request()) + { + return; + } + + log_message('debug', 'CI_Session Class Initialized'); + + // Get valid drivers list + $this->valid_drivers = array( + 'native', + 'cookie' + ); + $key = 'sess_valid_drivers'; + $drivers = isset($params[$key]) ? $params[$key] : $CI->config->item($key); + if ($drivers) + { + // Add driver names to valid list + foreach ((array) $drivers as $driver) + { + if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers))) + { + $this->valid_drivers[] = $driver; + } + } + } + + // Get driver to load + $key = 'sess_driver'; + $driver = isset($params[$key]) ? $params[$key] : $CI->config->item($key); + if ( ! $driver) + { + $driver = 'cookie'; + } + + if ( ! in_array(strtolower($driver), array_map('strtolower', $this->valid_drivers))) + { + $this->valid_drivers[] = $driver; + } + + // Save a copy of parameters in case drivers need access + $this->params = $params; + + // Load driver and get array reference + $this->load_driver($driver); + + // Delete 'old' flashdata (from last request) + $this->_flashdata_sweep(); + + // Mark all new flashdata as old (data will be deleted before next request) + $this->_flashdata_mark(); + + // Delete expired tempdata + $this->_tempdata_sweep(); + + log_message('debug', 'CI_Session routines successfully run'); + } + + // ------------------------------------------------------------------------ + + /** + * Loads session storage driver + * + * @param string Driver classname + * @return object Loaded driver object + */ + public function load_driver($driver) + { + // Save reference to most recently loaded driver as library default and sync userdata + $this->current = parent::load_driver($driver); + $this->userdata =& $this->current->get_userdata(); + return $this->current; + } + + // ------------------------------------------------------------------------ + + /** + * Select default session storage driver + * + * @param string Driver name + * @return void + */ + public function select_driver($driver) + { + // Validate driver name + $prefix = (string) get_instance()->config->item('subclass_prefix'); + $child = strtolower(str_replace(array('CI_', $prefix, $this->lib_name.'_'), '', $driver)); + if (in_array($child, array_map('strtolower', $this->valid_drivers))) + { + // See if driver is loaded + if (isset($this->$child)) + { + // See if driver is already current + if ($this->$child !== $this->current) + { + // Make driver current and sync userdata + $this->current = $this->$child; + $this->userdata =& $this->current->get_userdata(); + } + } + else + { + // Load new driver + $this->load_driver($child); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Just call destroy on driver + $this->current->sess_destroy(); + } + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * @param bool Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = FALSE) + { + // Call regenerate on driver and resync userdata + $this->current->sess_regenerate($destroy); + $this->userdata =& $this->current->get_userdata(); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific item from the session array + * + * @param string Item key + * @return string Item value or NULL if not found + */ + public function userdata($item) + { + return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch all session data + * + * @return array User data array + */ + public function all_userdata() + { + return isset($this->userdata) ? $this->userdata : NULL; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch all flashdata + * + * @return array Flash data array + */ + public function all_flashdata() + { + $out = array(); + + // loop through all userdata + foreach ($this->all_userdata() as $key => $val) + { + // if it contains flashdata, add it + if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_OLD) !== FALSE) + { + $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_OLD, '', $key); + $out[$key] = $val; + } + } + return $out; + } + + // ------------------------------------------------------------------------ + + /** + * Add or change data in the "userdata" array + * + * @param mixed Item name or array of items + * @param string Item value or empty string + * @return void + */ + public function set_userdata($newdata = array(), $newval = '') + { + // Wrap params as array if singular + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + // Set each name/value pair + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $this->userdata[$key] = $val; + } + } + + // Tell driver data changed + $this->current->sess_save(); + } + + // ------------------------------------------------------------------------ + + /** + * Delete a session variable from the "userdata" array + * + * @param mixed Item name or array of item names + * @return void + */ + public function unset_userdata($newdata = array()) + { + // Wrap single name as array + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + // Unset each item name + if (count($newdata) > 0) + { + foreach (array_keys($newdata) as $key) + { + unset($this->userdata[$key]); + } + } + + // Tell driver data changed + $this->current->sess_save(); + } + + // ------------------------------------------------------------------------ + + /** + * Determine if an item exists + * + * @param string Item name + * @return bool + */ + public function has_userdata($item) + { + return isset($this->userdata[$item]); + } + + // ------------------------------------------------------------------------ + + /** + * Add or change flashdata, only available until the next request + * + * @param mixed Item name or array of items + * @param string Item value or empty string + * @return void + */ + public function set_flashdata($newdata = array(), $newval = '') + { + // Wrap item as array if singular + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + // Prepend each key name and set value + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key; + $this->set_userdata($flashdata_key, $val); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Keeps existing flashdata available to next request. + * + * @param mixed Item key(s) + * @return void + */ + public function keep_flashdata($key) + { + + if (is_array($key)) + { + foreach ($key as $k) + { + $this->keep_flashdata($k); + } + + return; + } + + // 'old' flashdata gets removed. Here we mark all flashdata as 'new' to preserve it from _flashdata_sweep() + // Note the function will return NULL if the $key provided cannot be found + $old_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; + $value = $this->userdata($old_flashdata_key); + + $new_flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_NEW.$key; + $this->set_userdata($new_flashdata_key, $value); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific flashdata item from the session array + * + * @param string Item key + * @return string + */ + public function flashdata($key) + { + // Prepend key and retrieve value + $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; + return $this->userdata($flashdata_key); + } + + // ------------------------------------------------------------------------ + + /** + * Add or change tempdata, only available until expiration + * + * @param mixed Item name or array of items + * @param string Item value or empty string + * @param int Item lifetime in seconds or 0 for default + * @return void + */ + public function set_tempdata($newdata = array(), $newval = '', $expire = 0) + { + // Set expiration time + $expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF); + + // Wrap item as array if singular + if (is_string($newdata)) + { + $newdata = array($newdata => $newval); + } + + // Get or create expiration list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if ( ! $expirations) + { + $expirations = array(); + } + + // Prepend each key name and set value + if (count($newdata) > 0) + { + foreach ($newdata as $key => $val) + { + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + $expirations[$tempdata_key] = $expire; + $this->set_userdata($tempdata_key, $val); + } + } + + // Update expiration list + $this->set_userdata(self::EXPIRATION_KEY, $expirations); + } + + // ------------------------------------------------------------------------ + + /** + * Delete a temporary session variable from the "userdata" array + * + * @param mixed Item name or array of item names + * @return void + */ + public function unset_tempdata($newdata = array()) + { + // Get expirations list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if (empty($expirations)) + { + // Nothing to do + return; + } + + // Wrap single name as array + if (is_string($newdata)) + { + $newdata = array($newdata => ''); + } + + // Prepend each item name and unset + if (count($newdata) > 0) + { + foreach (array_keys($newdata) as $key) + { + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + unset($expirations[$tempdata_key]); + $this->unset_userdata($tempdata_key); + } + } + + // Update expiration list + $this->set_userdata(self::EXPIRATION_KEY, $expirations); + } + + // ------------------------------------------------------------------------ + + /** + * Fetch a specific tempdata item from the session array + * + * @param string Item key + * @return string + */ + public function tempdata($key) + { + // Prepend key and return value + $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; + return $this->userdata($tempdata_key); + } + + // ------------------------------------------------------------------------ + + /** + * Identifies flashdata as 'old' for removal + * when _flashdata_sweep() runs. + * + * @return void + */ + protected function _flashdata_mark() + { + foreach ($this->all_userdata() as $name => $value) + { + $parts = explode(self::FLASHDATA_NEW, $name); + if (count($parts) === 2) + { + $new_name = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1]; + $this->set_userdata($new_name, $value); + $this->unset_userdata($name); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Removes all flashdata marked as 'old' + * + * @return void + */ + protected function _flashdata_sweep() + { + $userdata = $this->all_userdata(); + foreach (array_keys($userdata) as $key) + { + if (strpos($key, self::FLASHDATA_OLD)) + { + $this->unset_userdata($key); + } + } + } + + // ------------------------------------------------------------------------ + + /** + * Removes all expired tempdata + * + * @return void + */ + protected function _tempdata_sweep() + { + // Get expirations list + $expirations = $this->userdata(self::EXPIRATION_KEY); + if (empty($expirations)) + { + // Nothing to do + return; + } + + // Unset expired elements + $now = time(); + $userdata = $this->all_userdata(); + foreach (array_keys($userdata) as $key) + { + if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now) + { + unset($expirations[$key]); + $this->unset_userdata($key); + } + } + + // Update expiration list + $this->set_userdata(self::EXPIRATION_KEY, $expirations); + } + +} + +// ------------------------------------------------------------------------ + +/** + * CI_Session_driver Class + * + * Extend this class to make a new CI_Session driver. + * A CI_Session driver basically manages an array of name/value pairs with some sort of storage mechanism. + * To make a new driver, derive from (extend) CI_Session_driver. Overload the initialize method and read or create + * session data. Then implement a save handler to write changed data to storage (sess_save), a destroy handler + * to remove deleted data (sess_destroy), and an access handler to expose the data (get_userdata). + * Put your driver in the libraries/Session/drivers folder anywhere in the loader paths. This includes the + * application directory, the system directory, or any path you add with $CI->load->add_package_path(). + * Your driver must be named CI_Session_<name>, and your filename must be Session_<name>.php, + * preferably also capitalized. (e.g.: CI_Session_foo in libraries/Session/drivers/Session_foo.php) + * Then specify the driver by setting 'sess_driver' in your config file or as a parameter when loading the CI_Session + * object. (e.g.: $config['sess_driver'] = 'foo'; OR $CI->load->driver('session', array('sess_driver' => 'foo')); ) + * Already provided are the Native driver, which manages the native PHP $_SESSION array, and + * the Cookie driver, which manages the data in a browser cookie, with optional extra storage in a database table. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + */ +abstract class CI_Session_driver extends CI_Driver { + + /** + * CI Singleton + * + * @see get_instance() + * @var object + */ + protected $CI; + + // ------------------------------------------------------------------------ + + /** + * Constructor + * + * Gets the CI singleton, so that individual drivers + * don't have to do it separately. + * + * @return void + */ + public function __construct() + { + $this->CI =& get_instance(); + } + + // ------------------------------------------------------------------------ + + /** + * Decorate + * + * Decorates the child with the parent driver lib's methods and properties + * + * @param object Parent library object + * @return void + */ + public function decorate($parent) + { + // Call base class decorate first + parent::decorate($parent); + + // Call initialize method now that driver has access to $this->_parent + $this->initialize(); + } + + // ------------------------------------------------------------------------ + + /** + * __call magic method + * + * Handles access to the parent driver library's methods + * + * @param string Library method name + * @param array Method arguments (default: none) + * @return mixed + */ + public function __call($method, $args = array()) + { + // Make sure the parent library uses this driver + $this->_parent->select_driver(get_class($this)); + return parent::__call($method, $args); + } + + // ------------------------------------------------------------------------ + + /** + * Initialize driver + * + * @return void + */ + protected function initialize() + { + // Overload this method to implement initialization + } + + // ------------------------------------------------------------------------ + + /** + * Save the session data + * + * Data in the array has changed - perform any storage synchronization + * necessary. The child class MUST implement this abstract method! + * + * @return void + */ + abstract public function sess_save(); + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * Clean up storage for this session - it has been terminated. + * The child class MUST implement this abstract method! + * + * @return void + */ + abstract public function sess_destroy(); + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * Regenerate the session ID. + * The child class MUST implement this abstract method! + * + * @param bool Destroy session data flag (default: false) + * @return void + */ + abstract public function sess_regenerate($destroy = FALSE); + + // ------------------------------------------------------------------------ + + /** + * Get a reference to user data array + * + * Give array access to the main CI_Session object. + * The child class MUST implement this abstract method! + * + * @return array Reference to userdata + */ + abstract public function &get_userdata(); + +} + +/* End of file Session.php */ +/* Location: ./system/libraries/Session/Session.php */
\ No newline at end of file diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php new file mode 100644 index 000000000..9392a4dbe --- /dev/null +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -0,0 +1,845 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * Cookie-based session management driver + * + * This is the classic CI_Session functionality, as written by EllisLab, abstracted out to a driver. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + * @link http://codeigniter.com/user_guide/libraries/sessions.html + */ +class CI_Session_cookie extends CI_Session_driver { + + /** + * Whether to encrypt the session cookie + * + * @var bool + */ + public $sess_encrypt_cookie = FALSE; + + /** + * Whether to use to the database for session storage + * + * @var bool + */ + public $sess_use_database = FALSE; + + /** + * Name of the database table in which to store sessions + * + * @var string + */ + public $sess_table_name = ''; + + /** + * Length of time (in seconds) for sessions to expire + * + * @var int + */ + public $sess_expiration = 7200; + + /** + * Whether to kill session on close of browser window + * + * @var bool + */ + public $sess_expire_on_close = FALSE; + + /** + * Whether to match session on ip address + * + * @var bool + */ + public $sess_match_ip = FALSE; + + /** + * Whether to match session on user-agent + * + * @var bool + */ + public $sess_match_useragent = TRUE; + + /** + * Name of session cookie + * + * @var string + */ + public $sess_cookie_name = 'ci_session'; + + /** + * Session cookie prefix + * + * @var string + */ + public $cookie_prefix = ''; + + /** + * Session cookie path + * + * @var string + */ + public $cookie_path = ''; + + /** + * Session cookie domain + * + * @var string + */ + public $cookie_domain = ''; + + /** + * Whether to set the cookie only on HTTPS connections + * + * @var bool + */ + public $cookie_secure = FALSE; + + /** + * Whether cookie should be allowed only to be sent by the server + * + * @var bool + */ + public $cookie_httponly = FALSE; + + /** + * Interval at which to update session + * + * @var int + */ + public $sess_time_to_update = 300; + + /** + * Key with which to encrypt the session cookie + * + * @var string + */ + public $encryption_key = ''; + + /** + * Timezone to use for the current time + * + * @var string + */ + public $time_reference = 'local'; + + /** + * Session data + * + * @var array + */ + public $userdata = array(); + + /** + * Current time + * + * @var int + */ + public $now; + + /** + * Default userdata keys + * + * @var array + */ + protected $defaults = array( + 'session_id' => NULL, + 'ip_address' => NULL, + 'user_agent' => NULL, + 'last_activity' => NULL + ); + + /** + * Data needs DB update flag + * + * @var bool + */ + protected $data_dirty = FALSE; + + /** + * Initialize session driver object + * + * @return void + */ + protected function initialize() + { + // Set all the session preferences, which can either be set + // manually via the $params array or via the config file + $prefs = array( + 'sess_encrypt_cookie', + 'sess_use_database', + 'sess_table_name', + 'sess_expiration', + 'sess_expire_on_close', + 'sess_match_ip', + 'sess_match_useragent', + 'sess_cookie_name', + 'cookie_path', + 'cookie_domain', + 'cookie_secure', + 'cookie_httponly', + 'sess_time_to_update', + 'time_reference', + 'cookie_prefix', + 'encryption_key' + ); + + foreach ($prefs as $key) + { + $this->$key = isset($this->_parent->params[$key]) + ? $this->_parent->params[$key] + : $this->CI->config->item($key); + } + + if (empty($this->encryption_key)) + { + show_error('In order to use the Cookie Session driver you are required to set an encryption key in your config file.'); + } + + // Do we need encryption? If so, load the encryption class + if ($this->sess_encrypt_cookie === TRUE) + { + $this->CI->load->library('encrypt'); + } + + // Check for database + if ($this->sess_use_database === TRUE && $this->sess_table_name !== '') + { + // Load database driver + $this->CI->load->database(); + + // Register shutdown function + register_shutdown_function(array($this, '_update_db')); + } + + // Set the "now" time. Can either be GMT or server time, based on the config prefs. + // We use this to set the "last activity" time + $this->now = $this->_get_time(); + + // Set the session length. If the session expiration is + // set to zero we'll set the expiration two years from now. + if ($this->sess_expiration === 0) + { + $this->sess_expiration = (60*60*24*365*2); + } + + // Set the cookie name + $this->sess_cookie_name = $this->cookie_prefix.$this->sess_cookie_name; + + // Run the Session routine. If a session doesn't exist we'll + // create a new one. If it does, we'll update it. + if ( ! $this->_sess_read()) + { + $this->_sess_create(); + } + else + { + $this->_sess_update(); + } + + // Delete expired sessions if necessary + $this->_sess_gc(); + } + + // ------------------------------------------------------------------------ + + /** + * Write the session data + * + * @return void + */ + public function sess_save() + { + // Check for database + if ($this->sess_use_database === TRUE) + { + // Mark custom data as dirty so we know to update the DB + $this->data_dirty = TRUE; + } + + // Write the cookie + $this->_set_cookie(); + } + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Kill the session DB row + if ($this->sess_use_database === TRUE && isset($this->userdata['session_id'])) + { + $this->CI->db->delete($this->sess_table_name, array('session_id' => $this->userdata['session_id'])); + $this->data_dirty = FALSE; + } + + // Kill the cookie + $this->_setcookie($this->sess_cookie_name, '', ($this->now - 31500000), + $this->cookie_path, $this->cookie_domain, 0); + + // Kill session data + $this->userdata = array(); + } + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * Regenerate the session id + * + * @param bool Destroy session data flag (default: false) + * @return void + */ + public function sess_regenerate($destroy = FALSE) + { + // Check destroy flag + if ($destroy) + { + // Destroy old session and create new one + $this->sess_destroy(); + $this->_sess_create(); + } + else + { + // Just force an update to recreate the id + $this->_sess_update(TRUE); + } + } + + // ------------------------------------------------------------------------ + + /** + * Get a reference to user data array + * + * @return array Reference to userdata + */ + public function &get_userdata() + { + return $this->userdata; + } + + // ------------------------------------------------------------------------ + + /** + * Fetch the current session data if it exists + * + * @return bool + */ + protected function _sess_read() + { + // Fetch the cookie + $session = $this->CI->input->cookie($this->sess_cookie_name); + + // No cookie? Goodbye cruel world!... + if ($session === NULL) + { + log_message('debug', 'A session cookie was not found.'); + return FALSE; + } + + $len = strlen($session) - 40; + + if ($len < 0) + { + log_message('debug', 'The session cookie was not signed.'); + return FALSE; + } + + // Check cookie authentication + $hmac = substr($session, $len); + $session = substr($session, 0, $len); + + if ($hmac !== hash_hmac('sha1', $session, $this->encryption_key)) + { + log_message('error', 'The session cookie data did not match what was expected.'); + $this->sess_destroy(); + return FALSE; + } + + // Check for encryption + if ($this->sess_encrypt_cookie === TRUE) + { + // Decrypt the cookie data + $session = $this->CI->encrypt->decode($session); + } + + // Unserialize the session array + $session = $this->_unserialize($session); + + // Is the session data we unserialized an array with the correct format? + if ( ! is_array($session) OR ! isset($session['session_id'], $session['ip_address'], $session['user_agent'], $session['last_activity'])) + { + $this->sess_destroy(); + return FALSE; + } + + // Is the session current? + if (($session['last_activity'] + $this->sess_expiration) < $this->now OR $session['last_activity'] > $this->now) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the IP match? + if ($this->sess_match_ip === TRUE && $session['ip_address'] !== $this->CI->input->ip_address()) + { + $this->sess_destroy(); + return FALSE; + } + + // Does the User Agent Match? + if ($this->sess_match_useragent === TRUE && + trim($session['user_agent']) !== trim(substr($this->CI->input->user_agent(), 0, 120))) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there a corresponding session in the DB? + if ($this->sess_use_database === TRUE) + { + $this->CI->db->where('session_id', $session['session_id']); + + if ($this->sess_match_ip === TRUE) + { + $this->CI->db->where('ip_address', $session['ip_address']); + } + + if ($this->sess_match_useragent === TRUE) + { + $this->CI->db->where('user_agent', $session['user_agent']); + } + + // Is caching in effect? Turn it off + $db_cache = $this->CI->db->cache_on; + $this->CI->db->cache_off(); + + $query = $this->CI->db->limit(1)->get($this->sess_table_name); + + // Was caching in effect? + if ($db_cache) + { + // Turn it back on + $this->CI->db->cache_on(); + } + + // No result? Kill it! + if (empty($query) OR $query->num_rows() === 0) + { + $this->sess_destroy(); + return FALSE; + } + + // Is there custom data? If so, add it to the main session array + $row = $query->row(); + if ( ! empty($row->user_data)) + { + $custom_data = $this->_unserialize($row->user_data); + + if (is_array($custom_data)) + { + $session = $session + $custom_data; + } + } + } + + // Session is valid! + $this->userdata = $session; + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Create a new session + * + * @return void + */ + protected function _sess_create() + { + // Initialize userdata + $this->userdata = array( + 'session_id' => $this->_make_sess_id(), + 'ip_address' => $this->CI->input->ip_address(), + 'user_agent' => substr($this->CI->input->user_agent(), 0, 120), + 'last_activity' => $this->now, + ); + + // Check for database + if ($this->sess_use_database === TRUE) + { + // Add empty user_data field and save the data to the DB + $this->CI->db->set('user_data', '')->insert($this->sess_table_name, $this->userdata); + } + + // Write the cookie + $this->_set_cookie(); + } + + // ------------------------------------------------------------------------ + + /** + * Update an existing session + * + * @param bool Force update flag (default: false) + * @return void + */ + protected function _sess_update($force = FALSE) + { + // We only update the session every five minutes by default (unless forced) + if ( ! $force && ($this->userdata['last_activity'] + $this->sess_time_to_update) >= $this->now) + { + return; + } + + // Update last activity to now + $this->userdata['last_activity'] = $this->now; + + // Save the old session id so we know which DB record to update + $old_sessid = $this->userdata['session_id']; + + // Changing the session ID during an AJAX call causes problems + if ( ! $this->CI->input->is_ajax_request()) + { + // Get new id + $this->userdata['session_id'] = $this->_make_sess_id(); + } + + // Check for database + if ($this->sess_use_database === TRUE) + { + $this->CI->db->where('session_id', $old_sessid); + + if ($this->sess_match_ip === TRUE) + { + $this->CI->db->where('ip_address', $this->CI->input->ip_address()); + } + + if ($this->sess_match_useragent === TRUE) + { + $this->CI->db->where('user_agent', trim(substr($this->CI->input->user_agent(), 0, 120))); + } + + // Update the session ID and last_activity field in the DB + $this->CI->db->update($this->sess_table_name, + array( + 'last_activity' => $this->now, + 'session_id' => $this->userdata['session_id'] + ) + ); + } + + // Write the cookie + $this->_set_cookie(); + } + + // ------------------------------------------------------------------------ + + /** + * Update database with current data + * + * This gets called from the shutdown function and also + * registered with PHP to run at the end of the request + * so it's guaranteed to update even when a fatal error + * occurs. The first call makes the update and clears the + * dirty flag so it won't happen twice. + * + * @return void + */ + public function _update_db() + { + // Check for database and dirty flag and unsaved + if ($this->sess_use_database === TRUE && $this->data_dirty === TRUE) + { + // Set up activity and data fields to be set + // If we don't find custom data, user_data will remain an empty string + $set = array( + 'last_activity' => $this->userdata['last_activity'], + 'user_data' => '' + ); + + // Get the custom userdata, leaving out the defaults + // (which get stored in the cookie) + $userdata = array_diff_key($this->userdata, $this->defaults); + + // Did we find any custom data? + if ( ! empty($userdata)) + { + // Serialize the custom data array so we can store it + $set['user_data'] = $this->_serialize($userdata); + } + + // Run the update query + // Any time we change the session id, it gets updated immediately, + // so our where clause below is always safe + $this->CI->db->where('session_id', $this->userdata['session_id']); + + if ($this->sess_match_ip === TRUE) + { + $this->CI->db->where('ip_address', $this->CI->input->ip_address()); + } + + if ($this->sess_match_useragent === TRUE) + { + $this->CI->db->where('user_agent', trim(substr($this->CI->input->user_agent(), 0, 120))); + } + + $this->CI->db->update($this->sess_table_name, $set); + + // Clear dirty flag to prevent double updates + $this->data_dirty = FALSE; + + log_message('debug', 'CI_Session Data Saved To DB'); + } + } + + // ------------------------------------------------------------------------ + + /** + * Generate a new session id + * + * @return string Hashed session id + */ + protected function _make_sess_id() + { + $new_sessid = ''; + do + { + $new_sessid .= mt_rand(0, mt_getrandmax()); + } + while (strlen($new_sessid) < 32); + + // To make the session ID even more secure we'll combine it with the user's IP + $new_sessid .= $this->CI->input->ip_address(); + + // Turn it into a hash and return + return md5(uniqid($new_sessid, TRUE)); + } + + // ------------------------------------------------------------------------ + + /** + * Get the "now" time + * + * @return int Time + */ + protected function _get_time() + { + if ($this->time_reference === 'local' OR $this->time_reference === date_default_timezone_get()) + { + return time(); + } + + $datetime = new DateTime('now', new DateTimeZone($this->time_reference)); + sscanf($datetime->format('j-n-Y G:i:s'), '%d-%d-%d %d:%d:%d', $day, $month, $year, $hour, $minute, $second); + + return mktime($hour, $minute, $second, $month, $day, $year); + } + + // ------------------------------------------------------------------------ + + /** + * Write the session cookie + * + * @return void + */ + protected function _set_cookie() + { + // Get userdata (only defaults if database) + $cookie_data = ($this->sess_use_database === TRUE) + ? array_intersect_key($this->userdata, $this->defaults) + : $this->userdata; + + // Serialize the userdata for the cookie + $cookie_data = $this->_serialize($cookie_data); + + if ($this->sess_encrypt_cookie === TRUE) + { + $cookie_data = $this->CI->encrypt->encode($cookie_data); + } + + // Require message authentication + $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); + + $expire = ($this->sess_expire_on_close === TRUE) ? 0 : $this->sess_expiration + time(); + + // Set the cookie + $this->_setcookie($this->sess_cookie_name, $cookie_data, $expire, $this->cookie_path, $this->cookie_domain, + $this->cookie_secure, $this->cookie_httponly); + } + + // ------------------------------------------------------------------------ + + /** + * Set a cookie with the system + * + * This abstraction of the setcookie call allows overriding for unit testing + * + * @param string Cookie name + * @param string Cookie value + * @param int Expiration time + * @param string Cookie path + * @param string Cookie domain + * @param bool Secure connection flag + * @param bool HTTP protocol only flag + * @return void + */ + protected function _setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = FALSE, $httponly = FALSE) + { + setcookie($name, $value, $expire, $path, $domain, $secure, $httponly); + } + + // ------------------------------------------------------------------------ + + /** + * Serialize an array + * + * This function first converts any slashes found in the array to a temporary + * marker, so when it gets unserialized the slashes will be preserved + * + * @param mixed Data to serialize + * @return string Serialized data + */ + protected function _serialize($data) + { + if (is_array($data)) + { + array_walk_recursive($data, array(&$this, '_escape_slashes')); + } + elseif (is_string($data)) + { + $data = str_replace('\\', '{{slash}}', $data); + } + + return serialize($data); + } + + // ------------------------------------------------------------------------ + + /** + * Escape slashes + * + * This function converts any slashes found into a temporary marker + * + * @param string Value + * @param string Key + * @return void + */ + protected function _escape_slashes(&$val, $key) + { + if (is_string($val)) + { + $val = str_replace('\\', '{{slash}}', $val); + } + } + + // ------------------------------------------------------------------------ + + /** + * Unserialize + * + * This function unserializes a data string, then converts any + * temporary slash markers back to actual slashes + * + * @param mixed Data to unserialize + * @return mixed Unserialized data + */ + protected function _unserialize($data) + { + $data = @unserialize(trim($data)); + + if (is_array($data)) + { + array_walk_recursive($data, array(&$this, '_unescape_slashes')); + return $data; + } + + return is_string($data) ? str_replace('{{slash}}', '\\', $data) : $data; + } + + // ------------------------------------------------------------------------ + + /** + * Unescape slashes + * + * This function converts any slash markers back into actual slashes + * + * @param string Value + * @param string Key + * @return void + */ + protected function _unescape_slashes(&$val, $key) + { + if (is_string($val)) + { + $val= str_replace('{{slash}}', '\\', $val); + } + } + + // ------------------------------------------------------------------------ + + /** + * Garbage collection + * + * This deletes expired session rows from database + * if the probability percentage is met + * + * @return void + */ + protected function _sess_gc() + { + if ($this->sess_use_database !== TRUE) + { + return; + } + + $probability = ini_get('session.gc_probability'); + $divisor = ini_get('session.gc_divisor'); + + srand(time()); + if ((mt_rand(0, $divisor) / $divisor) < $probability) + { + $expire = $this->now - $this->sess_expiration; + $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire); + + log_message('debug', 'Session garbage collection performed.'); + } + } + +} + +/* End of file Session_cookie.php */ +/* Location: ./system/libraries/Session/drivers/Session_cookie.php */
\ No newline at end of file diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php new file mode 100644 index 000000000..3e700ad5d --- /dev/null +++ b/system/libraries/Session/drivers/Session_native.php @@ -0,0 +1,242 @@ +<?php +/** + * CodeIgniter + * + * An open source application development framework for PHP 5.2.4 or newer + * + * NOTICE OF LICENSE + * + * Licensed under the Open Software License version 3.0 + * + * This source file is subject to the Open Software License (OSL 3.0) that is + * bundled with this package in the files license.txt / license.rst. It is + * also available through the world wide web at this URL: + * http://opensource.org/licenses/OSL-3.0 + * If you did not receive a copy of the license and are unable to obtain it + * through the world wide web, please send an email to + * licensing@ellislab.com so we can send you a copy immediately. + * + * @package CodeIgniter + * @author EllisLab Dev Team + * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/) + * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) + * @link http://codeigniter.com + * @since Version 1.0 + * @filesource + */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +/** + * Native PHP session management driver + * + * This is the driver that uses the native PHP $_SESSION array through the Session driver library. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Sessions + * @author EllisLab Dev Team + */ +class CI_Session_native extends CI_Session_driver { + + /** + * Initialize session driver object + * + * @return void + */ + protected function initialize() + { + // Get config parameters + $config = array(); + $prefs = array( + 'sess_cookie_name', + 'sess_expire_on_close', + 'sess_expiration', + 'sess_match_ip', + 'sess_match_useragent', + 'sess_time_to_update', + 'cookie_prefix', + 'cookie_path', + 'cookie_domain', + 'cookie_secure', + 'cookie_httponly' + ); + + foreach ($prefs as $key) + { + $config[$key] = isset($this->_parent->params[$key]) + ? $this->_parent->params[$key] + : $this->CI->config->item($key); + } + + // Set session name, if specified + if ($config['sess_cookie_name']) + { + // Differentiate name from cookie driver with '_id' suffix + $name = $config['sess_cookie_name'].'_id'; + if ($config['cookie_prefix']) + { + // Prepend cookie prefix + $name = $config['cookie_prefix'].$name; + } + session_name($name); + } + + // Set expiration, path, and domain + $expire = 7200; + $path = '/'; + $domain = ''; + $secure = (bool) $config['cookie_secure']; + $http_only = (bool) $config['cookie_httponly']; + + if ($config['sess_expiration'] !== FALSE) + { + // Default to 2 years if expiration is "0" + $expire = ($config['sess_expiration'] == 0) ? (60*60*24*365*2) : $config['sess_expiration']; + } + + if ($config['cookie_path']) + { + // Use specified path + $path = $config['cookie_path']; + } + + if ($config['cookie_domain']) + { + // Use specified domain + $domain = $config['cookie_domain']; + } + + session_set_cookie_params($config['sess_expire_on_close'] ? 0 : $expire, $path, $domain, $secure, $http_only); + + // Start session + session_start(); + + // Check session expiration, ip, and agent + $now = time(); + $destroy = FALSE; + if (isset($_SESSION['last_activity']) && (($_SESSION['last_activity'] + $expire) < $now OR $_SESSION['last_activity'] > $now)) + { + // Expired - destroy + $destroy = TRUE; + } + elseif ($config['sess_match_ip'] === TRUE && isset($_SESSION['ip_address']) + && $_SESSION['ip_address'] !== $this->CI->input->ip_address()) + { + // IP doesn't match - destroy + $destroy = TRUE; + } + elseif ($config['sess_match_useragent'] === TRUE && isset($_SESSION['user_agent']) + && $_SESSION['user_agent'] !== trim(substr($this->CI->input->user_agent(), 0, 50))) + { + // Agent doesn't match - destroy + $destroy = TRUE; + } + + // Destroy expired or invalid session + if ($destroy) + { + // Clear old session and start new + $this->sess_destroy(); + session_start(); + } + + // Check for update time + if ($config['sess_time_to_update'] && isset($_SESSION['last_activity']) + && ($_SESSION['last_activity'] + $config['sess_time_to_update']) < $now) + { + // Changing the session ID amidst a series of AJAX calls causes problems + if( ! $this->CI->input->is_ajax_request()) + { + // Regenerate ID, but don't destroy session + $this->sess_regenerate(FALSE); + } + } + + // Set activity time + $_SESSION['last_activity'] = $now; + + // Set matching values as required + if ($config['sess_match_ip'] === TRUE && ! isset($_SESSION['ip_address'])) + { + // Store user IP address + $_SESSION['ip_address'] = $this->CI->input->ip_address(); + } + + if ($config['sess_match_useragent'] === TRUE && ! isset($_SESSION['user_agent'])) + { + // Store user agent string + $_SESSION['user_agent'] = trim(substr($this->CI->input->user_agent(), 0, 50)); + } + + // Make session ID available + $_SESSION['session_id'] = session_id(); + } + + // ------------------------------------------------------------------------ + + /** + * Save the session data + * + * @return void + */ + public function sess_save() + { + // Nothing to do - changes to $_SESSION are automatically saved + } + + // ------------------------------------------------------------------------ + + /** + * Destroy the current session + * + * @return void + */ + public function sess_destroy() + { + // Cleanup session + $_SESSION = array(); + $name = session_name(); + if (isset($_COOKIE[$name])) + { + // Clear session cookie + $params = session_get_cookie_params(); + setcookie($name, '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']); + unset($_COOKIE[$name]); + } + session_destroy(); + } + + // ------------------------------------------------------------------------ + + /** + * Regenerate the current session + * + * Regenerate the session id + * + * @param bool Destroy session data flag (default: FALSE) + * @return void + */ + public function sess_regenerate($destroy = FALSE) + { + // Just regenerate id, passing destroy flag + session_regenerate_id($destroy); + $_SESSION['session_id'] = session_id(); + } + + // ------------------------------------------------------------------------ + + /** + * Get a reference to user data array + * + * @return array Reference to userdata + */ + public function &get_userdata() + { + // Just return reference to $_SESSION + return $_SESSION; + } + +} + +/* End of file Session_native.php */ +/* Location: ./system/libraries/Session/drivers/Session_native.php */
\ No newline at end of file diff --git a/system/libraries/Session/drivers/index.html b/system/libraries/Session/drivers/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/system/libraries/Session/drivers/index.html @@ -0,0 +1,10 @@ +<html> +<head> + <title>403 Forbidden</title> +</head> +<body> + +<p>Directory access is forbidden.</p> + +</body> +</html>
\ No newline at end of file diff --git a/system/libraries/Session/index.html b/system/libraries/Session/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/system/libraries/Session/index.html @@ -0,0 +1,10 @@ +<html> +<head> + <title>403 Forbidden</title> +</head> +<body> + +<p>Directory access is forbidden.</p> + +</body> +</html>
\ No newline at end of file diff --git a/system/libraries/Table.php b/system/libraries/Table.php index 0f8404d85..3d53b1c00 100644 --- a/system/libraries/Table.php +++ b/system/libraries/Table.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.3.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * HTML Table Generating Class @@ -526,7 +527,7 @@ class CI_Table { */ protected function _default_template() { - return array( + return array( 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', 'thead_open' => '<thead>', diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php index 9a680dc2a..d30350340 100644 --- a/system/libraries/Trackback.php +++ b/system/libraries/Trackback.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Trackback Class @@ -38,13 +39,51 @@ */ class CI_Trackback { - public $time_format = 'local'; + /** + * Character set + * + * @var string + */ public $charset = 'UTF-8'; - public $data = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); + + /** + * Trackback data + * + * @var array + */ + public $data = array('url' => '', 'title' => '', 'excerpt' => '', 'blog_name' => '', 'charset' => ''); + + /** + * Convert ASCII flag + * + * Whether to convert high-ASCII and MS Word + * characters to HTML entities. + * + * @var bool + */ public $convert_ascii = TRUE; - public $response = ''; - public $error_msg = array(); + /** + * Response + * + * @var string + */ + public $response = ''; + + /** + * Error messages list + * + * @var string[] + */ + public $error_msg = array(); + + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @return void + */ public function __construct() { log_message('debug', 'Trackback Class Initialized'); @@ -355,7 +394,7 @@ class CI_Trackback { } } - return preg_match('/^[0-9]+$/', $tb_id) ? $tb_id : FALSE; + return ctype_digit((string) $tb_id) ? $tb_id : FALSE; } // -------------------------------------------------------------------- diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php index a50934f2c..d83bf519b 100644 --- a/system/libraries/Typography.php +++ b/system/libraries/Typography.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Typography Class diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php index 70ad8dc41..05c7eef78 100644 --- a/system/libraries/Unit_test.php +++ b/system/libraries/Unit_test.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.3.1 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Unit Testing Class @@ -38,13 +39,57 @@ */ class CI_Unit_test { - public $active = TRUE; - public $results = array(); - public $strict = FALSE; - protected $_template = NULL; - protected $_template_rows = NULL; + /** + * Active flag + * + * @var bool + */ + public $active = TRUE; + + /** + * Test results + * + * @var array + */ + public $results = array(); + + /** + * Strict comparison flag + * + * Whether to use === or == when comparing + * + * @var bool + */ + public $strict = FALSE; + + /** + * Template + * + * @var string + */ + protected $_template = NULL; + + /** + * Template rows + * + * @var string + */ + protected $_template_rows = NULL; + + /** + * List of visible test items + * + * @var array + */ protected $_test_items_visible = array(); + // -------------------------------------------------------------------- + + /** + * Constructor + * + * @return void + */ public function __construct() { // These are the default items visible when a test is run. @@ -86,9 +131,10 @@ class CI_Unit_test { * * Runs the supplied tests * - * @param mixed - * @param mixed - * @param string + * @param mixed $test + * @param mixed $expected + * @param string $test_name + * @param string $notes * @return string */ public function run($test, $expected = TRUE, $test_name = 'undefined', $notes = '') @@ -106,13 +152,13 @@ class CI_Unit_test { } else { - $result = ($this->strict === TRUE) ? ($test === $expected) : ($test === $expected); + $result = ($this->strict === TRUE) ? ($test === $expected) : ($test == $expected); $extype = gettype($expected); } $back = $this->_backtrace(); - $report[] = array ( + $report = array ( 'test_name' => $test_name, 'test_datatype' => gettype($test), 'res_datatype' => $extype, @@ -124,7 +170,7 @@ class CI_Unit_test { $this->results[] = $report; - return $this->report($this->result($report)); + return $this->report($this->result(array($report))); } // -------------------------------------------------------------------- @@ -134,6 +180,7 @@ class CI_Unit_test { * * Displays a table with the test data * + * @param array $result * @return string */ public function report($result = array()) @@ -213,6 +260,7 @@ class CI_Unit_test { * * Returns the raw result data * + * @param array $results * @return array */ public function result($results = array()) @@ -236,25 +284,11 @@ class CI_Unit_test { continue; } - if (is_array($val)) + if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val), FALSE))) { - foreach ($val as $k => $v) - { - if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$v)))) - { - $v = $line; - } - $temp[$CI->lang->line('ut_'.$k)] = $v; - } - } - else - { - if (FALSE !== ($line = $CI->lang->line(strtolower('ut_'.$val)))) - { - $val = $line; - } - $temp[$CI->lang->line('ut_'.$key)] = $val; + $val = $line; } + $temp[$CI->lang->line('ut_'.$key, FALSE)] = $val; } $retval[] = $temp; @@ -340,18 +374,26 @@ class CI_Unit_test { } /** - * Helper functions to test boolean true/false + * Helper function to test boolean TRUE * + * @param mixed $test * @return bool */ function is_true($test) { return ($test === TRUE); } + +/** + * Helper function to test boolean FALSE + * + * @param mixed $test + * @return bool + */ function is_false($test) { return ($test === FALSE); } /* End of file Unit_test.php */ -/* Location: ./system/libraries/Unit_test.php */
\ No newline at end of file +/* Location: ./system/libraries/Unit_test.php */ diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index d381440cd..4f65c9eb1 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * File Uploading Class @@ -36,40 +37,224 @@ */ class CI_Upload { + /** + * Maximum file size + * + * @var int + */ public $max_size = 0; + + /** + * Maximum image width + * + * @var int + */ public $max_width = 0; + + /** + * Maximum image height + * + * @var int + */ public $max_height = 0; + + /** + * Minimum image width + * + * @var int + */ + public $min_width = 0; + + /** + * Minimum image height + * + * @var int + */ + public $min_height = 0; + + /** + * Maximum filename length + * + * @var int + */ public $max_filename = 0; + + /** + * Maximum duplicate filename increment ID + * + * @var int + */ public $max_filename_increment = 100; + + /** + * Allowed file types + * + * @var string + */ public $allowed_types = ''; + + /** + * Temporary filename + * + * @var string + */ public $file_temp = ''; + + /** + * Filename + * + * @var string + */ public $file_name = ''; + + /** + * Original filename + * + * @var string + */ public $orig_name = ''; + + /** + * File type + * + * @var string + */ public $file_type = ''; - public $file_size = ''; + + /** + * File size + * + * @var int + */ + public $file_size = NULL; + + /** + * Filename extension + * + * @var string + */ public $file_ext = ''; + + /** + * Upload path + * + * @var string + */ public $upload_path = ''; + + /** + * Overwrite flag + * + * @var bool + */ public $overwrite = FALSE; + + /** + * Obfuscate filename flag + * + * @var bool + */ public $encrypt_name = FALSE; + + /** + * Is image flag + * + * @var bool + */ public $is_image = FALSE; - public $image_width = ''; - public $image_height = ''; + + /** + * Image width + * + * @var int + */ + public $image_width = NULL; + + /** + * Image height + * + * @var int + */ + public $image_height = NULL; + + /** + * Image type + * + * @var string + */ public $image_type = ''; + + /** + * Image size string + * + * @var string + */ public $image_size_str = ''; + + /** + * Error messages list + * + * @var array + */ public $error_msg = array(); + + /** + * MIME types list + * + * @var array + */ public $mimes = array(); + + /** + * Remove spaces flag + * + * @var bool + */ public $remove_spaces = TRUE; + + /** + * MIME detection flag + * + * @var bool + */ public $detect_mime = TRUE; + + /** + * XSS filter flag + * + * @var bool + */ public $xss_clean = FALSE; + + /** + * Temporary filename prefix + * + * @var string + */ public $temp_prefix = 'temp_file_'; + + /** + * Filename sent by the client + * + * @var bool + */ public $client_name = ''; + // -------------------------------------------------------------------- + + /** + * Filename override + * + * @var string + */ protected $_file_name_override = ''; + // -------------------------------------------------------------------- + /** * Constructor * - * @param array + * @param array $props * @return void */ public function __construct($props = array()) @@ -89,7 +274,7 @@ class CI_Upload { /** * Initialize preferences * - * @param array + * @param array $config * @return void */ public function initialize($config = array()) @@ -98,6 +283,8 @@ class CI_Upload { 'max_size' => 0, 'max_width' => 0, 'max_height' => 0, + 'min_width' => 0, + 'min_height' => 0, 'max_filename' => 0, 'max_filename_increment' => 100, 'allowed_types' => '', @@ -105,14 +292,14 @@ class CI_Upload { 'file_name' => '', 'orig_name' => '', 'file_type' => '', - 'file_size' => '', + 'file_size' => NULL, 'file_ext' => '', 'upload_path' => '', 'overwrite' => FALSE, 'encrypt_name' => FALSE, 'is_image' => FALSE, - 'image_width' => '', - 'image_height' => '', + 'image_width' => NULL, + 'image_height' => NULL, 'image_type' => '', 'image_size_str' => '', 'error_msg' => array(), @@ -123,7 +310,6 @@ class CI_Upload { 'client_name' => '' ); - foreach ($defaults as $key => $val) { if (isset($config[$key])) @@ -154,6 +340,7 @@ class CI_Upload { /** * Perform the file upload * + * @param string $field * @return bool */ public function do_upload($field = 'userfile') @@ -355,7 +542,7 @@ class CI_Upload { * Returns an associative array containing all of the information * related to the upload, allowing the developer easy access in one array. * - * @param string + * @param string $index * @return mixed */ public function data($index = NULL) @@ -390,7 +577,7 @@ class CI_Upload { /** * Set Upload Path * - * @param string + * @param string $path * @return void */ public function set_upload_path($path) @@ -408,8 +595,8 @@ class CI_Upload { * existence of a file with the same name. If found, it will append a * number to the end of the filename to avoid overwriting a pre-existing file. * - * @param string - * @param string + * @param string $path + * @param string $filename * @return string */ public function set_filename($path, $filename) @@ -453,7 +640,7 @@ class CI_Upload { /** * Set Maximum File Size * - * @param int + * @param int $n * @return void */ public function set_max_filesize($n) @@ -466,7 +653,7 @@ class CI_Upload { /** * Set Maximum File Name Length * - * @param int + * @param int $n * @return void */ public function set_max_filename($n) @@ -479,7 +666,7 @@ class CI_Upload { /** * Set Maximum Image Width * - * @param int + * @param int $n * @return void */ public function set_max_width($n) @@ -492,7 +679,7 @@ class CI_Upload { /** * Set Maximum Image Height * - * @param int + * @param int $n * @return void */ public function set_max_height($n) @@ -503,9 +690,35 @@ class CI_Upload { // -------------------------------------------------------------------- /** + * Set minimum image width + * + * @param int $n + * @return void + */ + public function set_min_width($n) + { + $this->min_width = ((int) $n < 0) ? 0 : (int) $n; + } + + // -------------------------------------------------------------------- + + /** + * Set minimum image height + * + * @param int $n + * @return void + */ + public function set_min_height($n) + { + $this->min_height = ((int) $n < 0) ? 0 : (int) $n; + } + + // -------------------------------------------------------------------- + + /** * Set Allowed File Types * - * @param string + * @param string $types * @return void */ public function set_allowed_types($types) @@ -525,7 +738,7 @@ class CI_Upload { * * Uses GD to determine the width/height/type of image * - * @param string + * @param string $path * @return void */ public function set_image_properties($path = '') @@ -557,7 +770,7 @@ class CI_Upload { * Enables the XSS flag so that the file that was uploaded * will be run through the XSS filter. * - * @param bool + * @param bool $flag * @return void */ public function set_xss_clean($flag = FALSE) @@ -599,7 +812,7 @@ class CI_Upload { /** * Verify that the filetype is allowed * - * @param bool + * @param bool $ignore_mime * @return bool */ public function is_allowed_filetype($ignore_mime = FALSE) @@ -688,6 +901,16 @@ class CI_Upload { { return FALSE; } + + if ($this->min_width > 0 && $D[0] < $this->min_width) + { + return FALSE; + } + + if ($this->min_height > 0 && $D[1] < $this->min_height) + { + return FALSE; + } } return TRUE; @@ -736,7 +959,7 @@ class CI_Upload { /** * Extract the file extension * - * @param string + * @param string $filename * @return string */ public function get_extension($filename) @@ -750,7 +973,7 @@ class CI_Upload { /** * Clean the file name for security * - * @param string + * @param string $filename * @return string */ public function clean_file_name($filename) @@ -790,7 +1013,8 @@ class CI_Upload { /** * Limit the File Name Length * - * @param string + * @param string $filename + * @param int $length * @return string */ public function limit_filename_length($filename, $length) @@ -883,7 +1107,7 @@ class CI_Upload { /** * Set an error message * - * @param string + * @param string $msg * @return void */ public function set_error($msg) @@ -913,8 +1137,8 @@ class CI_Upload { /** * Display the error message * - * @param string - * @param string + * @param string $open + * @param string $close * @return string */ public function display_errors($open = '<p>', $close = '</p>') @@ -930,7 +1154,7 @@ class CI_Upload { * This is a list of mime types. We use it to validate * the "allowed types" set by the developer * - * @param string + * @param string $mime * @return string */ public function mimes_types($mime) @@ -943,10 +1167,12 @@ class CI_Upload { /** * Prep Filename * - * Prevents possible script execution from Apache's handling of files multiple extensions - * http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext + * Prevents possible script execution from Apache's handling + * of files' multiple extensions. + * + * @link http://httpd.apache.org/docs/1.3/mod/mod_mime.html#multipleext * - * @param string + * @param string $filename * @return string */ protected function _prep_filename($filename) @@ -983,7 +1209,7 @@ class CI_Upload { * Detects the (actual) MIME type of the uploaded file, if possible. * The input array is expected to be $_FILES[$field] * - * @param array + * @param array $file * @return void */ protected function _file_mime_type($file) @@ -1033,7 +1259,7 @@ class CI_Upload { ? 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1' : 'file --brief --mime '.$file['tmp_name'].' 2>&1'; - if (function_exists('exec')) + if (function_usable('exec')) { /* This might look confusing, as $mime is being populated with all of the output when set in the second parameter. * However, we only neeed the last line, which is the actual return value of exec(), and as such - it overwrites @@ -1048,7 +1274,7 @@ class CI_Upload { } } - if ( (bool) @ini_get('safe_mode') === FALSE && function_exists('shell_exec')) + if ( (bool) @ini_get('safe_mode') === FALSE && function_usable('shell_exec')) { $mime = @shell_exec($cmd); if (strlen($mime) > 0) @@ -1062,7 +1288,7 @@ class CI_Upload { } } - if (function_exists('popen')) + if (function_usable('popen')) { $proc = @popen($cmd, 'r'); if (is_resource($proc)) diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php index ff596f04b..659371ab5 100644 --- a/system/libraries/User_agent.php +++ b/system/libraries/User_agent.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * User Agent Class @@ -309,6 +310,7 @@ class CI_User_agent { { $this->is_robot = TRUE; $this->robot = $val; + $this->_set_mobile(); return TRUE; } } @@ -466,7 +468,13 @@ class CI_User_agent { */ public function is_referral() { - return ! empty($_SERVER['HTTP_REFERER']); + if (empty($_SERVER['HTTP_REFERER'])) + { + return FALSE; + } + + $referer = parse_url($_SERVER['HTTP_REFERER']); + return ! (empty($referer['host']) && strpos(config_item('base_url'), $referer['host']) !== FALSE); } // -------------------------------------------------------------------- diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index cbb91c40a..529089914 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,14 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); + +if ( ! function_exists('xml_parser_create')) +{ + show_error('Your PHP installation does not support XML'); +} + +// ------------------------------------------------------------------------ /** * XML-RPC request handler class @@ -34,56 +42,212 @@ * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html */ - -if ( ! function_exists('xml_parser_create')) -{ - show_error('Your PHP installation does not support XML'); -} - -// ------------------------------------------------------------------------ - class CI_Xmlrpc { - public $debug = FALSE; // Debugging on or off + /** + * Debug flag + * + * @var bool + */ + public $debug = FALSE; + + /** + * I4 data type + * + * @var string + */ public $xmlrpcI4 = 'i4'; + + /** + * Integer data type + * + * @var string + */ public $xmlrpcInt = 'int'; + + /** + * Boolean data type + * + * @var string + */ public $xmlrpcBoolean = 'boolean'; + + /** + * Double data type + * + * @var string + */ public $xmlrpcDouble = 'double'; + + /** + * String data type + * + * @var string + */ public $xmlrpcString = 'string'; + + /** + * DateTime format + * + * @var string + */ public $xmlrpcDateTime = 'dateTime.iso8601'; + + /** + * Base64 data type + * + * @var string + */ public $xmlrpcBase64 = 'base64'; + + /** + * Array data type + * + * @var string + */ public $xmlrpcArray = 'array'; + + /** + * Struct data type + * + * @var string + */ public $xmlrpcStruct = 'struct'; + /** + * Data types list + * + * @var array + */ public $xmlrpcTypes = array(); + + /** + * Valid parents list + * + * @var array + */ public $valid_parents = array(); - public $xmlrpcerr = array(); // Response numbers - public $xmlrpcstr = array(); // Response strings + /** + * Response error numbers list + * + * @var array + */ + public $xmlrpcerr = array(); + + /** + * Response error messages list + * + * @var string[] + */ + public $xmlrpcstr = array(); + + /** + * Encoding charset + * + * @var string + */ public $xmlrpc_defencoding = 'UTF-8'; + + /** + * XML-RPC client name + * + * @var string + */ public $xmlrpcName = 'XML-RPC for CodeIgniter'; + + /** + * XML-RPC version + * + * @var string + */ public $xmlrpcVersion = '1.1'; - public $xmlrpcerruser = 800; // Start of user errors - public $xmlrpcerrxml = 100; // Start of XML Parse errors - public $xmlrpc_backslash = ''; // formulate backslashes for escaping regexp + /** + * Start of user errors + * + * @var int + */ + public $xmlrpcerruser = 800; + + /** + * Start of XML parse errors + * + * @var int + */ + public $xmlrpcerrxml = 100; + + /** + * Backslash replacement value + * + * @var string + */ + public $xmlrpc_backslash = ''; + + /** + * XML-RPC Client object + * + * @var object + */ public $client; + + /** + * XML-RPC Method name + * + * @var string + */ public $method; + + /** + * XML-RPC Data + * + * @var array + */ public $data; + + /** + * XML-RPC Message + * + * @var string + */ public $message = ''; - public $error = ''; // Error string for request + + /** + * Request error message + * + * @var string + */ + public $error = ''; + + /** + * XML-RPC result object + * + * @var object + */ public $result; - public $response = array(); // Response from remote server + /** + * XML-RPC Reponse + * + * @var array + */ + public $response = array(); // Response from remote server + + /** + * XSS Filter flag + * + * @var bool + */ public $xss_clean = TRUE; + // -------------------------------------------------------------------- /** * Constructor * * Initializes property default values * - * @param array + * @param array $config * @return void */ public function __construct($config = array()) @@ -101,7 +265,7 @@ class CI_Xmlrpc { $this->xmlrpcBase64 => '1', $this->xmlrpcArray => '2', $this->xmlrpcStruct => '3' - ); + ); // Array of Valid Parents for Various XML-RPC elements $this->valid_parents = array('BOOLEAN' => array('VALUE'), @@ -121,14 +285,13 @@ class CI_Xmlrpc { 'DATA' => array('ARRAY'), 'FAULT' => array('METHODRESPONSE'), 'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT') - ); - + ); // XML-RPC Responses $this->xmlrpcerr['unknown_method'] = '1'; $this->xmlrpcstr['unknown_method'] = 'This is not a known method for this XML-RPC Server'; $this->xmlrpcerr['invalid_return'] = '2'; - $this->xmlrpcstr['invalid_return'] = 'The XML data received was either invalid or not in the correct form for XML-RPC. Turn on debugging to examine the XML data further.'; + $this->xmlrpcstr['invalid_return'] = 'The XML data received was either invalid or not in the correct form for XML-RPC. Turn on debugging to examine the XML data further.'; $this->xmlrpcerr['incorrect_params'] = '3'; $this->xmlrpcstr['incorrect_params'] = 'Incorrect parameters were passed to method'; $this->xmlrpcerr['introspect_unknown'] = '4'; @@ -136,7 +299,7 @@ class CI_Xmlrpc { $this->xmlrpcerr['http_error'] = '5'; $this->xmlrpcstr['http_error'] = "Did not receive a '200 OK' response from remote server."; $this->xmlrpcerr['no_data'] = '6'; - $this->xmlrpcstr['no_data'] ='No data received from server.'; + $this->xmlrpcstr['no_data'] = 'No data received from server.'; $this->initialize($config); @@ -148,7 +311,7 @@ class CI_Xmlrpc { /** * Initialize * - * @param array + * @param array $config * @return void */ public function initialize($config = array()) @@ -170,8 +333,10 @@ class CI_Xmlrpc { /** * Parse server URL * - * @param string url - * @param int port + * @param string $url + * @param int $port + * @param string $proxy + * @param int $proxy_port * @return void */ public function server($url, $port = 80, $proxy = FALSE, $proxy_port = 8080) @@ -198,7 +363,7 @@ class CI_Xmlrpc { /** * Set Timeout * - * @param int seconds + * @param int $seconds * @return void */ public function timeout($seconds = 5) @@ -214,7 +379,7 @@ class CI_Xmlrpc { /** * Set Methods * - * @param string method name + * @param string $function Method name * @return void */ public function method($function) @@ -227,7 +392,7 @@ class CI_Xmlrpc { /** * Take Array of Data and Create Objects * - * @param array + * @param array $incoming * @return void */ public function request($incoming) @@ -251,7 +416,7 @@ class CI_Xmlrpc { /** * Set Debug * - * @param bool + * @param bool $flag * @return void */ public function set_debug($flag = TRUE) @@ -264,7 +429,7 @@ class CI_Xmlrpc { /** * Values Parsing * - * @param mixed + * @param mixed $value * @return object */ public function values_parsing($value) @@ -347,8 +512,8 @@ class CI_Xmlrpc { /** * Sends an Error Message for Server Request * - * @param int - * @param string + * @param int $number + * @param string $message * @return object */ public function send_error_message($number, $message) @@ -361,7 +526,7 @@ class CI_Xmlrpc { /** * Send Response for Server Request * - * @param array + * @param array $response * @return object */ public function send_response($response) @@ -382,22 +547,79 @@ class CI_Xmlrpc { */ class XML_RPC_Client extends CI_Xmlrpc { + /** + * Path + * + * @var string + */ public $path = ''; + + /** + * Server hostname + * + * @var string + */ public $server = ''; + + /** + * Server port + * + * @var int + */ public $port = 80; + + /** + * Proxy hostname + * + * @var string + */ public $proxy = FALSE; + + /** + * Proxy port + * + * @var int + */ public $proxy_port = 8080; + + /** + * Error number + * + * @var string + */ public $errno = ''; + + /** + * Error message + * + * @var string + */ public $errstring = ''; + + /** + * Timeout in seconds + * + * @var int + */ public $timeout = 5; + + /** + * No Multicall flag + * + * @var bool + */ public $no_multicall = FALSE; + // -------------------------------------------------------------------- + /** * Constructor * - * @param string - * @param object - * @param int + * @param string $path + * @param object $server + * @param int $port + * @param string $proxy + * @param int $proxy_port * @return void */ public function __construct($path, $server, $port = 80, $proxy = FALSE, $proxy_port = 8080) @@ -416,7 +638,7 @@ class XML_RPC_Client extends CI_Xmlrpc /** * Send message * - * @param mixed + * @param mixed $msg * @return object */ public function send($msg) @@ -435,7 +657,7 @@ class XML_RPC_Client extends CI_Xmlrpc /** * Send payload * - * @param object + * @param object $msg * @return object */ public function sendPayload($msg) @@ -495,18 +717,50 @@ class XML_RPC_Client extends CI_Xmlrpc */ class XML_RPC_Response { + + /** + * Value + * + * @var mixed + */ public $val = 0; + + /** + * Error number + * + * @var int + */ public $errno = 0; + + /** + * Error message + * + * @var string + */ public $errstr = ''; + + /** + * Headers list + * + * @var array + */ public $headers = array(); + + /** + * XSS Filter flag + * + * @var bool + */ public $xss_clean = TRUE; + // -------------------------------------------------------------------- + /** * Constructor * - * @param mixed - * @param int - * @param string + * @param mixed $val + * @param int $code + * @param string $fstr * @return void */ public function __construct($val, $code = 0, $fstr = '') @@ -691,7 +945,7 @@ class XML_RPC_Response */ public function iso8601_decode($time, $utc = FALSE) { - // return a time in the localtime, or UTC + // Return a time in the localtime, or UTC $t = 0; if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $time, $regs)) { @@ -712,16 +966,42 @@ class XML_RPC_Response */ class XML_RPC_Message extends CI_Xmlrpc { + + /** + * Payload + * + * @var string + */ public $payload; + + /** + * Method name + * + * @var string + */ public $method_name; + + /** + * Parameter list + * + * @var array + */ public $params = array(); + + /** + * XH? + * + * @var array + */ public $xh = array(); + // -------------------------------------------------------------------- + /** * Constructor * - * @param string method name - * @param array + * @param string $method + * @param array $pars * @return void */ public function __construct($method, $pars = FALSE) @@ -800,7 +1080,7 @@ class XML_RPC_Message extends CI_Xmlrpc } //------------------------------------- - // Create and Set Up XML Parser + // Create and Set Up XML Parser //------------------------------------- $parser = xml_parser_create($this->xmlrpc_defencoding); @@ -838,7 +1118,7 @@ class XML_RPC_Message extends CI_Xmlrpc $errstr = sprintf('XML error: %s at line %d', xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser)); - //error_log($errstr); + $r = new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return']); xml_parser_free($parser); return $r; @@ -949,7 +1229,7 @@ class XML_RPC_Message extends CI_Xmlrpc elseif ( ! in_array($this->xh[$the_parser]['stack'][0], $this->valid_parents[$name], TRUE)) { $this->xh[$the_parser]['isf'] = 2; - $this->xh[$the_parser]['isf_reason'] = 'XML-RPC element $name cannot be child of '.$this->xh[$the_parser]['stack'][0]; + $this->xh[$the_parser]['isf_reason'] = 'XML-RPC element '.$name.' cannot be child of '.$this->xh[$the_parser]['stack'][0]; return; } @@ -987,7 +1267,7 @@ class XML_RPC_Message extends CI_Xmlrpc { //two data elements inside a value: an error occurred! $this->xh[$the_parser]['isf'] = 2; - $this->xh[$the_parser]['isf_reason'] = "'Twas a ".$name.' element following a ' + $this->xh[$the_parser]['isf_reason'] = 'There is a '.$name.' element following a ' .$this->xh[$the_parser]['vt'].' element inside a single value'; return; } @@ -1099,7 +1379,7 @@ class XML_RPC_Message extends CI_Xmlrpc break; case 'VALUE': // This if() detects if no scalar was inside <VALUE></VALUE> - if ($this->xh[$the_parser]['vt']=='value') + if ($this->xh[$the_parser]['vt'] == 'value') { $this->xh[$the_parser]['value'] = $this->xh[$the_parser]['ac']; $this->xh[$the_parser]['vt'] = $this->xmlrpcString; @@ -1299,14 +1579,27 @@ class XML_RPC_Message extends CI_Xmlrpc */ class XML_RPC_Values extends CI_Xmlrpc { + /** + * Value data + * + * @var array + */ public $me = array(); + + /** + * Value type + * + * @var int + */ public $mytype = 0; + // -------------------------------------------------------------------- + /** * Constructor * - * @param mixed - * @param string + * @param mixed $val + * @param string $type * @return void */ public function __construct($val = -1, $type = '') @@ -1317,15 +1610,15 @@ class XML_RPC_Values extends CI_Xmlrpc { $type = $type === '' ? 'string' : $type; - if ($this->xmlrpcTypes[$type] === 1) + if ($this->xmlrpcTypes[$type] == 1) { - $this->addScalar($val,$type); + $this->addScalar($val, $type); } - elseif ($this->xmlrpcTypes[$type] === 2) + elseif ($this->xmlrpcTypes[$type] == 2) { $this->addArray($val); } - elseif ($this->xmlrpcTypes[$type] === 3) + elseif ($this->xmlrpcTypes[$type] == 3) { $this->addStruct($val); } @@ -1351,7 +1644,7 @@ class XML_RPC_Values extends CI_Xmlrpc return 0; } - if ($typeof !== 1) + if ($typeof != 1) { echo '<strong>XML_RPC_Values</strong>: not a scalar type (${typeof})<br />'; return 0; @@ -1359,7 +1652,7 @@ class XML_RPC_Values extends CI_Xmlrpc if ($type === $this->xmlrpcBoolean) { - $val = (int) (strcasecmp($val,'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false'))); + $val = (int) (strcasecmp($val, 'true') === 0 OR $val === 1 OR ($val === TRUE && strcasecmp($val, 'false'))); } if ($this->mytype === 2) diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php index e81f2ca9a..d6c3416c9 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); if ( ! function_exists('xml_parser_create')) { @@ -46,10 +47,10 @@ if ( ! class_exists('CI_Xmlrpc')) * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/xmlrpc.html */ -class CI_Xmlrpcs extends CI_Xmlrpc -{ +class CI_Xmlrpcs extends CI_Xmlrpc { + /** - * array of methods mapped to function names and signatures + * Array of methods mapped to function names and signatures * * @var array */ @@ -186,9 +187,9 @@ class CI_Xmlrpcs extends CI_Xmlrpc public function add_to_map($methodname, $function, $sig, $doc) { $this->methods[$methodname] = array( - 'function' => $function, - 'signature' => $sig, - 'docstring' => $doc + 'function' => $function, + 'signature' => $sig, + 'docstring' => $doc ); } @@ -230,21 +231,21 @@ class CI_Xmlrpcs extends CI_Xmlrpc ); xml_set_object($parser, $parser_object); - xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE); xml_set_element_handler($parser, 'open_tag', 'closing_tag'); xml_set_character_data_handler($parser, 'character_data'); //xml_set_default_handler($parser, 'default_handler'); //------------------------------------- - // PARSE + PROCESS XML DATA + // PARSE + PROCESS XML DATA //------------------------------------- if ( ! xml_parse($parser, $data, 1)) { - // return XML error as a faultCode + // Return XML error as a faultCode $r = new XML_RPC_Response(0, - $this->xmlrpcerrxml + xml_get_error_code($parser), - sprintf('XML error: %s at line %d', + $this->xmlrpcerrxml + xml_get_error_code($parser), + sprintf('XML error: %s at line %d', xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser))); xml_parser_free($parser); @@ -258,7 +259,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc xml_parser_free($parser); $m = new XML_RPC_Message($parser_object->xh[$parser]['method']); - $plist=''; + $plist = ''; for ($i = 0, $c = count($parser_object->xh[$parser]['params']); $i < $c; $i++) { @@ -279,7 +280,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc } //------------------------------------- - // SET DEBUGGING MESSAGE + // SET DEBUGGING MESSAGE //------------------------------------- if ($this->debug === TRUE) @@ -311,7 +312,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc } //------------------------------------- - // Valid Method + // Valid Method //------------------------------------- if ( ! isset($this->methods[$methName]['function'])) @@ -320,7 +321,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc } //------------------------------------- - // Check for Method (and Object) + // Check for Method (and Object) //------------------------------------- $method_parts = explode('.', $this->methods[$methName]['function']); @@ -341,7 +342,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc } //------------------------------------- - // Checking Methods Signature + // Checking Methods Signature //------------------------------------- if (isset($this->methods[$methName]['signature'])) @@ -374,7 +375,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc } //------------------------------------- - // Calls the Function + // Calls the Function //------------------------------------- if ($objectCall === TRUE) @@ -393,7 +394,6 @@ class CI_Xmlrpcs extends CI_Xmlrpc else { return $this->object->$method_parts[1]($m); - //return call_user_func(array(&$method_parts['0'],$method_parts['1']), $m); } } } @@ -406,7 +406,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc // -------------------------------------------------------------------- /** - * Server Function: List Methods + * Server Function: List Methods * * @param mixed * @return object @@ -433,7 +433,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc // -------------------------------------------------------------------- /** - * Server Function: Return Signature for Method + * Server Function: Return Signature for Method * * @param mixed * @return object @@ -467,13 +467,13 @@ class CI_Xmlrpcs extends CI_Xmlrpc return new XML_RPC_Response(new XML_RPC_Values('undef', 'string')); } - return new XML_RPC_Response(0,$this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); + return new XML_RPC_Response(0, $this->xmlrpcerr['introspect_unknown'], $this->xmlrpcstr['introspect_unknown']); } // -------------------------------------------------------------------- /** - * Server Function: Doc String for Method + * Server Function: Doc String for Method * * @param mixed * @return object @@ -498,7 +498,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc // -------------------------------------------------------------------- /** - * Server Function: Multi-call + * Server Function: Multi-call * * @param mixed * @return object @@ -515,10 +515,8 @@ class CI_Xmlrpcs extends CI_Xmlrpc foreach ($calls as $value) { - //$attempt = $this->_execute(new XML_RPC_Message($value[0], $value[1])); - $m = new XML_RPC_Message($value[0]); - $plist=''; + $plist = ''; for ($i = 0, $c = count($value[1]); $i < $c; $i++) { @@ -541,14 +539,14 @@ class CI_Xmlrpcs extends CI_Xmlrpc // -------------------------------------------------------------------- /** - * Multi-call Function: Error Handling + * Multi-call Function: Error Handling * * @param mixed * @return object */ public function multicall_error($err) { - $str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString(); + $str = is_string($err) ? $this->xmlrpcstr["multicall_${err}"] : $err->faultString(); $code = is_string($err) ? $this->xmlrpcerr["multicall_${err}"] : $err->faultCode(); $struct['faultCode'] = new XML_RPC_Values($code, 'int'); @@ -560,7 +558,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc // -------------------------------------------------------------------- /** - * Multi-call Function: Processes method + * Multi-call Function: Processes method * * @param mixed * @return object @@ -576,7 +574,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc return $this->multicall_error('nomethod'); } - list($scalar_type,$scalar_value)=each($methName->me); + list($scalar_type, $scalar_value) = each($methName->me); $scalar_type = $scalar_type === $this->xmlrpcI4 ? $this->xmlrpcInt : $scalar_type; if ($methName->kindOf() !== 'scalar' OR $scalar_type !== 'string') @@ -596,7 +594,7 @@ class CI_Xmlrpcs extends CI_Xmlrpc return $this->multicall_error('notarray'); } - list($a,$b) = each($params->me); + list($a, $b) = each($params->me); $msg = new XML_RPC_Message($scalar_value); for ($i = 0, $numParams = count($b); $i < $numParams; $i++) diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index 5c4c257f8..5eb33d29c 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Zip Compression Class @@ -132,7 +133,7 @@ class CI_Zip { protected function _get_mod_time($dir) { // filemtime() may return false, but raises an error for non-existing files - $date = file_exists($dir) ? filemtime($dir) : getdate($this->now); + $date = file_exists($dir) ? @filemtime($dir) : getdate($this->now); return array( 'file_mtime' => ($date['hours'] << 11) + ($date['minutes'] << 5) + $date['seconds'] / 2, diff --git a/system/libraries/javascript/Jquery.php b/system/libraries/javascript/Jquery.php index 44c16b578..2bf47957f 100644 --- a/system/libraries/javascript/Jquery.php +++ b/system/libraries/javascript/Jquery.php @@ -1,4 +1,4 @@ -<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); +<?php /** * CodeIgniter * @@ -24,6 +24,7 @@ * @since Version 1.0 * @filesource */ +defined('BASEPATH') OR exit('No direct script access allowed'); /** * Jquery Class @@ -34,17 +35,65 @@ * @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 sorder 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(); @@ -101,15 +150,12 @@ class CI_Jquery extends CI_Javascript { * * @param string The element to attach the event to * @param string The code to execute - * @param boolean whether or not to return false + * @param bool whether or not to return false * @return string */ protected function _click($element = 'this', $js = '', $ret_false = TRUE) { - if ( ! is_array($js)) - { - $js = array($js); - } + is_array($js) OR $js = array($js); if ($ret_false) { @@ -307,11 +353,10 @@ class CI_Jquery extends CI_Javascript { * * Outputs script directly * - * @param string The element to attach the event to - * @param string The code to execute - * @return string + * @param array $array_js = array() + * @return void */ - protected function _output($array_js = '') + protected function _output($array_js = array()) { if ( ! is_array($array_js)) { @@ -381,10 +426,11 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery addClass event * - * @param string - element + * @param string $element + * @param string $class * @return string */ - protected function _addClass($element = 'this', $class='') + protected function _addClass($element = 'this', $class = '') { $element = $this->_prep_element($element); return '$('.$element.').addClass("'.$class.'");'; @@ -397,9 +443,10 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery animate event * - * @param string - element - * @param string - One of 'slow', 'normal', 'fast', or time in milliseconds - * @param string - Javascript callback function + * @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 = '') @@ -511,10 +558,11 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery remove class event * - * @param string - element + * @param string $element + * @param string $class * @return string */ - protected function _removeClass($element = 'this', $class='') + protected function _removeClass($element = 'this', $class = '') { $element = $this->_prep_element($element); return '$('.$element.').removeClass("'.$class.'");'; @@ -618,10 +666,11 @@ class CI_Jquery extends CI_Javascript { * * Outputs a jQuery toggle class event * - * @param string - element + * @param string $element + * @param string $class * @return string */ - protected function _toggleClass($element = 'this', $class='') + protected function _toggleClass($element = 'this', $class = '') { $element = $this->_prep_element($element); return '$('.$element.').toggleClass("'.$class.'");'; @@ -695,7 +744,6 @@ class CI_Jquery extends CI_Javascript { return $updater."\t\t$($container).load('$controller'$request_options);"; } - // -------------------------------------------------------------------- // Pre-written handy stuff // -------------------------------------------------------------------- @@ -703,14 +751,15 @@ class CI_Jquery extends CI_Javascript { /** * Zebra tables * - * @param string table name - * @param string plugin location + * @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}\");"; + $zebra = "\t\$(\"table{$class} tbody tr:nth-child(even)\").addClass(\"{$odd}\");"; $this->jquery_code_for_compile[] = $zebra; @@ -729,9 +778,9 @@ class CI_Jquery extends CI_Javascript { /** * Corner Plugin * - * http://www.malsup.com/jquery/corner/ - * - * @param string target + * @link http://www.malsup.com/jquery/corner/ + * @param string $element + * @param string $corner_style * @return string */ public function corner($element = '', $corner_style = '') @@ -750,10 +799,12 @@ class CI_Jquery extends CI_Javascript { // -------------------------------------------------------------------- /** - * modal window + * Modal window * * Load a thickbox modal window * + * @param string $src + * @param bool $relative * @return void */ public function modal($src, $relative = FALSE) @@ -768,6 +819,8 @@ class CI_Jquery extends CI_Javascript { * * Load an Effect library * + * @param string $src + * @param bool $relative * @return void */ public function effect($src, $relative = FALSE) @@ -782,6 +835,8 @@ class CI_Jquery extends CI_Javascript { * * Load a plugin library * + * @param string $src + * @param bool $relative * @return void */ public function plugin($src, $relative = FALSE) @@ -796,12 +851,15 @@ class CI_Jquery extends CI_Javascript { * * 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); } + // -------------------------------------------------------------------- /** @@ -809,11 +867,12 @@ class CI_Jquery extends CI_Javascript { * * Creates a jQuery sortable * - * @return void + * @param string $element + * @param array $options + * @return string */ public function sortable($element, $options = array()) { - if (count($options) > 0) { $sort_options = array(); @@ -880,7 +939,9 @@ class CI_Jquery extends CI_Javascript { * As events are specified, they are stored in an array * This funciton compiles them all for output on a page * - * @return string + * @param string $view_var + * @param bool $script_tags + * @return void */ protected function _compile($view_var = 'script_foot', $script_tags = TRUE) { @@ -902,7 +963,6 @@ class CI_Jquery extends CI_Javascript { $output = ($script_tags === FALSE) ? $script : $this->inline($script); $this->CI->load->vars(array($view_var => $output)); - } // -------------------------------------------------------------------- @@ -926,14 +986,12 @@ class CI_Jquery extends CI_Javascript { * * A wrapper for writing document.ready() * - * @return string + * @param array $js + * @return void */ protected function _document_ready($js) { - if ( ! is_array($js)) - { - $js = array($js); - } + is_array($js) OR $js = array($js); foreach ($js as $script) { @@ -948,7 +1006,8 @@ class CI_Jquery extends CI_Javascript { * * Outputs the script tag that loads the jquery.js file into an HTML document * - * @param string + * @param string $library_src + * @param bool $relative * @return string */ public function script($library_src = '', $relative = FALSE) diff --git a/system/libraries/javascript/index.html b/system/libraries/javascript/index.html new file mode 100644 index 000000000..c942a79ce --- /dev/null +++ b/system/libraries/javascript/index.html @@ -0,0 +1,10 @@ +<html> +<head> + <title>403 Forbidden</title> +</head> +<body> + +<p>Directory access is forbidden.</p> + +</body> +</html>
\ No newline at end of file |