diff options
author | Brennan Thompson <brenjt@gmail.com> | 2014-02-14 20:03:57 +0100 |
---|---|---|
committer | Brennan Thompson <brenjt@gmail.com> | 2014-02-14 20:03:57 +0100 |
commit | 6949f95f6e21980f36095490bf38fc8a172dbc0f (patch) | |
tree | b3141f390acd0051396cda6a3da51c1f98384cca /system/libraries | |
parent | 68a02a01a086bbb1b8128ea2744439de84873d11 (diff) | |
parent | 81f036753272391360ba5b64e6dd93c4101a8733 (diff) |
Merge remote-tracking branch 'upstream/develop' into develop
Conflicts:
system/helpers/form_helper.php
Diffstat (limited to 'system/libraries')
34 files changed, 2002 insertions, 648 deletions
diff --git a/system/libraries/Cache/Cache.php b/system/libraries/Cache/Cache.php index 537897eaf..f9768b10c 100644 --- a/system/libraries/Cache/Cache.php +++ b/system/libraries/Cache/Cache.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -150,14 +150,15 @@ class CI_Cache extends CI_Driver_Library { /** * Cache Save * - * @param string $id Cache ID - * @param mixed $data Data to store - * @param int $ttl = 60 Cache TTL (in seconds) + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Cache TTL (in seconds) + * @param bool $raw Whether to store the raw value * @return bool TRUE on success, FALSE on failure */ - public function save($id, $data, $ttl = 60) + public function save($id, $data, $ttl = 60, $raw = FALSE) { - return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl); + return $this->{$this->_adapter}->save($this->key_prefix.$id, $data, $ttl, $raw); } // ------------------------------------------------------------------------ @@ -176,6 +177,34 @@ class CI_Cache extends CI_Driver_Library { // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return $this->{$this->_adapter}->increment($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return $this->{$this->_adapter}->decrement($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** * Clean the cache * * @return bool TRUE on success, FALSE on failure diff --git a/system/libraries/Cache/drivers/Cache_apc.php b/system/libraries/Cache/drivers/Cache_apc.php index a84e7d2d3..d062103bd 100644 --- a/system/libraries/Cache/drivers/Cache_apc.php +++ b/system/libraries/Cache/drivers/Cache_apc.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -51,8 +51,14 @@ class CI_Cache_apc extends CI_Driver { $success = FALSE; $data = apc_fetch($id, $success); - return ($success === TRUE && is_array($data)) - ? unserialize($data[0]) : FALSE; + if ($success === TRUE) + { + return is_array($data) + ? unserialize($data[0]) + : $data; + } + + return FALSE; } // ------------------------------------------------------------------------ @@ -60,16 +66,21 @@ class CI_Cache_apc extends CI_Driver { /** * 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 $ttol Length of time (in seconds) to cache the data + * @param bool $raw Whether to store the raw value + * @return bool TRUE on success, FALSE on failure */ - public function save($id, $data, $ttl = 60) + public function save($id, $data, $ttl = 60, $raw = FALSE) { $ttl = (int) $ttl; - return apc_store($id, array(serialize($data), time(), $ttl), $ttl); + + return apc_store( + $id, + ($raw === TRUE ? $data : array(serialize($data), time(), $ttl)), + $ttl + ); } // ------------------------------------------------------------------------ @@ -88,6 +99,34 @@ class CI_Cache_apc extends CI_Driver { // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return apc_inc($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return apc_dec($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** * Clean the cache * * @return bool false on failure/true on success diff --git a/system/libraries/Cache/drivers/Cache_dummy.php b/system/libraries/Cache/drivers/Cache_dummy.php index d9af3773b..521b9e6dd 100644 --- a/system/libraries/Cache/drivers/Cache_dummy.php +++ b/system/libraries/Cache/drivers/Cache_dummy.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -58,9 +58,10 @@ class CI_Cache_dummy extends CI_Driver { * @param string Unique Key * @param mixed Data to store * @param int Length of time (in seconds) to cache the data + * @param bool Whether to store the raw value * @return bool TRUE, Simulating success */ - public function save($id, $data, $ttl = 60) + public function save($id, $data, $ttl = 60, $raw = FALSE) { return TRUE; } @@ -81,6 +82,34 @@ class CI_Cache_dummy extends CI_Driver { // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return TRUE; + } + + // ------------------------------------------------------------------------ + + /** * Clean the cache * * @return bool TRUE, simulating success diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php index 769bd5a26..c6aa848fe 100644 --- a/system/libraries/Cache/drivers/Cache_file.php +++ b/system/libraries/Cache/drivers/Cache_file.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -62,25 +62,13 @@ class CI_Cache_file extends CI_Driver { /** * Fetch from cache * - * @param mixed unique key id - * @return mixed data on success/false on failure + * @param string $id Cache ID + * @return mixed Data on success, FALSE on failure */ public function get($id) { - if ( ! file_exists($this->_cache_path.$id)) - { - return FALSE; - } - - $data = unserialize(file_get_contents($this->_cache_path.$id)); - - if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) - { - unlink($this->_cache_path.$id); - return FALSE; - } - - return $data['data']; + $data = $this->_get($id); + return is_array($data) ? $data['data'] : FALSE; } // ------------------------------------------------------------------------ @@ -88,13 +76,13 @@ class CI_Cache_file extends CI_Driver { /** * Save into cache * - * @param string unique key - * @param mixed data to store - * @param int length of time (in seconds) the cache is valid - * - Default is 60 seconds - * @return bool true on success/false on failure + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Time to live in seconds + * @param bool $raw Whether to store the raw value (unused) + * @return bool TRUE on success, FALSE on failure */ - public function save($id, $data, $ttl = 60) + public function save($id, $data, $ttl = 60, $raw = FALSE) { $contents = array( 'time' => time(), @@ -127,6 +115,54 @@ class CI_Cache_file extends CI_Driver { // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return New value on success, FALSE on failure + */ + public function increment($id, $offset = 1) + { + $data = $this->_get($id); + + if ($data === FALSE OR ! is_int($data['data'])) + { + return FALSE; + } + + $new_value = $data['data'] + $offset; + return $this->save($id, $new_value, $data['ttl']) + ? $new_value + : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return New value on success, FALSE on failure + */ + public function decrement($id, $offset = 1) + { + $data = $this->_get($id); + + if ($data === FALSE OR ! is_int($data['data'])) + { + return FALSE; + } + + $new_value = $data['data'] - $offset; + return $this->save($id, $new_value, $data['ttl']) + ? $new_value + : FALSE; + } + + // ------------------------------------------------------------------------ + + /** * Clean the Cache * * @return bool false on failure/true on success @@ -200,6 +236,34 @@ class CI_Cache_file extends CI_Driver { return is_really_writable($this->_cache_path); } + // ------------------------------------------------------------------------ + + /** + * Get all data + * + * Internal method to get all the relevant data about a cache item + * + * @param string $id Cache ID + * @return mixed Data array on success or FALSE on failure + */ + protected function _get($id) + { + if ( ! file_exists($this->_cache_path.$id)) + { + return FALSE; + } + + $data = unserialize(file_get_contents($this->_cache_path.$id)); + + if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) + { + unlink($this->_cache_path.$id); + return FALSE; + } + + return $data; + } + } /* End of file Cache_file.php */ diff --git a/system/libraries/Cache/drivers/Cache_memcached.php b/system/libraries/Cache/drivers/Cache_memcached.php index d2a3a489d..bed606afb 100644 --- a/system/libraries/Cache/drivers/Cache_memcached.php +++ b/system/libraries/Cache/drivers/Cache_memcached.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -60,14 +60,14 @@ class CI_Cache_memcached extends CI_Driver { /** * Fetch from cache * - * @param mixed unique key id - * @return mixed data on success/false on failure + * @param string $id Cache ID + * @return mixed Data on success, FALSE on failure */ public function get($id) { $data = $this->_memcached->get($id); - return is_array($data) ? $data[0] : FALSE; + return is_array($data) ? $data[0] : $data; } // ------------------------------------------------------------------------ @@ -75,20 +75,26 @@ class CI_Cache_memcached extends CI_Driver { /** * Save * - * @param string unique identifier - * @param mixed data being cached - * @param int time to live - * @return bool true on success, false on failure + * @param string $id Cache ID + * @param mixed $data Data being cached + * @param int $ttl Time to live + * @param bool $raw Whether to store the raw value + * @return bool TRUE on success, FALSE on failure */ - public function save($id, $data, $ttl = 60) + public function save($id, $data, $ttl = 60, $raw = FALSE) { + if ($raw !== TRUE) + { + $data = array($data, time(), $ttl); + } + if (get_class($this->_memcached) === 'Memcached') { - return $this->_memcached->set($id, array($data, time(), $ttl), $ttl); + return $this->_memcached->set($id, $data, $ttl); } elseif (get_class($this->_memcached) === 'Memcache') { - return $this->_memcached->set($id, array($data, time(), $ttl), 0, $ttl); + return $this->_memcached->set($id, $data, 0, $ttl); } return FALSE; @@ -110,6 +116,34 @@ class CI_Cache_memcached extends CI_Driver { // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return $this->_memcached->increment($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return $this->_memcached->decrement($id, $offset); + } + + // ------------------------------------------------------------------------ + + /** * Clean the Cache * * @return bool false on failure/true on success diff --git a/system/libraries/Cache/drivers/Cache_redis.php b/system/libraries/Cache/drivers/Cache_redis.php index 40823fcb4..1c76426c5 100644 --- a/system/libraries/Cache/drivers/Cache_redis.php +++ b/system/libraries/Cache/drivers/Cache_redis.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -44,6 +44,7 @@ class CI_Cache_redis extends CI_Driver * @var array */ protected static $_default_config = array( + 'socket_type' => 'tcp', 'host' => '127.0.0.1', 'password' => NULL, 'port' => 6379, @@ -62,7 +63,7 @@ class CI_Cache_redis extends CI_Driver /** * Get cache * - * @param string Cache key identifier + * @param string Cache ID * @return mixed */ public function get($key) @@ -75,16 +76,17 @@ class CI_Cache_redis extends CI_Driver /** * Save cache * - * @param string Cache key identifier - * @param mixed Data to save - * @param int Time to live - * @return bool + * @param string $id Cache ID + * @param mixed $data Data to save + * @param int $ttl Time to live in seconds + * @param bool $raw Whether to store the raw value (unused) + * @return bool TRUE on success, FALSE on failure */ - public function save($key, $value, $ttl = NULL) + public function save($id, $data, $ttl = 60, $raw = FALSE) { return ($ttl) - ? $this->_redis->setex($key, $ttl, $value) - : $this->_redis->set($key, $value); + ? $this->_redis->setex($id, $ttl, $data) + : $this->_redis->set($id, $data); } // ------------------------------------------------------------------------ @@ -103,6 +105,38 @@ class CI_Cache_redis extends CI_Driver // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + return $this->_redis->exists($id) + ? $this->_redis->incr($id, $offset) + : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + return $this->_redis->exists($id) + ? $this->_redis->decr($id, $offset) + : FALSE; + } + + // ------------------------------------------------------------------------ + + /** * Clean cache * * @return bool @@ -163,8 +197,7 @@ class CI_Cache_redis extends CI_Driver { if (extension_loaded('redis')) { - $this->_setup_redis(); - return TRUE; + return $this->_setup_redis(); } else { @@ -200,17 +233,33 @@ class CI_Cache_redis extends CI_Driver try { - $this->_redis->connect($config['host'], $config['port'], $config['timeout']); + if ($config['socket_type'] === 'unix') + { + $success = $this->_redis->connect($config['socket']); + } + else // tcp socket + { + $success = $this->_redis->connect($config['host'], $config['port'], $config['timeout']); + } + + if ( ! $success) + { + log_message('debug', 'Cache: Redis connection refused. Check the config.'); + return FALSE; + } } catch (RedisException $e) { - show_error('Redis connection refused. ' . $e->getMessage()); + log_message('debug', 'Cache: Redis connection refused ('.$e->getMessage().')'); + return FALSE; } if (isset($config['password'])) { $this->_redis->auth($config['password']); } + + return TRUE; } // ------------------------------------------------------------------------ diff --git a/system/libraries/Cache/drivers/Cache_wincache.php b/system/libraries/Cache/drivers/Cache_wincache.php index 80d3ac13d..f412a538d 100644 --- a/system/libraries/Cache/drivers/Cache_wincache.php +++ b/system/libraries/Cache/drivers/Cache_wincache.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -46,8 +46,8 @@ class CI_Cache_wincache extends CI_Driver { * 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 Cache Ide + * @return mixed Value that is stored/FALSE on failure */ public function get($id) { @@ -63,12 +63,13 @@ class CI_Cache_wincache extends CI_Driver { /** * Cache Save * - * @param string Unique Key - * @param mixed Data to store - * @param int Length of time (in seconds) to cache the data + * @param string $id Cache ID + * @param mixed $data Data to store + * @param int $ttl Time to live (in seconds) + * @param bool $raw Whether to store the raw value (unused) * @return bool true on success/false on failure */ - public function save($id, $data, $ttl = 60) + public function save($id, $data, $ttl = 60, $raw = FALSE) { return wincache_ucache_set($id, $data, $ttl); } @@ -89,6 +90,40 @@ class CI_Cache_wincache extends CI_Driver { // ------------------------------------------------------------------------ /** + * Increment a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to add + * @return mixed New value on success or FALSE on failure + */ + public function increment($id, $offset = 1) + { + $success = FALSE; + $value = wincache_ucache_inc($id, $offset, $success); + + return ($success === TRUE) ? $value : FALSE; + } + + // ------------------------------------------------------------------------ + + /** + * Decrement a raw value + * + * @param string $id Cache ID + * @param int $offset Step/value to reduce by + * @return mixed New value on success or FALSE on failure + */ + public function decrement($id, $offset = 1) + { + $success = FALSE; + $value = wincache_ucache_dec($id, $offset, $success); + + return ($success === TRUE) ? $value : FALSE; + } + + // ------------------------------------------------------------------------ + + /** * Clean the cache * * @return bool false on failure/true on success diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php index 23d8ffb42..30f393318 100644 --- a/system/libraries/Calendar.php +++ b/system/libraries/Calendar.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -96,6 +96,13 @@ class CI_Calendar { public $next_prev_url = ''; /** + * Show days of other months + * + * @var bool + */ + public $show_other_days = FALSE; + + /** * Class constructor * * Loads the calendar language file and sets the default time reference. @@ -132,7 +139,7 @@ class CI_Calendar { * Accepts an associative array as input, containing display preferences * * @param array config preferences - * @return void + * @return CI_Calendar */ public function initialize($config = array()) { @@ -143,6 +150,14 @@ class CI_Calendar { $this->$key = $val; } } + + // Set the next_prev_url to the controller if required but not defined + if ($this->show_next_prev === TRUE && empty($this->next_prev_url)) + { + $this->next_prev_url = $this->CI->config->site_url($this->CI->router->class.'/'.$this->CI->router->method); + } + + return $this; } // -------------------------------------------------------------------- @@ -261,10 +276,10 @@ class CI_Calendar { for ($i = 0; $i < 7; $i++) { - $out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start']; - if ($day > 0 && $day <= $total_days) { + $out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_start_today'] : $this->temp['cal_cell_start']; + if (isset($data[$day])) { // Cells with content @@ -279,14 +294,34 @@ class CI_Calendar { $this->temp['cal_cell_no_content_today'] : $this->temp['cal_cell_no_content']; $out .= str_replace('{day}', $day, $temp); } + + $out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end']; + } + elseif ($this->show_other_days === TRUE) + { + $out .= $this->temp['cal_cell_start_other']; + + if ($day <= 0) + { + // Day of previous month + $prev_month = $this->adjust_date($month - 1, $year); + $prev_month_days = $this->get_total_days($prev_month['month'], $prev_month['year']); + $out .= str_replace('{day}', $prev_month_days + $day, $this->temp['cal_cell_other']); + } + else + { + // Day of next month + $out .= str_replace('{day}', $day - $total_days, $this->temp['cal_cell_other']); + } + + $out .= $this->temp['cal_cell_end_other']; } else { // Blank cells - $out .= $this->temp['cal_cell_blank']; + $out .= $this->temp['cal_cell_start'].$this->temp['cal_cell_blank'].$this->temp['cal_cell_end']; } - $out .= ($is_current_month === TRUE && $day == $cur_day) ? $this->temp['cal_cell_end_today'] : $this->temp['cal_cell_end']; $day++; } @@ -329,7 +364,7 @@ class CI_Calendar { * Get Day Names * * Returns an array of day names (Sunday, Monday, etc.) based - * on the type. Options: long, short, abrev + * on the type. Options: long, short, abr * * @param string * @return array @@ -457,13 +492,16 @@ class CI_Calendar { 'cal_row_start' => '<tr>', 'cal_cell_start' => '<td>', 'cal_cell_start_today' => '<td>', + 'cal_cell_start_other' => '<td style="color: #666;">', 'cal_cell_content' => '<a href="{content}">{day}</a>', 'cal_cell_content_today' => '<a href="{content}"><strong>{day}</strong></a>', 'cal_cell_no_content' => '{day}', 'cal_cell_no_content_today' => '<strong>{day}</strong>', 'cal_cell_blank' => ' ', + 'cal_cell_other' => '{day}', 'cal_cell_end' => '</td>', 'cal_cell_end_today' => '</td>', + 'cal_cell_end_other' => '</td>', 'cal_row_end' => '</tr>', 'table_close' => '</table>' ); @@ -477,7 +515,7 @@ class CI_Calendar { * Harvests the data within the template {pseudo-variables} * used to display the calendar * - * @return void + * @return CI_Calendar */ public function parse_template() { @@ -485,12 +523,12 @@ class CI_Calendar { if ($this->template === '') { - return; + return $this; } $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', 'cal_cell_start_other', 'cal_cell_other', 'cal_cell_end_other') as $val) { if (preg_match('/\{'.$val.'\}(.*?)\{\/'.$val.'\}/si', $this->template, $match)) { @@ -501,6 +539,8 @@ class CI_Calendar { $this->temp[$val] = $this->temp[substr($val, 0, -6)]; } } + + return $this; } } diff --git a/system/libraries/Cart.php b/system/libraries/Cart.php index edc300bd7..5b05974e4 100644 --- a/system/libraries/Cart.php +++ b/system/libraries/Cart.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2006 - 2014, 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 @@ -61,8 +61,6 @@ class CI_Cart { public $product_name_safe = TRUE; // -------------------------------------------------------------------------- - // Protected variables. Do not change! - // -------------------------------------------------------------------------- /** * Reference to CodeIgniter instance @@ -323,10 +321,10 @@ class CI_Cart { /** * Update the cart * - * This function permits the quantity of a given item to be changed. + * This function permits changing item properties. * Typically it is called from the "view cart" page if a user makes * changes to the quantity before checkout. That array must contain the - * product ID and quantity for each item. + * rowid and quantity for each item. * * @param array * @return bool @@ -350,7 +348,19 @@ class CI_Cart { } else { - $this->_cart_contents[$items['rowid']]['qty'] = $items['qty']; + // find updatable keys + $keys = array_intersect(array_keys($this->_cart_contents[$items['rowid']]), array_keys($items)); + // if a price was passed, make sure it contains valid data + if (isset($items['price'])) + { + $items['price'] = (float) $items['price']; + } + + // product id & name shouldn't be changed + foreach (array_diff($keys, array('id', 'name')) as $key) + { + $this->_cart_contents[$items['rowid']][$key] = $items[$key]; + } } return TRUE; diff --git a/system/libraries/Driver.php b/system/libraries/Driver.php index 1bc365cbc..d2e41d6dd 100644 --- a/system/libraries/Driver.php +++ b/system/libraries/Driver.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2006 - 2014, 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 diff --git a/system/libraries/Email.php b/system/libraries/Email.php index efdbfd7c1..93c19de5e 100644 --- a/system/libraries/Email.php +++ b/system/libraries/Email.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -710,18 +710,42 @@ class CI_Email { /** * Assign file attachments * - * @param string $filename + * @param string $file Can be local path, URL or buffered content * @param string $disposition = 'attachment' * @param string $newname = NULL * @param string $mime = '' * @return CI_Email */ - public function attach($filename, $disposition = '', $newname = NULL, $mime = '') + public function attach($file, $disposition = '', $newname = NULL, $mime = '') { + if ($mime === '') + { + if (strpos($file, '://') === FALSE && ! file_exists($file)) + { + $this->_set_error_message('lang:email_attachment_missing', $file); + return FALSE; + } + + if ( ! $fp = @fopen($file, FOPEN_READ)) + { + $this->_set_error_message('lang:email_attachment_unreadable', $file); + return FALSE; + } + + $file_content = stream_get_contents($fp); + $mime = $this->_mime_types(pathinfo($file, PATHINFO_EXTENSION)); + fclose($fp); + } + else + { + $file_content =& $file; // buffered file + } + $this->_attachments[] = array( - 'name' => array($filename, $newname), + 'name' => array($file, $newname), 'disposition' => empty($disposition) ? 'attachment' : $disposition, // Can also be 'inline' Not sure if it matters - 'type' => $mime + 'type' => $mime, + 'content' => chunk_split(base64_encode($file_content)) ); return $this; @@ -730,6 +754,35 @@ class CI_Email { // -------------------------------------------------------------------- /** + * Set and return attachment Content-ID + * + * Useful for attached inline pictures + * + * @param string $filename + * @return string + */ + public function attachment_cid($filename) + { + if ($this->multipart !== 'related') + { + $this->multipart = 'related'; // Thunderbird need this for inline images + } + + for ($i = 0, $c = count($this->_attachments); $i < $c; $i++) + { + if ($this->_attachments[$i]['name'][0] === $filename) + { + $this->_attachments[$i]['cid'] = uniqid(basename($this->_attachments[$i]['name'][0]).'@'); + return $this->_attachments[$i]['cid']; + } + } + + return FALSE; + } + + // -------------------------------------------------------------------- + + /** * Add a Header Item * * @param string @@ -769,7 +822,7 @@ class CI_Email { * @param string * @return CI_Email */ - public function set_alt_message($str = '') + public function set_alt_message($str) { $this->alt_message = (string) $str; return $this; @@ -1361,47 +1414,22 @@ class CI_Email { $filename = $this->_attachments[$i]['name'][0]; $basename = ($this->_attachments[$i]['name'][1] === NULL) ? basename($filename) : $this->_attachments[$i]['name'][1]; - $ctype = $this->_attachments[$i]['type']; - $file_content = ''; - - if ($ctype === '') - { - if ( ! file_exists($filename)) - { - $this->_set_error_message('lang:email_attachment_missing', $filename); - return FALSE; - } - - $file = filesize($filename) +1; - - if ( ! $fp = fopen($filename, FOPEN_READ)) - { - $this->_set_error_message('lang:email_attachment_unreadable', $filename); - return FALSE; - } - - $ctype = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION)); - $file_content = fread($fp, $file); - fclose($fp); - } - else - { - $file_content =& $this->_attachments[$i]['name'][0]; - } $attachment[$z++] = '--'.$this->_atc_boundary.$this->newline - .'Content-type: '.$ctype.'; ' + .'Content-type: '.$this->_attachments[$i]['type'].'; ' .'name="'.$basename.'"'.$this->newline .'Content-Disposition: '.$this->_attachments[$i]['disposition'].';'.$this->newline - .'Content-Transfer-Encoding: base64'.$this->newline; + .'Content-Transfer-Encoding: base64'.$this->newline + .(empty($this->_attachments[$i]['cid']) ? '' : 'Content-ID: <'.$this->_attachments[$i]['cid'].'>'.$this->newline); - $attachment[$z++] = chunk_split(base64_encode($file_content)); + $attachment[$z++] = $this->_attachments[$i]['content']; } $body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--'; $this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$this->newline.$this->newline.$body; + return TRUE; } @@ -1516,7 +1544,7 @@ class CI_Email { { return mb_encode_mimeheader($str, $this->charset, 'Q', $this->crlf); } - elseif (extension_loaded('iconv')) + elseif (ICONV_ENABLED === TRUE) { $output = @iconv_mime_encode('', $str, array( @@ -1545,9 +1573,9 @@ class CI_Email { isset($chars) OR $chars = strlen($str); $output = '=?'.$this->charset.'?Q?'; - for ($i = 0, $length = strlen($output), $iconv = extension_loaded('iconv'); $i < $chars; $i++) + for ($i = 0, $length = strlen($output); $i < $chars; $i++) { - $chr = ($this->charset === 'UTF-8' && $iconv === TRUE) + $chr = ($this->charset === 'UTF-8' && ICONV_ENABLED === TRUE) ? '='.implode('=', str_split(strtoupper(bin2hex(iconv_substr($str, $i, 1, $this->charset))), 2)) : '='.strtoupper(bin2hex($str[$i])); @@ -2069,7 +2097,16 @@ class CI_Email { */ protected function _send_data($data) { - if ( ! fwrite($this->_smtp_connect, $data.$this->newline)) + $data .= $this->newline; + for ($written = 0, $length = strlen($data); $written < $length; $written += $result) + { + if (($result = fwrite($this->_smtp_connect, substr($data, $written))) === FALSE) + { + break; + } + } + + if ($result === FALSE) { $this->_set_error_message('lang:email_smtp_data_failure', $data); return FALSE; diff --git a/system/libraries/Encrypt.php b/system/libraries/Encrypt.php index 8ac5420de..f72bd2302 100644 --- a/system/libraries/Encrypt.php +++ b/system/libraries/Encrypt.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 diff --git a/system/libraries/Encryption.php b/system/libraries/Encryption.php new file mode 100644 index 000000000..3ce9f1b95 --- /dev/null +++ b/system/libraries/Encryption.php @@ -0,0 +1,887 @@ +<?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 - 2014, 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 Encryption Class + * + * Provides two-way keyed encryption via PHP's MCrypt and/or OpenSSL extensions. + * + * @package CodeIgniter + * @subpackage Libraries + * @category Libraries + * @author Andrey Andreev + * @link http://codeigniter.com/user_guide/libraries/encryption.html + */ +class CI_Encryption { + + /** + * Encryption cipher + * + * @var string + */ + protected $_cipher = 'aes-128'; + + /** + * Cipher mode + * + * @var string + */ + protected $_mode = 'cbc'; + + /** + * Cipher handle + * + * @var mixed + */ + protected $_handle; + + /** + * Encryption key + * + * @var string + */ + protected $_key; + + /** + * PHP extension to be used + * + * @var string + */ + protected $_driver; + + /** + * List of usable drivers (PHP extensions) + * + * @var array + */ + protected $_drivers = array(); + + /** + * List of available modes + * + * @var array + */ + protected $_modes = array( + 'mcrypt' => array( + 'cbc' => 'cbc', + 'ecb' => 'ecb', + 'ofb' => 'nofb', + 'ofb8' => 'ofb', + 'cfb' => 'ncfb', + 'cfb8' => 'cfb', + 'ctr' => 'ctr', + 'stream' => 'stream' + ), + 'openssl' => array( + 'cbc' => 'cbc', + 'ecb' => 'ecb', + 'ofb' => 'ofb', + 'cfb' => 'cfb', + 'cfb8' => 'cfb8', + 'ctr' => 'ctr', + 'stream' => '', + 'gcm' => 'gcm', + 'xts' => 'xts' + ) + ); + + /** + * List of supported HMAC algorightms + * + * name => digest size pairs + * + * @var array + */ + protected $_digests = array( + 'sha224' => 28, + 'sha256' => 32, + 'sha384' => 48, + 'sha512' => 64 + ); + + // -------------------------------------------------------------------- + + /** + * Class constructor + * + * @param array $params Configuration parameters + * @return void + */ + public function __construct(array $params = array()) + { + $this->_drivers = array( + 'mcrypt' => defined('MCRYPT_DEV_URANDOM'), + // While OpenSSL is available for PHP 5.3.0, an IV parameter + // for the encrypt/decrypt functions is only available since 5.3.3 + 'openssl' => (is_php('5.3.3') && extension_loaded('openssl')) + ); + + if ( ! $this->_drivers['mcrypt'] && ! $this->_drivers['openssl']) + { + return show_error('Encryption: Unable to find an available encryption driver.'); + } + + $this->initialize($params); + if ( ! isset($this->_key) && strlen($key = config_item('encryption_key')) > 0) + { + $this->_key = $key; + } + + log_message('debug', 'Encryption Class Initialized'); + } + + // -------------------------------------------------------------------- + + /** + * Initialize + * + * @param array $params Configuration parameters + * @return CI_Encryption + */ + public function initialize(array $params) + { + if ( ! empty($params['driver'])) + { + if (isset($this->_drivers[$params['driver']])) + { + if ($this->_drivers[$params['driver']]) + { + $this->_driver = $params['driver']; + } + else + { + log_message('error', "Encryption: Driver '".$params['driver']."' is not available."); + } + } + else + { + log_message('error', "Encryption: Unknown driver '".$params['driver']."' cannot be configured."); + } + } + + if (empty($this->_driver)) + { + $this->_driver = ($this->_drivers['openssl'] === TRUE) + ? 'openssl' + : 'mcrypt'; + + log_message('debug', "Encryption: Auto-configured driver '".$this->_driver."'."); + } + + empty($params['key']) OR $this->_key = $params['key']; + $this->{'_'.$this->_driver.'_initialize'}($params); + return $this; + } + + // -------------------------------------------------------------------- + + /** + * Initialize MCrypt + * + * @param array $params Configuration parameters + * @return void + */ + protected function _mcrypt_initialize($params) + { + if ( ! empty($params['cipher'])) + { + $params['cipher'] = strtolower($params['cipher']); + $this->_cipher_alias($params['cipher']); + + if ( ! in_array($params['cipher'], mcrypt_list_algorithms(), TRUE)) + { + log_message('error', 'Encryption: MCrypt cipher '.strtoupper($params['cipher']).' is not available.'); + } + else + { + $this->_cipher = $params['cipher']; + } + } + + if ( ! empty($params['mode'])) + { + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes['mcrypt'][$params['mode']])) + { + log_message('error', 'Encryption: MCrypt mode '.strtotupper($params['mode']).' is not available.'); + } + else + { + $this->_mode = $this->_modes['mcrypt'][$params['mode']]; + } + } + + if (isset($this->_cipher, $this->_mode)) + { + if (is_resource($this->_handle) + && (strtolower(mcrypt_enc_get_algorithms_name($this->_handle)) !== $this->_cipher + OR strtolower(mcrypt_enc_get_modes_name($this->_handle)) !== $this->_mode) + ) + { + mcrypt_module_close($this->_handle); + } + + if ($this->_handle = mcrypt_module_open($this->_cipher, '', $this->_mode, '')) + { + log_message('debug', 'Encryption: MCrypt cipher '.strtoupper($this->_cipher).' initialized in '.strtoupper($this->_mode).' mode.'); + } + else + { + log_message('error', 'Encryption: Unable to initialize MCrypt with cipher '.strtoupper($this->_cipher).' in '.strtoupper($this->_mode).' mode.'); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Initialize OpenSSL + * + * @param array $params Configuration parameters + * @return void + */ + protected function _openssl_initialize($params) + { + if ( ! empty($params['cipher'])) + { + $params['cipher'] = strtolower($params['cipher']); + $this->_cipher_alias($params['cipher']); + $this->_cipher = $params['cipher']; + } + + if ( ! empty($params['mode'])) + { + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes['openssl'][$params['mode']])) + { + log_message('error', 'Encryption: OpenSSL mode '.strtotupper($params['mode']).' is not available.'); + } + else + { + $this->_mode = $this->_modes['openssl'][$params['mode']]; + } + } + + if (isset($this->_cipher, $this->_mode)) + { + // This is mostly for the stream mode, which doesn't get suffixed in OpenSSL + $handle = empty($this->_mode) + ? $this->_cipher + : $this->_cipher.'-'.$this->_mode; + + if ( ! in_array($handle, openssl_get_cipher_methods(), TRUE)) + { + $this->_handle = NULL; + log_message('error', 'Encryption: Unable to initialize OpenSSL with method '.strtoupper($handle).'.'); + } + else + { + $this->_handle = $handle; + log_message('debug', 'Encryption: OpenSSL initialized with method '.strtoupper($handle).'.'); + } + } + } + + // -------------------------------------------------------------------- + + /** + * Encrypt + * + * @param string $data Input data + * @param array $params Input parameters + * @return string + */ + public function encrypt($data, array $params = NULL) + { + if (($params = $this->_get_params($params)) === FALSE) + { + return FALSE; + } + + isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + + if (($data = $this->{'_'.$this->_driver.'_encrypt'}($data, $params)) === FALSE) + { + return FALSE; + } + + $params['base64'] && $data = base64_encode($data); + + if (isset($params['hmac_digest'])) + { + isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); + return hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']).$data; + } + + return $data; + } + + // -------------------------------------------------------------------- + + /** + * Encrypt via MCrypt + * + * @param string $data Input data + * @param array $params Input parameters + * @return string + */ + protected function _mcrypt_encrypt($data, $params) + { + if ( ! is_resource($params['handle'])) + { + return FALSE; + } + elseif ( ! isset($params['iv'])) + { + // The greater-than-1 comparison is mostly a work-around for a bug, + // where 1 is returned for ARCFour instead of 0. + $params['iv'] = (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) + ? mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM) + : NULL; + } + + // CAST-128 compatibility (http://tools.ietf.org/rfc/rfc2144.txt) + // + // RFC2144 says that keys shorter than 16 bytes are to be padded with + // zero bytes to 16 bytes, but (surprise) MCrypt doesn't do that. + if ($params['cipher'] === 'cast-128' && ($kl = strlen($params['key'])) < 16) + { + $params['key'] .= str_repeat("\x0", 16 - $kl); + } + + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + { + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($params['handle']); + } + + return FALSE; + } + + // Use PKCS#7 padding in order to ensure compatibility with OpenSSL + // and other implementations outside of PHP. + if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE)) + { + $block_size = mcrypt_enc_get_block_size($params['handle']); + $pad = $block_size - (strlen($data) % $block_size); + $data .= str_repeat(chr($pad), $pad); + } + + // Work-around for yet another strange behavior in MCrypt. + // + // When encrypting in ECB mode, the IV is ignored. Yet + // mcrypt_enc_get_iv_size() returns a value larger than 0 + // even if ECB is used AND mcrypt_generic_init() complains + // if you don't pass an IV with length equal to the said + // return value. + // + // This probably would've been fine (even though still wasteful), + // but OpenSSL isn't that dumb and we need to make the process + // portable, so ... + $data = (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') + ? $params['iv'].mcrypt_generic($params['handle'], $data) + : mcrypt_generic($params['handle'], $data); + + mcrypt_generic_deinit($params['handle']); + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($params['handle']); + } + + return $data; + } + + // -------------------------------------------------------------------- + + /** + * Encrypt via OpenSSL + * + * @param string $data Input data + * @param array $params Input parameters + * @return string + */ + protected function _openssl_encrypt($data, $params) + { + if (empty($params['handle'])) + { + return FALSE; + } + elseif ( ! isset($params['iv'])) + { + $params['iv'] = ($iv_size = openssl_cipher_iv_length($params['handle'])) + ? openssl_random_pseudo_bytes($iv_size) + : NULL; + } + + $data = openssl_encrypt( + $data, + $params['handle'], + $params['key'], + 1, // DO NOT TOUCH! + $params['iv'] + ); + + if ($data === FALSE) + { + return FALSE; + } + + return $params['iv'].$data; + } + + // -------------------------------------------------------------------- + + /** + * Decrypt + * + * @param string $data Encrypted data + * @param array $params Input parameters + * @return string + */ + public function decrypt($data, array $params = NULL) + { + if (($params = $this->_get_params($params)) === FALSE) + { + return FALSE; + } + + if (isset($params['hmac_digest'])) + { + // This might look illogical, but it is done during encryption as well ... + // The 'base64' value is effectively an inverted "raw data" parameter + $digest_size = ($params['base64']) + ? $this->_digests[$params['hmac_digest']] * 2 + : $this->_digests[$params['hmac_digest']]; + + if (strlen($data) <= $digest_size) + { + return FALSE; + } + + $hmac_input = substr($data, 0, $digest_size); + $data = substr($data, $digest_size); + + isset($params['hmac_key']) OR $params['hmac_key'] = $this->hkdf($this->_key, 'sha512', NULL, NULL, 'authentication'); + $hmac_check = hash_hmac($params['hmac_digest'], $data, $params['hmac_key'], ! $params['base64']); + + // Time-attack-safe comparison + $diff = 0; + for ($i = 0; $i < $digest_size; $i++) + { + $diff |= ord($hmac_input[$i]) ^ ord($hmac_check[$i]); + } + + if ($diff !== 0) + { + return FALSE; + } + } + + if ($params['base64']) + { + $data = base64_decode($data); + } + + if (isset($params['iv']) && strncmp($params['iv'], $data, $iv_size = strlen($params['iv'])) === 0) + { + $data = substr($data, $iv_size); + } + + isset($params['key']) OR $params['key'] = $this->hkdf($this->_key, 'sha512', NULL, strlen($this->_key), 'encryption'); + + return $this->{'_'.$this->_driver.'_decrypt'}($data, $params); + } + + // -------------------------------------------------------------------- + + /** + * Decrypt via MCrypt + * + * @param string $data Encrypted data + * @param array $params Input parameters + * @return string + */ + protected function _mcrypt_decrypt($data, $params) + { + if ( ! is_resource($params['handle'])) + { + return FALSE; + } + elseif ( ! isset($params['iv'])) + { + // The greater-than-1 comparison is mostly a work-around for a bug, + // where 1 is returned for ARCFour instead of 0. + if (($iv_size = mcrypt_enc_get_iv_size($params['handle'])) > 1) + { + if (mcrypt_enc_get_modes_name($params['handle']) !== 'ECB') + { + $params['iv'] = substr($data, 0, $iv_size); + $data = substr($data, $iv_size); + } + else + { + // MCrypt is dumb and this is ignored, only size matters + $params['iv'] = str_repeat("\x0", $iv_size); + } + } + else + { + $params['iv'] = NULL; + } + } + + // CAST-128 compatibility (http://tools.ietf.org/rfc/rfc2144.txt) + // + // RFC2144 says that keys shorter than 16 bytes are to be padded with + // zero bytes to 16 bytes, but (surprise) MCrypt doesn't do that. + if ($params['cipher'] === 'cast-128' && ($kl = strlen($params['key'])) < 16) + { + $params['key'] .= str_repeat("\x0", 16 - $kl); + } + + if (mcrypt_generic_init($params['handle'], $params['key'], $params['iv']) < 0) + { + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($params['handle']); + } + + return FALSE; + } + + $data = mdecrypt_generic($params['handle'], $data); + // Remove PKCS#7 padding, if necessary + if (in_array(strtolower(mcrypt_enc_get_modes_name($params['handle'])), array('cbc', 'ecb'), TRUE)) + { + $data = substr($data, 0, -ord($data[strlen($data)-1])); + } + + mcrypt_generic_deinit($params['handle']); + if ($params['handle'] !== $this->_handle) + { + mcrypt_module_close($params['handle']); + } + + return $data; + } + + // -------------------------------------------------------------------- + + /** + * Decrypt via OpenSSL + * + * @param string $data Encrypted data + * @param array $params Input parameters + * @return string + */ + protected function _openssl_decrypt($data, $params) + { + if ( ! isset($params['iv'])) + { + if ($iv_size = openssl_cipher_iv_length($params['handle'])) + { + $params['iv'] = substr($data, 0, $iv_size); + $data = substr($data, $iv_size); + } + else + { + $params['iv'] = NULL; + } + } + + return empty($params['handle']) + ? FALSE + : openssl_decrypt( + $data, + $params['handle'], + $params['key'], + 1, // DO NOT TOUCH! + $params['iv'] + ); + } + + // -------------------------------------------------------------------- + + /** + * Get params + * + * @param array $params Input parameters + * @return array + */ + protected function _get_params($params) + { + if (empty($params)) + { + return isset($this->_cipher, $this->_mode, $this->_key, $this->_handle) + ? array( + 'handle' => $this->_handle, + 'cipher' => $this->_cipher, + 'mode' => $this->_mode, + 'key' => NULL, + 'base64' => TRUE, + 'hmac_digest' => ($this->_mode !== 'gcm' ? 'sha512' : NULL), + 'hmac_key' => NULL + ) + : FALSE; + } + elseif ( ! isset($params['cipher'], $params['mode'], $params['key'])) + { + return FALSE; + } + + if (isset($params['mode'])) + { + $params['mode'] = strtolower($params['mode']); + if ( ! isset($this->_modes[$this->_driver][$params['mode']])) + { + return FALSE; + } + else + { + $params['mode'] = $this->_modes[$this->_driver][$params['mode']]; + } + } + + if ($params['mode'] === 'gcm' OR (isset($params['hmac']) && $params['hmac'] === FALSE)) + { + $params['hmac_digest'] = $params['hmac_key'] = NULL; + } + else + { + if ( ! isset($params['hmac_key'])) + { + return FALSE; + } + elseif (isset($params['hmac_digest'])) + { + $params['hmac_digest'] = strtolower($params['hmac_digest']); + if ( ! isset($this->_digests[$params['hmac_digest']])) + { + return FALSE; + } + } + else + { + $params['hmac_digest'] = 'sha512'; + } + } + + $params = array( + 'handle' => NULL, + 'cipher' => $params['cipher'], + 'mode' => $params['mode'], + 'key' => $params['key'], + 'iv' => isset($params['iv']) ? $params['iv'] : NULL, + 'base64' => isset($params['raw_data']) ? ! $params['raw_data'] : FALSE, + 'hmac_digest' => $params['hmac_digest'], + 'hmac_key' => $params['hmac_key'] + ); + + $this->_cipher_alias($params['cipher']); + $params['handle'] = ($params['cipher'] !== $this->_cipher OR $params['mode'] !== $this->_mode) + ? $this->{'_'.$this->_driver.'_get_handle'}($params['cipher'], $params['mode']) + : $this->_handle; + + return $params; + } + + // -------------------------------------------------------------------- + + /** + * Get MCrypt handle + * + * @param string $cipher Cipher name + * @param string $mode Encryption mode + * @return resource + */ + protected function _mcrypt_get_handle($cipher, $mode) + { + return mcrypt_module_open($cipher, '', $mode, ''); + } + + // -------------------------------------------------------------------- + + /** + * Get OpenSSL handle + * + * @param string $cipher Cipher name + * @param string $mode Encryption mode + * @return string + */ + protected function _openssl_get_handle($cipher, $mode) + { + // OpenSSL methods aren't suffixed with '-stream' for this mode + return ($mode === 'stream') + ? $cipher + : $cipher.'-'.$mode; + } + + // -------------------------------------------------------------------- + + /** + * Cipher alias + * + * Tries to translate cipher names between MCrypt and OpenSSL's "dialects". + * + * @param string $cipher Cipher name + * @return void + */ + protected function _cipher_alias(&$cipher) + { + static $dictionary; + + if (empty($dictionary)) + { + $dictionary = array( + 'mcrypt' => array( + 'aes-128' => 'rijndael-128', + 'aes-192' => 'rijndael-128', + 'aes-256' => 'rijndael-128', + 'des3-ede3' => 'tripledes', + 'bf' => 'blowfish', + 'cast5' => 'cast-128', + 'rc4' => 'arcfour', + 'rc4-40' => 'arcfour' + ), + 'openssl' => array( + 'rijndael-128' => 'aes-128', + 'tripledes' => 'des-ede3', + 'blowfish' => 'bf', + 'cast-128' => 'cast5', + 'arcfour' => 'rc4-40', + 'rc4' => 'rc4-40' + ) + ); + + // Notes: + // + // - Rijndael-128 is, at the same time all three of AES-128, + // AES-192 and AES-256. The only difference between them is + // the key size. Rijndael-192, Rijndael-256 on the other hand + // also have different block sizes and are NOT AES-compatible. + // + // - Blowfish is said to be supporting key sizes between + // 4 and 56 bytes, but it appears that between MCrypt and + // OpenSSL, only those of 16 and more bytes are compatible. + // Also, don't know what MCrypt's 'blowfish-compat' is. + // + // - CAST-128/CAST5 produces a longer cipher when encrypted via + // OpenSSL, but (strangely enough) can be decrypted by either + // extension anyway. + // Also, RFC2144 says that the cipher supports key sizes + // between 5 and 16 bytes by the implementation actually + // zero-padding them to 16 bytes, but MCrypt doesn't do that. + // + // - RC4 (ARCFour) has a strange implementation under OpenSSL. + // Its 'rc4-40' cipher method seems to work flawlessly, yet + // there's another one, 'rc4' that only works with a 16-byte key. + // + // - DES is compatible, but doesn't need an alias. + // + // Other seemingly matching ciphers between MCrypt, OpenSSL: + // + // - RC2 is NOT compatible and only an obscure forum post + // confirms that it is MCrypt's fault. + } + + if (isset($dictionary[$this->_driver][$cipher])) + { + $cipher = $dictionary[$this->_driver][$cipher]; + } + } + + // -------------------------------------------------------------------- + + /** + * HKDF + * + * @link https://tools.ietf.org/rfc/rfc5869.txt + * @param $key Input key + * @param $digest A SHA-2 hashing algorithm + * @param $salt Optional salt + * @param $length Output length (defaults to the selected digest size) + * @param $info Optional context/application-specific info + * @return string A pseudo-random key + */ + public function hkdf($key, $digest = 'sha512', $salt = NULL, $length = NULL, $info = '') + { + if ( ! isset($this->_digests[$digest])) + { + return FALSE; + } + + if (empty($length) OR ! is_int($length)) + { + $length = $this->_digests[$digest]; + } + elseif ($length > (255 * $this->_digests[$digest])) + { + return FALSE; + } + + isset($salt) OR $salt = str_repeat("\0", $this->_digests[$digest]); + + $prk = hash_hmac($digest, $key, $salt, TRUE); + $key = ''; + for ($key_block = '', $block_index = 1; strlen($key) < $length; $block_index++) + { + $key_block = hash_hmac($digest, $key_block.$info.chr($block_index), $prk, TRUE); + $key .= $key_block; + } + + return substr($key, 0, $length); + } + + // -------------------------------------------------------------------- + + /** + * __get() magic + * + * @param string $key Property name + * @return mixed + */ + public function __get($key) + { + // Because aliases + if ($key === 'mode') + { + return array_search($this->_mode, $this->_modes[$this->_driver], TRUE); + } + elseif (in_array($key, array('cipher', 'driver', 'drivers', 'digests'), TRUE)) + { + return $this->{'_'.$key}; + } + + return NULL; + } + +} + +/* End of file Encryption.php */ +/* Location: ./system/libraries/Encryption.php */
\ No newline at end of file diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php index 8b9bfa897..0c4f94914 100644 --- a/system/libraries/Form_validation.php +++ b/system/libraries/Form_validation.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -144,14 +144,16 @@ class CI_Form_validation { * Set Rules * * This function takes an array of field names and validation - * rules as input, validates the info, and stores it + * rules as input, any custom error messages, validates the info, + * and stores it * * @param mixed $field * @param string $label * @param mixed $rules + * @param array $errors * @return CI_Form_validation */ - public function set_rules($field, $label = '', $rules = '') + public function set_rules($field, $label = '', $rules = '', $errors = array()) { // No reason to set rules if we have no POST data // or a validation array has not been specified @@ -175,8 +177,11 @@ class CI_Form_validation { // If the field label wasn't passed we use the field name $label = isset($row['label']) ? $row['label'] : $row['field']; + // Add the custom error message array + $errors = (isset($row['errors']) && is_array($row['errors'])) ? $row['errors'] : array(); + // Here we go! - $this->set_rules($row['field'], $label, $row['rules']); + $this->set_rules($row['field'], $label, $row['rules'], $errors); } return $this; @@ -224,6 +229,7 @@ class CI_Form_validation { 'field' => $field, 'label' => $label, 'rules' => $rules, + 'errors' => $errors, 'is_array' => $is_array, 'keys' => $indexes, 'postdata' => NULL, @@ -246,14 +252,16 @@ class CI_Form_validation { * each array due to the limitations of CI's singleton * * @param array $data - * @return void + * @return CI_Form_validation */ - public function set_data($data = '') + public function set_data(array $data) { - if ( ! empty($data) && is_array($data)) + if ( ! empty($data)) { $this->validation_data = $data; } + + return $this; } // -------------------------------------------------------------------- @@ -304,12 +312,12 @@ class CI_Form_validation { * * Gets the error message associated with a particular field * - * @param string the field name - * @param string the html start tag - * @param strign the html end tag + * @param string $field Field name + * @param string $prefix HTML start tag + * @param string $suffix HTML end tag * @return string */ - public function error($field = '', $prefix = '', $suffix = '') + public function error($field, $prefix = '', $suffix = '') { if (empty($this->_field_data[$field]['error'])) { @@ -414,18 +422,15 @@ class CI_Form_validation { return FALSE; } - // Is there a validation rule for the particular URI being accessed? - $uri = ($group === '') ? trim($this->CI->uri->ruri_string(), '/') : $group; - - if ($uri !== '' && isset($this->_config_rules[$uri])) + if (empty($group)) { - $this->set_rules($this->_config_rules[$uri]); - } - else - { - $this->set_rules($this->_config_rules); + // Is there a validation rule for the particular URI being accessed? + $group = trim($this->CI->uri->ruri_string(), '/'); + isset($this->_config_rules[$group]) OR $group = $this->CI->router->class.'/'.$this->CI->router->method; } + $this->set_rules(isset($this->_config_rules[$group]) ? $this->_config_rules[$group] : $this->_config_rules); + // Were we able to set the rules correctly? if (count($this->_field_data) === 0) { @@ -605,7 +610,12 @@ class CI_Form_validation { // Set the message type $type = in_array('required', $rules) ? 'required' : 'isset'; - if (isset($this->_error_messages[$type])) + // Check if a custom message is defined + if (isset($this->_field_data[$row['field']]['errors'][$type])) + { + $line = $this->_field_data[$row['field']]['errors'][$type]; + } + elseif (isset($this->_error_messages[$type])) { $line = $this->_error_messages[$type]; } @@ -749,7 +759,12 @@ class CI_Form_validation { // Did the rule test negatively? If so, grab the error. if ($result === FALSE) { - if ( ! isset($this->_error_messages[$rule])) + // Check if a custom message is defined + if (isset($this->_field_data[$row['field']]['errors'][$rule])) + { + $line = $this->_field_data[$row['field']]['errors'][$rule]; + } + elseif ( ! isset($this->_error_messages[$rule])) { if (FALSE === ($line = $this->CI->lang->line('form_validation_'.$rule)) // DEPRECATED support for non-prefixed keys @@ -898,12 +913,19 @@ class CI_Form_validation { } $field = $this->_field_data[$field]['postdata']; + $value = (string) $value; if (is_array($field)) { - if ( ! in_array($value, $field)) + // Note: in_array('', array(0)) returns TRUE, do not use it + foreach ($field as &$v) { - return ''; + if ($value === $v) + { + return ' selected="selected"'; + } } + + return ''; } elseif (($field === '' OR $value === '') OR ($field !== $value)) { @@ -934,12 +956,19 @@ class CI_Form_validation { } $field = $this->_field_data[$field]['postdata']; + $value = (string) $value; if (is_array($field)) { - if ( ! in_array($value, $field)) + // Note: in_array('', array(0)) returns TRUE, do not use it + foreach ($field as &$v) { - return ''; + if ($value === $v) + { + return ' checked="checked"'; + } } + + return ''; } elseif (($field === '' OR $value === '') OR ($field !== $value)) { @@ -1509,7 +1538,7 @@ class CI_Form_validation { * Prevents subsequent validation routines from being affected by the * results of any previous validation routine due to the CI singleton. * - * @return void + * @return CI_Form_validation */ public function reset_validation() { @@ -1518,6 +1547,7 @@ class CI_Form_validation { $this->_error_array = array(); $this->_error_messages = array(); $this->error_string = ''; + return $this; } } diff --git a/system/libraries/Ftp.php b/system/libraries/Ftp.php index dc6bbd226..ef3b7d70d 100644 --- a/system/libraries/Ftp.php +++ b/system/libraries/Ftp.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -214,12 +214,12 @@ class CI_FTP { * Internally, this parameter is only used by the "mirror" function below. * * @param string $path - * @param bool $supress_debug + * @param bool $suppress_debug * @return bool */ - public function changedir($path = '', $supress_debug = FALSE) + public function changedir($path, $suppress_debug = FALSE) { - if ($path === '' OR ! $this->_is_conn()) + if ( ! $this->_is_conn()) { return FALSE; } @@ -228,7 +228,7 @@ class CI_FTP { if ($result === FALSE) { - if ($this->debug === TRUE && $supress_debug === FALSE) + if ($this->debug === TRUE && $suppress_debug === FALSE) { $this->_error('ftp_unable_to_changedir'); } @@ -247,7 +247,7 @@ class CI_FTP { * @param int $permissions * @return bool */ - public function mkdir($path = '', $permissions = NULL) + public function mkdir($path, $permissions = NULL) { if ($path === '' OR ! $this->_is_conn()) { @@ -260,7 +260,7 @@ class CI_FTP { { if ($this->debug === TRUE) { - $this->_error('ftp_unable_to_makdir'); + $this->_error('ftp_unable_to_mkdir'); } return FALSE; } @@ -392,7 +392,7 @@ class CI_FTP { { if ($this->debug === TRUE) { - $this->_error('ftp_unable_to_' . ($move === FALSE ? 'rename' : 'move')); + $this->_error('ftp_unable_to_'.($move === FALSE ? 'rename' : 'move')); } return FALSE; } diff --git a/system/libraries/Image_lib.php b/system/libraries/Image_lib.php index b6a11a3a5..db45a80fc 100644 --- a/system/libraries/Image_lib.php +++ b/system/libraries/Image_lib.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -1245,22 +1245,37 @@ class CI_Image_lib { // offset flips itself automatically if ($this->wm_vrt_alignment === 'B') + { $this->wm_vrt_offset = $this->wm_vrt_offset * -1; + } if ($this->wm_hor_alignment === 'R') + { $this->wm_hor_offset = $this->wm_hor_offset * -1; + } // Set font width and height // These are calculated differently depending on // whether we are using the true type font or not if ($this->wm_use_truetype === TRUE) { - if ($this->wm_font_size === '') + if (empty($this->wm_font_size)) { $this->wm_font_size = 17; } - $fontwidth = $this->wm_font_size-($this->wm_font_size/4); + if (function_exists('imagettfbbox')) + { + $temp = imagettfbbox($this->wm_font_size, 0, $this->wm_font_path, $this->wm_text); + $temp = $temp[2] - $temp[0]; + + $fontwidth = $temp / strlen($this->wm_text); + } + else + { + $fontwidth = $this->wm_font_size - ($this->wm_font_size / 4); + } + $fontheight = $this->wm_font_size; $this->wm_vrt_offset += $this->wm_font_size; } @@ -1368,45 +1383,45 @@ class CI_Image_lib { public function image_create_gd($path = '', $image_type = '') { if ($path === '') + { $path = $this->full_src_path; + } if ($image_type === '') + { $image_type = $this->image_type; + } switch ($image_type) { - case 1 : - if ( ! function_exists('imagecreatefromgif')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); - return FALSE; - } + case 1 : + if ( ! function_exists('imagecreatefromgif')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_gif_not_supported')); + return FALSE; + } - return imagecreatefromgif($path); - break; + return imagecreatefromgif($path); case 2 : - if ( ! function_exists('imagecreatefromjpeg')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); - return FALSE; - } + if ( ! function_exists('imagecreatefromjpeg')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_jpg_not_supported')); + return FALSE; + } - return imagecreatefromjpeg($path); - break; + return imagecreatefromjpeg($path); case 3 : - if ( ! function_exists('imagecreatefrompng')) - { - $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); - return FALSE; - } - - return imagecreatefrompng($path); - break; + if ( ! function_exists('imagecreatefrompng')) + { + $this->set_error(array('imglib_unsupported_imagecreate', 'imglib_png_not_supported')); + return FALSE; + } + return imagecreatefrompng($path); + default: + $this->set_error(array('imglib_unsupported_imagecreate')); + return FALSE; } - - $this->set_error(array('imglib_unsupported_imagecreate')); - return FALSE; } // -------------------------------------------------------------------- diff --git a/system/libraries/Javascript.php b/system/libraries/Javascript.php index 26a16850c..c71a4204e 100644 --- a/system/libraries/Javascript.php +++ b/system/libraries/Javascript.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -34,6 +34,7 @@ defined('BASEPATH') OR exit('No direct script access allowed'); * @category Javascript * @author EllisLab Dev Team * @link http://codeigniter.com/user_guide/libraries/javascript.html + * @deprecated 3.0.0 This was never a good idea in the first place. */ class CI_Javascript { diff --git a/system/libraries/Javascript/Jquery.php b/system/libraries/Javascript/Jquery.php index ab78e8b2e..1cc3d2c21 100644 --- a/system/libraries/Javascript/Jquery.php +++ b/system/libraries/Javascript/Jquery.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 diff --git a/system/libraries/Migration.php b/system/libraries/Migration.php index cc6fe48f0..932b06ef0 100644 --- a/system/libraries/Migration.php +++ b/system/libraries/Migration.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2006 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2006 - 2014, 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 diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php index 10fb29dbd..f2d38a852 100644 --- a/system/libraries/Pagination.php +++ b/system/libraries/Pagination.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -304,6 +304,16 @@ class CI_Pagination { */ public function __construct($params = array()) { + $CI =& get_instance(); + $CI->load->language('pagination'); + foreach (array('first_link', 'next_link', 'prev_link', 'last_link') as $key) + { + if (($val = $CI->lang->line('pagination_'.$key)) !== FALSE) + { + $this->$key = $val; + } + } + $this->initialize($params); log_message('debug', 'Pagination Class Initialized'); } @@ -314,9 +324,9 @@ class CI_Pagination { * Initialize Preferences * * @param array $params Initialization parameters - * @return void + * @return CI_Pagination */ - public function initialize($params = array()) + public function initialize(array $params = array()) { if (isset($params['attributes']) && is_array($params['attributes'])) { @@ -332,16 +342,15 @@ class CI_Pagination { unset($params['anchor_class']); } - if (count($params) > 0) + foreach ($params as $key => $val) { - foreach ($params as $key => $val) + if (property_exists($this, $this->$key)) { - if (isset($this->$key)) - { - $this->$key = $val; - } + $this->$key = $val; } } + + return $this; } // -------------------------------------------------------------------- @@ -354,7 +363,8 @@ class CI_Pagination { public function create_links() { // If our item count or per-page total is zero there is no need to continue. - if ($this->total_rows === 0 OR $this->per_page === 0) + // Note: DO NOT change the operator to === here! + if ($this->total_rows == 0 OR $this->per_page == 0) { return ''; } @@ -393,30 +403,32 @@ class CI_Pagination { } // Put together our base and first URLs. - $this->base_url = trim($this->base_url); + // Note: DO NOT append to the properties as that would break successive calls + $base_url = trim($this->base_url); + $first_url = $this->first_url; $query_string = ''; - $query_string_sep = (strpos($this->base_url, '?') === FALSE) ? '?' : '&'; + $query_string_sep = (strpos($base_url, '?') === FALSE) ? '?' : '&'; // Are we using query strings? if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE) { // If a custom first_url hasn't been specified, we'll create one from // the base_url, but without the page item. - if ($this->first_url === '') + if ($first_url === '') { - $this->first_url = $this->base_url; + $first_url = $base_url; // If we saved any GET items earlier, make sure they're appended. if ( ! empty($get)) { - $this->first_url .= $query_string_sep.http_build_query($get); + $first_url .= $query_string_sep.http_build_query($get); } } // Add the page segment to the end of the query string, where the // page number will be appended. - $this->base_url .= $query_string_sep.http_build_query(array_merge($get, array($this->query_string_segment => ''))); + $base_url .= $query_string_sep.http_build_query(array_merge($get, array($this->query_string_segment => ''))); } else { @@ -430,17 +442,17 @@ class CI_Pagination { // Does the base_url have the query string in it? // If we're supposed to save it, remove it so we can append it later. - if ($this->reuse_query_string === TRUE && ($base_query_pos = strpos($this->base_url, '?')) !== FALSE) + if ($this->reuse_query_string === TRUE && ($base_query_pos = strpos($base_url, '?')) !== FALSE) { - $this->base_url = substr($this->base_url, 0, $base_query_pos); + $base_url = substr($base_url, 0, $base_query_pos); } - if ($this->first_url === '') + if ($first_url === '') { - $this->first_url = $this->base_url.$query_string; + $first_url = $base_url.$query_string; } - $this->base_url = rtrim($this->base_url, '/').'/'; + $base_url = rtrim($base_url, '/').'/'; } // Determine the current page number. @@ -516,8 +528,8 @@ class CI_Pagination { // Take the general parameters, and squeeze this pagination-page attr in for JS frameworks. $attributes = sprintf('%s %s="%d"', $this->_attributes, $this->data_page_attr, 1); - $output .= $this->first_tag_open.'<a href="'.$this->first_url.'"'.$attributes.$this->_attr_rel('start').'>' - .$this->first_link.'</a>'.$this->first_tag_close; + $output .= $this->first_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>' + .$first_link.'</a>'.$this->first_tag_close; } // Render the "Previous" link. @@ -530,13 +542,13 @@ class CI_Pagination { if ($i === $base_page) { // First page - $output .= $this->prev_tag_open.'<a href="'.$this->first_url.'"'.$attributes.$this->_attr_rel('prev').'>' + $output .= $this->prev_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('prev').'>' .$this->prev_link.'</a>'.$this->prev_tag_close; } else { $append = $this->prefix.$i.$this->suffix; - $output .= $this->prev_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>' + $output .= $this->prev_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.$this->_attr_rel('prev').'>' .$this->prev_link.'</a>'.$this->prev_tag_close; } @@ -562,13 +574,13 @@ class CI_Pagination { elseif ($i === $base_page) { // First page - $output .= $this->num_tag_open.'<a href="'.$this->first_url.'"'.$attributes.$this->_attr_rel('start').'>' + $output .= $this->num_tag_open.'<a href="'.$first_url.'"'.$attributes.$this->_attr_rel('start').'>' .$loop.'</a>'.$this->num_tag_close; } else { $append = $this->prefix.$i.$this->suffix; - $output .= $this->num_tag_open.'<a href="'.$this->base_url.$append.'"'.$attributes.$this->_attr_rel('start').'>' + $output .= $this->num_tag_open.'<a href="'.$base_url.$append.'"'.$attributes.$this->_attr_rel('start').'>' .$loop.'</a>'.$this->num_tag_close; } } @@ -582,7 +594,7 @@ class CI_Pagination { $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 + $output .= $this->next_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes .$this->_attr_rel('next').'>'.$this->next_link.'</a>'.$this->next_tag_close; } @@ -593,7 +605,7 @@ class CI_Pagination { $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.'>' + $output .= $this->last_tag_open.'<a href="'.$base_url.$this->prefix.$i.$this->suffix.'"'.$attributes.'>' .$this->last_link.'</a>'.$this->last_tag_close; } diff --git a/system/libraries/Parser.php b/system/libraries/Parser.php index c1f1ad73b..d23a53423 100644 --- a/system/libraries/Parser.php +++ b/system/libraries/Parser.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -187,26 +187,34 @@ class CI_Parser { */ protected function _parse_pair($variable, $data, $string) { - if (FALSE === ($match = $this->_match_pair($string, $variable))) + if (FALSE === ($matches = $this->_match_pair($string, $variable))) { return $string; } $str = ''; - foreach ($data as $row) + $search = $replace = array(); + foreach ($matches as $match) { - $temp = $match[1]; - foreach ($row as $key => $val) + $str = ''; + foreach ($data as $row) { - $temp = is_array($val) + $temp = $match[1]; + foreach ($row as $key => $val) + { + $temp = is_array($val) ? $this->_parse_pair($key, $val, $temp) : $this->_parse_single($key, $val, $temp); + } + + $str .= $temp; } - $str .= $temp; + $search[] = $match[0]; + $replace[] = $str; } - return str_replace($match[0], $str, $string); + return str_replace($search, $replace, $string); } // -------------------------------------------------------------------- @@ -214,14 +222,14 @@ class CI_Parser { /** * Matches a variable pair * - * @param string - * @param string + * @param string $string + * @param string $variable * @return mixed */ protected function _match_pair($string, $variable) { - return preg_match('|'.preg_quote($this->l_delim).$variable.preg_quote($this->r_delim).'(.+?)'.preg_quote($this->l_delim).'/'.$variable.preg_quote($this->r_delim).'|s', - $string, $match) + return preg_match_all('|'.preg_quote($this->l_delim).$variable.preg_quote($this->r_delim).'(.+?)'.preg_quote($this->l_delim).'/'.$variable.preg_quote($this->r_delim).'|s', + $string, $match, PREG_SET_ORDER) ? $match : FALSE; } diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php index 9e9e7d08d..810a025a4 100644 --- a/system/libraries/Profiler.php +++ b/system/libraries/Profiler.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -278,6 +278,7 @@ class CI_Profiler { } $output .= "</table>\n</fieldset>"; + $count++; } return $output; @@ -307,10 +308,7 @@ class CI_Profiler { foreach ($_GET as $key => $val) { - if ( ! is_numeric($key)) - { - $key = "'".$key."'"; - } + is_int($key) OR $key = "'".$key."'"; $output .= '<tr><td style="width:50%;color:#000;background-color:#ddd;padding:5px;">$_GET[' .$key.'] </td><td style="width:50%;padding:5px;color:#cd6e00;font-weight:normal;background-color:#ddd;">' @@ -338,7 +336,7 @@ class CI_Profiler { ."\n" .'<legend style="color:#009900;"> '.$this->CI->lang->line('profiler_post_data')." </legend>\n"; - if (count($_POST) === 0) + if (count($_POST) === 0 && count($_FILES) === 0) { $output .= '<div style="color:#009900;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_post').'</div>'; } @@ -348,10 +346,7 @@ class CI_Profiler { foreach ($_POST as $key => $val) { - if ( ! is_numeric($key)) - { - $key = "'".$key."'"; - } + is_int($key) OR $key = "'".$key."'"; $output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">$_POST[' .$key.'] </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">'; @@ -368,6 +363,21 @@ class CI_Profiler { $output .= "</td></tr>\n"; } + foreach ($_FILES as $key => $val) + { + is_int($key) OR $key = "'".$key."'"; + + $output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">$_FILES[' + .$key.'] </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">'; + + if (is_array($val) OR is_object($val)) + { + $output .= '<pre>'.htmlspecialchars(stripslashes(print_r($val, TRUE))).'</pre>'; + } + + $output .= "</td></tr>\n"; + } + $output .= "</table>\n"; } @@ -506,7 +516,7 @@ class CI_Profiler { .'<legend style="color:#000;"> '.$this->CI->lang->line('profiler_session_data').' (<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_session_data\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>' .'<table style="width:100%;display:none;" id="ci_profiler_session_data">'; - foreach ($this->CI->session->all_userdata() as $key => $val) + foreach ($this->CI->session->userdata() as $key => $val) { if (is_array($val) OR is_object($val)) { diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php index 659a0269e..905352bb3 100644 --- a/system/libraries/Session/Session.php +++ b/system/libraries/Session/Session.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -102,10 +102,10 @@ class CI_Session extends CI_Driver_Library { */ public function __construct(array $params = array()) { - $CI =& get_instance(); + $_config =& get_instance()->config; // No sessions under CLI - if ($CI->input->is_cli_request()) + if (is_cli()) { return; } @@ -113,7 +113,7 @@ class CI_Session extends CI_Driver_Library { log_message('debug', 'CI_Session Class Initialized'); // Add possible extra entries to our valid drivers list - $drivers = isset($params['sess_valid_drivers']) ? $params['sess_valid_drivers'] : $CI->config->item('sess_valid_drivers'); + $drivers = isset($params['sess_valid_drivers']) ? $params['sess_valid_drivers'] : $_config->item('sess_valid_drivers'); if ( ! empty($drivers)) { $drivers = array_map('strtolower', (array) $drivers); @@ -121,7 +121,7 @@ class CI_Session extends CI_Driver_Library { } // Get driver to load - $driver = isset($params['sess_driver']) ? $params['sess_driver'] : $CI->config->item('sess_driver'); + $driver = isset($params['sess_driver']) ? $params['sess_driver'] : $_config->item('sess_driver'); if ( ! $driver) { log_message('debug', "Session: No driver name is configured, defaulting to 'cookie'."); @@ -238,9 +238,14 @@ class CI_Session extends CI_Driver_Library { * @param string Item key * @return string Item value or NULL if not found */ - public function userdata($item) + public function userdata($item = NULL) { - return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL; + if (isset($item)) + { + return isset($this->userdata[$item]) ? $this->userdata[$item] : NULL; + } + + return isset($this->userdata) ? $this->userdata : array(); } // ------------------------------------------------------------------------ @@ -248,35 +253,12 @@ class CI_Session extends CI_Driver_Library { /** * Fetch all session data * + * @deprecated 3.0.0 Use userdata() with no parameters instead * @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; + return isset($this->userdata) ? $this->userdata : array(); } // ------------------------------------------------------------------------ @@ -288,7 +270,7 @@ class CI_Session extends CI_Driver_Library { * @param string Item value or empty string * @return void */ - public function set_userdata($newdata = array(), $newval = '') + public function set_userdata($newdata, $newval = '') { // Wrap params as array if singular if (is_string($newdata)) @@ -317,7 +299,7 @@ class CI_Session extends CI_Driver_Library { * @param mixed Item name or array of item names * @return void */ - public function unset_userdata($newdata = array()) + public function unset_userdata($newdata) { // Wrap single name as array if (is_string($newdata)) @@ -360,7 +342,7 @@ class CI_Session extends CI_Driver_Library { * @param string Item value or empty string * @return void */ - public function set_flashdata($newdata = array(), $newval = '') + public function set_flashdata($newdata, $newval = '') { // Wrap item as array if singular if (is_string($newdata)) @@ -417,11 +399,25 @@ class CI_Session extends CI_Driver_Library { * @param string Item key * @return string */ - public function flashdata($key) + public function flashdata($key = NULL) { - // Prepend key and retrieve value - $flashdata_key = self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key; - return $this->userdata($flashdata_key); + if (isset($key)) + { + return $this->userdata(self::FLASHDATA_KEY.self::FLASHDATA_OLD.$key); + } + + // Get our flashdata items from userdata + $out = array(); + foreach ($this->userdata() as $key => $val) + { + 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; } // ------------------------------------------------------------------------ @@ -434,7 +430,7 @@ class CI_Session extends CI_Driver_Library { * @param int Item lifetime in seconds or 0 for default * @return void */ - public function set_tempdata($newdata = array(), $newval = '', $expire = 0) + public function set_tempdata($newdata, $newval = '', $expire = 0) { // Set expiration time $expire = time() + ($expire ? $expire : self::TEMP_EXP_DEF); @@ -475,7 +471,7 @@ class CI_Session extends CI_Driver_Library { * @param mixed Item name or array of item names * @return void */ - public function unset_tempdata($newdata = array()) + public function unset_tempdata($newdata) { // Get expirations list $expirations = $this->userdata(self::EXPIRATION_KEY); @@ -514,11 +510,25 @@ class CI_Session extends CI_Driver_Library { * @param string Item key * @return string */ - public function tempdata($key) + public function tempdata($key = NULL) { - // Prepend key and return value - $tempdata_key = self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key; - return $this->userdata($tempdata_key); + if (isset($key)) + { + return $this->userdata(self::FLASHDATA_KEY.self::FLASHDATA_EXP.$key); + } + + // Get our tempdata items from userdata + $out = array(); + foreach ($this->userdata() as $key => $val) + { + if (strpos($key, self::FLASHDATA_KEY.self::FLASHDATA_EXP) !== FALSE) + { + $key = str_replace(self::FLASHDATA_KEY.self::FLASHDATA_EXP, '', $key); + $out[$key] = $val; + } + } + + return $out; } // ------------------------------------------------------------------------ @@ -531,13 +541,12 @@ class CI_Session extends CI_Driver_Library { */ protected function _flashdata_mark() { - foreach ($this->all_userdata() as $name => $value) + foreach ($this->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->set_userdata(self::FLASHDATA_KEY.self::FLASHDATA_OLD.$parts[1], $value); $this->unset_userdata($name); } } @@ -552,7 +561,7 @@ class CI_Session extends CI_Driver_Library { */ protected function _flashdata_sweep() { - $userdata = $this->all_userdata(); + $userdata = $this->userdata(); foreach (array_keys($userdata) as $key) { if (strpos($key, self::FLASHDATA_OLD)) @@ -581,7 +590,7 @@ class CI_Session extends CI_Driver_Library { // Unset expired elements $now = time(); - $userdata = $this->all_userdata(); + $userdata = $this->userdata(); foreach (array_keys($userdata) as $key) { if (strpos($key, self::FLASHDATA_EXP) && $expirations[$key] < $now) diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php index d3d22d03a..566c40bd8 100644 --- a/system/libraries/Session/drivers/Session_cookie.php +++ b/system/libraries/Session/drivers/Session_cookie.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -165,6 +165,8 @@ class CI_Session_cookie extends CI_Session_driver { */ public $now; + // ------------------------------------------------------------------------ + /** * Default userdata keys * @@ -185,6 +187,15 @@ class CI_Session_cookie extends CI_Session_driver { protected $data_dirty = FALSE; /** + * Standardize newlines flag + * + * @var bool + */ + protected $_standardize_newlines; + + // ------------------------------------------------------------------------ + + /** * Initialize session driver object * * @return void @@ -209,9 +220,11 @@ class CI_Session_cookie extends CI_Session_driver { 'sess_time_to_update', 'time_reference', 'cookie_prefix', - 'encryption_key' + 'encryption_key', ); + $this->_standardize_newlines = (bool) config_item('standardize_newlines'); + foreach ($prefs as $key) { $this->$key = isset($this->_parent->params[$key]) @@ -227,7 +240,7 @@ class CI_Session_cookie extends CI_Session_driver { // Do we need encryption? If so, load the encryption class if ($this->sess_encrypt_cookie === TRUE) { - $this->CI->load->library('encrypt'); + $this->CI->load->library('encryption'); } // Check for database @@ -370,34 +383,45 @@ class CI_Session_cookie extends CI_Session_driver { return FALSE; } - $len = strlen($session) - 40; - - if ($len < 0) + if ($this->sess_encrypt_cookie === TRUE) { - log_message('debug', 'The session cookie was not signed.'); - return FALSE; + $session = $this->CI->encryption->decrypt($session); + if ($session === FALSE) + { + log_message('error', 'Session: Unable to decrypt the session cookie, possibly due to a HMAC mismatch.'); + return FALSE; + } } + else + { + if (($len = strlen($session) - 40) <= 0) + { + log_message('error', 'Session: The session cookie was not signed.'); + return FALSE; + } - // Check cookie authentication - $hmac = substr($session, $len); - $session = substr($session, 0, $len); + // 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; - } + // Time-attack-safe comparison + $hmac_check = hash_hmac('sha1', $session, $this->encryption_key); + $diff = 0; + for ($i = 0; $i < 40; $i++) + { + $diff |= ord($hmac[$i]) ^ ord($hmac_check[$i]); + } - // Check for encryption - if ($this->sess_encrypt_cookie === TRUE) - { - // Decrypt the cookie data - $session = $this->CI->encrypt->decode($session); + if ($diff !== 0) + { + log_message('error', 'Session: HMAC mismatch. The session cookie data did not match what was expected.'); + $this->sess_destroy(); + return FALSE; + } } // Unserialize the session array - $session = $this->_unserialize($session); + $session = @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'])) @@ -472,7 +496,7 @@ class CI_Session_cookie extends CI_Session_driver { $row = $query->row(); if ( ! empty($row->user_data)) { - $custom_data = $this->_unserialize($row->user_data); + $custom_data = unserialize(trim($row->user_data)); if (is_array($custom_data)) { @@ -608,7 +632,7 @@ class CI_Session_cookie extends CI_Session_driver { if ( ! empty($userdata)) { // Serialize the custom data array so we can store it - $set['user_data'] = $this->_serialize($userdata); + $set['user_data'] = serialize($userdata); } // Reset query builder values. @@ -695,16 +719,28 @@ class CI_Session_cookie extends CI_Session_driver { ? array_intersect_key($this->userdata, $this->defaults) : $this->userdata; + // The Input class will do this and since we use HMAC verification, + // unless we standardize here as well, the hash won't match. + if ($this->_standardize_newlines) + { + foreach (array_keys($this->userdata) as $key) + { + $this->userdata[$key] = preg_replace('/(?:\r\n|[\r\n])/', PHP_EOL, $this->userdata[$key]); + } + } + // Serialize the userdata for the cookie - $cookie_data = $this->_serialize($cookie_data); + $cookie_data = serialize($cookie_data); if ($this->sess_encrypt_cookie === TRUE) { - $cookie_data = $this->CI->encrypt->encode($cookie_data); + $cookie_data = $this->CI->encryption->encrypt($cookie_data); + } + else + { + // Require message authentication + $cookie_data .= hash_hmac('sha1', $cookie_data, $this->encryption_key); } - - // 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(); @@ -737,93 +773,6 @@ class CI_Session_cookie extends CI_Session_driver { // ------------------------------------------------------------------------ /** - * 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 @@ -841,7 +790,7 @@ class CI_Session_cookie extends CI_Session_driver { $probability = ini_get('session.gc_probability'); $divisor = ini_get('session.gc_divisor'); - if ((mt_rand(0, $divisor) / $divisor) < $probability) + if (mt_rand(1, $divisor) <= $probability) { $expire = $this->now - $this->sess_expiration; $this->CI->db->delete($this->sess_table_name, 'last_activity < '.$expire); diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php index c237ad059..4104652b8 100644 --- a/system/libraries/Session/drivers/Session_native.php +++ b/system/libraries/Session/drivers/Session_native.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 diff --git a/system/libraries/Table.php b/system/libraries/Table.php index b77fcf19d..ff96d9275 100644 --- a/system/libraries/Table.php +++ b/system/libraries/Table.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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.3.1 @@ -93,7 +93,7 @@ class CI_Table { * * @var function */ - public $function = FALSE; + public $function = NULL; /** * Set the template from the table config file if it exists @@ -117,7 +117,7 @@ class CI_Table { /** * Set the template * - * @param array + * @param array $template * @return bool */ public function set_template($template) @@ -139,12 +139,12 @@ class CI_Table { * Can be passed as an array or discreet params * * @param mixed - * @return void + * @return CI_Table */ public function set_heading($args = array()) { - $args = func_get_args(); - $this->heading = $this->_prep_args($args); + $this->heading = $this->_prep_args(func_get_args()); + return $this; } // -------------------------------------------------------------------- @@ -155,9 +155,9 @@ class CI_Table { * columns. This allows a single array with many elements to be * displayed in a table that has a fixed column count. * - * @param array - * @param int - * @return void + * @param array $array + * @param int $col_limit + * @return array */ public function make_columns($array = array(), $col_limit = 0) { @@ -202,12 +202,13 @@ class CI_Table { * * Can be passed as an array or discreet params * - * @param mixed - * @return void + * @param mixed $value + * @return CI_Table */ public function set_empty($value) { $this->empty_cells = $value; + return $this; } // -------------------------------------------------------------------- @@ -218,12 +219,12 @@ class CI_Table { * Can be passed as an array or discreet params * * @param mixed - * @return void + * @return CI_Table */ public function add_row($args = array()) { - $args = func_get_args(); - $this->rows[] = $this->_prep_args($args); + $this->rows[] = $this->_prep_args(func_get_args()); + return $this; } // -------------------------------------------------------------------- @@ -241,26 +242,14 @@ class CI_Table { // If there is no $args[0], skip this and treat as an associative array // This can happen if there is only a single key, for example this is passed to table->generate // array(array('foo'=>'bar')) - if (isset($args[0]) && count($args) === 1 && is_array($args[0])) + if (isset($args[0]) && count($args) === 1 && is_array($args[0]) && ! isset($args[0]['data'])) { - // args sent as indexed array - if ( ! isset($args[0]['data'])) - { - foreach ($args[0] as $key => $val) - { - $args[$key] = (is_array($val) && isset($val['data'])) ? $val : array('data' => $val); - } - } + $args = $args[0]; } - else + + foreach ($args as $key => $val) { - foreach ($args as $key => $val) - { - if ( ! is_array($val)) - { - $args[$key] = array('data' => $val); - } - } + is_array($val) OR $args[$key] = array('data' => $val); } return $args; @@ -271,8 +260,8 @@ class CI_Table { /** * Add a table caption * - * @param string - * @return void + * @param string $caption + * @return CI_Table */ public function set_caption($caption) { @@ -284,28 +273,27 @@ class CI_Table { /** * Generate the table * - * @param mixed + * @param mixed $table_data * @return string */ public function generate($table_data = NULL) { // The table data can optionally be passed to this function // either as a database result object or an array - if ($table_data !== NULL) + if ( ! empty($table_data)) { - if (is_object($table_data)) + if ($table_data instanceof CI_DB_result) { - $this->_set_from_object($table_data); + $this->_set_from_db_result($table_data); } elseif (is_array($table_data)) { - $set_heading = (count($this->heading) !== 0 OR $this->auto_heading !== FALSE); - $this->_set_from_array($table_data, $set_heading); + $this->_set_from_array($table_data); } } // Is there anything to display? No? Smite them! - if (count($this->heading) === 0 && count($this->rows) === 0) + if (empty($this->heading) && empty($this->rows)) { return 'Undefined table data'; } @@ -313,8 +301,11 @@ class CI_Table { // Compile and validate the template date $this->_compile_template(); - // set a custom cell manipulation function to a locally scoped variable so its callable - $function = $this->function; + // Validate a possibly existing custom cell manipulation function + if (isset($this->function) && ! is_callable($this->function)) + { + $this->function = NULL; + } // Build the table! @@ -323,11 +314,11 @@ class CI_Table { // Add any caption here if ($this->caption) { - $out .= $this->newline.'<caption>'.$this->caption.'</caption>'.$this->newline; + $out .= '<caption>'.$this->caption.'</caption>'.$this->newline; } // Is there a table heading to display? - if (count($this->heading) > 0) + if ( ! empty($this->heading)) { $out .= $this->template['thead_open'].$this->newline.$this->template['heading_row_start'].$this->newline; @@ -350,7 +341,7 @@ class CI_Table { } // Build the table rows - if (count($this->rows) > 0) + if ( ! empty($this->rows)) { $out .= $this->template['tbody_open'].$this->newline; @@ -386,9 +377,9 @@ class CI_Table { { $out .= $this->empty_cells; } - elseif ($function !== FALSE && is_callable($function)) + elseif (isset($this->function)) { - $out .= call_user_func($function, $cell); + $out .= call_user_func($this->function, $cell); } else { @@ -417,13 +408,14 @@ class CI_Table { /** * Clears the table arrays. Useful if multiple tables are being generated * - * @return void + * @return CI_Table */ public function clear() { - $this->rows = array(); - $this->heading = array(); - $this->auto_heading = TRUE; + $this->rows = array(); + $this->heading = array(); + $this->auto_heading = TRUE; + return $this; } // -------------------------------------------------------------------- @@ -431,34 +423,20 @@ class CI_Table { /** * Set table data from a database result object * - * @param object + * @param CI_DB_result $db_result Database result object * @return void */ - protected function _set_from_object($query) + protected function _set_from_db_result($object) { - if ( ! is_object($query)) - { - return; - } - // First generate the headings from the table column names - if (count($this->heading) === 0) + if ($this->auto_heading === TRUE && empty($this->heading)) { - if ( ! is_callable(array($query, 'list_fields'))) - { - return; - } - - $this->heading = $this->_prep_args($query->list_fields()); + $this->heading = $this->_prep_args($object->list_fields()); } - // Next blast through the result array and build out the rows - if ($query->num_rows() > 0) + foreach ($object->result_array() as $row) { - foreach ($query->result_array() as $row) - { - $this->rows[] = $this->_prep_args($row); - } + $this->rows[] = $this->_prep_args($row); } } @@ -467,29 +445,19 @@ class CI_Table { /** * Set table data from an array * - * @param array - * @param bool + * @param array $data * @return void */ - protected function _set_from_array($data, $set_heading = TRUE) + protected function _set_from_array($data) { - if ( ! is_array($data) OR count($data) === 0) + if ($this->auto_heading === TRUE && empty($this->heading)) { - return FALSE; + $this->heading = $this->_prep_args(array_shift($data)); } - $i = 0; - foreach ($data as $row) + foreach ($data as &$row) { - // If a heading hasn't already been set we'll use the first row of the array as the heading - if ($i++ === 0 && count($data) > 1 && count($this->heading) === 0 && $set_heading === TRUE) - { - $this->heading = $this->_prep_args($row); - } - else - { - $this->rows[] = $this->_prep_args($row); - } + $this->rows[] = $this->_prep_args($row); } } @@ -528,31 +496,31 @@ class CI_Table { protected function _default_template() { return array( - 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', + 'table_open' => '<table border="0" cellpadding="4" cellspacing="0">', - 'thead_open' => '<thead>', - 'thead_close' => '</thead>', + 'thead_open' => '<thead>', + 'thead_close' => '</thead>', - 'heading_row_start' => '<tr>', - 'heading_row_end' => '</tr>', - 'heading_cell_start' => '<th>', - 'heading_cell_end' => '</th>', + 'heading_row_start' => '<tr>', + 'heading_row_end' => '</tr>', + 'heading_cell_start' => '<th>', + 'heading_cell_end' => '</th>', - 'tbody_open' => '<tbody>', - 'tbody_close' => '</tbody>', + 'tbody_open' => '<tbody>', + 'tbody_close' => '</tbody>', - 'row_start' => '<tr>', - 'row_end' => '</tr>', - 'cell_start' => '<td>', - 'cell_end' => '</td>', + 'row_start' => '<tr>', + 'row_end' => '</tr>', + 'cell_start' => '<td>', + 'cell_end' => '</td>', - 'row_alt_start' => '<tr>', - 'row_alt_end' => '</tr>', - 'cell_alt_start' => '<td>', - 'cell_alt_end' => '</td>', + 'row_alt_start' => '<tr>', + 'row_alt_end' => '</tr>', + 'cell_alt_start' => '<td>', + 'cell_alt_end' => '</td>', - 'table_close' => '</table>' - ); + 'table_close' => '</table>' + ); } } diff --git a/system/libraries/Trackback.php b/system/libraries/Trackback.php index 5a45be8dd..9fa4a8edb 100644 --- a/system/libraries/Trackback.php +++ b/system/libraries/Trackback.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -181,7 +181,14 @@ class CI_Trackback { if ($val !== 'url' && MB_ENABLED === TRUE) { - $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']); + if (MB_ENABLED === TRUE) + { + $_POST[$val] = mb_convert_encoding($_POST[$val], $this->charset, $this->data['charset']); + } + elseif (ICONV_ENABLED === TRUE) + { + $_POST[$val] = @iconv($this->data['charset'], $this->charset.'//IGNORE', $_POST[$val]); + } } $_POST[$val] = ($val !== 'url') ? $this->convert_xml(strip_tags($_POST[$val])) : strip_tags($_POST[$val]); diff --git a/system/libraries/Typography.php b/system/libraries/Typography.php index dd79e850a..d5e4ee06b 100644 --- a/system/libraries/Typography.php +++ b/system/libraries/Typography.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php index 7a67c7276..cc882bc72 100644 --- a/system/libraries/Unit_test.php +++ b/system/libraries/Unit_test.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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.3.1 @@ -81,7 +81,15 @@ class CI_Unit_test { * * @var array */ - protected $_test_items_visible = array(); + protected $_test_items_visible = array( + 'test_name', + 'test_datatype', + 'res_datatype', + 'result', + 'file', + 'line', + 'notes' + ); // -------------------------------------------------------------------- @@ -92,17 +100,6 @@ class CI_Unit_test { */ public function __construct() { - // These are the default items visible when a test is run. - $this->_test_items_visible = array ( - 'test_name', - 'test_datatype', - 'res_datatype', - 'result', - 'file', - 'line', - 'notes' - ); - log_message('debug', 'Unit Testing Class Initialized'); } @@ -113,10 +110,10 @@ class CI_Unit_test { * * Runs the supplied tests * - * @param array + * @param array $items * @return void */ - public function set_test_items($items = array()) + public function set_test_items($items) { if ( ! empty($items) && is_array($items)) { @@ -230,7 +227,7 @@ class CI_Unit_test { * * Causes the evaluation to use === rather than == * - * @param bool + * @param bool $state * @return void */ public function use_strict($state = TRUE) @@ -288,6 +285,7 @@ class CI_Unit_test { { $val = $line; } + $temp[$CI->lang->line('ut_'.$key, FALSE)] = $val; } @@ -396,4 +394,4 @@ function is_false($test) } /* End of file Unit_test.php */ -/* Location: ./system/libraries/Unit_test.php */ +/* Location: ./system/libraries/Unit_test.php */
\ No newline at end of file diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php index 060973847..983d832fd 100644 --- a/system/libraries/Upload.php +++ b/system/libraries/Upload.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -234,6 +234,13 @@ class CI_Upload { public $xss_clean = FALSE; /** + * Apache mod_mime fix flag + * + * @var bool + */ + public $mod_mime_fix = TRUE; + + /** * Temporary filename prefix * * @var string @@ -256,6 +263,13 @@ class CI_Upload { */ protected $_file_name_override = ''; + /** + * CI Singleton + * + * @var object + */ + protected $CI; + // -------------------------------------------------------------------- /** @@ -272,6 +286,7 @@ class CI_Upload { } $this->mimes =& get_mimes(); + $this->CI =& get_instance(); log_message('debug', 'Upload Class Initialized'); } @@ -314,6 +329,7 @@ class CI_Upload { 'remove_spaces' => TRUE, 'detect_mime' => TRUE, 'xss_clean' => FALSE, + 'mod_mime_fix' => TRUE, 'temp_prefix' => 'temp_file_', 'client_name' => '' ); @@ -471,8 +487,7 @@ class CI_Upload { } // Sanitize the file name for security - $CI =& get_instance(); - $this->file_name = $CI->security->sanitize_filename($this->file_name); + $this->file_name = $this->CI->security->sanitize_filename($this->file_name); // Truncate the file name if it's too long if ($this->max_filename > 0) @@ -1073,8 +1088,7 @@ class CI_Upload { return FALSE; } - $CI =& get_instance(); - return $CI->security->xss_clean($data, TRUE); + return $this->CI->security->xss_clean($data, TRUE); } // -------------------------------------------------------------------- @@ -1087,17 +1101,13 @@ class CI_Upload { */ public function set_error($msg) { - $CI =& get_instance(); - $CI->lang->load('upload'); + $this->CI->lang->load('upload'); - if ( ! is_array($msg)) - { - $msg = array($msg); - } + is_array($msg) OR $msg = array($msg); foreach ($msg as $val) { - $msg = ($CI->lang->line($val) === FALSE) ? $val : $CI->lang->line($val); + $msg = ($this->CI->lang->line($val) === FALSE) ? $val : $this->CI->lang->line($val); $this->error_msg[] = $msg; log_message('error', $msg); } @@ -1148,7 +1158,7 @@ class CI_Upload { */ protected function _prep_filename($filename) { - if (strpos($filename, '.') === FALSE OR $this->allowed_types === '*') + if ($this->mod_mime_fix === FALSE OR $this->allowed_types === '*' OR strpos($filename, '.') === FALSE) { return $filename; } diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php index 50ac9be98..9bab8666e 100644 --- a/system/libraries/User_agent.php +++ b/system/libraries/User_agent.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -145,6 +145,15 @@ class CI_User_agent { public $robot = ''; /** + * HTTP Referer + * + * @var mixed + */ + public $referer; + + // -------------------------------------------------------------------- + + /** * Constructor * * Sets the User Agent and runs the compilation routine @@ -282,7 +291,7 @@ class CI_User_agent { { foreach ($this->browsers as $key => $val) { - if (preg_match('|'.preg_quote($key).'.*?([0-9\.]+)|i', $this->agent, $match)) + if (preg_match('|'.$key.'.*?([0-9\.]+)|i', $this->agent, $match)) { $this->is_browser = TRUE; $this->version = $match[1]; @@ -358,7 +367,7 @@ class CI_User_agent { { if ((count($this->languages) === 0) && ! empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - $this->languages = explode(',', preg_replace('/(;q=[0-9\.]+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE'])))); + $this->languages = explode(',', preg_replace('/(;\s?q=[0-9\.]+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE'])))); } if (count($this->languages) === 0) @@ -378,7 +387,7 @@ class CI_User_agent { { if ((count($this->charsets) === 0) && ! empty($_SERVER['HTTP_ACCEPT_CHARSET'])) { - $this->charsets = explode(',', preg_replace('/(;q=.+)/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET'])))); + $this->charsets = explode(',', preg_replace('/(;\s?q=.+)|\s/i', '', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET'])))); } if (count($this->charsets) === 0) @@ -471,24 +480,22 @@ class CI_User_agent { */ public function is_referral() { - static $result; - - if ( ! isset($result)) + if ( ! isset($this->referer)) { if (empty($_SERVER['HTTP_REFERER'])) { - $result = FALSE; + $this->referer = FALSE; } else { $referer_host = @parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST); $own_host = parse_url(config_item('base_url'), PHP_URL_HOST); - $result = ($referer_host && $referer_host !== $own_host); + $this->referer = ($referer_host && $referer_host !== $own_host); } } - return $result; + return $this->referer; } // -------------------------------------------------------------------- @@ -634,6 +641,34 @@ class CI_User_agent { return in_array(strtolower($charset), $this->charsets(), TRUE); } + // -------------------------------------------------------------------- + + /** + * Parse a custom user-agent string + * + * @param string $string + * @return void + */ + public function parse($string) + { + // Reset values + $this->is_browser = FALSE; + $this->is_robot = FALSE; + $this->is_mobile = FALSE; + $this->browser = ''; + $this->version = ''; + $this->mobile = ''; + $this->robot = ''; + + // Set the new user-agent string and parse it, unless empty + $this->agent = $string; + + if ( ! empty($string)) + { + $this->_compile_data(); + } + } + } /* End of file User_agent.php */ diff --git a/system/libraries/Xmlrpc.php b/system/libraries/Xmlrpc.php index 16c5b0ed8..83dc00e45 100644 --- a/system/libraries/Xmlrpc.php +++ b/system/libraries/Xmlrpc.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -348,6 +348,11 @@ class CI_Xmlrpc { $parts = parse_url($url); + if (isset($parts['user'], $parts['pass'])) + { + $parts['host'] = $parts['user'].':'.$parts['pass'].'@'.$parts['host']; + } + $path = isset($parts['path']) ? $parts['path'] : '/'; if ( ! empty($parts['query'])) @@ -569,6 +574,21 @@ class XML_RPC_Client extends CI_Xmlrpc public $port = 80; /** + * + * Server username + * + * @var string + */ + public $username; + + /** + * Server password + * + * @var string + */ + public $password; + + /** * Proxy hostname * * @var string @@ -626,8 +646,16 @@ class XML_RPC_Client extends CI_Xmlrpc { parent::__construct(); + $url = parse_url('http://'.$server); + + if (isset($url['user'], $url['pass'])) + { + $this->username = $url['user']; + $this->password = $url['pass']; + } + $this->port = $port; - $this->server = $server; + $this->server = $url['host']; $this->path = $path; $this->proxy = $proxy; $this->proxy_port = $proxy_port; @@ -691,11 +719,20 @@ class XML_RPC_Client extends CI_Xmlrpc $op = 'POST '.$this->path.' HTTP/1.0'.$r .'Host: '.$this->server.$r .'Content-Type: text/xml'.$r + .(isset($this->username, $this->password) ? 'Authorization: Basic '.base64_encode($this->username.':'.$this->password).$r : '') .'User-Agent: '.$this->xmlrpcName.$r .'Content-Length: '.strlen($msg->payload).$r.$r .$msg->payload; - if ( ! fwrite($fp, $op, strlen($op))) + for ($written = 0, $length = strlen($op); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($op, $written))) === FALSE) + { + break; + } + } + + if ($result === FALSE) { error_log($this->xmlrpcstr['http_error']); return new XML_RPC_Response(0, $this->xmlrpcerr['http_error'], $this->xmlrpcstr['http_error']); @@ -855,10 +892,10 @@ class XML_RPC_Response /** * Decode * - * @param mixed + * @param mixed $array * @return array */ - public function decode($array = FALSE) + public function decode($array = NULL) { $CI =& get_instance(); @@ -870,9 +907,9 @@ class XML_RPC_Response { $array[$key] = $this->decode($array[$key]); } - else + elseif ($this->xss_clean) { - $array[$key] = ($this->xss_clean) ? $CI->security->xss_clean($array[$key]) : $array[$key]; + $array[$key] = $CI->security->xss_clean($array[$key]); } } @@ -885,9 +922,9 @@ class XML_RPC_Response { $result = $this->decode($result); } - else + elseif ($this->xss_clean) { - $result = ($this->xss_clean) ? $CI->security->xss_clean($result) : $result; + $result = $CI->security->xss_clean($result); } return $result; @@ -1084,15 +1121,15 @@ class XML_RPC_Message extends CI_Xmlrpc //------------------------------------- $parser = xml_parser_create($this->xmlrpc_defencoding); - - $this->xh[$parser] = array( - 'isf' => 0, - 'ac' => '', - 'headers' => array(), - 'stack' => array(), - 'valuestack' => array(), - 'isf_reason' => 0 - ); + $pname = (string) $parser; + $this->xh[$pname] = array( + 'isf' => 0, + 'ac' => '', + 'headers' => array(), + 'stack' => array(), + 'valuestack' => array(), + 'isf_reason' => 0 + ); xml_set_object($parser, $this); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, TRUE); @@ -1108,7 +1145,7 @@ class XML_RPC_Message extends CI_Xmlrpc { break; } - $this->xh[$parser]['headers'][] = $line; + $this->xh[$pname]['headers'][] = $line; } $data = implode("\r\n", $lines); @@ -1126,18 +1163,18 @@ class XML_RPC_Message extends CI_Xmlrpc xml_parser_free($parser); // Got ourselves some badness, it seems - if ($this->xh[$parser]['isf'] > 1) + if ($this->xh[$pname]['isf'] > 1) { if ($this->debug === TRUE) { - echo "---Invalid Return---\n".$this->xh[$parser]['isf_reason']."---Invalid Return---\n\n"; + echo "---Invalid Return---\n".$this->xh[$pname]['isf_reason']."---Invalid Return---\n\n"; } - return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']); + return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']); } - elseif ( ! is_object($this->xh[$parser]['value'])) + elseif ( ! is_object($this->xh[$pname]['value'])) { - return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$parser]['isf_reason']); + return new XML_RPC_Response(0, $this->xmlrpcerr['invalid_return'], $this->xmlrpcstr['invalid_return'].' '.$this->xh[$pname]['isf_reason']); } // Display XML content for debugging @@ -1145,10 +1182,10 @@ class XML_RPC_Message extends CI_Xmlrpc { echo '<pre>'; - if (count($this->xh[$parser]['headers'] > 0)) + if (count($this->xh[$pname]['headers'] > 0)) { echo "---HEADERS---\n"; - foreach ($this->xh[$parser]['headers'] as $header) + foreach ($this->xh[$pname]['headers'] as $header) { echo $header."\n"; } @@ -1156,13 +1193,13 @@ class XML_RPC_Message extends CI_Xmlrpc } echo "---DATA---\n".htmlspecialchars($data)."\n---END DATA---\n\n---PARSED---\n"; - var_dump($this->xh[$parser]['value']); + var_dump($this->xh[$pname]['value']); echo "\n---END PARSED---</pre>"; } // Send response - $v = $this->xh[$parser]['value']; - if ($this->xh[$parser]['isf']) + $v = $this->xh[$pname]['value']; + if ($this->xh[$pname]['isf']) { $errno_v = $v->me['struct']['faultCode']; $errstr_v = $v->me['struct']['faultString']; @@ -1181,7 +1218,7 @@ class XML_RPC_Message extends CI_Xmlrpc $r = new XML_RPC_Response($v); } - $r->headers = $this->xh[$parser]['headers']; + $r->headers = $this->xh[$pname]['headers']; return $r; } @@ -1212,6 +1249,8 @@ class XML_RPC_Message extends CI_Xmlrpc */ public function open_tag($the_parser, $name) { + $the_parser = (string) $the_parser; + // If invalid nesting, then return if ($this->xh[$the_parser]['isf'] > 1) return; @@ -1311,6 +1350,8 @@ class XML_RPC_Message extends CI_Xmlrpc */ public function closing_tag($the_parser, $name) { + $the_parser = (string) $the_parser; + if ($this->xh[$the_parser]['isf'] > 1) return; // Remove current element from stack and set variable @@ -1443,6 +1484,8 @@ class XML_RPC_Message extends CI_Xmlrpc */ public function character_data($the_parser, $data) { + $the_parser = (string) $the_parser; + if ($this->xh[$the_parser]['isf'] > 1) return; // XML Fault found already // If a value has not been found @@ -1480,14 +1523,14 @@ class XML_RPC_Message extends CI_Xmlrpc /** * Output parameters * - * @param array + * @param array $array * @return array */ - public function output_parameters($array = FALSE) + public function output_parameters(array $array = array()) { $CI =& get_instance(); - if (is_array($array)) + if ( ! empty($array)) { while (list($key) = each($array)) { @@ -1495,11 +1538,11 @@ class XML_RPC_Message extends CI_Xmlrpc { $array[$key] = $this->output_parameters($array[$key]); } - else + elseif ($key !== 'bits' && $this->xss_clean) { // 'bits' is for the MetaWeblog API image bits // @todo - this needs to be made more general purpose - $array[$key] = ($key === 'bits' OR $this->xss_clean === FALSE) ? $array[$key] : $CI->security->xss_clean($array[$key]); + $array[$key] = $CI->security->xss_clean($array[$key]); } } @@ -1684,7 +1727,7 @@ class XML_RPC_Values extends CI_Xmlrpc { if ($this->mytype !== 0) { - echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />'; + echo '<strong>XML_RPC_Values</strong>: already initialized as a ['.$this->kindOf().']<br />'; return 0; } @@ -1705,7 +1748,7 @@ class XML_RPC_Values extends CI_Xmlrpc { if ($this->mytype !== 0) { - echo '<strong>XML_RPC_Values</strong>: already initialized as a [' . $this->kindOf() . ']<br />'; + echo '<strong>XML_RPC_Values</strong>: already initialized as a ['.$this->kindOf().']<br />'; return 0; } $this->mytype = $this->xmlrpcTypes['struct']; diff --git a/system/libraries/Xmlrpcs.php b/system/libraries/Xmlrpcs.php index d263d789d..e8e06d756 100644 --- a/system/libraries/Xmlrpcs.php +++ b/system/libraries/Xmlrpcs.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -384,17 +384,13 @@ class CI_Xmlrpcs extends CI_Xmlrpc { { return call_user_func(array($this, $method_parts[1]), $m); } + elseif ($this->object === FALSE) + { + return get_instance()->$method_parts[1]($m); + } else { - if ($this->object === FALSE) - { - $CI =& get_instance(); - return $CI->$method_parts[1]($m); - } - else - { - return $this->object->$method_parts[1]($m); - } + return $this->object->$method_parts[1]($m); } } else diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php index 6608f050e..40b661abc 100644 --- a/system/libraries/Zip.php +++ b/system/libraries/Zip.php @@ -18,7 +18,7 @@ * * @package CodeIgniter * @author EllisLab Dev Team - * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/) + * @copyright Copyright (c) 2008 - 2014, 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 @@ -103,12 +103,12 @@ class CI_Zip { * * Lets you add a virtual directory into which you can place files. * - * @param mixed the directory name. Can be string or array + * @param mixed $directory the directory name. Can be string or array * @return void */ public function add_dir($directory) { - foreach ( (array) $directory as $dir) + foreach ((array) $directory as $dir) { if ( ! preg_match('|.+/$|', $dir)) { @@ -127,7 +127,7 @@ class CI_Zip { * * If this is a newly created file/dir, we will set the time to 'now' * - * @param string path to file + * @param string $dir path to file * @return array filemtime/filemdate */ protected function _get_mod_time($dir) @@ -146,9 +146,9 @@ class CI_Zip { /** * Add Directory * - * @param string the directory name - * @param int - * @param int + * @param string $dir the directory name + * @param int $file_mtime + * @param int $file_mdate * @return void */ protected function _add_dir($dir, $file_mtime, $file_mdate) @@ -199,8 +199,8 @@ class CI_Zip { * in the filename it will be placed within a directory. Make * sure you use add_dir() first to create the folder. * - * @param mixed - * @param string + * @param mixed $filepath A single filepath or an array of file => data pairs + * @param string $data Single file contents * @return void */ public function add_data($filepath, $data = NULL) @@ -225,10 +225,10 @@ class CI_Zip { /** * Add Data to Zip * - * @param string the file name/path - * @param string the data to be encoded - * @param int - * @param int + * @param string $filepath the file name/path + * @param string $data the data to be encoded + * @param int $file_mtime + * @param int $file_mdate * @return void */ protected function _add_data($filepath, $data, $file_mtime, $file_mdate) @@ -278,23 +278,26 @@ class CI_Zip { /** * Read the contents of a file and add it to the zip * - * @param string - * @param bool + * @param string $path + * @param bool $archive_filepath * @return bool */ - public function read_file($path, $preserve_filepath = FALSE) + public function read_file($path, $archive_filepath = FALSE) { - if ( ! file_exists($path)) + if (file_exists($path) && FALSE !== ($data = file_get_contents($path))) { - return FALSE; - } - - if (FALSE !== ($data = file_get_contents($path))) - { - $name = str_replace('\\', '/', $path); - if ($preserve_filepath === FALSE) + if (is_string($archive_filepath)) { - $name = preg_replace('|.*/(.+)|', '\\1', $name); + $name = str_replace('\\', '/', $archive_filepath); + } + else + { + $name = str_replace('\\', '/', $path); + + if ($archive_filepath === FALSE) + { + $name = preg_replace('|.*/(.+)|', '\\1', $name); + } } $this->add_data($name, $data); @@ -313,9 +316,9 @@ class CI_Zip { * sub-folders) and creates a zip based on it. Whatever directory structure * is in the original file path will be recreated in the zip file. * - * @param string path to source - * @param bool - * @param bool + * @param string $path path to source directory + * @param bool $preserve_filepath + * @param string $root_path * @return bool */ public function read_dir($path, $preserve_filepath = TRUE, $root_path = NULL) @@ -389,7 +392,7 @@ class CI_Zip { * * Lets you write a file * - * @param string the file name + * @param string $filepath the file name * @return bool */ public function archive($filepath) @@ -400,11 +403,19 @@ class CI_Zip { } flock($fp, LOCK_EX); - fwrite($fp, $this->get_zip()); + + for ($written = 0, $data = $this->get_zip(), $length = strlen($data); $written < $length; $written += $result) + { + if (($result = fwrite($fp, substr($data, $written))) === FALSE) + { + break; + } + } + flock($fp, LOCK_UN); fclose($fp); - return TRUE; + return is_int($result); } // -------------------------------------------------------------------- @@ -412,7 +423,7 @@ class CI_Zip { /** * Download * - * @param string the file name + * @param string $filename the file name * @return void */ public function download($filename = 'backup.zip') @@ -422,8 +433,7 @@ class CI_Zip { $filename .= '.zip'; } - $CI =& get_instance(); - $CI->load->helper('download'); + get_instance()->load->helper('download'); $get_zip = $this->get_zip(); $zip_content =& $get_zip; |