summaryrefslogtreecommitdiffstats
path: root/system/core
diff options
context:
space:
mode:
authorEric Roberts <eric@cryode.com>2012-12-12 14:02:11 +0100
committerEric Roberts <eric@cryode.com>2012-12-12 14:02:11 +0100
commitb9e35f21e1c70b6aa67c47e9244ed83195abc00a (patch)
tree64f82db362deeac48cc20d1d1afd80651f36f5a5 /system/core
parent0b05705c52c3bca7f9b3aee657c888e8ad1ff422 (diff)
parent545a7c86701875e1412bcde316e9bcc76d9a23a0 (diff)
Merge branch 'refs/heads/develop' into feature/form_error_msgs
Conflicts: system/language/english/form_validation_lang.php user_guide_src/source/libraries/form_validation.rst Signed-off-by: Eric Roberts <eric@cryode.com>
Diffstat (limited to 'system/core')
-rw-r--r--[-rwxr-xr-x]system/core/Benchmark.php50
-rw-r--r--[-rwxr-xr-x]system/core/CodeIgniter.php156
-rw-r--r--system/core/Common.php558
-rw-r--r--[-rwxr-xr-x]system/core/Config.php165
-rw-r--r--system/core/Controller.php28
-rw-r--r--[-rwxr-xr-x]system/core/Exceptions.php100
-rw-r--r--[-rwxr-xr-x]system/core/Hooks.php81
-rw-r--r--[-rwxr-xr-x]system/core/Input.php595
-rw-r--r--[-rwxr-xr-x]system/core/Lang.php109
-rw-r--r--system/core/Loader.php523
-rw-r--r--system/core/Log.php180
-rw-r--r--[-rwxr-xr-x]system/core/Model.php21
-rw-r--r--[-rwxr-xr-x]system/core/Output.php456
-rw-r--r--[-rwxr-xr-x]system/core/Router.php253
-rw-r--r--[-rwxr-xr-x]system/core/Security.php331
-rw-r--r--[-rwxr-xr-x]system/core/URI.php423
-rw-r--r--system/core/Utf8.php73
17 files changed, 2537 insertions, 1565 deletions
diff --git a/system/core/Benchmark.php b/system/core/Benchmark.php
index f6b634deb..e80ee54dd 100755..100644
--- a/system/core/Benchmark.php
+++ b/system/core/Benchmark.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,14 +24,13 @@
* @since Version 1.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
- * CodeIgniter Benchmark Class
+ * Benchmark Class
*
* This class enables you to mark points and calculate the time difference
- * between them. Memory consumption can also be displayed.
+ * between them. Memory consumption can also be displayed.
*
* @package CodeIgniter
* @subpackage Libraries
@@ -42,31 +41,31 @@
class CI_Benchmark {
/**
- * List of all benchmark markers and when they were added
+ * List of all benchmark markers
*
- * @var array
+ * @var array
*/
public $marker = array();
- // --------------------------------------------------------------------
-
/**
* Set a benchmark marker
*
* Multiple calls to this function can be made so that several
- * execution points can be timed
+ * execution points can be timed.
*
- * @param string $name name of the marker
+ * @param string $name Marker name
* @return void
*/
public function mark($name)
{
- $this->marker[$name] = microtime();
+ $this->marker[$name] = microtime(TRUE);
}
// --------------------------------------------------------------------
/**
+ * Elapsed time
+ *
* Calculates the time difference between two marked points.
*
* If the first parameter is empty this function instead returns the
@@ -74,14 +73,17 @@ class CI_Benchmark {
* execution time to be shown in a template. The output class will
* swap the real value for this variable.
*
- * @param string a particular marked point
- * @param string a particular marked point
- * @param integer the number of decimal places
- * @return mixed
+ * @param string $point1 A particular marked point
+ * @param string $point2 A particular marked point
+ * @param int $decimals Number of decimal places
+ *
+ * @return string Calculated elapsed time on success,
+ * an '{elapsed_string}' if $point1 is empty
+ * or an empty string if $point1 is not found.
*/
public function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
{
- if ($point1 == '')
+ if ($point1 === '')
{
return '{elapsed_time}';
}
@@ -93,13 +95,10 @@ class CI_Benchmark {
if ( ! isset($this->marker[$point2]))
{
- $this->marker[$point2] = microtime();
+ $this->marker[$point2] = microtime(TRUE);
}
- list($sm, $ss) = explode(' ', $this->marker[$point1]);
- list($em, $es) = explode(' ', $this->marker[$point2]);
-
- return number_format(($em + $es) - ($sm + $ss), $decimals);
+ return number_format($this->marker[$point2] - $this->marker[$point1], $decimals);
}
// --------------------------------------------------------------------
@@ -107,12 +106,13 @@ class CI_Benchmark {
/**
* Memory Usage
*
- * This function returns the {memory_usage} pseudo-variable.
+ * Simply returns the {memory_usage} marker.
+ *
* This permits it to be put it anywhere in a template
* without the memory being calculated until the end.
* The output class will swap the real value for this variable.
*
- * @return string
+ * @return string '{memory_usage}'
*/
public function memory_usage()
{
@@ -122,4 +122,4 @@ class CI_Benchmark {
}
/* End of file Benchmark.php */
-/* Location: ./system/core/Benchmark.php */
+/* Location: ./system/core/Benchmark.php */ \ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index 4885f310c..89081b572 100755..100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,8 +24,7 @@
* @since Version 1.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* System Initialization File
@@ -33,7 +32,7 @@
* Loads the base classes and executes the request.
*
* @package CodeIgniter
- * @subpackage codeigniter
+ * @subpackage CodeIgniter
* @category Front-controller
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/
@@ -42,7 +41,7 @@
/**
* CodeIgniter Version
*
- * @var string
+ * @var string
*
*/
define('CI_VERSION', '3.0-dev');
@@ -52,7 +51,7 @@
* Load the global functions
* ------------------------------------------------------
*/
- require(BASEPATH.'core/Common.php');
+ require_once(BASEPATH.'core/Common.php');
/*
* ------------------------------------------------------
@@ -75,9 +74,9 @@
*/
set_error_handler('_exception_handler');
- if ( ! is_php('5.3'))
+ if ( ! is_php('5.4'))
{
- @set_magic_quotes_runtime(0); // Kill magic quotes
+ @ini_set('magic_quotes_runtime', 0); // Kill magic quotes
}
/*
@@ -96,24 +95,13 @@
* Note: Since the config file data is cached it doesn't
* hurt to load it here.
*/
- if (isset($assign_to_config['subclass_prefix']) && $assign_to_config['subclass_prefix'] != '')
+ if ( ! empty($assign_to_config['subclass_prefix']))
{
get_config(array('subclass_prefix' => $assign_to_config['subclass_prefix']));
}
/*
* ------------------------------------------------------
- * Set a liberal script execution time limit
- * ------------------------------------------------------
- */
- if (function_exists('set_time_limit') && @ini_get('safe_mode') == 0
- && php_sapi_name() !== 'cli') // Do not override the Time Limit value if running from Command Line
- {
- @set_time_limit(300);
- }
-
-/*
- * ------------------------------------------------------
* Start the timer... tick tock tick tock...
* ------------------------------------------------------
*/
@@ -143,9 +131,12 @@
$CFG =& load_class('Config', 'core');
// Do we have any manually set config items in the index.php file?
- if (isset($assign_to_config))
+ if (isset($assign_to_config) && is_array($assign_to_config))
{
- $CFG->_assign_to_config($assign_to_config);
+ foreach ($assign_to_config as $key => $value)
+ {
+ $CFG->set_item($key, $value);
+ }
}
/*
@@ -155,7 +146,7 @@
*
* Note: Order here is rather important as the UTF-8
* class needs to be used very early on, but it cannot
- * properly determine if UTf-8 can be supported until
+ * properly determine if UTF-8 can be supported until
* after the Config class is instantiated.
*
*/
@@ -195,7 +186,7 @@
* ------------------------------------------------------
*/
if ($EXT->call_hook('cache_override') === FALSE
- && $OUT->_display_cache($CFG, $URI) == TRUE)
+ && $OUT->_display_cache($CFG, $URI) === TRUE)
{
exit;
}
@@ -230,12 +221,18 @@
// Load the base controller class
require BASEPATH.'core/Controller.php';
+ /**
+ * Reference to the CI_Controller method.
+ *
+ * Returns current CI instance object
+ *
+ * @return object
+ */
function &get_instance()
{
return CI_Controller::get_instance();
}
-
if (file_exists(APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php'))
{
require APPPATH.'core/'.$CFG->config['subclass_prefix'].'Controller.php';
@@ -259,28 +256,27 @@
* Security check
* ------------------------------------------------------
*
- * None of the functions in the app controller or the
+ * None of the methods in the app controller or the
* loader class can be called via the URI, nor can
- * controller functions that begin with an underscore
+ * controller functions that begin with an underscore.
*/
$class = $RTR->fetch_class();
$method = $RTR->fetch_method();
- if ( ! class_exists($class)
- OR strpos($method, '_') === 0
- OR in_array(strtolower($method), array_map('strtolower', get_class_methods('CI_Controller')))
- )
+ if ( ! class_exists($class) OR $method[0] === '_' OR method_exists('CI_Controller', $method))
{
if ( ! empty($RTR->routes['404_override']))
{
- $x = explode('/', $RTR->routes['404_override'], 2);
- $class = $x[0];
- $method = (isset($x[1]) ? $x[1] : 'index');
+ if (sscanf($RTR->routes['404_override'], '%[^/]/%s', $class, $method) !== 2)
+ {
+ $method = 'index';
+ }
+
if ( ! class_exists($class))
{
if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
{
- show_404("{$class}/{$method}");
+ show_404($class.'/'.$method);
}
include_once(APPPATH.'controllers/'.$class.'.php');
@@ -288,10 +284,46 @@
}
else
{
- show_404("{$class}/{$method}");
+ show_404($class.'/'.$method);
}
}
+ if (method_exists($class, '_remap'))
+ {
+ $params = array($method, array_slice($URI->rsegments, 2));
+ $method = '_remap';
+ }
+ else
+ {
+ // WARNING: It appears that there are issues with is_callable() even in PHP 5.2!
+ // Furthermore, there are bug reports and feature/change requests related to it
+ // that make it unreliable to use in this context. Please, DO NOT change this
+ // work-around until a better alternative is available.
+ if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($class)), TRUE))
+ {
+ if (empty($RTR->routes['404_override']))
+ {
+ show_404($class.'/'.$method);
+ }
+ elseif (sscanf($RTR->routes['404_override'], '%[^/]/%s', $class, $method) !== 2)
+ {
+ $method = 'index';
+ }
+
+ if ( ! class_exists($class))
+ {
+ if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
+ {
+ show_404($class.'/'.$method);
+ }
+
+ include_once(APPPATH.'controllers/'.$class.'.php');
+ }
+ }
+
+ $params = array_slice($URI->rsegments, 2);
+ }
+
/*
* ------------------------------------------------------
* Is there a "pre_controller" hook?
@@ -321,45 +353,7 @@
* Call the requested method
* ------------------------------------------------------
*/
- // Is there a "remap" function? If so, we call it instead
- if (method_exists($CI, '_remap'))
- {
- $CI->_remap($method, array_slice($URI->rsegments, 2));
- }
- else
- {
- // is_callable() returns TRUE on some versions of PHP 5 for private and protected
- // methods, so we'll use this workaround for consistent behavior
- if ( ! in_array(strtolower($method), array_map('strtolower', get_class_methods($CI))))
- {
- // Check and see if we are using a 404 override and use it.
- if ( ! empty($RTR->routes['404_override']))
- {
- $x = explode('/', $RTR->routes['404_override'], 2);
- $class = $x[0];
- $method = (isset($x[1]) ? $x[1] : 'index');
- if ( ! class_exists($class))
- {
- if ( ! file_exists(APPPATH.'controllers/'.$class.'.php'))
- {
- show_404("{$class}/{$method}");
- }
-
- include_once(APPPATH.'controllers/'.$class.'.php');
- unset($CI);
- $CI = new $class();
- }
- }
- else
- {
- show_404("{$class}/{$method}");
- }
- }
-
- // Call the requested method.
- // Any URI segments present (besides the class/function) will be passed to the method for convenience
- call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));
- }
+ call_user_func_array(array(&$CI, $method), $params);
// Mark a benchmark end point
$BM->mark('controller_execution_time_( '.$class.' / '.$method.' )_end');
@@ -388,15 +382,5 @@
*/
$EXT->call_hook('post_system');
-/*
- * ------------------------------------------------------
- * Close the DB connection if one exists
- * ------------------------------------------------------
- */
- if (class_exists('CI_DB') && isset($CI->db))
- {
- $CI->db->close();
- }
-
/* End of file CodeIgniter.php */
-/* Location: ./system/core/CodeIgniter.php */
+/* Location: ./system/core/CodeIgniter.php */ \ No newline at end of file
diff --git a/system/core/Common.php b/system/core/Common.php
index aeb784bbe..7feb16bfd 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Common Functions
@@ -31,7 +32,7 @@
* Loads the base classes and executes the request.
*
* @package CodeIgniter
- * @subpackage codeigniter
+ * @subpackage CodeIgniter
* @category Common Functions
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/
@@ -39,25 +40,25 @@
// ------------------------------------------------------------------------
-/**
- * Determines if the current version of PHP is greater then the supplied value
- *
- * Since there are a few places where we conditionally test for PHP > 5
- * we'll set a static variable.
- *
- * @param string
- * @return bool TRUE if the current version is $version or higher
- */
if ( ! function_exists('is_php'))
{
- function is_php($version = '5.0.0')
+ /**
+ * Determines if the current version of PHP is greater then the supplied value
+ *
+ * Since there are a few places where we conditionally test for PHP > 5.3
+ * we'll set a static variable.
+ *
+ * @param string
+ * @return bool TRUE if the current version is $version or higher
+ */
+ function is_php($version = '5.3.0')
{
static $_is_php;
$version = (string) $version;
if ( ! isset($_is_php[$version]))
{
- $_is_php[$version] = (version_compare(PHP_VERSION, $version) < 0) ? FALSE : TRUE;
+ $_is_php[$version] = (version_compare(PHP_VERSION, $version) >= 0);
}
return $_is_php[$version];
@@ -66,18 +67,18 @@ if ( ! function_exists('is_php'))
// ------------------------------------------------------------------------
-/**
- * Tests for file writability
- *
- * is_writable() returns TRUE on Windows servers when you really can't write to
- * the file, based on the read-only attribute. is_writable() is also unreliable
- * on Unix servers if safe_mode is on.
- *
- * @param string
- * @return void
- */
if ( ! function_exists('is_really_writable'))
{
+ /**
+ * Tests for file writability
+ *
+ * is_writable() returns TRUE on Windows servers when you really can't write to
+ * the file, based on the read-only attribute. is_writable() is also unreliable
+ * on Unix servers if safe_mode is on.
+ *
+ * @param string
+ * @return void
+ */
function is_really_writable($file)
{
// If we're on a Unix server with safe_mode off we call is_writable
@@ -114,20 +115,20 @@ if ( ! function_exists('is_really_writable'))
// ------------------------------------------------------------------------
-/**
- * Class registry
- *
- * This function acts as a singleton. If the requested class does not
- * exist it is instantiated and set to a static variable. If it has
- * previously been instantiated the variable is returned.
- *
- * @param string the class name being requested
- * @param string the directory where the class should be found
- * @param string the class name prefix
- * @return object
- */
if ( ! function_exists('load_class'))
{
+ /**
+ * Class registry
+ *
+ * This function acts as a singleton. If the requested class does not
+ * exist it is instantiated and set to a static variable. If it has
+ * previously been instantiated the variable is returned.
+ *
+ * @param string the class name being requested
+ * @param string the directory where the class should be found
+ * @param string the class name prefix
+ * @return object
+ */
function &load_class($class, $directory = 'libraries', $prefix = 'CI_')
{
static $_classes = array();
@@ -150,7 +151,7 @@ if ( ! function_exists('load_class'))
if (class_exists($name) === FALSE)
{
- require($path.$directory.'/'.$class.'.php');
+ require_once($path.$directory.'/'.$class.'.php');
}
break;
@@ -164,7 +165,7 @@ if ( ! function_exists('load_class'))
if (class_exists($name) === FALSE)
{
- require(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
+ require_once(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php');
}
}
@@ -172,7 +173,7 @@ if ( ! function_exists('load_class'))
if ($name === FALSE)
{
// Note: We use exit() rather then show_error() in order to avoid a
- // self-referencing loop with the Excptions class
+ // self-referencing loop with the Exceptions class
set_status_header(503);
exit('Unable to locate the specified class: '.$class.'.php');
}
@@ -187,20 +188,20 @@ if ( ! function_exists('load_class'))
// --------------------------------------------------------------------
-/**
- * Keeps track of which libraries have been loaded. This function is
- * called by the load_class() function above
- *
- * @param string
- * @return array
- */
if ( ! function_exists('is_loaded'))
{
+ /**
+ * Keeps track of which libraries have been loaded. This function is
+ * called by the load_class() function above
+ *
+ * @param string
+ * @return array
+ */
function &is_loaded($class = '')
{
static $_is_loaded = array();
- if ($class != '')
+ if ($class !== '')
{
$_is_loaded[strtolower($class)] = $class;
}
@@ -211,17 +212,17 @@ if ( ! function_exists('is_loaded'))
// ------------------------------------------------------------------------
-/**
- * Loads the main config.php file
- *
- * This function lets us grab the config file even if the Config class
- * hasn't been instantiated yet
- *
- * @param array
- * @return array
- */
if ( ! function_exists('get_config'))
{
+ /**
+ * Loads the main config.php file
+ *
+ * This function lets us grab the config file even if the Config class
+ * hasn't been instantiated yet
+ *
+ * @param array
+ * @return array
+ */
function &get_config($replace = array())
{
static $_config;
@@ -231,21 +232,25 @@ if ( ! function_exists('get_config'))
return $_config[0];
}
- // Is the config file in the environment folder?
- if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+ $file_path = APPPATH.'config/config.php';
+ $found = FALSE;
+ if (file_exists($file_path))
{
- $file_path = APPPATH.'config/config.php';
+ $found = TRUE;
+ require($file_path);
}
- // Fetch the config file
- if ( ! file_exists($file_path))
+ // Is the config file in the environment folder?
+ if (defined('ENVIRONMENT') && file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
+ {
+ require($file_path);
+ }
+ elseif ( ! $found)
{
set_status_header(503);
exit('The configuration file does not exist.');
}
- require($file_path);
-
// Does the $config array exist in the file?
if ( ! isset($config) OR ! is_array($config))
{
@@ -271,14 +276,14 @@ if ( ! function_exists('get_config'))
// ------------------------------------------------------------------------
-/**
- * Returns the specified config item
- *
- * @param string
- * @return mixed
- */
if ( ! function_exists('config_item'))
{
+ /**
+ * Returns the specified config item
+ *
+ * @param string
+ * @return mixed
+ */
function config_item($item)
{
static $_config_item = array();
@@ -300,22 +305,66 @@ if ( ! function_exists('config_item'))
// ------------------------------------------------------------------------
-/**
- * Error Handler
- *
- * This function lets us invoke the exception class and
- * display errors using the standard error template located
- * in application/errors/errors.php
- * This function will send the error page directly to the
- * browser and exit.
- *
- * @param string
- * @param int
- * @param string
- * @return void
- */
+if ( ! function_exists('get_mimes'))
+{
+ /**
+ * Returns the MIME types array from config/mimes.php
+ *
+ * @return array
+ */
+ function &get_mimes()
+ {
+ static $_mimes = array();
+
+ if (defined('ENVIRONMENT') && is_file(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
+ {
+ $_mimes = include(APPPATH.'config/'.ENVIRONMENT.'/mimes.php');
+ }
+ elseif (is_file(APPPATH.'config/mimes.php'))
+ {
+ $_mimes = include(APPPATH.'config/mimes.php');
+ }
+
+ return $_mimes;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('is_https'))
+{
+ /**
+ * Is HTTPS?
+ *
+ * Determines if the application is accessed via an encrypted
+ * (HTTPS) connection.
+ *
+ * @return bool
+ */
+ function is_https()
+ {
+ return ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off');
+ }
+}
+
+// ------------------------------------------------------------------------
+
if ( ! function_exists('show_error'))
{
+ /**
+ * Error Handler
+ *
+ * This function lets us invoke the exception class and
+ * display errors using the standard error template located
+ * in application/errors/errors.php
+ * This function will send the error page directly to the
+ * browser and exit.
+ *
+ * @param string
+ * @param int
+ * @param string
+ * @return void
+ */
function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered')
{
$_error =& load_class('Exceptions', 'core');
@@ -326,19 +375,19 @@ if ( ! function_exists('show_error'))
// ------------------------------------------------------------------------
-/**
- * 404 Page Handler
- *
- * This function is similar to the show_error() function above
- * However, instead of the standard error template it displays
- * 404 errors.
- *
- * @param string
- * @param bool
- * @return void
- */
if ( ! function_exists('show_404'))
{
+ /**
+ * 404 Page Handler
+ *
+ * This function is similar to the show_error() function above
+ * However, instead of the standard error template it displays
+ * 404 errors.
+ *
+ * @param string
+ * @param bool
+ * @return void
+ */
function show_404($page = '', $log_error = TRUE)
{
$_error =& load_class('Exceptions', 'core');
@@ -349,102 +398,107 @@ if ( ! function_exists('show_404'))
// ------------------------------------------------------------------------
-/**
- * Error Logging Interface
- *
- * We use this as a simple mechanism to access the logging
- * class and send messages to be logged.
- *
- * @param string
- * @param string
- * @param bool
- * @return void
- */
if ( ! function_exists('log_message'))
{
+ /**
+ * Error Logging Interface
+ *
+ * We use this as a simple mechanism to access the logging
+ * class and send messages to be logged.
+ *
+ * @param string
+ * @param string
+ * @param bool
+ * @return void
+ */
function log_message($level = 'error', $message, $php_error = FALSE)
{
static $_log;
- if (config_item('log_threshold') == 0)
+ if (config_item('log_threshold') === 0)
{
return;
}
- $_log =& load_class('Log');
+ $_log =& load_class('Log', 'core');
$_log->write_log($level, $message, $php_error);
}
}
// ------------------------------------------------------------------------
-/**
- * Set HTTP Status Header
- *
- * @param int the status code
- * @param string
- * @return void
- */
if ( ! function_exists('set_status_header'))
{
+ /**
+ * Set HTTP Status Header
+ *
+ * @param int the status code
+ * @param string
+ * @return void
+ */
function set_status_header($code = 200, $text = '')
{
$stati = array(
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
-
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary Redirect',
-
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Request Entity Too Large',
- 414 => 'Request-URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Requested Range Not Satisfiable',
- 417 => 'Expectation Failed',
- 422 => 'Unprocessable Entity',
-
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported'
- );
-
- if ($code == '' OR ! is_numeric($code))
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
+
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity',
+
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported'
+ );
+
+ if (empty($code) OR ! is_numeric($code))
{
show_error('Status codes must be numeric', 500);
}
- if (isset($stati[$code]) && $text == '')
- {
- $text = $stati[$code];
- }
+ is_int($code) OR $code = (int) $code;
- if ($text == '')
+ if (empty($text))
{
- show_error('No status text available. Please check your status code number or supply your own message text.', 500);
+ if (isset($stati[$code]))
+ {
+ $text = $stati[$code];
+ }
+ else
+ {
+ show_error('No status text available. Please check your status code number or supply your own message text.', 500);
+ }
}
$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : FALSE;
@@ -453,63 +507,49 @@ if ( ! function_exists('set_status_header'))
{
header('Status: '.$code.' '.$text, TRUE);
}
- elseif ($server_protocol === 'HTTP/1.0')
- {
- header('HTTP/1.0 '.$code.' '.$text, TRUE, $code);
- }
else
{
- header('HTTP/1.1 '.$code.' '.$text, TRUE, $code);
+ header(($server_protocol ? $server_protocol : 'HTTP/1.1').' '.$code.' '.$text, TRUE, $code);
}
}
}
// --------------------------------------------------------------------
-/**
- * Exception Handler
- *
- * This is the custom exception handler that is declaired at the top
- * of Codeigniter.php. The main reason we use this is to permit
- * PHP errors to be logged in our own log files since the user may
- * not have access to server logs. Since this function
- * effectively intercepts PHP errors, however, we also need
- * to display errors based on the current error_reporting level.
- * We do that with the use of a PHP error template.
- *
- * @param int
- * @param string
- * @param string
- * @param int
- * @return void
- */
if ( ! function_exists('_exception_handler'))
{
+ /**
+ * Exception Handler
+ *
+ * This is the custom exception handler that is declaired at the top
+ * of Codeigniter.php. The main reason we use this is to permit
+ * PHP errors to be logged in our own log files since the user may
+ * not have access to server logs. Since this function
+ * effectively intercepts PHP errors, however, we also need
+ * to display errors based on the current error_reporting level.
+ * We do that with the use of a PHP error template.
+ *
+ * @param int
+ * @param string
+ * @param string
+ * @param int
+ * @return void
+ */
function _exception_handler($severity, $message, $filepath, $line)
{
- // We don't bother with "strict" notices since they tend to fill up
- // the log file with excess information that isn't normally very helpful.
- // For example, if you are running PHP 5 and you use version 4 style
- // class functions (without prefixes like "public", "private", etc.)
- // you'll get notices telling you that these have been deprecated.
- if ($severity == E_STRICT)
- {
- return;
- }
-
$_error =& load_class('Exceptions', 'core');
- // Should we display the error? We'll get the current error_reporting
+ // Should we ignore the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
- if (($severity & error_reporting()) == $severity)
+ if (($severity & error_reporting()) !== $severity)
{
- $_error->show_php_error($severity, $message, $filepath, $line);
+ return;
}
- // Should we log the error? No? We're done...
- if (config_item('log_threshold') == 0)
+ // Should we display the error?
+ if ((bool) ini_get('display_errors') === TRUE)
{
- return;
+ $_error->show_php_error($severity, $message, $filepath, $line);
}
$_error->log_exception($severity, $message, $filepath, $line);
@@ -518,18 +558,18 @@ if ( ! function_exists('_exception_handler'))
// --------------------------------------------------------------------
-/**
- * Remove Invisible Characters
- *
- * This prevents sandwiching null characters
- * between ascii characters, like Java\0script.
- *
- * @param string
- * @param bool
- * @return string
- */
if ( ! function_exists('remove_invisible_characters'))
{
+ /**
+ * Remove Invisible Characters
+ *
+ * This prevents sandwiching null characters
+ * between ascii characters, like Java\0script.
+ *
+ * @param string
+ * @param bool
+ * @return string
+ */
function remove_invisible_characters($str, $url_encoded = TRUE)
{
$non_displayables = array();
@@ -556,14 +596,14 @@ if ( ! function_exists('remove_invisible_characters'))
// ------------------------------------------------------------------------
-/**
- * Returns HTML escaped variable
- *
- * @param mixed
- * @return mixed
- */
if ( ! function_exists('html_escape'))
{
+ /**
+ * Returns HTML escaped variable
+ *
+ * @param mixed
+ * @return mixed
+ */
function html_escape($var)
{
return is_array($var)
@@ -572,5 +612,91 @@ if ( ! function_exists('html_escape'))
}
}
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('_stringify_attributes'))
+{
+ /**
+ * Stringify attributes for use in HTML tags.
+ *
+ * Helper function used to convert a string, array, or object
+ * of attributes to a string.
+ *
+ * @param mixed string, array, object
+ * @param bool
+ * @return string
+ */
+ function _stringify_attributes($attributes, $js = FALSE)
+ {
+ $atts = NULL;
+
+ if (empty($attributes))
+ {
+ return $atts;
+ }
+
+ if (is_string($attributes))
+ {
+ return ' '.$attributes;
+ }
+
+ $attributes = (array) $attributes;
+
+ foreach ($attributes as $key => $val)
+ {
+ $atts .= ($js) ? $key.'='.$val.',' : ' '.$key.'="'.$val.'"';
+ }
+
+ return rtrim($atts, ',');
+ }
+}
+
+// ------------------------------------------------------------------------
+
+if ( ! function_exists('function_usable'))
+{
+ /**
+ * Function usable
+ *
+ * Executes a function_exists() check, and if the Suhosin PHP
+ * extension is loaded - checks whether the function that is
+ * checked might be disabled in there as well.
+ *
+ * This is useful as function_exists() will return FALSE for
+ * functions disabled via the *disable_functions* php.ini
+ * setting, but not for *suhosin.executor.func.blacklist* and
+ * *suhosin.executor.disable_eval*. These settings will just
+ * terminate script execution if a disabled function is executed.
+ *
+ * @link http://www.hardened-php.net/suhosin/
+ * @param string $function_name Function to check for
+ * @return bool TRUE if the function exists and is safe to call,
+ * FALSE otherwise.
+ */
+ function function_usable($function_name)
+ {
+ static $_suhosin_func_blacklist;
+
+ if (function_exists($function_name))
+ {
+ if ( ! isset($_suhosin_func_blacklist))
+ {
+ $_suhosin_func_blacklist = extension_loaded('suhosin')
+ ? array()
+ : explode(',', trim(@ini_get('suhosin.executor.func.blacklist')));
+
+ if ( ! in_array('eval', $_suhosin_func_blacklist, TRUE) && @ini_get('suhosin.executor.disable_eval'))
+ {
+ $_suhosin_func_blacklist[] = 'eval';
+ }
+ }
+
+ return in_array($function_name, $_suhosin_func_blacklist, TRUE);
+ }
+
+ return FALSE;
+ }
+}
+
/* End of file Common.php */
/* Location: ./system/core/Common.php */ \ No newline at end of file
diff --git a/system/core/Config.php b/system/core/Config.php
index 91826bd41..38bcd5c8f 100755..100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,11 +24,10 @@
* @since Version 1.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
- * CodeIgniter Config Class
+ * Config Class
*
* This class contains functions that enable config files to be managed
*
@@ -43,32 +42,31 @@ class CI_Config {
/**
* List of all loaded config values
*
- * @var array
+ * @var array
*/
public $config = array();
+
/**
* List of all loaded config files
*
- * @var array
+ * @var array
*/
- public $is_loaded = array();
+ public $is_loaded = array();
+
/**
* List of paths to search when trying to load a config file.
- * This must be public as it's used by the Loader class.
*
- * @var array
+ * @used-by CI_Loader
+ * @var array
*/
- public $_config_paths = array(APPPATH);
+ public $_config_paths = array(APPPATH);
/**
- * Constructor
+ * Class constructor
*
- * Sets the $config data from the primary config.php file as a class variable
+ * Sets the $config data from the primary config.php file as a class variable.
*
- * @param string the config file name
- * @param boolean if configuration values should be loaded into their own section
- * @param boolean true if errors should just return false, false if an error message should be displayed
- * @return boolean if the file was successfully loaded or not
+ * @return void
*/
public function __construct()
{
@@ -80,9 +78,9 @@ class CI_Config {
{
if (isset($_SERVER['HTTP_HOST']))
{
- $base_url = ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
- $base_url .= '://'. $_SERVER['HTTP_HOST']
- . str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
+ $base_url = is_https() ? 'https' : 'http';
+ $base_url .= '://'.$_SERVER['HTTP_HOST']
+ .str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
}
else
{
@@ -98,22 +96,22 @@ class CI_Config {
/**
* Load Config File
*
- * @param string the config file name
- * @param boolean if configuration values should be loaded into their own section
- * @param boolean true if errors should just return false, false if an error message should be displayed
- * @return boolean if the file was loaded correctly
+ * @param string $file Configuration file name
+ * @param bool $use_sections Whether configuration values should be loaded into their own section
+ * @param bool $fail_gracefully Whether to just return FALSE or display an error message
+ * @return bool TRUE if the file was loaded correctly or FALSE on failure
*/
public function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
{
- $file = ($file == '') ? 'config' : str_replace('.php', '', $file);
+ $file = ($file === '') ? 'config' : str_replace('.php', '', $file);
$found = $loaded = FALSE;
+ $check_locations = defined('ENVIRONMENT')
+ ? array(ENVIRONMENT.'/'.$file, $file)
+ : array($file);
+
foreach ($this->_config_paths as $path)
{
- $check_locations = defined('ENVIRONMENT')
- ? array(ENVIRONMENT.'/'.$file, $file)
- : array($file);
-
foreach ($check_locations as $location)
{
$file_path = $path.'config/'.$location.'.php';
@@ -177,7 +175,7 @@ class CI_Config {
{
return FALSE;
}
- show_error('The configuration file '.$file.'.php'.' does not exist.');
+ show_error('The configuration file '.$file.'.php does not exist.');
}
return TRUE;
@@ -188,11 +186,9 @@ class CI_Config {
/**
* Fetch a config file item
*
- *
- * @param string the config item name
- * @param string the index name
- * @param bool
- * @return string
+ * @param string $item Config item name
+ * @param string $index Index name
+ * @return string|bool The configuration item or FALSE on failure
*/
public function item($item, $index = '')
{
@@ -207,11 +203,10 @@ class CI_Config {
// --------------------------------------------------------------------
/**
- * Fetch a config file item - adds slash after item (if item is not empty)
+ * Fetch a config file item with slash appended (if not empty)
*
- * @param string the config item name
- * @param bool
- * @return string
+ * @param string $item Config item name
+ * @return string|bool The configuration item or FALSE on failure
*/
public function slash_item($item)
{
@@ -219,7 +214,7 @@ class CI_Config {
{
return FALSE;
}
- elseif (trim($this->config[$item]) == '')
+ elseif (trim($this->config[$item]) === '')
{
return '';
}
@@ -231,54 +226,80 @@ class CI_Config {
/**
* Site URL
+ *
* Returns base_url . index_page [. uri_string]
*
- * @param string the URI string
+ * @uses CI_Config::_uri_string()
+ *
+ * @param string|string[] $uri URI string or an array of segments
* @return string
*/
public function site_url($uri = '')
{
- if ($uri == '')
+ if (empty($uri))
{
return $this->slash_item('base_url').$this->item('index_page');
}
- if ($this->item('enable_query_strings') == FALSE)
+ $uri = $this->_uri_string($uri);
+
+ if ($this->item('enable_query_strings') === FALSE)
{
- $suffix = ($this->item('url_suffix') == FALSE) ? '' : $this->item('url_suffix');
- return $this->slash_item('base_url').$this->slash_item('index_page').$this->_uri_string($uri).$suffix;
+ $suffix = isset($this->config['url_suffix']) ? $this->config['url_suffix'] : '';
+
+ if ($suffix !== '')
+ {
+ if (($offset = strpos($uri, '?')) !== FALSE)
+ {
+ $uri = substr($uri, 0, $offset).$suffix.substr($uri, $offset);
+ }
+ else
+ {
+ $uri .= $suffix;
+ }
+ }
+
+ return $this->slash_item('base_url').$this->slash_item('index_page').$uri;
}
- else
+ elseif (strpos($uri, '?') === FALSE)
{
- return $this->slash_item('base_url').$this->item('index_page').'?'.$this->_uri_string($uri);
+ $uri = '?'.$uri;
}
+
+ return $this->slash_item('base_url').$this->item('index_page').$uri;
}
// -------------------------------------------------------------
/**
* Base URL
+ *
* Returns base_url [. uri_string]
*
- * @param string $uri
- * @return string
+ * @uses CI_Config::_uri_string()
+ *
+ * @param string|string[] $uri URI string or an array of segments
+ * @return string
*/
public function base_url($uri = '')
{
- return $this->slash_item('base_url').ltrim($this->_uri_string($uri),'/');
+ return $this->slash_item('base_url').ltrim($this->_uri_string($uri), '/');
}
// -------------------------------------------------------------
/**
- * Build URI string for use in Config::site_url() and Config::base_url()
+ * Build URI string
+ *
+ * @used-by CI_Config::site_url()
+ * @used-by CI_Config::base_url()
*
- * @param mixed $uri
- * @return string
+ * @param string|string[] $uri URI string or an array of segments
+ * @return string
*/
protected function _uri_string($uri)
{
- if ($this->item('enable_query_strings') == FALSE)
+ if ($this->item('enable_query_strings') === FALSE)
{
if (is_array($uri))
{
@@ -288,15 +309,7 @@ class CI_Config {
}
elseif (is_array($uri))
{
- $i = 0;
- $str = '';
- foreach ($uri as $key => $val)
- {
- $prefix = ($i === 0) ? '' : '&';
- $str .= $prefix.$key.'='.$val;
- $i++;
- }
- return $str;
+ return http_build_query($uri);
}
return $uri;
@@ -320,8 +333,8 @@ class CI_Config {
/**
* Set a config file item
*
- * @param string the config item key
- * @param string the config item value
+ * @param string $item Config item key
+ * @param string $value Config item value
* @return void
*/
public function set_item($item, $value)
@@ -329,29 +342,7 @@ class CI_Config {
$this->config[$item] = $value;
}
- // --------------------------------------------------------------------
-
- /**
- * Assign to Config
- *
- * This function is called by the front controller (CodeIgniter.php)
- * after the Config class is instantiated. It permits config items
- * to be assigned or overriden by variables contained in the index.php file
- *
- * @param array
- * @return void
- */
- public function _assign_to_config($items = array())
- {
- if (is_array($items))
- {
- foreach ($items as $key => $val)
- {
- $this->set_item($key, $val);
- }
- }
- }
}
/* End of file Config.php */
-/* Location: ./system/core/Config.php */
+/* Location: ./system/core/Config.php */ \ No newline at end of file
diff --git a/system/core/Controller.php b/system/core/Controller.php
index 05e1bf5bf..ee6fec8d5 100644
--- a/system/core/Controller.php
+++ b/system/core/Controller.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,11 +24,10 @@
* @since Version 1.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
- * CodeIgniter Application Controller Class
+ * Application Controller Class
*
* This class object is the super class that every library in
* CodeIgniter will be assigned to.
@@ -41,8 +40,18 @@
*/
class CI_Controller {
+ /**
+ * Reference to the CI singleton
+ *
+ * @var object
+ */
private static $instance;
+ /**
+ * Class constructor
+ *
+ * @return void
+ */
public function __construct()
{
self::$instance =& $this;
@@ -60,11 +69,20 @@ class CI_Controller {
log_message('debug', 'Controller Class Initialized');
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Get the CI singleton
+ *
+ * @static
+ * @return object
+ */
public static function &get_instance()
{
return self::$instance;
}
+
}
/* End of file Controller.php */
-/* Location: ./system/core/Controller.php */
+/* Location: ./system/core/Controller.php */ \ No newline at end of file
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
index f36b31598..ced65ece4 100755..100644
--- a/system/core/Exceptions.php
+++ b/system/core/Exceptions.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Exceptions Class
@@ -36,39 +37,38 @@
*/
class CI_Exceptions {
- public $action;
- public $severity;
- public $message;
- public $filename;
- public $line;
-
/**
* Nesting level of the output buffering mechanism
*
- * @var int
+ * @var int
*/
public $ob_level;
/**
* List if available error levels
*
- * @var array
+ * @var array
*/
public $levels = array(
- E_ERROR => 'Error',
- E_WARNING => 'Warning',
- E_PARSE => 'Parsing Error',
- E_NOTICE => 'Notice',
- E_CORE_ERROR => 'Core Error',
- E_CORE_WARNING => 'Core Warning',
- E_COMPILE_ERROR => 'Compile Error',
- E_COMPILE_WARNING => 'Compile Warning',
- E_USER_ERROR => 'User Error',
- E_USER_WARNING => 'User Warning',
- E_USER_NOTICE => 'User Notice',
- E_STRICT => 'Runtime Notice'
- );
+ E_ERROR => 'Error',
+ E_WARNING => 'Warning',
+ E_PARSE => 'Parsing Error',
+ E_NOTICE => 'Notice',
+ E_CORE_ERROR => 'Core Error',
+ E_CORE_WARNING => 'Core Warning',
+ E_COMPILE_ERROR => 'Compile Error',
+ E_COMPILE_WARNING => 'Compile Warning',
+ E_USER_ERROR => 'User Error',
+ E_USER_WARNING => 'User Warning',
+ E_USER_NOTICE => 'User Notice',
+ E_STRICT => 'Runtime Notice'
+ );
+ /**
+ * Class constructor
+ *
+ * @return void
+ */
public function __construct()
{
$this->ob_level = ob_get_level();
@@ -80,28 +80,30 @@ class CI_Exceptions {
/**
* Exception Logger
*
- * This function logs PHP generated error messages
+ * Logs PHP generated error messages
*
- * @param string the error severity
- * @param string the error string
- * @param string the error filepath
- * @param string the error line number
+ * @param int $severity Log level
+ * @param string $message Error message
+ * @param string $filepath File path
+ * @param int $line Line number
* @return void
*/
public function log_exception($severity, $message, $filepath, $line)
{
- $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
+ $severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
log_message('error', 'Severity: '.$severity.' --> '.$message. ' '.$filepath.' '.$line, TRUE);
}
// --------------------------------------------------------------------
/**
- * 404 Page Not Found Handler
+ * 404 Error Handler
+ *
+ * @uses CI_Exceptions::show_error()
*
- * @param string the page
- * @param bool log error yes/no
- * @return string
+ * @param string $page Page URI
+ * @param bool $log_error Whether to log the error
+ * @return void
*/
public function show_404($page = '', $log_error = TRUE)
{
@@ -123,28 +125,28 @@ class CI_Exceptions {
/**
* General Error Page
*
- * This function takes an error message as input
- * (either as a string or an array) and displays
- * it using the specified template.
+ * Takes an error message as input (either as a string or an array)
+ * and displays it using the specified template.
+ *
+ * @param string $heading Page heading
+ * @param string|string[] $message Error message
+ * @param string $template Template name
+ * @param int $status_code (default: 500)
*
- * @param string the heading
- * @param string the message
- * @param string the template name
- * @param int the status code
- * @return string
+ * @return string Error page output
*/
public function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
set_status_header($status_code);
- $message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';
+ $message = '<p>'.implode('</p><p>', is_array($message) ? $message : array($message)).'</p>';
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
- include(APPPATH.'errors/'.$template.'.php');
+ include(VIEWPATH.'errors/'.$template.'.php');
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
@@ -155,15 +157,15 @@ class CI_Exceptions {
/**
* Native PHP error handler
*
- * @param string the error severity
- * @param string the error string
- * @param string the error filepath
- * @param string the error line number
- * @return string
+ * @param int $severity Error level
+ * @param string $message Error message
+ * @param string $filepath File path
+ * @param int $line Line number
+ * @return string Error page output
*/
public function show_php_error($severity, $message, $filepath, $line)
{
- $severity = ( ! isset($this->levels[$severity])) ? $severity : $this->levels[$severity];
+ $severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
$filepath = str_replace('\\', '/', $filepath);
// For safety reasons we do not show the full file path
@@ -178,7 +180,7 @@ class CI_Exceptions {
ob_end_flush();
}
ob_start();
- include(APPPATH.'errors/'.'error_php.php');
+ include(VIEWPATH.'errors/error_php.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
index 68e30ef0f..3c28ec9ba 100755..100644
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,9 +24,10 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
- * CodeIgniter Hooks Class
+ * Hooks Class
*
* Provides a mechanism to extend the base system without hacking.
*
@@ -39,26 +40,30 @@
class CI_Hooks {
/**
- * Determines wether hooks are enabled
+ * Determines whether hooks are enabled
*
- * @var bool
+ * @var bool
*/
- public $enabled = FALSE;
+ public $enabled = FALSE;
+
/**
* List of all hooks set in config/hooks.php
*
- * @var array
+ * @var array
*/
- public $hooks = array();
+ public $hooks = array();
+
/**
- * Determines wether hook is in progress, used to prevent infinte loops
+ * In progress flag
+ *
+ * Determines whether hook is in progress, used to prevent infinte loops
*
- * @var bool
+ * @var bool
*/
- public $in_progress = FALSE;
+ protected $_in_progress = FALSE;
/**
- * Initialize the Hooks Preferences
+ * Class constructor
*
* @return void
*/
@@ -70,7 +75,7 @@ class CI_Hooks {
// If hooks are not enabled in the config file
// there is nothing else to do
- if ($CFG->item('enable_hooks') == FALSE)
+ if ($CFG->item('enable_hooks') === FALSE)
{
return;
}
@@ -102,8 +107,10 @@ class CI_Hooks {
*
* Calls a particular hook. Called by CodeIgniter.php.
*
- * @param string the hook name
- * @return mixed
+ * @uses CI_Hooks::_run_hook()
+ *
+ * @param string $which Hook name
+ * @return bool TRUE on success or FALSE on failure
*/
public function call_hook($which = '')
{
@@ -134,8 +141,8 @@ class CI_Hooks {
*
* Runs a particular hook
*
- * @param array the hook details
- * @return bool
+ * @param array $data Hook details
+ * @return bool TRUE on success or FALSE on failure
*/
protected function _run_hook($data)
{
@@ -150,7 +157,7 @@ class CI_Hooks {
// If the script being called happens to have the same
// hook call within it a loop can happen
- if ($this->in_progress == TRUE)
+ if ($this->_in_progress === TRUE)
{
return;
}
@@ -171,44 +178,20 @@ class CI_Hooks {
return FALSE;
}
- // -----------------------------------
- // Set class/function name
- // -----------------------------------
-
- $class = FALSE;
- $function = FALSE;
- $params = '';
-
- if ( ! empty($data['class']))
- {
- $class = $data['class'];
- }
-
- if ( ! empty($data['function']))
- {
- $function = $data['function'];
- }
-
- if (isset($data['params']))
- {
- $params = $data['params'];
- }
+ // Determine and class and/or function names
+ $class = empty($data['class']) ? FALSE : $data['class'];
+ $function = empty($data['function']) ? FALSE : $data['function'];
+ $params = isset($data['params']) ? $data['params'] : '';
if ($class === FALSE && $function === FALSE)
{
return FALSE;
}
- // -----------------------------------
- // Set the in_progress flag
- // -----------------------------------
-
- $this->in_progress = TRUE;
+ // Set the _in_progress flag
+ $this->_in_progress = TRUE;
- // -----------------------------------
// Call the requested class and/or function
- // -----------------------------------
-
if ($class !== FALSE)
{
if ( ! class_exists($class))
@@ -216,7 +199,7 @@ class CI_Hooks {
require($filepath);
}
- $HOOK = new $class;
+ $HOOK = new $class();
$HOOK->$function($params);
}
else
@@ -229,7 +212,7 @@ class CI_Hooks {
$function($params);
}
- $this->in_progress = FALSE;
+ $this->_in_progress = FALSE;
return TRUE;
}
diff --git a/system/core/Input.php b/system/core/Input.php
index 6e6885992..a3ad14e24 100755..100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Input Class
@@ -41,53 +42,80 @@ class CI_Input {
/**
* IP address of the current user
*
- * @var string
+ * @var string
*/
- public $ip_address = FALSE;
+ public $ip_address = FALSE;
+
/**
- * user agent (web browser) being used by the current user
+ * User agent strin
*
- * @var string
+ * @var string
*/
- public $user_agent = FALSE;
+ public $user_agent = FALSE;
+
/**
- * If FALSE, then $_GET will be set to an empty array
+ * Allow GET array flag
+ *
+ * If set to FALSE, then $_GET will be set to an empty array.
*
- * @var bool
+ * @var bool
*/
- protected $_allow_get_array = TRUE;
+ protected $_allow_get_array = TRUE;
+
/**
- * If TRUE, then newlines are standardized
+ * Standartize new lines flag
+ *
+ * If set to TRUE, then newlines are standardized.
*
- * @var bool
+ * @var bool
*/
- protected $_standardize_newlines = TRUE;
+ protected $_standardize_newlines = TRUE;
+
/**
- * Determines whether the XSS filter is always active when GET, POST or COOKIE data is encountered
- * Set automatically based on config setting
+ * Enable XSS flag
+ *
+ * Determines whether the XSS filter is always active when
+ * GET, POST or COOKIE data is encountered.
+ * Set automatically based on config setting.
*
- * @var bool
+ * @var bool
*/
- protected $_enable_xss = FALSE;
+ protected $_enable_xss = FALSE;
+
/**
+ * Enable CSRF flag
+ *
* Enables a CSRF cookie token to be set.
- * Set automatically based on config setting
+ * Set automatically based on config setting.
*
- * @var bool
+ * @var bool
*/
- protected $_enable_csrf = FALSE;
+ protected $_enable_csrf = FALSE;
+
/**
* List of all HTTP request headers
*
* @var array
*/
- protected $headers = array();
+ protected $headers = array();
/**
- * Constructor
+ * Input stream data
*
- * Sets whether to globally enable the XSS processing
- * and whether to allow the $_GET array
+ * Parsed from php://input at runtime
+ *
+ * @see CI_Input::input_stream()
+ * @var array
+ */
+ protected $_input_stream = NULL;
+
+ /**
+ * Class constructor
+ *
+ * Determines whether to globally enable the XSS processing
+ * and whether to allow the $_GET array.
+ *
+ * @return void
*/
public function __construct()
{
@@ -116,18 +144,18 @@ class CI_Input {
/**
* Fetch from array
*
- * This is a helper function to retrieve values from global arrays
+ * Internal method used to retrieve values from global arrays.
*
- * @param array
- * @param string
- * @param bool
- * @return string
+ * @param array &$array $_GET, $_POST, $_COOKIE, $_SERVER, etc.
+ * @param string $index Index for item to be fetched from $array
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
*/
protected function _fetch_from_array(&$array, $index = '', $xss_clean = FALSE)
{
if ( ! isset($array[$index]))
{
- return FALSE;
+ return NULL;
}
if ($xss_clean === TRUE)
@@ -141,17 +169,22 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Fetch an item from the GET array
- *
- * @param string
- * @param bool
- * @return string
- */
+ * Fetch an item from the GET array
+ *
+ * @param string $index Index for item to be fetched from $_GET
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
+ */
public function get($index = NULL, $xss_clean = FALSE)
{
// Check if a field has been provided
- if ($index === NULL && ! empty($_GET))
+ if ($index === NULL)
{
+ if (empty($_GET))
+ {
+ return array();
+ }
+
$get = array();
// loop through the full _GET array
@@ -168,17 +201,22 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Fetch an item from the POST array
- *
- * @param string
- * @param bool
- * @return string
- */
+ * Fetch an item from the POST array
+ *
+ * @param string $index Index for item to be fetched from $_POST
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
+ */
public function post($index = NULL, $xss_clean = FALSE)
{
// Check if a field has been provided
- if ($index === NULL && ! empty($_POST))
+ if ($index === NULL)
{
+ if (empty($_POST))
+ {
+ return array();
+ }
+
$post = array();
// Loop through the full _POST array and return it
@@ -192,16 +230,15 @@ class CI_Input {
return $this->_fetch_from_array($_POST, $index, $xss_clean);
}
-
// --------------------------------------------------------------------
/**
- * Fetch an item from either the GET array or the POST
- *
- * @param string The index key
- * @param bool XSS cleaning
- * @return string
- */
+ * Fetch an item from POST data with fallback to GET
+ *
+ * @param string $index Index for item to be fetched from $_POST or $_GET
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
+ */
public function get_post($index = '', $xss_clean = FALSE)
{
return isset($_POST[$index])
@@ -212,35 +249,80 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Fetch an item from the COOKIE array
- *
- * @param string
- * @param bool
- * @return string
- */
+ * Fetch an item from the COOKIE array
+ *
+ * @param string $index Index for item to be fetched from $_COOKIE
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
+ */
public function cookie($index = '', $xss_clean = FALSE)
{
return $this->_fetch_from_array($_COOKIE, $index, $xss_clean);
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Fetch an item from the SERVER array
+ *
+ * @param string $index Index for item to be fetched from $_SERVER
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
+ */
+ public function server($index = '', $xss_clean = FALSE)
+ {
+ return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
+ }
+
+ // ------------------------------------------------------------------------
+
+ /**
+ * Fetch an item from the php://input stream
+ *
+ * Useful when you need to access PUT, DELETE or PATCH request data.
+ *
+ * @param string $index Index for item to be fetched
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return mixed
+ */
+ public function input_stream($index = '', $xss_clean = FALSE)
+ {
+ // The input stream can only be read once, so we'll need to check
+ // if we have already done that first.
+ if (is_array($this->_input_stream))
+ {
+ return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
+ }
+
+ // Parse the input stream in our cache var
+ parse_str(file_get_contents('php://input'), $this->_input_stream);
+ if ( ! is_array($this->_input_stream))
+ {
+ $this->_input_stream = array();
+ return NULL;
+ }
+
+ return $this->_fetch_from_array($this->_input_stream, $index, $xss_clean);
+ }
+
// ------------------------------------------------------------------------
/**
- * Set cookie
- *
- * Accepts seven parameters, or you can submit an associative
- * array in the first parameter containing all the values.
- *
- * @param mixed
- * @param string the value of the cookie
- * @param string the number of seconds until expiration
- * @param string the cookie domain. Usually: .yourdomain.com
- * @param string the cookie path
- * @param string the cookie prefix
- * @param bool true makes the cookie secure
- * @param bool true makes the cookie accessible via http(s) only (no javascript)
- * @return void
- */
+ * Set cookie
+ *
+ * Accepts an arbitrary number of parameters (up to 7) or an associative
+ * array in the first parameter containing all the values.
+ *
+ * @param string|mixed[] $name Cookie name or an array containing parameters
+ * @param string $value Cookie value
+ * @param int $expire Cookie expiration time in seconds
+ * @param string $domain Cookie domain (e.g.: '.yourdomain.com')
+ * @param string $path Cookie path (default: '/')
+ * @param string $prefix Cookie name prefix
+ * @param bool $secure Whether to only transfer cookies via SSL
+ * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript)
+ * @return void
+ */
public function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE, $httponly = FALSE)
{
if (is_array($name))
@@ -255,23 +337,27 @@ class CI_Input {
}
}
- if ($prefix == '' && config_item('cookie_prefix') != '')
+ if ($prefix === '' && config_item('cookie_prefix') !== '')
{
$prefix = config_item('cookie_prefix');
}
+
if ($domain == '' && config_item('cookie_domain') != '')
{
$domain = config_item('cookie_domain');
}
- if ($path == '/' && config_item('cookie_path') !== '/')
+
+ if ($path === '/' && config_item('cookie_path') !== '/')
{
$path = config_item('cookie_path');
}
- if ($secure == FALSE && config_item('cookie_secure') != FALSE)
+
+ if ($secure === FALSE && config_item('cookie_secure') !== FALSE)
{
$secure = config_item('cookie_secure');
}
- if ($httponly == FALSE && config_item('cookie_httponly') != FALSE)
+
+ if ($httponly === FALSE && config_item('cookie_httponly') !== FALSE)
{
$httponly = config_item('cookie_httponly');
}
@@ -291,24 +377,12 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Fetch an item from the SERVER array
- *
- * @param string
- * @param bool
- * @return string
- */
- public function server($index = '', $xss_clean = FALSE)
- {
- return $this->_fetch_from_array($_SERVER, $index, $xss_clean);
- }
-
- // --------------------------------------------------------------------
-
- /**
- * Fetch the IP Address
- *
- * @return string
- */
+ * Fetch the IP Address
+ *
+ * Determines and validates the visitor's IP address.
+ *
+ * @return string IP address
+ */
public function ip_address()
{
if ($this->ip_address !== FALSE)
@@ -316,39 +390,117 @@ class CI_Input {
return $this->ip_address;
}
- if (config_item('proxy_ips') != '' && $this->server('HTTP_X_FORWARDED_FOR') && $this->server('REMOTE_ADDR'))
+ $proxy_ips = config_item('proxy_ips');
+ if ( ! empty($proxy_ips) && ! is_array($proxy_ips))
{
- $proxies = preg_split('/[\s,]/', config_item('proxy_ips'), -1, PREG_SPLIT_NO_EMPTY);
- $proxies = is_array($proxies) ? $proxies : array($proxies);
-
- $this->ip_address = in_array($_SERVER['REMOTE_ADDR'], $proxies) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
- }
- elseif ( ! $this->server('HTTP_CLIENT_IP') && $this->server('REMOTE_ADDR'))
- {
- $this->ip_address = $_SERVER['REMOTE_ADDR'];
- }
- elseif ($this->server('REMOTE_ADDR') && $this->server('HTTP_CLIENT_IP'))
- {
- $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
- }
- elseif ($this->server('HTTP_CLIENT_IP'))
- {
- $this->ip_address = $_SERVER['HTTP_CLIENT_IP'];
- }
- elseif ($this->server('HTTP_X_FORWARDED_FOR'))
- {
- $this->ip_address = $_SERVER['HTTP_X_FORWARDED_FOR'];
+ $proxy_ips = explode(',', str_replace(' ', '', $proxy_ips));
}
- if ($this->ip_address === FALSE)
- {
- return $this->ip_address = '0.0.0.0';
- }
+ $this->ip_address = $this->server('REMOTE_ADDR');
- if (strpos($this->ip_address, ',') !== FALSE)
+ if ($proxy_ips)
{
- $x = explode(',', $this->ip_address);
- $this->ip_address = trim(end($x));
+ foreach (array('HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'HTTP_X_CLIENT_IP', 'HTTP_X_CLUSTER_CLIENT_IP') as $header)
+ {
+ if (($spoof = $this->server($header)) !== NULL)
+ {
+ // Some proxies typically list the whole chain of IP
+ // addresses through which the client has reached us.
+ // e.g. client_ip, proxy_ip1, proxy_ip2, etc.
+ sscanf($spoof, '%[^,]', $spoof);
+
+ if ( ! $this->valid_ip($spoof))
+ {
+ $spoof = NULL;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ if ($spoof)
+ {
+ for ($i = 0, $c = count($proxy_ips); $i < $c; $i++)
+ {
+ // Check if we have an IP address or a subnet
+ if (strpos($proxy_ips[$i], '/') === FALSE)
+ {
+ // An IP address (and not a subnet) is specified.
+ // We can compare right away.
+ if ($proxy_ips[$i] === $this->ip_address)
+ {
+ $this->ip_address = $spoof;
+ break;
+ }
+
+ continue;
+ }
+
+ // We have a subnet ... now the heavy lifting begins
+ isset($separator) OR $separator = $this->valid_ip($this->ip_address, 'ipv6') ? ':' : '.';
+
+ // If the proxy entry doesn't match the IP protocol - skip it
+ if (strpos($proxy_ips[$i], $separator) === FALSE)
+ {
+ continue;
+ }
+
+ // Convert the REMOTE_ADDR IP address to binary, if needed
+ if ( ! isset($ip, $sprintf))
+ {
+ if ($separator === ':')
+ {
+ // Make sure we're have the "full" IPv6 format
+ $ip = explode(':',
+ str_replace('::',
+ str_repeat(':', 9 - substr_count($this->ip_address, ':')),
+ $this->ip_address
+ )
+ );
+
+ for ($i = 0; $i < 8; $i++)
+ {
+ $ip[$i] = intval($ip[$i], 16);
+ }
+
+ $sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
+ }
+ else
+ {
+ $ip = explode('.', $this->ip_address);
+ $sprintf = '%08b%08b%08b%08b';
+ }
+
+ $ip = vsprintf($sprintf, $ip);
+ }
+
+ // Split the netmask length off the network address
+ sscanf($proxy_ips[$i], '%[^/]/%d', $netaddr, $masklen);
+
+ // Again, an IPv6 address is most likely in a compressed form
+ if ($separator === ':')
+ {
+ $netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
+ for ($i = 0; $i < 8; $i++)
+ {
+ $netaddr[$i] = intval($netaddr[$i], 16);
+ }
+ }
+ else
+ {
+ $netaddr = explode('.', $netaddr);
+ }
+
+ // Convert to binary and finally compare
+ if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
+ {
+ $this->ip_address = $spoof;
+ break;
+ }
+ }
+ }
}
if ( ! $this->valid_ip($this->ip_address))
@@ -362,25 +514,37 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Validate IP Address
- *
- * Updated version suggested by Geert De Deckere
- *
- * @param string
- * @return bool
- */
- public function valid_ip($ip)
+ * Validate IP Address
+ *
+ * @param string $ip IP address
+ * @param string $which IP protocol: 'ipv4' or 'ipv6'
+ * @return bool
+ */
+ public function valid_ip($ip, $which = '')
{
- return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
+ switch (strtolower($which))
+ {
+ case 'ipv4':
+ $which = FILTER_FLAG_IPV4;
+ break;
+ case 'ipv6':
+ $which = FILTER_FLAG_IPV6;
+ break;
+ default:
+ $which = NULL;
+ break;
+ }
+
+ return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which);
}
// --------------------------------------------------------------------
/**
- * User Agent
- *
- * @return string
- */
+ * Fetch User Agent string
+ *
+ * @return string|null User Agent string or NULL if it doesn't exist
+ */
public function user_agent()
{
if ($this->user_agent !== FALSE)
@@ -388,58 +552,75 @@ class CI_Input {
return $this->user_agent;
}
- return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : FALSE;
+ return $this->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : NULL;
}
// --------------------------------------------------------------------
/**
- * Sanitize Globals
- *
- * This function does the following:
- *
- * - Unsets $_GET data (if query strings are not enabled)
- * - Unsets all globals if register_globals is enabled
- * - Standardizes newline characters to \n
- *
- * @return void
- */
+ * Sanitize Globals
+ *
+ * Internal method serving for the following purposes:
+ *
+ * - Unsets $_GET data (if query strings are not enabled)
+ * - Unsets all globals if register_globals is enabled
+ * - Cleans POST, COOKIE and SERVER data
+ * - Standardizes newline characters to PHP_EOL
+ *
+ * @return void
+ */
protected function _sanitize_globals()
{
// It would be "wrong" to unset any of these GLOBALS.
- $protected = array('_SERVER', '_GET', '_POST', '_FILES', '_REQUEST',
- '_SESSION', '_ENV', 'GLOBALS', 'HTTP_RAW_POST_DATA',
- 'system_folder', 'application_folder', 'BM', 'EXT',
- 'CFG', 'URI', 'RTR', 'OUT', 'IN'
- );
-
- // Unset globals for securiy.
+ $protected = array(
+ '_SERVER',
+ '_GET',
+ '_POST',
+ '_FILES',
+ '_REQUEST',
+ '_SESSION',
+ '_ENV',
+ 'GLOBALS',
+ 'HTTP_RAW_POST_DATA',
+ 'system_folder',
+ 'application_folder',
+ 'BM',
+ 'EXT',
+ 'CFG',
+ 'URI',
+ 'RTR',
+ 'OUT',
+ 'IN'
+ );
+
+ // Unset globals for security.
// This is effectively the same as register_globals = off
- foreach (array($_GET, $_POST, $_COOKIE) as $global)
+ // PHP 5.4 no longer has the register_globals functionality.
+ if ( ! is_php('5.4'))
{
- if ( ! is_array($global))
+ foreach (array($_GET, $_POST, $_COOKIE) as $global)
{
- if ( ! in_array($global, $protected))
+ if (is_array($global))
{
- global $$global;
- $$global = NULL;
- }
- }
- else
- {
- foreach ($global as $key => $val)
- {
- if ( ! in_array($key, $protected))
+ foreach ($global as $key => $val)
{
- global $$key;
- $$key = NULL;
+ if ( ! in_array($key, $protected))
+ {
+ global $$key;
+ $$key = NULL;
+ }
}
}
+ elseif ( ! in_array($global, $protected))
+ {
+ global $$global;
+ $$global = NULL;
+ }
}
}
// Is $_GET data allowed? If not we'll set the $_GET to an empty array
- if ($this->_allow_get_array == FALSE)
+ if ($this->_allow_get_array === FALSE)
{
$_GET = array();
}
@@ -482,7 +663,7 @@ class CI_Input {
$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']);
// CSRF Protection check
- if ($this->_enable_csrf == TRUE)
+ if ($this->_enable_csrf === TRUE && ! $this->is_cli_request())
{
$this->security->csrf_verify();
}
@@ -493,22 +674,22 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Clean Input Data
- *
- * This is a helper function. It escapes data and
- * standardizes newline characters to \n
- *
- * @param string
- * @return string
- */
+ * Clean Input Data
+ *
+ * Internal method that aids in escaping data and
+ * standardizing newline characters to PHP_EOL.
+ *
+ * @param string|string[] $str Input string(s)
+ * @return string
+ */
protected function _clean_input_data($str)
{
if (is_array($str))
{
$new_array = array();
- foreach ($str as $key => $val)
+ foreach (array_keys($str) as $key)
{
- $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
+ $new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]);
}
return $new_array;
}
@@ -539,7 +720,7 @@ class CI_Input {
}
// Standardize newlines if needed
- if ($this->_standardize_newlines == TRUE && strpos($str, "\r") !== FALSE)
+ if ($this->_standardize_newlines === TRUE && strpos($str, "\r") !== FALSE)
{
return str_replace(array("\r\n", "\r", "\r\n\n"), PHP_EOL, $str);
}
@@ -550,18 +731,18 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Clean Keys
- *
- * This is a helper function. To prevent malicious users
- * from trying to exploit keys we make sure that keys are
- * only named with alpha-numeric text and a few other items.
- *
- * @param string
- * @return string
- */
+ * Clean Keys
+ *
+ * Internal method that helps to prevent malicious users
+ * from trying to exploit keys we make sure that keys are
+ * only named with alpha-numeric text and a few other items.
+ *
+ * @param string $str Input string
+ * @return string
+ */
protected function _clean_input_keys($str)
{
- if ( ! preg_match('/^[a-z0-9:_\/-]+$/i', $str))
+ if ( ! preg_match('/^[a-z0-9:_\/|-]+$/i', $str))
{
set_status_header(503);
exit('Disallowed Key Characters.');
@@ -581,15 +762,12 @@ class CI_Input {
/**
* Request Headers
*
- * In Apache, you can simply call apache_request_headers(), however for
- * people running other webservers the function is undefined.
- *
- * @param bool XSS cleaning
+ * @param bool $xss_clean Whether to apply XSS filtering
* @return array
*/
public function request_headers($xss_clean = FALSE)
{
- // Look at Apache go!
+ // In Apache, you can simply call apache_request_headers()
if (function_exists('apache_request_headers'))
{
$headers = apache_request_headers();
@@ -600,9 +778,9 @@ class CI_Input {
foreach ($_SERVER as $key => $val)
{
- if (strpos($key, 'HTTP_') === 0)
+ if (sscanf($key, 'HTTP_%s', $header) === 1)
{
- $headers[substr($key, 5)] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
+ $headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
}
}
}
@@ -626,9 +804,9 @@ class CI_Input {
*
* Returns the value of a single member of the headers class member
*
- * @param string array key for $this->headers
- * @param bool XSS Clean or not
- * @return mixed FALSE on failure, string on success
+ * @param string $index Header name
+ * @param bool $xss_clean Whether to apply XSS filtering
+ * @return string|bool The requested header on success or FALSE on failure
*/
public function get_request_header($index, $xss_clean = FALSE)
{
@@ -639,7 +817,7 @@ class CI_Input {
if ( ! isset($this->headers[$index]))
{
- return FALSE;
+ return NULL;
}
return ($xss_clean === TRUE)
@@ -650,9 +828,9 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Is ajax Request?
+ * Is AJAX request?
*
- * Test to see if a request contains the HTTP_X_REQUESTED_WITH header
+ * Test to see if a request contains the HTTP_X_REQUESTED_WITH header.
*
* @return bool
*/
@@ -664,9 +842,9 @@ class CI_Input {
// --------------------------------------------------------------------
/**
- * Is cli Request?
+ * Is CLI request?
*
- * Test to see if a request was made from the command line
+ * Test to see if a request was made from the command line.
*
* @return bool
*/
@@ -680,10 +858,11 @@ class CI_Input {
/**
* Get Request Method
*
- * Return the Request Method
+ * Return the request method
*
- * @param bool uppercase or lowercase
- * @return bool
+ * @param bool $upper Whether to return in upper or lower case
+ * (default: FALSE)
+ * @return string
*/
public function method($upper = FALSE)
{
@@ -695,4 +874,4 @@ class CI_Input {
}
/* End of file Input.php */
-/* Location: ./system/core/Input.php */
+/* Location: ./system/core/Input.php */ \ No newline at end of file
diff --git a/system/core/Lang.php b/system/core/Lang.php
index 9ef76f4d6..9e6f43716 100755..100644
--- a/system/core/Lang.php
+++ b/system/core/Lang.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,8 +24,7 @@
* @since Version 1.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Language Class
@@ -41,16 +40,22 @@ class CI_Lang {
/**
* List of translations
*
- * @var array
+ * @var array
*/
- public $language = array();
+ public $language = array();
+
/**
* List of loaded language files
*
- * @var array
+ * @var array
*/
- public $is_loaded = array();
+ public $is_loaded = array();
+ /**
+ * Class constructor
+ *
+ * @return void
+ */
public function __construct()
{
log_message('debug', 'Language Class Initialized');
@@ -61,77 +66,90 @@ class CI_Lang {
/**
* Load a language file
*
- * @param mixed the name of the language file to be loaded. Can be an array
- * @param string the language (english, etc.)
- * @param bool return loaded array of translations
- * @param bool add suffix to $langfile
- * @param string alternative path to look for language file
- * @return mixed
+ * @param mixed $langfile Language file name
+ * @param string $idiom Language name (english, etc.)
+ * @param bool $return Whether to return the loaded array of translations
+ * @param bool $add_suffix Whether to add suffix to $langfile
+ * @param string $alt_path Alternative path to look for the language file
+ *
+ * @return void|string[] Array containing translations, if $return is set to TRUE
*/
- public function load($langfile = '', $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '')
+ public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '')
{
$langfile = str_replace('.php', '', $langfile);
- if ($add_suffix == TRUE)
+ if ($add_suffix === TRUE)
{
- $langfile = str_replace('_lang.', '', $langfile).'_lang';
+ $langfile = str_replace('_lang', '', $langfile).'_lang';
}
$langfile .= '.php';
- if (in_array($langfile, $this->is_loaded, TRUE))
+ if (empty($idiom) OR ! ctype_alpha($idiom))
{
- return;
+ $config =& get_config();
+ $idiom = empty($config['language']) ? 'english' : $config['language'];
}
- $config =& get_config();
+ if ($return === FALSE && isset($this->is_loaded[$langfile]) && $this->is_loaded[$langfile] === $idiom)
+ {
+ return;
+ }
- if ($idiom == '')
+ // Load the base file, so any others found can override it
+ $basepath = BASEPATH.'language/'.$idiom.'/'.$langfile;
+ if (($found = file_exists($basepath)) === TRUE)
{
- $deft_lang = ( ! isset($config['language'])) ? 'english' : $config['language'];
- $idiom = ($deft_lang == '') ? 'english' : $deft_lang;
+ include($basepath);
}
- // Determine where the language file is and load it
- if ($alt_path != '' && file_exists($alt_path.'language/'.$idiom.'/'.$langfile))
+ // Do we have an alternative path to look in?
+ if ($alt_path !== '')
{
- include($alt_path.'language/'.$idiom.'/'.$langfile);
+ $alt_path .= 'language/'.$idiom.'/'.$langfile;
+ if (file_exists($alt_path))
+ {
+ include($alt_path);
+ $found = TRUE;
+ }
}
else
{
- $found = FALSE;
-
foreach (get_instance()->load->get_package_paths(TRUE) as $package_path)
{
- if (file_exists($package_path.'language/'.$idiom.'/'.$langfile))
+ $package_path .= 'language/'.$idiom.'/'.$langfile;
+ if ($basepath !== $package_path && file_exists($package_path))
{
- include($package_path.'language/'.$idiom.'/'.$langfile);
+ include($package_path);
$found = TRUE;
break;
}
}
-
- if ($found !== TRUE)
- {
- show_error('Unable to load the requested language file: language/'.$idiom.'/'.$langfile);
- }
}
+ if ($found !== TRUE)
+ {
+ show_error('Unable to load the requested language file: language/'.$idiom.'/'.$langfile);
+ }
if ( ! isset($lang) OR ! is_array($lang))
{
log_message('error', 'Language file contains no data: language/'.$idiom.'/'.$langfile);
+
+ if ($return === TRUE)
+ {
+ return array();
+ }
return;
}
- if ($return == TRUE)
+ if ($return === TRUE)
{
return $lang;
}
- $this->is_loaded[] = $langfile;
+ $this->is_loaded[$langfile] = $idiom;
$this->language = array_merge($this->language, $lang);
- unset($lang);
log_message('debug', 'Language file loaded: language/'.$idiom.'/'.$langfile);
return TRUE;
@@ -140,17 +158,20 @@ class CI_Lang {
// --------------------------------------------------------------------
/**
- * Fetch a single line of text from the language array
+ * Language line
+ *
+ * Fetches a single line of text from the language array
*
- * @param string $line the language line
- * @return string
+ * @param string $line Language line key
+ * @param bool $log_errors Whether to log an error message if the line is not found
+ * @return string Translation
*/
- public function line($line = '')
+ public function line($line = '', $log_errors = TRUE)
{
- $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
+ $value = ($line === '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];
// Because killer robots like unicorns!
- if ($value === FALSE)
+ if ($value === FALSE && $log_errors === TRUE)
{
log_message('error', 'Could not find the language line "'.$line.'"');
}
@@ -161,4 +182,4 @@ class CI_Lang {
}
/* End of file Lang.php */
-/* Location: ./system/core/Lang.php */
+/* Location: ./system/core/Lang.php */ \ No newline at end of file
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 027ed20e5..651507470 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,16 +24,17 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Loader Class
*
- * Loads views and files
+ * Loads framework components.
*
* @package CodeIgniter
* @subpackage Libraries
- * @author EllisLab Dev Team
* @category Loader
+ * @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/libraries/loader.html
*/
class CI_Loader {
@@ -42,83 +43,96 @@ class CI_Loader {
/**
* Nesting level of the output buffering mechanism
*
- * @var int
+ * @var int
*/
protected $_ci_ob_level;
+
/**
* List of paths to load views from
*
- * @var array
+ * @var array
*/
- protected $_ci_view_paths = array();
+ protected $_ci_view_paths = array();
+
/**
* List of paths to load libraries from
*
- * @var array
+ * @var array
*/
- protected $_ci_library_paths = array();
+ protected $_ci_library_paths = array();
+
/**
* List of paths to load models from
*
- * @var array
+ * @var array
*/
- protected $_ci_model_paths = array();
+ protected $_ci_model_paths = array();
+
/**
* List of paths to load helpers from
*
- * @var array
+ * @var array
*/
- protected $_ci_helper_paths = array();
+ protected $_ci_helper_paths = array();
+
/**
* List of loaded base classes
*
- * @var array
+ * @var array
*/
- protected $_base_classes = array(); // Set by the controller class
+ protected $_base_classes = array(); // Set by the controller class
+
/**
* List of cached variables
*
- * @var array
+ * @var array
*/
- protected $_ci_cached_vars = array();
+ protected $_ci_cached_vars = array();
+
/**
* List of loaded classes
*
- * @var array
+ * @var array
*/
- protected $_ci_classes = array();
+ protected $_ci_classes = array();
+
/**
* List of loaded files
*
- * @var array
+ * @var array
*/
- protected $_ci_loaded_files = array();
+ protected $_ci_loaded_files = array();
+
/**
* List of loaded models
*
- * @var array
+ * @var array
*/
- protected $_ci_models = array();
+ protected $_ci_models = array();
+
/**
* List of loaded helpers
*
- * @var array
+ * @var array
*/
- protected $_ci_helpers = array();
+ protected $_ci_helpers = array();
+
/**
* List of class name mappings
*
- * @var array
+ * @var array
*/
- protected $_ci_varmap = array(
- 'unit_test' => 'unit',
- 'user_agent' => 'agent'
- );
+ protected $_ci_varmap = array(
+ 'unit_test' => 'unit',
+ 'user_agent' => 'agent'
+ );
/**
- * Constructor
+ * Class constructor
+ *
+ * Sets component load paths, gets the initial output buffering level.
*
- * Sets the path to the view files and gets the initial output buffering level
+ * @return void
*/
public function __construct()
{
@@ -134,22 +148,18 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Initialize the Loader
+ * Initializer
*
- * This method is called once in CI_Controller.
- *
- * @param array
- * @return object
+ * @todo Figure out a way to move this to the constructor
+ * without breaking *package_path*() methods.
+ * @uses CI_Loader::_ci_autoloader()
+ * @used-by CI_Controller::__construct()
+ * @return void
*/
public function initialize()
{
- $this->_ci_classes = array();
- $this->_ci_loaded_files = array();
- $this->_ci_models = array();
$this->_base_classes =& is_loaded();
-
$this->_ci_autoloader();
- return $this;
}
// --------------------------------------------------------------------
@@ -157,36 +167,29 @@ class CI_Loader {
/**
* Is Loaded
*
- * A utility function to test if a class is in the self::$_ci_classes array.
- * This function returns the object name if the class tested for is loaded,
- * and returns FALSE if it isn't.
+ * A utility method to test if a class is in the self::$_ci_classes array.
*
- * It is mainly used in the form_helper -> _get_validation_object()
+ * @used-by Mainly used by Form Helper function _get_validation_object().
*
- * @param string class being checked for
- * @return mixed class object name on the CI SuperObject or FALSE
+ * @param string $class Class name to check for
+ * @return string|bool Class object name if loaded or FALSE
*/
public function is_loaded($class)
{
- if (isset($this->_ci_classes[$class]))
- {
- return $this->_ci_classes[$class];
- }
-
- return FALSE;
+ return isset($this->_ci_classes[$class]) ? $this->_ci_classes[$class] : FALSE;
}
// --------------------------------------------------------------------
/**
- * Class Loader
+ * Library Loader
*
- * This function lets users load and instantiate classes.
- * It is designed to be called from a user's app controllers.
+ * Loads and instantiates libraries.
+ * Designed to be called from application controllers.
*
- * @param string the name of the class
- * @param mixed the optional parameters
- * @param string an optional object name
+ * @param string $library Library name
+ * @param array $params Optional parameters to pass to the library class constructor
+ * @param string $object_name An optional object name to assign to
* @return void
*/
public function library($library = '', $params = NULL, $object_name = NULL)
@@ -201,9 +204,9 @@ class CI_Loader {
return;
}
- if ($library == '' OR isset($this->_base_classes[$library]))
+ if ($library === '' OR isset($this->_base_classes[$library]))
{
- return FALSE;
+ return;
}
if ( ! is_null($params) && ! is_array($params))
@@ -219,26 +222,25 @@ class CI_Loader {
/**
* Model Loader
*
- * This function lets users load and instantiate models.
+ * Loads and instantiates libraries.
*
- * @param string the name of the class
- * @param string name for the model
- * @param bool database connection
+ * @param string $model Model name
+ * @param string $name An optional object name to assign to
+ * @param bool $db_conn An optional database connection configuration to initialize
* @return void
*/
public function model($model, $name = '', $db_conn = FALSE)
{
- if (is_array($model))
+ if (empty($model))
{
- foreach ($model as $babe)
- {
- $this->model($babe);
- }
return;
}
-
- if ($model == '')
+ elseif (is_array($model))
{
+ foreach ($model as $class)
+ {
+ $this->model($class);
+ }
return;
}
@@ -254,7 +256,7 @@ class CI_Loader {
$model = substr($model, $last_slash);
}
- if ($name == '')
+ if (empty($name))
{
$name = $model;
}
@@ -311,18 +313,21 @@ class CI_Loader {
/**
* Database Loader
*
- * @param string the DB credentials
- * @param bool whether to return the DB object
- * @param bool whether to enable active record (this allows us to override the config setting)
- * @return object
+ * @param mixed $params Database configuration options
+ * @param bool $return Whether to return the database object
+ * @param bool $query_builder Whether to enable Query Builder
+ * (overrides the configuration setting)
+ *
+ * @return void|object|bool Database object if $return is set to TRUE,
+ * FALSE on failure, void in any other case
*/
- public function database($params = '', $return = FALSE, $active_record = NULL)
+ public function database($params = '', $return = FALSE, $query_builder = NULL)
{
// Grab the super object
$CI =& get_instance();
// Do we even need to load the database class?
- if (class_exists('CI_DB') && $return == FALSE && $active_record == NULL && isset($CI->db) && is_object($CI->db))
+ if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id))
{
return FALSE;
}
@@ -331,7 +336,7 @@ class CI_Loader {
if ($return === TRUE)
{
- return DB($params, $active_record);
+ return DB($params, $query_builder);
}
// Initialize the db variable. Needed to prevent
@@ -339,34 +344,38 @@ class CI_Loader {
$CI->db = '';
// Load the DB class
- $CI->db =& DB($params, $active_record);
+ $CI->db =& DB($params, $query_builder);
}
// --------------------------------------------------------------------
/**
- * Load the Utilities Class
+ * Load the Database Utilities Class
*
- * @return string
+ * @param object $db Database object
+ * @param bool $return Whether to return the DB Forge class object or not
+ * @return void|object
*/
- public function dbutil()
+ public function dbutil($db = NULL, $return = FALSE)
{
- if ( ! class_exists('CI_DB'))
- {
- $this->database();
- }
-
$CI =& get_instance();
- // for backwards compatibility, load dbforge so we can extend dbutils off it
- // this use is deprecated and strongly discouraged
- $CI->load->dbforge();
+ if ( ! is_object($db) OR ! ($db instanceof CI_DB))
+ {
+ class_exists('CI_DB', FALSE) OR $this->database();
+ $db =& $CI->db;
+ }
require_once(BASEPATH.'database/DB_utility.php');
- require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_utility.php');
- $class = 'CI_DB_'.$CI->db->dbdriver.'_utility';
+ require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_utility.php');
+ $class = 'CI_DB_'.$db->dbdriver.'_utility';
+
+ if ($return === TRUE)
+ {
+ return new $class($db);
+ }
- $CI->dbutil = new $class();
+ $CI->dbutil = new $class($db);
}
// --------------------------------------------------------------------
@@ -374,40 +383,56 @@ class CI_Loader {
/**
* Load the Database Forge Class
*
- * @return string
+ * @param object $db Database object
+ * @param bool $return Whether to return the DB Forge class object or not
+ * @return void|object
*/
- public function dbforge()
+ public function dbforge($db = NULL, $return = FALSE)
{
- if ( ! class_exists('CI_DB'))
+ $CI =& get_instance();
+ if ( ! is_object($db) OR ! ($db instanceof CI_DB))
{
- $this->database();
+ class_exists('CI_DB', FALSE) OR $this->database();
+ $db =& $CI->db;
}
- $CI =& get_instance();
-
require_once(BASEPATH.'database/DB_forge.php');
- require_once(BASEPATH.'database/drivers/'.$CI->db->dbdriver.'/'.$CI->db->dbdriver.'_forge.php');
- $class = 'CI_DB_'.$CI->db->dbdriver.'_forge';
+ require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_forge.php');
- $CI->dbforge = new $class();
+ if ( ! empty($db->subdriver))
+ {
+ $driver_path = BASEPATH.'database/drivers/'.$db->dbdriver.'/subdrivers/'.$db->dbdriver.'_'.$db->subdriver.'_forge.php';
+ if (file_exists($driver_path))
+ {
+ require_once($driver_path);
+ $class = 'CI_DB_'.$db->dbdriver.'_'.$db->subdriver.'_forge';
+ }
+ }
+ else
+ {
+ $class = 'CI_DB_'.$db->dbdriver.'_forge';
+ }
+
+ if ($return === TRUE)
+ {
+ return new $class($db);
+ }
+
+ $CI->dbforge = new $class($db);
}
// --------------------------------------------------------------------
/**
- * Load View
- *
- * This function is used to load a "view" file. It has three parameters:
+ * View Loader
*
- * 1. The name of the "view" file to be included.
- * 2. An associative array of data to be extracted for use in the view.
- * 3. TRUE/FALSE - whether to return the data or load it. In
- * some cases it's advantageous to be able to return data so that
- * a developer can process it in some way.
+ * Loads "view" files.
*
- * @param string
- * @param array
- * @param bool
+ * @param string $view View name
+ * @param array $vars An associative array of data
+ * to be extracted for use in the view
+ * @param bool $return Whether to return the view output
+ * or leave it to the Output class
* @return void
*/
public function view($view, $vars = array(), $return = FALSE)
@@ -418,13 +443,11 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Load File
+ * Generic File Loader
*
- * This is a generic file loader
- *
- * @param string
- * @param bool
- * @return string
+ * @param string $path File path
+ * @param bool $return Whether to return the file output
+ * @return void|string
*/
public function file($path, $return = FALSE)
{
@@ -439,13 +462,15 @@ class CI_Loader {
* Once variables are set they become available within
* the controller class and its "view" files.
*
- * @param array
- * @param string
+ * @param array|object|string $vars
+ * An associative array or object containing values
+ * to be set, or a value's name if string
+ * @param string $val Value to set, only used if $vars is a string
* @return void
*/
public function vars($vars = array(), $val = '')
{
- if ($val != '' && is_string($vars))
+ if ($val !== '' && is_string($vars))
{
$vars = array($vars => $val);
}
@@ -468,8 +493,8 @@ class CI_Loader {
*
* Check if a variable is set and retrieve it.
*
- * @param array
- * @return void
+ * @param string $key Variable name
+ * @return mixed The variable or NULL if not found
*/
public function get_var($key)
{
@@ -481,7 +506,7 @@ class CI_Loader {
/**
* Get Variables
*
- * Retrieve all loaded variables
+ * Retrieves all loaded variables.
*
* @return array
*/
@@ -493,11 +518,9 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Load Helper
- *
- * This function loads the specified helper file.
+ * Helper Loader
*
- * @param mixed
+ * @param string|string[] $helpers Helper name(s)
* @return void
*/
public function helper($helpers = array())
@@ -509,27 +532,34 @@ class CI_Loader {
continue;
}
- $ext_helper = APPPATH.'helpers/'.config_item('subclass_prefix').$helper.'.php';
-
// Is this a helper extension request?
- if (file_exists($ext_helper))
+ $ext_helper = config_item('subclass_prefix').$helper;
+ $ext_loaded = FALSE;
+ foreach ($this->_ci_helper_paths as $path)
{
- $base_helper = BASEPATH.'helpers/'.$helper.'.php';
+ if (file_exists($path.'helpers/'.$ext_helper.'.php'))
+ {
+ include_once($path.'helpers/'.$ext_helper.'.php');
+ $ext_loaded = TRUE;
+ }
+ }
+ // If we have loaded extensions - check if the base one is here
+ if ($ext_loaded === TRUE)
+ {
+ $base_helper = BASEPATH.'helpers/'.$helper.'.php';
if ( ! file_exists($base_helper))
{
show_error('Unable to load the requested file: helpers/'.$helper.'.php');
}
- include_once($ext_helper);
include_once($base_helper);
-
$this->_ci_helpers[$helper] = TRUE;
log_message('debug', 'Helper loaded: '.$helper);
continue;
}
- // Try to load the helper
+ // No extensions found ... try loading regular helpers and/or overrides
foreach ($this->_ci_helper_paths as $path)
{
if (file_exists($path.'helpers/'.$helper.'.php'))
@@ -555,10 +585,11 @@ class CI_Loader {
/**
* Load Helpers
*
- * This is simply an alias to the above function in case the
- * user has written the plural form of this function.
+ * An alias for the helper() method in case the developer has
+ * written the plural form of it.
*
- * @param array
+ * @uses CI_Loader::helper()
+ * @param string|string[] $helpers Helper name(s)
* @return void
*/
public function helpers($helpers = array())
@@ -569,22 +600,21 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Loads a language file
+ * Language Loader
*
- * @param array
- * @param string
+ * Loads language files.
+ *
+ * @param string|string[] $files List of language file names to load
+ * @param string Language name
* @return void
*/
- public function language($file = array(), $lang = '')
+ public function language($files = array(), $lang = '')
{
$CI =& get_instance();
- if ( ! is_array($file))
- {
- $file = array($file);
- }
+ is_array($files) OR $files = array($files);
- foreach ($file as $langfile)
+ foreach ($files as $langfile)
{
$CI->lang->load($langfile, $lang);
}
@@ -593,30 +623,35 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Loads a config file
+ * Config Loader
*
- * @param string
- * @param bool
- * @param bool
- * @return void
+ * Loads a config file (an alias for CI_Config::load()).
+ *
+ * @uses CI_Config::load()
+ * @param string $file Configuration file name
+ * @param bool $use_sections Whether configuration values should be loaded into their own section
+ * @param bool $fail_gracefully Whether to just return FALSE or display an error message
+ * @return bool TRUE if the file was loaded correctly or FALSE on failure
*/
public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
{
$CI =& get_instance();
- $CI->config->load($file, $use_sections, $fail_gracefully);
+ return $CI->config->load($file, $use_sections, $fail_gracefully);
}
// --------------------------------------------------------------------
/**
- * Driver
+ * Driver Loader
*
- * Loads a driver library
+ * Loads a driver library.
*
- * @param mixed the name of the class or array of classes
- * @param mixed the optional parameters
- * @param string an optional object name
- * @return void
+ * @param string|string[] $library Driver name(s)
+ * @param array $params Optional parameters to pass to the driver
+ * @param string $object_name An optional object name to assign to
+ *
+ * @return void|object|bool Object or FALSE on failure if $library is a string
+ * and $object_name is set. void otherwise.
*/
public function driver($library = '', $params = NULL, $object_name = NULL)
{
@@ -626,18 +661,18 @@ class CI_Loader {
{
$this->driver($driver);
}
- return FALSE;
+ return;
}
- if ( ! class_exists('CI_Driver_Library'))
+ if ($library === '')
{
- // we aren't instantiating an object here, that'll be done by the Library itself
- require BASEPATH.'libraries/Driver.php';
+ return FALSE;
}
- if ($library == '')
+ if ( ! class_exists('CI_Driver_Library'))
{
- return FALSE;
+ // We aren't instantiating an object here, just making the base class available
+ require BASEPATH.'libraries/Driver.php';
}
// We can save the loader some time since Drivers will *always* be in a subfolder,
@@ -655,13 +690,19 @@ class CI_Loader {
/**
* Add Package Path
*
- * Prepends a parent path to the library, model, helper, and config path arrays
+ * Prepends a parent path to the library, model, helper and config
+ * path arrays.
*
- * @param string
- * @param bool
+ * @see CI_Loader::$_ci_library_paths
+ * @see CI_Loader::$_ci_model_paths
+ * @see CI_Loader::$_ci_helper_paths
+ * @see CI_Config::$_config_paths
+ *
+ * @param string $path Path to add
+ * @param bool $view_cascade (default: TRUE)
* @return void
*/
- public function add_package_path($path, $view_cascade=TRUE)
+ public function add_package_path($path, $view_cascade = TRUE)
{
$path = rtrim($path, '/').'/';
@@ -673,7 +714,7 @@ class CI_Loader {
// Add config file path
$config =& $this->_ci_get_component('config');
- array_unshift($config->_config_paths, $path);
+ array_push($config->_config_paths, $path);
}
// --------------------------------------------------------------------
@@ -681,14 +722,14 @@ class CI_Loader {
/**
* Get Package Paths
*
- * Return a list of all package paths, by default it will ignore BASEPATH.
+ * Return a list of all package paths.
*
- * @param string
- * @return void
+ * @param bool $include_base Whether to include BASEPATH (default: TRUE)
+ * @return array
*/
public function get_package_paths($include_base = FALSE)
{
- return $include_base === TRUE ? $this->_ci_library_paths : $this->_ci_model_paths;
+ return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths;
}
// --------------------------------------------------------------------
@@ -696,24 +737,24 @@ class CI_Loader {
/**
* Remove Package Path
*
- * Remove a path from the library, model, and helper path arrays if it exists
- * If no path is provided, the most recently added path is removed.
+ * Remove a path from the library, model, helper and/or config
+ * path arrays if it exists. If no path is provided, the most recently
+ * added path will be removed removed.
*
- * @param string
- * @param bool
+ * @param string $path Path to remove
* @return void
*/
- public function remove_package_path($path = '', $remove_config_path = TRUE)
+ public function remove_package_path($path = '')
{
$config =& $this->_ci_get_component('config');
- if ($path == '')
+ if ($path === '')
{
array_shift($this->_ci_library_paths);
array_shift($this->_ci_model_paths);
array_shift($this->_ci_helper_paths);
array_shift($this->_ci_view_paths);
- array_shift($config->_config_paths);
+ array_pop($config->_config_paths);
}
else
{
@@ -748,13 +789,16 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Loader
+ * Internal CI Data Loader
+ *
+ * Used to load views and files.
*
- * This function is used to load views and files.
* Variables are prefixed with _ci_ to avoid symbol collision with
- * variables made available to view files
+ * variables made available to view files.
*
- * @param array
+ * @used-by CI_Loader::view()
+ * @used-by CI_Loader::file()
+ * @param array $_ci_data Data to load
* @return void
*/
protected function _ci_load($_ci_data)
@@ -768,7 +812,7 @@ class CI_Loader {
$file_exists = FALSE;
// Set the path to the requested file
- if ($_ci_path != '')
+ if (is_string($_ci_path) && $_ci_path !== '')
{
$_ci_x = explode('/', $_ci_path);
$_ci_file = end($_ci_x);
@@ -776,13 +820,13 @@ class CI_Loader {
else
{
$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
- $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;
+ $_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
- foreach ($this->_ci_view_paths as $view_file => $cascade)
+ foreach ($this->_ci_view_paths as $_ci_view_file => $cascade)
{
- if (file_exists($view_file.$_ci_file))
+ if (file_exists($_ci_view_file.$_ci_file))
{
- $_ci_path = $view_file.$_ci_file;
+ $_ci_path = $_ci_view_file.$_ci_file;
$file_exists = TRUE;
break;
}
@@ -813,7 +857,7 @@ class CI_Loader {
/*
* Extract and cache variables
*
- * You can either set variables using the dedicated $this->load_vars()
+ * You can either set variables using the dedicated $this->load->vars()
* function or via the second parameter of this function. We'll merge
* the two types and cache them so that views that are embedded within
* other views can have access to these variables.
@@ -830,17 +874,19 @@ class CI_Loader {
* We buffer the output for two reasons:
* 1. Speed. You get a significant speed boost.
* 2. So that the final rendered template can be post-processed by
- * the output class. Why do we need post processing? For one thing,
- * in order to show the elapsed page load time. Unless we can
- * intercept the content right before it's sent to the browser and
- * then stop the timer it won't be accurate.
+ * the output class. Why do we need post processing? For one thing,
+ * in order to show the elapsed page load time. Unless we can
+ * intercept the content right before it's sent to the browser and
+ * then stop the timer it won't be accurate.
*/
ob_start();
// If the PHP installation does not support short tags we'll
// do a little string replacement, changing the short tags
// to standard PHP echo statements.
- if ( ! is_php('5.4') && (bool) @ini_get('short_open_tag') === FALSE && config_item('rewrite_short_tags') == TRUE)
+ if ( ! is_php('5.4') && (bool) @ini_get('short_open_tag') === FALSE
+ && config_item('rewrite_short_tags') === TRUE && function_usable('eval')
+ )
{
echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
}
@@ -882,13 +928,14 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Load class
+ * Internal CI Class Loader
*
- * This function loads the requested class.
+ * @used-by CI_Loader::library()
+ * @uses CI_Loader::_ci_init_class()
*
- * @param string the item that is being loaded
- * @param mixed any additional parameters
- * @param string an optional object name
+ * @param string $class Class name to load
+ * @param mixed $params Optional parameters to pass to the class constructor
+ * @param string $object_name Optional object name to assign to
* @return void
*/
protected function _ci_load_class($class, $params = NULL, $object_name = NULL)
@@ -989,19 +1036,24 @@ class CI_Loader {
$this->_ci_loaded_files[] = $filepath;
return $this->_ci_init_class($class, '', $params, $object_name);
}
-
} // END FOREACH
// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
- if ($subdir == '')
+ if ($subdir === '')
{
$path = strtolower($class).'/'.$class;
- return $this->_ci_load_class($path, $params);
+ return $this->_ci_load_class($path, $params, $object_name);
+ }
+ elseif (ucfirst($subdir) != $subdir)
+ {
+ // Lowercase subdir failed - retry capitalized
+ $path = ucfirst($subdir).$class;
+ return $this->_ci_load_class($path, $params, $object_name);
}
// If we got this far we were unable to find the requested class.
// We do not issue errors if the load call failed due to a duplicate request
- if ($is_duplicate == FALSE)
+ if ($is_duplicate === FALSE)
{
log_message('error', 'Unable to load the requested class: '.$class);
show_error('Unable to load the requested class: '.$class);
@@ -1011,12 +1063,17 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Instantiates a class
+ * Internal CI Class Instantiator
+ *
+ * @used-by CI_Loader::_ci_load_class()
*
- * @param string
- * @param string
- * @param bool
- * @param string an optional object name
+ * @param string $class Class name
+ * @param string $prefix Class name prefix
+ * @param array|null|bool $config Optional configuration to pass to the class constructor:
+ * FALSE to skip;
+ * NULL to search in config paths;
+ * array containing configuration data
+ * @param string $object_name Optional object name to assign to
* @return void
*/
protected function _ci_init_class($class, $prefix = '', $config = FALSE, $object_name = NULL)
@@ -1060,7 +1117,7 @@ class CI_Loader {
}
}
- if ($prefix == '')
+ if ($prefix === '')
{
if (class_exists('CI_'.$class))
{
@@ -1084,7 +1141,7 @@ class CI_Loader {
if ( ! class_exists($name))
{
log_message('error', 'Non-existent class: '.$name);
- show_error('Non-existent class: '.$class);
+ show_error('Non-existent class: '.$name);
}
// Set the variable name we will assign the class to
@@ -1118,12 +1175,11 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Autoloader
+ * CI Autoloader
*
- * The config/autoload.php file contains an array that permits sub-systems,
- * libraries, and helpers to be loaded automatically.
+ * Loads component listed in the config/autoload.php file.
*
- * @param array
+ * @used-by CI_Loader::initialize()
* @return void
*/
protected function _ci_autoloader()
@@ -1187,6 +1243,15 @@ class CI_Loader {
}
}
+ // Autoload drivers
+ if (isset($autoload['drivers']))
+ {
+ foreach ($autoload['drivers'] as $item)
+ {
+ $this->driver($item);
+ }
+ }
+
// Autoload models
if (isset($autoload['model']))
{
@@ -1197,11 +1262,12 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Object to Array
+ * CI Object to Array translator
*
- * Takes an object as input and converts the class variables to array key/vals
+ * Takes an object as input and converts the class variables to
+ * an associative array with key/value pairs.
*
- * @param object
+ * @param object $object Object data to translate
* @return array
*/
protected function _ci_object_to_array($object)
@@ -1212,9 +1278,11 @@ class CI_Loader {
// --------------------------------------------------------------------
/**
- * Get a reference to a specific library or model
+ * CI Component getter
+ *
+ * Get a reference to a specific library or model.
*
- * @param string
+ * @param string $component Component name
* @return bool
*/
protected function &_ci_get_component($component)
@@ -1228,10 +1296,11 @@ class CI_Loader {
/**
* Prep filename
*
- * This function preps the name of various items to make loading them more reliable.
+ * This function prepares filenames of various items to
+ * make their loading more reliable.
*
- * @param mixed
- * @param string
+ * @param string|string[] $filename Filename(s)
+ * @param string $extension Filename extension
* @return array
*/
protected function _ci_prep_filename($filename, $extension)
diff --git a/system/core/Log.php b/system/core/Log.php
new file mode 100644
index 000000000..718f50587
--- /dev/null
+++ b/system/core/Log.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Open Software License version 3.0
+ *
+ * This source file is subject to the Open Software License (OSL 3.0) that is
+ * bundled with this package in the files license.txt / license.rst. It is
+ * also available through the world wide web at this URL:
+ * http://opensource.org/licenses/OSL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
+ * @link http://codeigniter.com
+ * @since Version 1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+/**
+ * Logging Class
+ *
+ * @package CodeIgniter
+ * @subpackage Libraries
+ * @category Logging
+ * @author EllisLab Dev Team
+ * @link http://codeigniter.com/user_guide/general/errors.html
+ */
+class CI_Log {
+
+ /**
+ * Path to save log files
+ *
+ * @var string
+ */
+ protected $_log_path;
+
+ /**
+ * Level of logging
+ *
+ * @var int
+ */
+ protected $_threshold = 1;
+
+ /**
+ * Highest level of logging
+ *
+ * @var int
+ */
+ protected $_threshold_max = 0;
+
+ /**
+ * Array of threshold levels to log
+ *
+ * @var array
+ */
+ protected $_threshold_array = array();
+
+ /**
+ * Format of timestamp for log files
+ *
+ * @var string
+ */
+ protected $_date_fmt = 'Y-m-d H:i:s';
+
+ /**
+ * Whether or not the logger can write to the log files
+ *
+ * @var bool
+ */
+ protected $_enabled = TRUE;
+
+ /**
+ * Predefined logging levels
+ *
+ * @var array
+ */
+ protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4);
+
+ /**
+ * Initialize Logging class
+ *
+ * @return void
+ */
+ public function __construct()
+ {
+ $config =& get_config();
+
+ $this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/';
+
+ if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path))
+ {
+ $this->_enabled = FALSE;
+ }
+
+ if (is_numeric($config['log_threshold']))
+ {
+ $this->_threshold = (int) $config['log_threshold'];
+ }
+ elseif (is_array($config['log_threshold']))
+ {
+ $this->_threshold = $this->_threshold_max;
+ $this->_threshold_array = array_flip($config['log_threshold']);
+ }
+
+ if ($config['log_date_format'] !== '')
+ {
+ $this->_date_fmt = $config['log_date_format'];
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Write Log File
+ *
+ * Generally this function will be called using the global log_message() function
+ *
+ * @param string the error level
+ * @param string the error message
+ * @param bool whether the error is a native PHP error
+ * @return bool
+ */
+ public function write_log($level = 'error', $msg, $php_error = FALSE)
+ {
+ if ($this->_enabled === FALSE)
+ {
+ return FALSE;
+ }
+
+ $level = strtoupper($level);
+
+ if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
+ && ! isset($this->_threshold_array[$this->_levels[$level]]))
+ {
+ return FALSE;
+ }
+
+ $filepath = $this->_log_path.'log-'.date('Y-m-d').'.php';
+ $message = '';
+
+ if ( ! file_exists($filepath))
+ {
+ $newfile = TRUE;
+ $message .= '<'."?php defined('BASEPATH') OR exit('No direct script access allowed'); ?".">\n\n";
+ }
+
+ if ( ! $fp = @fopen($filepath, FOPEN_WRITE_CREATE))
+ {
+ return FALSE;
+ }
+
+ $message .= $level.' '.($level === 'INFO' ? ' -' : '-').' '.date($this->_date_fmt).' --> '.$msg."\n";
+
+ flock($fp, LOCK_EX);
+ fwrite($fp, $message);
+ flock($fp, LOCK_UN);
+ fclose($fp);
+
+ if (isset($newfile) && $newfile === TRUE)
+ {
+ @chmod($filepath, FILE_WRITE_MODE);
+ }
+
+ return TRUE;
+ }
+
+}
+
+/* End of file Log.php */
+/* Location: ./system/libraries/Log.php */ \ No newline at end of file
diff --git a/system/core/Model.php b/system/core/Model.php
index 49b8d34e4..28fdfbb69 100755..100644
--- a/system/core/Model.php
+++ b/system/core/Model.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,11 +24,10 @@
* @since Version 1.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
- * CodeIgniter Model Class
+ * Model Class
*
* @package CodeIgniter
* @subpackage Libraries
@@ -38,25 +37,33 @@
*/
class CI_Model {
+ /**
+ * Class constructor
+ *
+ * @return void
+ */
public function __construct()
{
log_message('debug', 'Model Class Initialized');
}
+ // --------------------------------------------------------------------
+
/**
- * __get
+ * __get magic
*
* Allows models to access CI's loaded classes using the same
* syntax as controllers.
*
- * @param string
+ * @param string $key
*/
public function __get($key)
{
$CI =& get_instance();
return $CI->$key;
}
+
}
/* End of file Model.php */
-/* Location: ./system/core/Model.php */
+/* Location: ./system/core/Model.php */ \ No newline at end of file
diff --git a/system/core/Output.php b/system/core/Output.php
index 3cb40626a..98deff55c 100755..100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,11 +24,12 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Output Class
*
- * Responsible for sending final output to browser
+ * Responsible for sending final output to the browser.
*
* @package CodeIgniter
* @subpackage Libraries
@@ -39,70 +40,84 @@
class CI_Output {
/**
- * Current output string
+ * Final output string
*
- * @var string
+ * @var string
*/
public $final_output;
+
/**
* Cache expiration time
*
- * @var int
+ * @var int
*/
- public $cache_expiration = 0;
+ public $cache_expiration = 0;
+
/**
* List of server headers
*
- * @var array
+ * @var array
*/
- public $headers = array();
+ public $headers = array();
+
/**
* List of mime types
*
- * @var array
+ * @var array
*/
- public $mime_types = array();
+ public $mimes = array();
+
/**
- * Determines wether profiler is enabled
+ * Mime-type for the current page
*
- * @var book
+ * @var string
*/
- public $enable_profiler = FALSE;
+ protected $mime_type = 'text/html';
+
/**
- * Determines if output compression is enabled
+ * Enable Profiler flag
*
- * @var bool
+ * @var bool
*/
- protected $_zlib_oc = FALSE;
+ public $enable_profiler = FALSE;
+
+ /**
+ * zLib output compression flag
+ *
+ * @var bool
+ */
+ protected $_zlib_oc = FALSE;
+
/**
* List of profiler sections
*
- * @var array
+ * @var array
*/
- protected $_profiler_sections = array();
+ protected $_profiler_sections = array();
+
/**
- * Whether or not to parse variables like {elapsed_time} and {memory_usage}
+ * Parse markers flag
*
- * @var bool
+ * Whether or not to parse variables like {elapsed_time} and {memory_usage}.
+ *
+ * @var bool
*/
- public $parse_exec_vars = TRUE;
+ public $parse_exec_vars = TRUE;
+ /**
+ * Class constructor
+ *
+ * Determines whether zLib output compression will be used.
+ *
+ * @return void
+ */
public function __construct()
{
- $this->_zlib_oc = @ini_get('zlib.output_compression');
+ $this->_zlib_oc = (bool) @ini_get('zlib.output_compression');
// Get mime types for later
- if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
- {
- include APPPATH.'config/'.ENVIRONMENT.'/mimes.php';
- }
- else
- {
- include APPPATH.'config/mimes.php';
- }
-
+ $this->mimes =& get_mimes();
- $this->mime_types = $mimes;
log_message('debug', 'Output Class Initialized');
}
@@ -111,7 +126,7 @@ class CI_Output {
/**
* Get Output
*
- * Returns the current output string
+ * Returns the current output string.
*
* @return string
*/
@@ -125,10 +140,10 @@ class CI_Output {
/**
* Set Output
*
- * Sets the output string
+ * Sets the output string.
*
- * @param string
- * @return void
+ * @param string $output Output data
+ * @return object $this
*/
public function set_output($output)
{
@@ -141,14 +156,14 @@ class CI_Output {
/**
* Append Output
*
- * Appends data onto the output string
+ * Appends data onto the output string.
*
- * @param string
- * @return void
+ * @param string $output Data to append
+ * @return object $this
*/
public function append_output($output)
{
- if ($this->final_output == '')
+ if (empty($this->final_output))
{
$this->final_output = $output;
}
@@ -165,14 +180,14 @@ class CI_Output {
/**
* Set Header
*
- * Lets you set a server header which will be outputted with the final display.
+ * Lets you set a server header which will be sent with the final output.
*
- * Note: If a file is cached, headers will not be sent. We need to figure out
- * how to permit header data to be saved with the cache data...
+ * Note: If a file is cached, headers will not be sent.
+ * @todo We need to figure out how to permit headers to be cached.
*
- * @param string
- * @param bool
- * @return void
+ * @param string $header Header
+ * @param bool $replace Whether to replace the old header value, if already set
+ * @return object $this
*/
public function set_header($header, $replace = TRUE)
{
@@ -180,9 +195,9 @@ class CI_Output {
// but it will not modify the content-length header to compensate for
// the reduction, causing the browser to hang waiting for more data.
// We'll just skip content-length in those cases.
- if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0)
+ if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)
{
- return;
+ return $this;
}
$this->headers[] = array($header, $replace);
@@ -192,21 +207,22 @@ class CI_Output {
// --------------------------------------------------------------------
/**
- * Set Content Type Header
+ * Set Content-Type Header
*
- * @param string extension of the file we're outputting
- * @return void
+ * @param string $mime_type Extension of the file we're outputting
+ * @param string $charset Character set (default: NULL)
+ * @return object $this
*/
- public function set_content_type($mime_type)
+ public function set_content_type($mime_type, $charset = NULL)
{
if (strpos($mime_type, '/') === FALSE)
{
$extension = ltrim($mime_type, '.');
// Is this extension supported?
- if (isset($this->mime_types[$extension]))
+ if (isset($this->mimes[$extension]))
{
- $mime_type =& $this->mime_types[$extension];
+ $mime_type =& $this->mimes[$extension];
if (is_array($mime_type))
{
@@ -215,7 +231,15 @@ class CI_Output {
}
}
- $header = 'Content-Type: '.$mime_type;
+ $this->mime_type = $mime_type;
+
+ if (empty($charset))
+ {
+ $charset = config_item('charset');
+ }
+
+ $header = 'Content-Type: '.$mime_type
+ .(empty($charset) ? NULL : '; charset='.strtolower($charset));
$this->headers[] = array($header, TRUE);
return $this;
@@ -224,7 +248,7 @@ class CI_Output {
// --------------------------------------------------------------------
/**
- * Get Current Content Type Header
+ * Get Current Content-Type Header
*
* @return string 'text/html', if not already set
*/
@@ -232,9 +256,9 @@ class CI_Output {
{
for ($i = 0, $c = count($this->headers); $i < $c; $i++)
{
- if (preg_match('/^Content-Type:\s(.+)$/', $this->headers[$i][0], $matches))
+ if (sscanf($this->headers[$i][0], 'Content-Type: %[^;]', $content_type) === 1)
{
- return $matches[1];
+ return $content_type;
}
}
@@ -244,12 +268,47 @@ class CI_Output {
// --------------------------------------------------------------------
/**
+ * Get Header
+ *
+ * @param string $header_name
+ * @return string
+ */
+ public function get_header($header)
+ {
+ // Combine headers already sent with our batched headers
+ $headers = array_merge(
+ // We only need [x][0] from our multi-dimensional array
+ array_map('array_shift', $this->headers),
+ headers_list()
+ );
+
+ if (empty($headers) OR empty($header))
+ {
+ return NULL;
+ }
+
+ for ($i = 0, $c = count($headers); $i < $c; $i++)
+ {
+ if (strncasecmp($header, $headers[$i], $l = strlen($header)) === 0)
+ {
+ return trim(substr($headers[$i], $l+1));
+ }
+ }
+
+ return NULL;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
* Set HTTP Status Header
- * moved to Common procedural functions in 1.7.2
*
- * @param int the status code
- * @param string
- * @return void
+ * As of version 1.7.2, this is an alias for common function
+ * set_status_header().
+ *
+ * @param int $code Status code (default: 200)
+ * @param string $text Optional message
+ * @return object $this
*/
public function set_status_header($code = 200, $text = '')
{
@@ -262,8 +321,8 @@ class CI_Output {
/**
* Enable/disable Profiler
*
- * @param bool
- * @return void
+ * @param bool $val TRUE to enable or FALSE to disable
+ * @return object $this
*/
public function enable_profiler($val = TRUE)
{
@@ -276,13 +335,20 @@ class CI_Output {
/**
* Set Profiler Sections
*
- * Allows override of default / config settings for Profiler section display
+ * Allows override of default/config settings for
+ * Profiler section display.
*
- * @param array
- * @return void
+ * @param array $sections Profiler sections
+ * @return object $this
*/
public function set_profiler_sections($sections)
{
+ if (isset($sections['query_toggle_count']))
+ {
+ $this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count'];
+ unset($sections['query_toggle_count']);
+ }
+
foreach ($sections as $section => $enable)
{
$this->_profiler_sections[$section] = ($enable !== FALSE);
@@ -296,8 +362,8 @@ class CI_Output {
/**
* Set Cache
*
- * @param int
- * @return void
+ * @param int $time Cache expiration time in seconds
+ * @return object $this
*/
public function cache($time)
{
@@ -310,16 +376,16 @@ class CI_Output {
/**
* Display Output
*
- * All "view" data is automatically put into this variable by the controller class:
- *
- * $this->final_output
+ * Processes sends the sends finalized output data to the browser along
+ * with any server headers and profile data. It also stops benchmark
+ * timers so the page rendering speed and memory usage can be shown.
*
- * This function sends the finalized output data to the browser along
- * with any server headers and profile data. It also stops the
- * benchmark timer so the page rendering speed and memory usage can be shown.
+ * Note: All "view" data is automatically put into $this->final_output
+ * by controller class.
*
- * @param string
- * @return mixed
+ * @uses CI_Output::$final_output
+ * @param string $output Output data override
+ * @return void
*/
public function _display($output = '')
{
@@ -337,14 +403,22 @@ class CI_Output {
// --------------------------------------------------------------------
// Set the output data
- if ($output == '')
+ if ($output === '')
{
$output =& $this->final_output;
}
// --------------------------------------------------------------------
- // Do we need to write a cache file? Only if the controller does not have its
+ // Is minify requested?
+ if ($CFG->item('minify_output') === TRUE)
+ {
+ $output = $this->minify($output, $this->mime_type);
+ }
+
+ // --------------------------------------------------------------------
+
+ // Do we need to write a cache file? Only if the controller does not have its
// own _output() method and we are not dealing with a cache file, which we
// can determine by the existence of the $CI object above
if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
@@ -361,7 +435,7 @@ class CI_Output {
if ($this->parse_exec_vars === TRUE)
{
- $memory = function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024, 2).'MB' : '0';
+ $memory = round(memory_get_usage() / 1024 / 1024, 2).'MB';
$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
}
@@ -369,7 +443,7 @@ class CI_Output {
// --------------------------------------------------------------------
// Is compression requested?
- if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE
+ if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc === FALSE
&& extension_loaded('zlib')
&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
{
@@ -397,14 +471,14 @@ class CI_Output {
echo $output;
log_message('debug', 'Final output sent to browser');
log_message('debug', 'Total execution time: '.$elapsed);
- return TRUE;
+ return;
}
// --------------------------------------------------------------------
// Do we need to generate profile data?
// If so, load the Profile class and run it.
- if ($this->enable_profiler == TRUE)
+ if ($this->enable_profiler === TRUE)
{
$CI->load->library('profiler');
if ( ! empty($this->_profiler_sections))
@@ -439,16 +513,16 @@ class CI_Output {
// --------------------------------------------------------------------
/**
- * Write a Cache File
+ * Write Cache
*
- * @param string
+ * @param string $output Output data to cache
* @return void
*/
public function _write_cache($output)
{
$CI =& get_instance();
$path = $CI->config->item('cache_path');
- $cache_path = ($path == '') ? APPPATH.'cache/' : $path;
+ $cache_path = ($path === '') ? APPPATH.'cache/' : $path;
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
@@ -484,20 +558,26 @@ class CI_Output {
@chmod($cache_path, FILE_WRITE_MODE);
log_message('debug', 'Cache file written: '.$cache_path);
+
+ // Send HTTP cache-control headers to browser to match file cache settings.
+ $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}
// --------------------------------------------------------------------
/**
- * Update/serve a cached file
+ * Update/serve cached output
*
- * @param object config class
- * @param object uri class
- * @return void
+ * @uses CI_Config
+ * @uses CI_URI
+ *
+ * @param object &$CFG CI_Config class instance
+ * @param object &$URI CI_URI class instance
+ * @return bool TRUE on success or FALSE on failure
*/
public function _display_cache(&$CFG, &$URI)
{
- $cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path');
+ $cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
@@ -516,25 +596,211 @@ class CI_Output {
fclose($fp);
// Strip out the embedded timestamp
- if ( ! preg_match('/(\d+TS--->)/', $cache, $match))
+ if ( ! preg_match('/^(\d+)TS--->/', $cache, $match))
{
return FALSE;
}
- // Has the file expired? If so we'll delete it.
- if (time() >= trim(str_replace('TS--->', '', $match[1])) && is_really_writable($cache_path))
+ $last_modified = filemtime($cache_path);
+ $expire = $match[1];
+
+ // Has the file expired?
+ if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
{
+ // If so we'll delete it.
@unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
return FALSE;
}
+ else
+ {
+ // Or else send the HTTP cache control headers.
+ $this->set_cache_header($last_modified, $expire);
+ }
// Display the cache
- $this->_display(str_replace($match[0], '', $cache));
+ $this->_display(substr($cache, strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Delete cache
+ *
+ * @param string $uri URI string
+ * @return bool
+ */
+ public function delete_cache($uri = '')
+ {
+ $CI =& get_instance();
+ $cache_path = $CI->config->item('cache_path');
+ if ($cache_path === '')
+ {
+ $cache_path = APPPATH.'cache/';
+ }
+
+ if ( ! is_dir($cache_path))
+ {
+ log_message('error', 'Unable to find cache path: '.$cache_path);
+ return FALSE;
+ }
+
+ if (empty($uri))
+ {
+ $uri = $CI->uri->uri_string();
+ }
+
+ $cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').$uri);
+
+ if ( ! @unlink($cache_path))
+ {
+ log_message('error', 'Unable to delete cache file for '.$uri);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Set Cache Header
+ *
+ * Set the HTTP headers to match the server-side file cache settings
+ * in order to reduce bandwidth.
+ *
+ * @param int $last_modified Timestamp of when the page was last modified
+ * @param int $expiration Timestamp of when should the requested page expire from cache
+ * @return void
+ */
+ public function set_cache_header($last_modified, $expiration)
+ {
+ $max_age = $expiration - $_SERVER['REQUEST_TIME'];
+
+ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
+ {
+ $this->set_status_header(304);
+ exit;
+ }
+ else
+ {
+ header('Pragma: public');
+ header('Cache-Control: max-age=' . $max_age . ', public');
+ header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
+ header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Minify
+ *
+ * Reduce excessive size of HTML/CSS/JavaScript content.
+ *
+ * @param string $output Output to minify
+ * @param string $type Output content MIME type
+ * @return string Minified output
+ */
+ public function minify($output, $type = 'text/html')
+ {
+ switch ($type)
+ {
+ case 'text/html':
+
+ $size_before = strlen($output);
+
+ if ($size_before === 0)
+ {
+ return '';
+ }
+
+ // Find all the <pre>,<code>,<textarea>, and <javascript> tags
+ // We'll want to return them to this unprocessed state later.
+ preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean);
+ preg_match_all('{<code.+</code>}msU', $output, $codes_clean);
+ preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean);
+ preg_match_all('{<script.+</script>}msU', $output, $javascript_clean);
+
+ // Minify the CSS in all the <style> tags.
+ preg_match_all('{<style.+</style>}msU', $output, $style_clean);
+ foreach ($style_clean[0] as $s)
+ {
+ $output = str_replace($s, $this->minify($s, 'text/css'), $output);
+ }
+
+ // Minify the javascript in <script> tags.
+ foreach ($javascript_clean[0] as $s)
+ {
+ $javascript_mini[] = $this->minify($s, 'text/javascript');
+ }
+
+ // Replace multiple spaces with a single space.
+ $output = preg_replace('!\s{2,}!', ' ', $output);
+
+ // Remove comments (non-MSIE conditionals)
+ $output = preg_replace('{\s*<!--[^\[].*-->\s*}msU', '', $output);
+
+ // Remove spaces around block-level elements.
+ $output = preg_replace('/\s*(<\/?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br)[^>]*>)\s*/is', '$1', $output);
+
+ // Replace mangled <pre> etc. tags with unprocessed ones.
+
+ if ( ! empty($pres_clean))
+ {
+ preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed);
+ $output = str_replace($pres_messed[0], $pres_clean[0], $output);
+ }
+
+ if ( ! empty($codes_clean))
+ {
+ preg_match_all('{<code.+</code>}msU', $output, $codes_messed);
+ $output = str_replace($codes_messed[0], $codes_clean[0], $output);
+ }
+
+ if ( ! empty($codes_clean))
+ {
+ preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed);
+ $output = str_replace($textareas_messed[0], $textareas_clean[0], $output);
+ }
+
+ if (isset($javascript_mini))
+ {
+ preg_match_all('{<script.+</script>}msU', $output, $javascript_messed);
+ $output = str_replace($javascript_messed[0], $javascript_mini, $output);
+ }
+
+ $size_removed = $size_before - strlen($output);
+ $savings_percent = round(($size_removed / $size_before * 100));
+
+ log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.');
+
+ break;
+
+ case 'text/css':
+
+ //Remove CSS comments
+ $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
+
+ // Remove spaces around curly brackets, colons,
+ // semi-colons, parenthesis, commas
+ $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!', '$1', $output);
+
+ break;
+
+ case 'text/javascript':
+
+ // Currently leaves JavaScript untouched.
+ break;
+
+ default: break;
+ }
+
+ return $output;
+ }
+
}
/* End of file Output.php */
diff --git a/system/core/Router.php b/system/core/Router.php
index 5477fed5d..76772a0fb 100755..100644
--- a/system/core/Router.php
+++ b/system/core/Router.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Router Class
@@ -32,59 +33,60 @@
*
* @package CodeIgniter
* @subpackage Libraries
- * @author EllisLab Dev Team
* @category Libraries
+ * @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/general/routing.html
*/
class CI_Router {
/**
- * Config class
+ * CI_Config class object
*
- * @var object
+ * @var object
*/
public $config;
+
/**
* List of routes
*
- * @var array
+ * @var array
*/
- public $routes = array();
- /**
- * List of error routes
- *
- * @var array
- */
- public $error_routes = array();
+ public $routes = array();
+
/**
* Current class name
*
- * @var string
+ * @var string
*/
- public $class = '';
+ public $class = '';
+
/**
* Current method name
*
- * @var string
+ * @var string
*/
- public $method = 'index';
+ public $method = 'index';
+
/**
* Sub-directory that contains the requested controller class
*
- * @var string
+ * @var string
*/
- public $directory = '';
+ public $directory = '';
+
/**
* Default controller (and method if specific)
*
- * @var string
+ * @var string
*/
public $default_controller;
/**
- * Constructor
+ * Class constructor
*
* Runs the route mapping function.
+ *
+ * @return void
*/
public function __construct()
{
@@ -96,9 +98,9 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Set the route mapping
+ * Set route mapping
*
- * This function determines what should be served based on the URI request,
+ * Determines what should be served based on the URI request,
* as well as any "routes" that have been set in the routing config file.
*
* @return void
@@ -109,21 +111,21 @@ class CI_Router {
// since URI segments are more search-engine friendly, but they can optionally be used.
// If this feature is enabled, we will gather the directory/class/method a little differently
$segments = array();
- if ($this->config->item('enable_query_strings') === TRUE && isset($_GET[$this->config->item('controller_trigger')]))
+ if ($this->config->item('enable_query_strings') === TRUE
+ && ! empty($_GET[$this->config->item('controller_trigger')])
+ && is_string($_GET[$this->config->item('controller_trigger')])
+ )
{
- if (isset($_GET[$this->config->item('directory_trigger')]))
+ if (isset($_GET[$this->config->item('directory_trigger')]) && is_string($_GET[$this->config->item('directory_trigger')]))
{
$this->set_directory(trim($this->uri->_filter_uri($_GET[$this->config->item('directory_trigger')])));
$segments[] = $this->fetch_directory();
}
- if (isset($_GET[$this->config->item('controller_trigger')]))
- {
- $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));
- $segments[] = $this->fetch_class();
- }
+ $this->set_class(trim($this->uri->_filter_uri($_GET[$this->config->item('controller_trigger')])));
+ $segments[] = $this->fetch_class();
- if (isset($_GET[$this->config->item('function_trigger')]))
+ if ( ! empty($_GET[$this->config->item('function_trigger')]) && is_string($_GET[$this->config->item('function_trigger')]))
{
$this->set_method(trim($this->uri->_filter_uri($_GET[$this->config->item('function_trigger')])));
$segments[] = $this->fetch_method();
@@ -140,12 +142,12 @@ class CI_Router {
include(APPPATH.'config/routes.php');
}
- $this->routes = ( ! isset($route) OR ! is_array($route)) ? array() : $route;
+ $this->routes = (empty($route) OR ! is_array($route)) ? array() : $route;
unset($route);
// Set the default controller so we can display it in the event
// the URI doesn't correlated to a valid controller.
- $this->default_controller = empty($this->routes['default_controller']) ? FALSE : strtolower($this->routes['default_controller']);
+ $this->default_controller = empty($this->routes['default_controller']) ? FALSE : $this->routes['default_controller'];
// Were there any query string segments? If so, we'll validate them and bail out since we're done.
if (count($segments) > 0)
@@ -171,31 +173,27 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Set the default controller
+ * Set default controller
*
* @return void
*/
protected function _set_default_controller()
{
- if ($this->default_controller === FALSE)
+ if (empty($this->default_controller))
{
show_error('Unable to determine what should be displayed. A default route has not been specified in the routing file.');
}
+
// Is the method being specified?
- if (strpos($this->default_controller, '/') !== FALSE)
- {
- $x = explode('/', $this->default_controller);
- $this->set_class($x[0]);
- $this->set_method($x[1]);
- $this->_set_request($x);
- }
- else
+ if (sscanf($this->default_controller, '%[^/]/%s', $class, $method) !== 2)
{
- $this->set_class($this->default_controller);
- $this->set_method('index');
- $this->_set_request(array($this->default_controller, 'index'));
+ $method = 'index';
}
+ $this->set_class($class);
+ $this->set_method($method);
+ $this->_set_request(array($class, $method));
+
// re-index the routed segments array so it starts with 1 rather than 0
$this->uri->_reindex_segments();
@@ -205,13 +203,12 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Set the Route
+ * Set request route
*
- * This function takes an array of URI segments as
- * input, and sets the current class/method
+ * Takes an array of URI segments as input and sets the class/method
+ * to be called.
*
- * @param array
- * @param bool
+ * @param array $segments URI segments
* @return void
*/
protected function _set_request($segments = array())
@@ -225,17 +222,8 @@ class CI_Router {
$this->set_class($segments[0]);
- if (isset($segments[1]))
- {
- // A standard method request
- $this->set_method($segments[1]);
- }
- else
- {
- // This lets the "routed" segment array identify that the default
- // index method is being used.
- $segments[1] = 'index';
- }
+ isset($segments[1]) OR $segments[1] = 'index';
+ $this->set_method($segments[1]);
// Update our "routed" segment array to contain the segments.
// Note: If there is no custom routing, this array will be
@@ -246,11 +234,12 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Validates the supplied segments.
- * Attempts to determine the path to the controller.
+ * Validate request
+ *
+ * Attempts validate the URI request and determine the controller path.
*
- * @param array
- * @return array
+ * @param array $segments URI segments
+ * @return array URI segments
*/
protected function _validate_request($segments)
{
@@ -259,9 +248,13 @@ class CI_Router {
return $segments;
}
+ $temp = str_replace('-', '_', $segments[0]);
+
// Does the requested controller exist in the root folder?
- if (file_exists(APPPATH.'controllers/'.$segments[0].'.php'))
+ if (file_exists(APPPATH.'controllers/'.$temp.'.php'))
{
+ $segments[0] = $temp;
+ empty($segments[1]) OR $segments[1] = str_replace('-', '_', $segments[1]);
return $segments;
}
@@ -269,22 +262,19 @@ class CI_Router {
if (is_dir(APPPATH.'controllers/'.$segments[0]))
{
// Set the directory and remove it from the segment array
- $this->set_directory($segments[0]);
- $segments = array_slice($segments, 1);
-
+ $this->set_directory(array_shift($segments));
if (count($segments) > 0)
{
+ $segments[0] = str_replace('-', '_', $segments[0]);
+ empty($segments[1]) OR $segments[1] = str_replace('-', '_', $segments[1]);
+
// Does the requested controller exist in the sub-folder?
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php'))
{
if ( ! empty($this->routes['404_override']))
{
- $x = explode('/', $this->routes['404_override']);
- $this->set_directory('');
- $this->set_class($x[0]);
- $this->set_method(isset($x[1]) ? $x[1] : 'index');
-
- return $x;
+ $this->directory = '';
+ return explode('/', $this->routes['404_override'], 2);
}
else
{
@@ -295,40 +285,26 @@ class CI_Router {
else
{
// Is the method being specified in the route?
- if (strpos($this->default_controller, '/') !== FALSE)
- {
- $x = explode('/', $this->default_controller);
- $this->set_class($x[0]);
- $this->set_method($x[1]);
- }
- else
- {
- $this->set_class($this->default_controller);
- $this->set_method('index');
- }
-
- // Does the default controller exist in the sub-folder?
- if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
+ $segments = explode('/', $this->default_controller);
+ if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php'))
{
$this->directory = '';
- return array();
}
-
}
return $segments;
}
-
// If we've gotten this far it means that the URI does not correlate to a valid
// controller class. We will now see if there is an override
if ( ! empty($this->routes['404_override']))
{
- $x = explode('/', $this->routes['404_override']);
- $this->set_class($x[0]);
- $this->set_method(isset($x[1]) ? $x[1] : 'index');
+ if (sscanf($this->routes['404_override'], '%[^/]/%s', $class, $method) !== 2)
+ {
+ $method = 'index';
+ }
- return $x;
+ return array($class, $method);
}
// Nothing else to do at this point but show a 404
@@ -340,9 +316,8 @@ class CI_Router {
/**
* Parse Routes
*
- * This function matches any routes that may exist in
- * the config/routes.php file against the URI to
- * determine if the class/method need to be remapped.
+ * Matches any routes that may exist in the config/routes.php file
+ * against the URI to determine if the class/method need to be remapped.
*
* @return void
*/
@@ -352,7 +327,7 @@ class CI_Router {
$uri = implode('/', $this->uri->segments);
// Is there a literal match? If so we're done
- if (isset($this->routes[$uri]))
+ if (isset($this->routes[$uri]) && is_string($this->routes[$uri]))
{
return $this->_set_request(explode('/', $this->routes[$uri]));
}
@@ -361,13 +336,51 @@ class CI_Router {
foreach ($this->routes as $key => $val)
{
// Convert wild-cards to RegEx
- $key = str_replace(array(':any', ':num'), array('.+', '[0-9]+'), $key);
+ $key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);
// Does the RegEx match?
- if (preg_match('#^'.$key.'$#', $uri))
+ if (preg_match('#^'.$key.'$#', $uri, $matches))
{
- // Do we have a back-reference?
- if (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE)
+ // Are we using callbacks to process back-references?
+ if ( ! is_string($val) && is_callable($val))
+ {
+ // Remove the original string from the matches array.
+ array_shift($matches);
+
+ // Get the match count.
+ $match_count = count($matches);
+
+ // Determine how many parameters the callback has.
+ $reflection = new ReflectionFunction($val);
+ $param_count = $reflection->getNumberOfParameters();
+
+ // Are there more parameters than matches?
+ if ($param_count > $match_count)
+ {
+ // Any params without matches will be set to an empty string.
+ $matches = array_merge($matches, array_fill($match_count, $param_count - $match_count, ''));
+
+ $match_count = $param_count;
+ }
+
+ // Get the parameters so we can use their default values.
+ $params = $reflection->getParameters();
+
+ for ($m = 0; $m < $match_count; $m++)
+ {
+ // Is the match empty and does a default value exist?
+ if (empty($matches[$m]) && $params[$m]->isDefaultValueAvailable())
+ {
+ // Substitute the empty match for the default value.
+ $matches[$m] = $params[$m]->getDefaultValue();
+ }
+ }
+
+ // Execute the callback using the values in matches as its parameters.
+ $val = call_user_func_array($val, $matches);
+ }
+ // Are we using the default routing method for back-references?
+ elseif (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE)
{
$val = preg_replace('#^'.$key.'$#', $val, $uri);
}
@@ -384,9 +397,9 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Set the class name
+ * Set class name
*
- * @param string
+ * @param string $class Class name
* @return void
*/
public function set_class($class)
@@ -409,9 +422,9 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Set the method name
+ * Set method name
*
- * @param string
+ * @param string $method Method name
* @return void
*/
public function set_method($method)
@@ -428,20 +441,15 @@ class CI_Router {
*/
public function fetch_method()
{
- if ($this->method == $this->fetch_class())
- {
- return 'index';
- }
-
- return $this->method;
+ return ($this->method === $this->fetch_class()) ? 'index' : $this->method;
}
// --------------------------------------------------------------------
/**
- * Set the directory name
+ * Set directory name
*
- * @param string
+ * @param string $dir Directory name
* @return void
*/
public function set_directory($dir)
@@ -452,7 +460,10 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Fetch the sub-directory (if any) that contains the requested controller class
+ * Fetch directory
+ *
+ * Feches the sub-directory (if any) that contains the requested
+ * controller class.
*
* @return string
*/
@@ -464,9 +475,9 @@ class CI_Router {
// --------------------------------------------------------------------
/**
- * Set the controller overrides
+ * Set controller overrides
*
- * @param array
+ * @param array $routing Route overrides
* @return void
*/
public function _set_overrides($routing)
@@ -481,14 +492,14 @@ class CI_Router {
$this->set_directory($routing['directory']);
}
- if (isset($routing['controller']) && $routing['controller'] != '')
+ if ( ! empty($routing['controller']))
{
$this->set_class($routing['controller']);
}
if (isset($routing['function']))
{
- $routing['function'] = ($routing['function'] == '') ? 'index' : $routing['function'];
+ $routing['function'] = empty($routing['function']) ? 'index' : $routing['function'];
$this->set_method($routing['function']);
}
}
diff --git a/system/core/Security.php b/system/core/Security.php
index ac39ce97b..c415544b6 100755..100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,6 +24,7 @@
* @since Version 1.0
* @filesource
*/
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Security Class
@@ -37,71 +38,87 @@
class CI_Security {
/**
- * Random Hash for protecting URLs
+ * XSS Hash
*
- * @var string
+ * Random Hash for protecting URLs.
+ *
+ * @var string
*/
- protected $_xss_hash = '';
+ protected $_xss_hash = '';
/**
- * Random Hash for Cross Site Request Forgery Protection Cookie
+ * CSRF Hash
+ *
+ * Random hash for Cross Site Request Forgery protection cookie
*
- * @var string
+ * @var string
*/
- protected $_csrf_hash = '';
+ protected $_csrf_hash = '';
/**
- * Expiration time for Cross Site Request Forgery Protection Cookie
- * Defaults to two hours (in seconds)
+ * CSRF Expire time
+ *
+ * Expiration time for Cross Site Request Forgery protection cookie.
+ * Defaults to two hours (in seconds).
*
- * @var int
+ * @var int
*/
- protected $_csrf_expire = 7200;
+ protected $_csrf_expire = 7200;
/**
- * Token name for Cross Site Request Forgery Protection Cookie
+ * CSRF Token name
*
- * @var string
+ * Token name for Cross Site Request Forgery protection cookie.
+ *
+ * @var string
*/
- protected $_csrf_token_name = 'ci_csrf_token';
+ protected $_csrf_token_name = 'ci_csrf_token';
/**
- * Cookie name for Cross Site Request Forgery Protection Cookie
+ * CSRF Cookie name
+ *
+ * Cookie name for Cross Site Request Forgery protection cookie.
*
- * @var string
+ * @var string
*/
- protected $_csrf_cookie_name = 'ci_csrf_token';
+ protected $_csrf_cookie_name = 'ci_csrf_token';
/**
* List of never allowed strings
*
- * @var array
+ * @var array
*/
- protected $_never_allowed_str = array(
- 'document.cookie' => '[removed]',
- 'document.write' => '[removed]',
- '.parentNode' => '[removed]',
- '.innerHTML' => '[removed]',
- 'window.location' => '[removed]',
- '-moz-binding' => '[removed]',
- '<!--' => '&lt;!--',
- '-->' => '--&gt;',
- '<![CDATA[' => '&lt;![CDATA[',
- '<comment>' => '&lt;comment&gt;'
- );
+ protected $_never_allowed_str = array(
+ 'document.cookie' => '[removed]',
+ 'document.write' => '[removed]',
+ '.parentNode' => '[removed]',
+ '.innerHTML' => '[removed]',
+ 'window.location' => '[removed]',
+ '-moz-binding' => '[removed]',
+ '<!--' => '&lt;!--',
+ '-->' => '--&gt;',
+ '<![CDATA[' => '&lt;![CDATA[',
+ '<comment>' => '&lt;comment&gt;'
+ );
/**
- * List of never allowed regex replacement
+ * List of never allowed regex replacements
*
- * @var array
+ * @var array
*/
protected $_never_allowed_regex = array(
- 'javascript\s*:',
- 'expression\s*(\(|&\#40;)', // CSS and IE
- 'vbscript\s*:', // IE, surprise!
- 'Redirect\s+302'
- );
+ 'javascript\s*:',
+ 'expression\s*(\(|&\#40;)', // CSS and IE
+ 'vbscript\s*:', // IE, surprise!
+ 'Redirect\s+302',
+ "([\"'])?data\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?"
+ );
+ /**
+ * Class constructor
+ *
+ * @return void
+ */
public function __construct()
{
// Is CSRF protection enabled?
@@ -132,7 +149,7 @@ class CI_Security {
// --------------------------------------------------------------------
/**
- * Verify Cross Site Request Forgery Protection
+ * CSRF Verify
*
* @return object
*/
@@ -155,8 +172,8 @@ class CI_Security {
}
// Do the tokens exist in both the _POST and _COOKIE arrays?
- if ( ! isset($_POST[$this->_csrf_token_name]) OR ! isset($_COOKIE[$this->_csrf_cookie_name])
- OR $_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
+ if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
+ OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
{
$this->csrf_show_error();
}
@@ -182,8 +199,9 @@ class CI_Security {
// --------------------------------------------------------------------
/**
- * Set Cross Site Request Forgery Protection Cookie
+ * CSRF Set Cookie
*
+ * @codeCoverageIgnore
* @return object
*/
public function csrf_set_cookie()
@@ -191,17 +209,17 @@ class CI_Security {
$expire = time() + $this->_csrf_expire;
$secure_cookie = (bool) config_item('cookie_secure');
- if ($secure_cookie && (empty($_SERVER['HTTPS']) OR strtolower($_SERVER['HTTPS']) === 'off'))
+ if ($secure_cookie && ! is_https())
{
return FALSE;
}
setcookie(
- $this->_csrf_cookie_name,
- $this->_csrf_hash,
- $expire,
- config_item('cookie_path'),
- config_item('cookie_domain'),
+ $this->_csrf_cookie_name,
+ $this->_csrf_hash,
+ $expire,
+ config_item('cookie_path'),
+ config_item('cookie_domain'),
$secure_cookie,
config_item('cookie_httponly')
);
@@ -227,9 +245,8 @@ class CI_Security {
/**
* Get CSRF Hash
*
- * Getter Method
- *
- * @return string self::_csrf_hash
+ * @see CI_Security::$_csrf_hash
+ * @return string CSRF hash
*/
public function get_csrf_hash()
{
@@ -241,9 +258,8 @@ class CI_Security {
/**
* Get CSRF Token Name
*
- * Getter Method
- *
- * @return string self::_csrf_token_name
+ * @see CI_Security::$_csrf_token_name
+ * @return string CSRF token name
*/
public function get_csrf_token_name()
{
@@ -256,26 +272,26 @@ class CI_Security {
* XSS Clean
*
* Sanitizes data so that Cross Site Scripting Hacks can be
- * prevented. This function does a fair amount of work but
+ * prevented. This method does a fair amount of work but
* it is extremely thorough, designed to prevent even the
* most obscure XSS attempts. Nothing is ever 100% foolproof,
* of course, but I haven't been able to get anything passed
* the filter.
*
- * Note: This function should only be used to deal with data
- * upon submission. It's not something that should
- * be used for general runtime processing.
+ * Note: Should only be used to deal with data upon submission.
+ * It's not something that should be used for general
+ * runtime processing.
*
- * This function was based in part on some code and ideas I
- * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention
+ * @link http://channel.bitflux.ch/wiki/XSS_Prevention
+ * Based in part on some code and ideas from Bitflux.
*
- * To help develop this script I used this great list of
- * vulnerabilities along with a few other hacks I've
- * harvested from examining vulnerabilities in other programs:
- * http://ha.ckers.org/xss.html
+ * @link http://ha.ckers.org/xss.html
+ * To help develop this script I used this great list of
+ * vulnerabilities along with a few other hacks I've
+ * harvested from examining vulnerabilities in other programs.
*
- * @param mixed string or array
- * @param bool
+ * @param string|string[] $str Input data
+ * @param bool $is_image Whether the input is an image
* @return string
*/
public function xss_clean($str, $is_image = FALSE)
@@ -352,7 +368,7 @@ class CI_Security {
}
else
{
- $str = str_replace(array('<?', '?'.'>'), array('&lt;?', '?&gt;'), $str);
+ $str = str_replace(array('<?', '?'.'>'), array('&lt;?', '?&gt;'), $str);
}
/*
@@ -362,9 +378,9 @@ class CI_Security {
* These words are compacted back to their correct state.
*/
$words = array(
- 'javascript', 'expression', 'vbscript', 'script',
- 'applet', 'alert', 'document', 'write', 'cookie', 'window'
- );
+ 'javascript', 'expression', 'vbscript', 'script', 'base64',
+ 'applet', 'alert', 'document', 'write', 'cookie', 'window'
+ );
foreach ($words as $word)
{
@@ -387,20 +403,20 @@ class CI_Security {
if (preg_match('/<a/i', $str))
{
- $str = preg_replace_callback('#<a\s+([^>]*?)(>|$)#si', array($this, '_js_link_removal'), $str);
+ $str = preg_replace_callback('#<a\s+([^>]*?)(?:>|$)#si', array($this, '_js_link_removal'), $str);
}
if (preg_match('/<img/i', $str))
{
- $str = preg_replace_callback('#<img\s+([^>]*?)(\s?/?>|$)#si', array($this, '_js_img_removal'), $str);
+ $str = preg_replace_callback('#<img\s+([^>]*?)(?:\s?/?>|$)#si', array($this, '_js_img_removal'), $str);
}
- if (preg_match('/(script|xss)/i', $str))
+ if (preg_match('/script|xss/i', $str))
{
- $str = preg_replace('#<(/*)(script|xss)(.*?)\>#si', '[removed]', $str);
+ $str = preg_replace('#</*(?:script|xss).*?>#si', '[removed]', $str);
}
}
- while($original != $str);
+ while ($original !== $str);
unset($original);
@@ -461,13 +477,16 @@ class CI_Security {
// --------------------------------------------------------------------
/**
- * Random Hash for protecting URLs
+ * XSS Hash
*
- * @return string
+ * Generates the XSS hash if needed and returns it.
+ *
+ * @see CI_Security::$_xss_hash
+ * @return string XSS hash
*/
public function xss_hash()
{
- if ($this->_xss_hash == '')
+ if ($this->_xss_hash === '')
{
mt_srand();
$this->_xss_hash = md5(time() + mt_rand(0, 1999999999));
@@ -481,7 +500,7 @@ class CI_Security {
/**
* HTML Entities Decode
*
- * This function is a replacement for html_entity_decode()
+ * A replacement for html_entity_decode()
*
* The reason we are not using html_entity_decode() by itself is because
* while it is not technically correct to leave out the semicolon
@@ -489,8 +508,10 @@ class CI_Security {
* correctly. html_entity_decode() does not convert entities without
* semicolons, so we are left with our own little solution here. Bummer.
*
- * @param string
- * @param string
+ * @link http://php.net/html-entity-decode
+ *
+ * @param string $str Input
+ * @param string $charset Character set
* @return string
*/
public function entity_decode($str, $charset = NULL)
@@ -513,32 +534,32 @@ class CI_Security {
// --------------------------------------------------------------------
/**
- * Filename Security
+ * Sanitize Filename
*
- * @param string
- * @param bool
+ * @param string $str Input file name
+ * @param bool $relative_path Whether to preserve paths
* @return string
*/
public function sanitize_filename($str, $relative_path = FALSE)
{
$bad = array(
- '../', '<!--', '-->', '<', '>',
- "'", '"', '&', '$', '#',
- '{', '}', '[', ']', '=',
- ';', '?', '%20', '%22',
- '%3c', // <
- '%253c', // <
- '%3e', // >
- '%0e', // >
- '%28', // (
- '%29', // )
- '%2528', // (
- '%26', // &
- '%24', // $
- '%3f', // ?
- '%3b', // ;
- '%3d' // =
- );
+ '../', '<!--', '-->', '<', '>',
+ "'", '"', '&', '$', '#',
+ '{', '}', '[', ']', '=',
+ ';', '?', '%20', '%22',
+ '%3c', // <
+ '%253c', // <
+ '%3e', // >
+ '%0e', // >
+ '%28', // (
+ '%29', // )
+ '%2528', // (
+ '%26', // &
+ '%24', // $
+ '%3f', // ?
+ '%3b', // ;
+ '%3d' // =
+ );
if ( ! $relative_path)
{
@@ -553,13 +574,27 @@ class CI_Security {
// ----------------------------------------------------------------
/**
+ * Strip Image Tags
+ *
+ * @param string $str
+ * @return string
+ */
+ public function strip_image_tags($str)
+ {
+ return preg_replace(array('#<img\s+.*?src\s*=\s*["\'](.+?)["\'].*?\>#', '#<img\s+.*?src\s*=\s*(.+?).*?\>#'), '\\1', $str);
+ }
+
+ // ----------------------------------------------------------------
+
+ /**
* Compact Exploded Words
*
- * Callback function for xss_clean() to remove whitespace from
- * things like j a v a s c r i p t
+ * Callback method for xss_clean() to remove whitespace from
+ * things like 'j a v a s c r i p t'.
*
- * @param type
- * @return type
+ * @used-by CI_Security::xss_clean()
+ * @param array $matches
+ * @return string
*/
protected function _compact_exploded_words($matches)
{
@@ -568,20 +603,26 @@ class CI_Security {
// --------------------------------------------------------------------
- /*
- * Remove Evil HTML Attributes (like evenhandlers and style)
+ /**
+ * Remove Evil HTML Attributes (like event handlers and style)
*
* It removes the evil attribute and either:
- * - Everything up until a space
- * For example, everything between the pipes:
+ *
+ * - Everything up until a space. For example, everything between the pipes:
+ *
+ * <code>
* <a |style=document.write('hello');alert('world');| class=link>
- * - Everything inside the quotes
- * For example, everything between the pipes:
+ * </code>
+ *
+ * - Everything inside the quotes. For example, everything between the pipes:
+ *
+ * <code>
* <a |style="document.write('hello'); alert('world');"| class="link">
+ * </code>
*
- * @param string $str The string to check
- * @param boolean $is_image TRUE if this is an image
- * @return string The string with the evil attributes removed
+ * @param string $str The string to check
+ * @param bool $is_image Whether the input is an image
+ * @return string The string with the evil attributes removed
*/
protected function _remove_evil_attributes($str, $is_image)
{
@@ -602,10 +643,11 @@ class CI_Security {
$attribs = array();
// find occurrences of illegal attribute strings without quotes
- preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s]*)/is', $str, $matches, PREG_SET_ORDER);
+ preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER);
foreach ($matches as $attr)
{
+
$attribs[] = preg_quote($attr[0], '/');
}
@@ -620,7 +662,7 @@ class CI_Security {
// replace illegal attribute strings that are inside an html tag
if (count($attribs) > 0)
{
- $str = preg_replace('/<(\/?[^><]+?)([^A-Za-z\-])('.implode('|', $attribs).')([\s><])([><]*)/i', '<$1$2$4$5', $str, -1, $count);
+ $str = preg_replace('/<(\/?[^><]+?)([^A-Za-z<>\-])(.*?)('.implode('|', $attribs).')(.*?)([\s><])([><]*)/i', '<$1 $3$5$6$7', $str, -1, $count);
}
} while ($count);
@@ -633,9 +675,10 @@ class CI_Security {
/**
* Sanitize Naughty HTML
*
- * Callback function for xss_clean() to remove naughty HTML elements
+ * Callback method for xss_clean() to remove naughty HTML elements.
*
- * @param array
+ * @used-by CI_Security::xss_clean()
+ * @param array $matches
* @return string
*/
protected function _sanitize_naughty_html($matches)
@@ -650,18 +693,20 @@ class CI_Security {
/**
* JS Link Removal
*
- * Callback function for xss_clean() to sanitize links
+ * Callback method for xss_clean() to sanitize links.
+ *
* This limits the PCRE backtracks, making it more performance friendly
* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
- * PHP 5.2+ on link-heavy strings
+ * PHP 5.2+ on link-heavy strings.
*
- * @param array
+ * @used-by CI_Security::xss_clean()
+ * @param array $match
* @return string
*/
protected function _js_link_removal($match)
{
return str_replace($match[1],
- preg_replace('#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
+ preg_replace('#href=.*?(?:alert\(|alert&\#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|data\s*:)#si',
'',
$this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]))
),
@@ -673,18 +718,20 @@ class CI_Security {
/**
* JS Image Removal
*
- * Callback function for xss_clean() to sanitize image tags
+ * Callback method for xss_clean() to sanitize image tags.
+ *
* This limits the PCRE backtracks, making it more performance friendly
* and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in
- * PHP 5.2+ on image tag heavy strings
+ * PHP 5.2+ on image tag heavy strings.
*
- * @param array
+ * @used-by CI_Security::xss_clean()
+ * @param array $match
* @return string
*/
protected function _js_img_removal($match)
{
return str_replace($match[1],
- preg_replace('#src=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
+ preg_replace('#src=.*?(?:alert\(|alert&\#40;|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si',
'',
$this->_filter_attributes(str_replace(array('<', '>'), '', $match[1]))
),
@@ -696,9 +743,8 @@ class CI_Security {
/**
* Attribute Conversion
*
- * Used as a callback for XSS Clean
- *
- * @param array
+ * @used-by CI_Security::xss_clean()
+ * @param array $match
* @return string
*/
protected function _convert_attribute($match)
@@ -711,9 +757,11 @@ class CI_Security {
/**
* Filter Attributes
*
- * Filters tag attributes for consistency and safety
+ * Filters tag attributes for consistency and safety.
*
- * @param string
+ * @used-by CI_Security::_js_img_removal()
+ * @used-by CI_Security::_js_link_removal()
+ * @param string $str
* @return string
*/
protected function _filter_attributes($str)
@@ -735,9 +783,8 @@ class CI_Security {
/**
* HTML Entity Decode Callback
*
- * Used as a callback for XSS Clean
- *
- * @param array
+ * @used-by CI_Security::xss_clean()
+ * @param array $match
* @return string
*/
protected function _decode_entity($match)
@@ -750,9 +797,8 @@ class CI_Security {
/**
* Validate URL entities
*
- * Called by xss_clean()
- *
- * @param string
+ * @used-by CI_Security::xss_clean()
+ * @param string $str
* @return string
*/
protected function _validate_entities($str)
@@ -790,8 +836,7 @@ class CI_Security {
/**
* Do Never Allowed
*
- * A utility function for xss_clean()
- *
+ * @used-by CI_Security::xss_clean()
* @param string
* @return string
*/
@@ -801,7 +846,7 @@ class CI_Security {
foreach ($this->_never_allowed_regex as $regex)
{
- $str = preg_replace('#'.$regex.'#i', '[removed]', $str);
+ $str = preg_replace('#'.$regex.'#is', '[removed]', $str);
}
return $str;
@@ -810,20 +855,20 @@ class CI_Security {
// --------------------------------------------------------------------
/**
- * Set Cross Site Request Forgery Protection Cookie
+ * Set CSRF Hash and Cookie
*
* @return string
*/
protected function _csrf_set_hash()
{
- if ($this->_csrf_hash == '')
+ if ($this->_csrf_hash === '')
{
// If the cookie exists we will use it's value.
// We don't necessarily want to regenerate it with
// each page load since a page could contain embedded
// sub-pages causing this feature to fail
if (isset($_COOKIE[$this->_csrf_cookie_name]) &&
- $_COOKIE[$this->_csrf_cookie_name] != '')
+ preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_csrf_cookie_name]) === 1)
{
return $this->_csrf_hash = $_COOKIE[$this->_csrf_cookie_name];
}
@@ -838,4 +883,4 @@ class CI_Security {
}
/* End of file Security.php */
-/* Location: ./system/core/Security.php */
+/* Location: ./system/core/Security.php */ \ No newline at end of file
diff --git a/system/core/URI.php b/system/core/URI.php
index 48bb7ae3c..900472b61 100755..100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -22,9 +22,9 @@
* @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* @link http://codeigniter.com
* @since Version 1.0
+ * @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* URI Class
@@ -40,37 +40,43 @@
class CI_URI {
/**
- * List of cached uri segments
+ * List of cached URI segments
*
- * @var array
+ * @var array
*/
- public $keyval = array();
+ public $keyval = array();
+
/**
- * Current uri string
+ * Current URI string
*
- * @var string
+ * @var string
*/
public $uri_string;
+
/**
- * List of uri segments
+ * List of URI segments
*
- * @var array
+ * @var array
*/
- public $segments = array();
+ public $segments = array();
+
/**
- * Re-indexed list of uri segments
- * Starts at 1 instead of 0
+ * Re-indexed list of URI segments
+ *
+ * Starts at 1 instead of 0.
*
- * @var array
+ * @var array
*/
- public $rsegments = array();
+ public $rsegments = array();
/**
- * Constructor
+ * Class constructor
*
* Simply globalizes the $RTR object. The front
* loads the Router class early on so it's not available
* normally as other classes are.
+ *
+ * @return void
*/
public function __construct()
{
@@ -81,10 +87,9 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Get the URI String
- *
- * Called by CI_Router
+ * Fetch URI String
*
+ * @used-by CI_Router
* @return void
*/
public function _fetch_uri_string()
@@ -94,36 +99,33 @@ class CI_URI {
// Is the request coming from the command line?
if ($this->_is_cli_request())
{
- $this->_set_uri_string($this->_parse_cli_args());
+ $this->_set_uri_string($this->_parse_argv());
return;
}
- // Let's try the REQUEST_URI first, this will work in most situations
- if ($uri = $this->_detect_uri())
+ // Is there a PATH_INFO variable? This should be the easiest solution.
+ if (isset($_SERVER['PATH_INFO']))
{
- $this->_set_uri_string($uri);
+ $this->_set_uri_string($_SERVER['PATH_INFO']);
return;
}
- // Is there a PATH_INFO variable?
- // Note: some servers seem to have trouble with getenv() so we'll test it two ways
- $path = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : @getenv('PATH_INFO');
- if (trim($path, '/') != '' && $path !== '/'.SELF)
+ // Let's try REQUEST_URI then, this will work in most situations
+ if (($uri = $this->_parse_request_uri()) !== '')
{
- $this->_set_uri_string($path);
+ $this->_set_uri_string($uri);
return;
}
- // No PATH_INFO?... What about QUERY_STRING?
- $path = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
- if (trim($path, '/') != '')
+ // No REQUEST_URI either?... What about QUERY_STRING?
+ if (($uri = $this->_parse_query_string()) !== '')
{
- $this->_set_uri_string($path);
+ $this->_set_uri_string($uri);
return;
}
// As a last ditch effort lets try using the $_GET array
- if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') != '')
+ if (is_array($_GET) && count($_GET) === 1 && trim(key($_GET), '/') !== '')
{
$this->_set_uri_string(key($_GET));
return;
@@ -136,138 +138,191 @@ class CI_URI {
$uri = strtoupper($this->config->item('uri_protocol'));
- if ($uri === 'REQUEST_URI')
+ if ($uri === 'CLI')
{
- $this->_set_uri_string($this->_detect_uri());
+ $this->_set_uri_string($this->_parse_argv());
return;
}
- elseif ($uri === 'CLI')
+ elseif (method_exists($this, ($method = '_parse_'.strtolower($uri))))
{
- $this->_set_uri_string($this->_parse_cli_args());
+ $this->_set_uri_string($this->$method());
return;
}
- $path = (isset($_SERVER[$uri])) ? $_SERVER[$uri] : @getenv($uri);
- $this->_set_uri_string($path);
+ $uri = isset($_SERVER[$uri]) ? $_SERVER[$uri] : @getenv($uri);
+ $this->_set_uri_string($uri);
}
// --------------------------------------------------------------------
/**
- * Set the URI String
+ * Set URI String
*
- * @param string
+ * @param string $str
* @return void
*/
- public function _set_uri_string($str)
+ protected function _set_uri_string($str)
{
- // Filter out control characters
- $str = remove_invisible_characters($str, FALSE);
-
- // If the URI contains only a slash we'll kill it
- $this->uri_string = ($str === '/') ? '' : $str;
+ // Filter out control characters and trim slashes
+ $this->uri_string = trim(remove_invisible_characters($str, FALSE), '/');
}
// --------------------------------------------------------------------
/**
- * Detects the URI
+ * Parse REQUEST_URI
*
- * This function will detect the URI automatically and fix the query string
- * if necessary.
+ * Will parse REQUEST_URI and automatically detect the URI from it,
+ * while fixing the query string if necessary.
*
+ * @used-by CI_URI::_fetch_uri_string()
* @return string
*/
- protected function _detect_uri()
+ protected function _parse_request_uri()
{
- if ( ! isset($_SERVER['REQUEST_URI']) OR ! isset($_SERVER['SCRIPT_NAME']))
+ if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
return '';
}
- $uri = $_SERVER['REQUEST_URI'];
+ $uri = parse_url($_SERVER['REQUEST_URI']);
+ $query = isset($uri['query']) ? $uri['query'] : '';
+ $uri = isset($uri['path']) ? rawurldecode($uri['path']) : '';
+
if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0)
{
- $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
+ $uri = (string) substr($uri, strlen($_SERVER['SCRIPT_NAME']));
}
elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0)
{
- $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
+ $uri = (string) substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
}
// This section ensures that even on servers that require the URI to be in the query string (Nginx) a correct
// URI is found, and also fixes the QUERY_STRING server var and $_GET array.
- if (strncmp($uri, '?/', 2) === 0)
- {
- $uri = substr($uri, 2);
- }
- $parts = preg_split('#\?#i', $uri, 2);
- $uri = $parts[0];
- if (isset($parts[1]))
+ if (trim($uri, '/') === '' && strncmp($query, '/', 1) === 0)
{
- $_SERVER['QUERY_STRING'] = $parts[1];
- parse_str($_SERVER['QUERY_STRING'], $_GET);
+ $query = explode('?', $query, 2);
+ $uri = rawurldecode($query[0]);
+ $_SERVER['QUERY_STRING'] = isset($query[1]) ? $query[1] : '';
}
else
{
- $_SERVER['QUERY_STRING'] = '';
- $_GET = array();
+ $_SERVER['QUERY_STRING'] = $query;
}
- if ($uri == '/' OR empty($uri))
+ parse_str($_SERVER['QUERY_STRING'], $_GET);
+
+ if ($uri === '/' OR $uri === '')
{
return '/';
}
- $uri = parse_url($uri, PHP_URL_PATH);
-
// Do some final cleaning of the URI and return it
- return str_replace(array('//', '../'), '/', trim($uri, '/'));
+ return $this->_remove_relative_directory($uri);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Remove relative directory (../) and multi slashes (///)
+ *
+ * Do some final cleaning of the URI and return it, currently only used in self::_parse_request_uri()
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function _remove_relative_directory($uri)
+ {
+ $uris = array();
+ $tok = strtok($uri, '/');
+ while ($tok !== FALSE)
+ {
+ if (( ! empty($tok) OR $tok === '0') && $tok !== '..')
+ {
+ $uris[] = $tok;
+ }
+ $tok = strtok('/');
+ }
+ return implode('/', $uris);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Parse QUERY_STRING
+ *
+ * Will parse QUERY_STRING and automatically detect the URI from it.
+ *
+ * @used-by CI_URI::_fetch_uri_string()
+ * @return string
+ */
+ protected function _parse_query_string()
+ {
+ $uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
+
+ if (trim($uri, '/') === '')
+ {
+ return '';
+ }
+ elseif (strncmp($uri, '/', 1) === 0)
+ {
+ $uri = explode('?', $uri, 2);
+ $_SERVER['QUERY_STRING'] = isset($uri[1]) ? $uri[1] : '';
+ $uri = rawurldecode($uri[0]);
+ }
+
+ parse_str($_SERVER['QUERY_STRING'], $_GET);
+
+ return $this->_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
-
+
/**
- * Is cli Request?
+ * Is CLI Request?
*
- * Duplicate of function from the Input class to test to see if a request was made from the command line
+ * Duplicate of method from the Input class to test to see if
+ * a request was made from the command line.
*
- * @return boolean
+ * @see CI_Input::is_cli_request()
+ * @used-by CI_URI::_fetch_uri_string()
+ * @return bool
*/
protected function _is_cli_request()
{
- return (php_sapi_name() == 'cli') OR defined('STDIN');
+ return (php_sapi_name() === 'cli') OR defined('STDIN');
}
-
// --------------------------------------------------------------------
/**
- * Parse cli arguments
+ * Parse CLI arguments
*
* Take each command line argument and assume it is a URI segment.
*
* @return string
*/
- protected function _parse_cli_args()
+ protected function _parse_argv()
{
$args = array_slice($_SERVER['argv'], 1);
- return $args ? '/' . implode('/', $args) : '';
+ return $args ? implode('/', $args) : '';
}
// --------------------------------------------------------------------
/**
- * Filter segments for malicious characters
+ * Filter URI
*
- * Called by CI_Router
+ * Filters segments for malicious characters.
*
- * @param string
+ * @used-by CI_Router
+ * @param string $str
* @return string
*/
public function _filter_uri($str)
{
- if ($str != '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') == FALSE)
+ if ($str !== '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') === FALSE)
{
// preg_quote() in PHP 5.3 escapes -, so the str_replace() and addition of - to preg_quote() is to maintain backwards
// compatibility as many are unaware of how characters in the permitted_uri_chars will be parsed as a regex pattern
@@ -287,28 +342,32 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Remove the suffix from the URL if needed
+ * Remove URL suffix
*
- * Called by CI_Router
+ * Removes the suffix from the URL if needed.
*
+ * @used-by CI_Router
* @return void
*/
public function _remove_url_suffix()
{
- if ($this->config->item('url_suffix') != '')
+ $suffix = (string) $this->config->item('url_suffix');
+
+ if ($suffix !== '' && ($offset = strrpos($this->uri_string, $suffix)) !== FALSE)
{
- $this->uri_string = preg_replace('|'.preg_quote($this->config->item('url_suffix')).'$|', '', $this->uri_string);
+ $this->uri_string = substr_replace($this->uri_string, '', $offset, strlen($suffix));
}
}
// --------------------------------------------------------------------
/**
- * Explode the URI Segments. The individual segments will
- * be stored in the $this->segments array.
+ * Explode URI segments
*
- * Called by CI_Router
+ * The individual segments will be stored in the $this->segments array.
*
+ * @see CI_URI::$segments
+ * @used-by CI_Router
* @return void
*/
public function _explode_segments()
@@ -318,7 +377,7 @@ class CI_URI {
// Filter segments for security
$val = trim($this->_filter_uri($val));
- if ($val != '')
+ if ($val !== '')
{
$this->segments[] = $val;
}
@@ -326,16 +385,16 @@ class CI_URI {
}
// --------------------------------------------------------------------
+
/**
* Re-index Segments
*
- * This function re-indexes the $this->segment array so that it
- * starts at 1 rather than 0. Doing so makes it simpler to
- * use functions like $this->uri->segment(n) since there is
- * a 1:1 relationship between the segment array and the actual segments.
- *
- * Called by CI_Router
+ * Re-indexes the CI_URI::$segment array so that it starts at 1 rather
+ * than 0. Doing so makes it simpler to use methods like
+ * CI_URI::segment(n) since there is a 1:1 relationship between the
+ * segment array and the actual segments.
*
+ * @used-by CI_Router
* @return void
*/
public function _reindex_segments()
@@ -349,68 +408,76 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Fetch a URI Segment
- *
- * This function returns the URI segment based on the number provided.
+ * Fetch URI Segment
*
- * @param integer
- * @param bool
- * @return string
+ * @see CI_URI::$segments
+ * @param int $n Index
+ * @param mixed $no_result What to return if the segment index is not found
+ * @return mixed
*/
- public function segment($n, $no_result = FALSE)
+ public function segment($n, $no_result = NULL)
{
- return ( ! isset($this->segments[$n])) ? $no_result : $this->segments[$n];
+ return isset($this->segments[$n]) ? $this->segments[$n] : $no_result;
}
// --------------------------------------------------------------------
/**
- * Fetch a URI "routed" Segment
+ * Fetch URI "routed" Segment
*
- * This function returns the re-routed URI segment (assuming routing rules are used)
- * based on the number provided. If there is no routing this function returns the
- * same result as $this->segment()
+ * Returns the re-routed URI segment (assuming routing rules are used)
+ * based on the index provided. If there is no routing, will return
+ * the same result as CI_URI::segment().
*
- * @param integer
- * @param bool
- * @return string
+ * @see CI_URI::$rsegments
+ * @see CI_URI::segment()
+ * @param int $n Index
+ * @param mixed $no_result What to return if the segment index is not found
+ * @return mixed
*/
- public function rsegment($n, $no_result = FALSE)
+ public function rsegment($n, $no_result = NULL)
{
- return ( ! isset($this->rsegments[$n])) ? $no_result : $this->rsegments[$n];
+ return isset($this->rsegments[$n]) ? $this->rsegments[$n] : $no_result;
}
// --------------------------------------------------------------------
/**
- * Generate a key value pair from the URI string
+ * URI to assoc
*
- * This function generates and associative array of URI data starting
- * at the supplied segment. For example, if this is your URI:
+ * Generates an associative array of URI data starting at the supplied
+ * segment index. For example, if this is your URI:
*
* example.com/user/search/name/joe/location/UK/gender/male
*
- * You can use this function to generate an array with this prototype:
+ * You can use this method to generate an array with this prototype:
*
- * array (
- * name => joe
- * location => UK
- * gender => male
- * )
+ * array (
+ * name => joe
+ * location => UK
+ * gender => male
+ * )
*
- * @param integer the starting segment number
- * @param array an array of default values
+ * @param int $n Index (default: 3)
+ * @param array $default Default values
* @return array
*/
public function uri_to_assoc($n = 3, $default = array())
{
return $this->_uri_to_assoc($n, $default, 'segment');
}
+
+ // --------------------------------------------------------------------
+
/**
- * Identical to above only it uses the re-routed segment array
+ * Routed URI to assoc
*
- * @param integer the starting segment number
- * @param array an array of default values
+ * Identical to CI_URI::uri_to_assoc(), only it uses the re-routed
+ * segment array.
+ *
+ * @see CI_URI::uri_to_assoc()
+ * @param int $n Index (default: 3)
+ * @param array $default Default values
* @return array
*/
public function ruri_to_assoc($n = 3, $default = array())
@@ -421,11 +488,15 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Generate a key value pair from the URI string or Re-routed URI string
+ * Internal URI-to-assoc
+ *
+ * Generates a key/value pair from the URI string or re-routed URI string.
*
- * @param integer the starting segment number
- * @param array an array of default values
- * @param string which array we should use
+ * @used-by CI_URI::uri_to_assoc()
+ * @used-by CI_URI::ruri_to_assoc()
+ * @param int $n Index (default: 3)
+ * @param array $default Default values
+ * @param string $which Array name ('segment' or 'rsegment')
* @return array
*/
protected function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
@@ -435,9 +506,11 @@ class CI_URI {
return $default;
}
- if (isset($this->keyval[$n]))
+ in_array($which, array('segment', 'rsegment'), TRUE) OR $which = 'segment';
+
+ if (isset($this->keyval[$which], $this->keyval[$which][$n]))
{
- return $this->keyval[$n];
+ return $this->keyval[$which][$n];
}
if ($which === 'segment')
@@ -453,18 +526,15 @@ class CI_URI {
if ($this->$total_segments() < $n)
{
- if (count($default) === 0)
- {
- return array();
- }
-
- return array_fill_keys($default, FALSE);
+ return (count($default) === 0)
+ ? array()
+ : array_fill_keys($default, NULL);
}
$segments = array_slice($this->$segment_array(), ($n - 1));
$i = 0;
$lastval = '';
- $retval = array();
+ $retval = array();
foreach ($segments as $seg)
{
if ($i % 2)
@@ -473,7 +543,7 @@ class CI_URI {
}
else
{
- $retval[$seg] = FALSE;
+ $retval[$seg] = NULL;
$lastval = $seg;
}
@@ -486,29 +556,31 @@ class CI_URI {
{
if ( ! array_key_exists($val, $retval))
{
- $retval[$val] = FALSE;
+ $retval[$val] = NULL;
}
}
}
// Cache the array for reuse
- $this->keyval[$n] = $retval;
+ isset($this->keyval[$which]) OR $this->keyval[$which] = array();
+ $this->keyval[$which][$n] = $retval;
return $retval;
}
// --------------------------------------------------------------------
/**
- * Generate a URI string from an associative array
+ * Assoc to URI
*
+ * Generates a URI string from an associative array.
*
- * @param array an associative array of key/values
- * @return array
+ * @param array $array Input array of key/value pairs
+ * @return string URI string
*/
public function assoc_to_uri($array)
{
$temp = array();
- foreach ((array)$array as $key => $val)
+ foreach ((array) $array as $key => $val)
{
$temp[] = $key;
$temp[] = $val;
@@ -520,10 +592,12 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Fetch a URI Segment and add a trailing slash
+ * Slash segment
+ *
+ * Fetches an URI segment with a slash.
*
- * @param integer
- * @param string
+ * @param int $n Index
+ * @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public function slash_segment($n, $where = 'trailing')
@@ -534,10 +608,12 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Fetch a URI Segment and add a trailing slash
+ * Slash routed segment
*
- * @param integer
- * @param string
+ * Fetches an URI routed segment with a slash.
+ *
+ * @param int $n Index
+ * @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public function slash_rsegment($n, $where = 'trailing')
@@ -548,11 +624,16 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Fetch a URI Segment and add a trailing slash - helper function
+ * Internal Slash segment
+ *
+ * Fetches an URI Segment and adds a slash to it.
*
- * @param integer
- * @param string
- * @param string
+ * @used-by CI_URI::slash_segment()
+ * @used-by CI_URI::slash_rsegment()
+ *
+ * @param int $n Index
+ * @param string $where Where to add the slash ('trailing' or 'leading')
+ * @param string $which Array name ('segment' or 'rsegment')
* @return string
*/
protected function _slash_segment($n, $where = 'trailing', $which = 'segment')
@@ -576,7 +657,7 @@ class CI_URI {
/**
* Segment Array
*
- * @return array
+ * @return array CI_URI::$segments
*/
public function segment_array()
{
@@ -588,7 +669,7 @@ class CI_URI {
/**
* Routed Segment Array
*
- * @return array
+ * @return array CI_URI::$rsegments
*/
public function rsegment_array()
{
@@ -600,7 +681,7 @@ class CI_URI {
/**
* Total number of segments
*
- * @return integer
+ * @return int
*/
public function total_segments()
{
@@ -612,7 +693,7 @@ class CI_URI {
/**
* Total number of routed segments
*
- * @return integer
+ * @return int
*/
public function total_rsegments()
{
@@ -622,29 +703,35 @@ class CI_URI {
// --------------------------------------------------------------------
/**
- * Fetch the entire URI string
+ * Fetch URI string
*
- * @return string
+ * @return string CI_URI::$uri_string
*/
public function uri_string()
{
return $this->uri_string;
}
-
// --------------------------------------------------------------------
/**
- * Fetch the entire Re-routed URI string
+ * Fetch Re-routed URI string
*
* @return string
*/
public function ruri_string()
{
- return '/'.implode('/', $this->rsegment_array());
+ global $RTR;
+
+ if (($dir = $RTR->fetch_directory()) === '/')
+ {
+ $dir = '';
+ }
+
+ return $dir.implode('/', $this->rsegment_array());
}
}
/* End of file URI.php */
-/* Location: ./system/core/URI.php */
+/* Location: ./system/core/URI.php */ \ No newline at end of file
diff --git a/system/core/Utf8.php b/system/core/Utf8.php
index ba3567453..5bc2dd5c9 100644
--- a/system/core/Utf8.php
+++ b/system/core/Utf8.php
@@ -1,4 +1,4 @@
-<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
+<?php
/**
* CodeIgniter
*
@@ -24,8 +24,7 @@
* @since Version 2.0
* @filesource
*/
-
-// ------------------------------------------------------------------------
+defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Utf8 Class
@@ -41,38 +40,40 @@
class CI_Utf8 {
/**
- * Constructor
+ * Class constructor
+ *
+ * Determines if UTF-8 support is to be enabled.
*
- * Determines if UTF-8 support is to be enabled
+ * @return void
*/
public function __construct()
{
log_message('debug', 'Utf8 Class Initialized');
- global $CFG;
+ $charset = strtoupper(config_item('charset'));
+
+ // set internal encoding for multibyte string functions if necessary
+ // and set a flag so we don't have to repeatedly use extension_loaded()
+ // or function_exists()
+ if (extension_loaded('mbstring'))
+ {
+ define('MB_ENABLED', TRUE);
+ mb_internal_encoding($charset);
+ }
+ else
+ {
+ define('MB_ENABLED', FALSE);
+ }
if (
- @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8
- && function_exists('iconv') // iconv must be installed
- && @ini_get('mbstring.func_overload') != 1 // Multibyte string function overloading cannot be enabled
- && $CFG->item('charset') === 'UTF-8' // Application charset must be UTF-8
+ @preg_match('/./u', 'é') === 1 // PCRE must support UTF-8
+ && function_exists('iconv') // iconv must be installed
+ && MB_ENABLED === TRUE // mbstring must be enabled
+ && $charset === 'UTF-8' // Application charset must be UTF-8
)
{
define('UTF8_ENABLED', TRUE);
log_message('debug', 'UTF-8 Support Enabled');
-
- // set internal encoding for multibyte string functions if necessary
- // and set a flag so we don't have to repeatedly use extension_loaded()
- // or function_exists()
- if (extension_loaded('mbstring'))
- {
- define('MB_ENABLED', TRUE);
- mb_internal_encoding('UTF-8');
- }
- else
- {
- define('MB_ENABLED', FALSE);
- }
}
else
{
@@ -86,9 +87,11 @@ class CI_Utf8 {
/**
* Clean UTF-8 strings
*
- * Ensures strings are UTF-8
+ * Ensures strings contain only valid UTF-8 characters.
*
- * @param string
+ * @uses CI_Utf8::_is_ascii() Decide whether a conversion is needed
+ *
+ * @param string $str String to clean
* @return string
*/
public function clean_string($str)
@@ -108,9 +111,9 @@ class CI_Utf8 {
*
* Removes all ASCII control characters except horizontal tabs,
* line feeds, and carriage returns, as all others can cause
- * problems in XML
+ * problems in XML.
*
- * @param string
+ * @param string $str String to clean
* @return string
*/
public function safe_ascii_for_xml($str)
@@ -123,11 +126,11 @@ class CI_Utf8 {
/**
* Convert to UTF-8
*
- * Attempts to convert a string to UTF-8
+ * Attempts to convert a string to UTF-8.
*
- * @param string
- * @param string - input encoding
- * @return string
+ * @param string $str Input string
+ * @param string $encoding Input encoding
+ * @return string $str encoded in UTF-8 or FALSE on failure
*/
public function convert_to_utf8($str, $encoding)
{
@@ -135,7 +138,7 @@ class CI_Utf8 {
{
return @iconv($encoding, 'UTF-8', $str);
}
- elseif (function_exists('mb_convert_encoding'))
+ elseif (MB_ENABLED === TRUE)
{
return @mb_convert_encoding($str, 'UTF-8', $encoding);
}
@@ -148,9 +151,9 @@ class CI_Utf8 {
/**
* Is ASCII?
*
- * Tests if a string is standard 7-bit ASCII or not
+ * Tests if a string is standard 7-bit ASCII or not.
*
- * @param string
+ * @param string $str String to check
* @return bool
*/
protected function _is_ascii($str)
@@ -161,4 +164,4 @@ class CI_Utf8 {
}
/* End of file Utf8.php */
-/* Location: ./system/core/Utf8.php */
+/* Location: ./system/core/Utf8.php */ \ No newline at end of file