Merge pull request #3995 from rajatsharma94/develop

set_realpath IP check
diff --git a/application/config/config.php b/application/config/config.php
index f4ba70a..a4d883f 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -480,6 +480,8 @@
 | can rewrite the tags on-the-fly, enabling you to utilize that syntax
 | in your view files.  Options are TRUE or FALSE (boolean)
 |
+| Note: You need to have eval() enabled for this to work.
+|
 */
 $config['rewrite_short_tags'] = FALSE;
 
diff --git a/system/core/Common.php b/system/core/Common.php
index b850fd3..ce324a1 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -833,19 +833,9 @@
 		{
 			if ( ! isset($_suhosin_func_blacklist))
 			{
-				if (extension_loaded('suhosin'))
-				{
-					$_suhosin_func_blacklist = 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';
-					}
-				}
-				else
-				{
-					$_suhosin_func_blacklist = array();
-				}
+				$_suhosin_func_blacklist = extension_loaded('suhosin')
+					? explode(',', trim(ini_get('suhosin.executor.func.blacklist')))
+					: array();
 			}
 
 			return ! in_array($function_name, $_suhosin_func_blacklist, TRUE);
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 9205ad1..1f48c07 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -272,7 +272,7 @@
 		$CI =& get_instance();
 		if (isset($CI->$name))
 		{
-			show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
+			throw new RuntimeException('The model name you are loading is the name of a resource that is already being used: '.$name);
 		}
 
 		if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE))
@@ -291,23 +291,37 @@
 		}
 
 		$model = ucfirst(strtolower($model));
-
-		foreach ($this->_ci_model_paths as $mod_path)
+		if ( ! class_exists($model))
 		{
-			if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
+			foreach ($this->_ci_model_paths as $mod_path)
 			{
-				continue;
+				if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
+				{
+					continue;
+				}
+
+				require_once($mod_path.'models/'.$path.$model.'.php');
+				if ( ! class_exists($model, FALSE))
+				{
+					throw new RuntimeException($mod_path."models/".$path.$model.".php exists, but doesn't declare class ".$model);
+				}
+
+				break;
 			}
 
-			require_once($mod_path.'models/'.$path.$model.'.php');
-
-			$this->_ci_models[] = $name;
-			$CI->$name = new $model();
-			return $this;
+			if ( ! class_exists($model, FALSE))
+			{
+				throw new RuntimeException('Unable to locate the model you have specified: '.$model);
+			}
+		}
+		elseif ( ! is_subclass_of($model, 'CI_Model'))
+		{
+			throw new RuntimeException("Class ".$model." already exists and doesn't extend CI_Model");
 		}
 
-		// couldn't find the model
-		show_error('Unable to locate the model you have specified: '.$model);
+		$this->_ci_models[] = $name;
+		$CI->$name = new $model();
+		return $this;
 	}
 
 	// --------------------------------------------------------------------
@@ -905,7 +919,7 @@
 		// 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') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE && function_usable('eval'))
+		if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE)
 		{
 			echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
 		}
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index fc2d590..e53fb54 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -1276,8 +1276,7 @@
 
 		foreach ($key as $k => $v)
 		{
-			$this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = ($escape)
-				? $this->escape($v) : $v;
+			$this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = $this->escape($v);
 		}
 
 		return $this;
@@ -1516,15 +1515,9 @@
 
 			ksort($row); // puts $row in the same order as our keys
 
-			if ($escape !== FALSE)
+			foreach ($row as $k => $v)
 			{
-				$clean = array();
-				foreach ($row as $value)
-				{
-					$clean[] = $this->escape($value);
-				}
-
-				$row = $clean;
+				$row[$k] = $this->escape($v);
 			}
 
 			$this->qb_set[] = '('.implode(',', $row).')';
@@ -1945,7 +1938,7 @@
 					$index_set = TRUE;
 				}
 
-				$clean[$this->protect_identifiers($k2, FALSE, $escape)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
+				$clean[$this->protect_identifiers($k2, FALSE, $escape)] = $this->escape($v2);
 			}
 
 			if ($index_set === FALSE)
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 51232f8..20ddfc1 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -695,6 +695,22 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Set Maximum File Size
+	 *
+	 * An internal alias to set_max_filesize() to help with configuration
+	 * as initialize() will look for a set_<property_name>() method ...
+	 *
+	 * @param	int	$n
+	 * @return	CI_Upload
+	 */
+	protected function set_max_size($n)
+	{
+		return $this->set_max_filesize($n);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Set Maximum File Name Length
 	 *
 	 * @param	int	$n
diff --git a/tests/README.md b/tests/README.md
index 47b5241..04dfbc3 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -6,7 +6,7 @@
 
 This is the preliminary CodeIgniter testing documentation. It
 will cover both internal as well as external APIs and the reasoning
-behind their implemenation, where appropriate. As with all CodeIgniter
+behind their implementation, where appropriate. As with all CodeIgniter
 documentation, this file should maintain a mostly human readable
 format to facilitate clean api design. [see http://arrenbrecht.ch/testing/]
 
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index cfaf6c7..889ab92 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -229,7 +229,7 @@
 		$this->ci_obj->$obj = new stdClass();
 		$this->setExpectedException(
 			'RuntimeException',
-			'CI Error: The model name you are loading is the name of a resource that is already being used: '.$obj
+			'The model name you are loading is the name of a resource that is already being used: '.$obj
 		);
 		$this->load->model('not_real', $obj);
 	}
@@ -240,7 +240,7 @@
 	{
 		$this->setExpectedException(
 			'RuntimeException',
-			'CI Error: Unable to locate the model you have specified: Ci_test_nonexistent_model.php'
+			'Unable to locate the model you have specified: Ci_test_nonexistent_model.php'
 		);
 
 		$this->load->model('ci_test_nonexistent_model.php');
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 22243cf..ee52d2e 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -34,6 +34,7 @@
 -  Core
 
    -  Added support for defining a list of specific query parameters in ``$config['cache_query_string']`` for the :doc:`Output Library <libraries/output>`.
+   -  Added class existence and inheritance checks to ``CI_Loader::model()`` in order to ease debugging in case of name collisions.
 
 Bug fixes for 3.0.1
 -------------------
@@ -67,8 +68,10 @@
 -  Fixed a bug (#3704) - :doc:`Database <database/index>` method ``stored_procedure()`` in the 'oci8' driver didn't properly bind parameters.
 -  Fixed a bug (#3778) - :doc:`Download Helper <helpers/download_helper>` function :php:func:`force_download()` incorrectly sent a *Pragma* response header.
 -  Fixed a bug (#3752) - ``$routing['directory']`` overrides were not properly handled and always resulted in a 404 "Not Found" error.
--  Fixed an internal bug in :doc:`Query Builder <database/query_builder>` escaping logic where if field name escaping is force-disabled, methods ``where()`` and ``having()`` will also treat values as fields.
+-  Fixed an internal bug (#3989) - :doc:`Query Builder <database/query_builder>` escaping logic where if field name escaping is force-disabled, would also treat values as fields in methods ``where()``, ``having()``, ``set()``, ``set_insert_batch()``, ``set_update_batch()``.
 -  Fixed a bug (#3279) - :doc:`Query Builder <database/query_builder>` methods ``update()`` and ``get_compiled_update()`` did double escaping on the table name if it was provided via ``from()``.
+-  Fixed a bug (#3991) - ``$config['rewrite_short_tags']`` never worked due to ``function_exists('eval')`` always returning FALSE.
+-  Fixed a bug where the :doc:`File Uploadin Library <libraries/file_uploading>` library will not properly configure its maximum file size unless the input value is of type integer.
 
 Version 3.0.0
 =============
diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst
index ac44566..5f5fafd 100644
--- a/user_guide_src/source/database/results.rst
+++ b/user_guide_src/source/database/results.rst
@@ -173,6 +173,94 @@
 	$query->unbuffered_row('array');	// associative array
 
 *********************
+Custom Result Objects
+*********************
+
+You can have the results returned as an instance of a custom class instead
+of a ``stdClass`` or array, as the ``result()`` and ``result_array()``
+methods allow. This requires that the class is already loaded into memory.
+The object will have all values returned from the database set as properties.
+If these have been declared and are non-public then you should provide a
+``__set()`` method to allow them to be set.
+
+Example::
+
+	class User {
+
+		public $id;
+		public $email;
+		public $username;
+
+		protected $last_login;
+
+		public function last_login($format)
+		{
+			return $this->last_login->format($format);
+		}
+
+		public function __set($name, $value)
+		{
+			if ($name === 'last_login')
+			{
+				$this->last_login = DateTime::createFromFormat('U', $value);
+			}
+		}
+
+		public function __get($name)
+		{
+			if (isset($this->$name))
+			{
+				return $this->$name;
+			}
+		}
+	}
+
+In addition to the two methods listed below, the following methods also can
+take a class name to return the results as: ``first_row()``, ``last_row()``,
+``next_row()``, and ``previous_row()``.
+
+**custom_result_object()**
+
+Returns the entire result set as an array of instances of the class requested.
+The only parameter is the name of the class to instantiate.
+
+Example::
+
+	$query = $this->db->query("YOUR QUERY");
+
+	$rows = $query->custom_result_object('User');
+
+	foreach ($rows as $row)
+	{
+		echo $row->id;
+		echo $row->email;
+		echo $row->last_login('Y-m-d');
+	}
+
+**custom_row_object()**
+
+Returns a single row from your query results. The first parameter is the row
+number of the results. The second parameter is the class name to instantiate.
+
+Example::
+
+	$query = $this->db->query("YOUR QUERY");
+
+	$row = $query->custom_row_object(0, 'User');
+
+	if (isset($row))
+	{
+		echo $row->email;   // access attributes
+		echo $row->last_login('Y-m-d');   // access class methods
+	}
+
+You can also use the ``row()`` method in exactly the same way.
+
+Example::
+
+	$row = $query->custom_row_object(0, 'User');
+
+*********************
 Result Helper Methods
 *********************