Merge branch 'develop' of git://github.com/EllisLab/CodeIgniter into develop
diff --git a/system/core/Lang.php b/system/core/Lang.php
index 3001f1b..601348a 100644
--- a/system/core/Lang.php
+++ b/system/core/Lang.php
@@ -65,11 +65,11 @@
 	/**
 	 * Load a language file
 	 *
-	 * @param	mixed	the name of the language file to be loaded
-	 * @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
+	 * @param	mixed	$langile		the name of the language file to be loaded
+	 * @param	string	$idiom = ''		the language (english, etc.)
+	 * @param	bool	$return = FALSE		return loaded array of translations
+	 * @param 	bool	$add_suffix = TRUE	add suffix to $langfile
+	 * @param 	string	$alt_path = ''		alternative path to look for language file
 	 * @return	mixed
 	 */
 	public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE, $alt_path = '')
@@ -83,10 +83,10 @@
 
 		$langfile .= '.php';
 
-		if ($idiom === '')
+		if (empty($idiom) OR ! ctype_alpha($idiom))
 		{
 			$config =& get_config();
-			$idiom = ( ! empty($config['language'])) ? $config['language'] : 'english';
+			$idiom = empty($config['language']) ? 'english' : $config['language'];
 		}
 
 		if ($return === FALSE && isset($this->is_loaded[$langfile]) && $this->is_loaded[$langfile] === $idiom)
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 5de2e5d..b316c8e 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -318,9 +318,9 @@
 	/**
 	 * Database Loader
 	 *
-	 * @param	string	the DB credentials
-	 * @param	bool	whether to return the DB object
-	 * @param	bool	whether to enable query builder (this allows us to override the config setting)
+	 * @param	mixed	$params = ''		the DB settings
+	 * @param	bool	$return = FALSE		whether to return the DB object
+	 * @param	bool	$query_builder = NULL	whether to enable query builder (overrides the config setting)
 	 * @return	object
 	 */
 	public function database($params = '', $return = FALSE, $query_builder = NULL)
@@ -329,7 +329,7 @@
 		$CI =& get_instance();
 
 		// Do we even need to load the database class?
-		if (class_exists('CI_DB') && $return === FALSE && $query_builder === 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;
 		}
diff --git a/system/core/Security.php b/system/core/Security.php
index 2fbc5b3..d7c8271 100644
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -161,7 +161,7 @@
 		}
 
 		// 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])
+		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();
diff --git a/system/core/URI.php b/system/core/URI.php
index 15e6a55..72f293c 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -433,9 +433,9 @@
 	/**
 	 * Generate a key value pair from the URI string or Re-routed URI string
 	 *
-	 * @param	int	the starting segment number
-	 * @param	array	an array of default values
-	 * @param	string	which array we should use
+	 * @param	int	$n = 3			the starting segment number
+	 * @param	array	$default = array()	an array of default values
+	 * @param	string	$which = 'segment'	which array we should use
 	 * @return	array
 	 */
 	protected function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
@@ -445,9 +445,11 @@
 			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')
@@ -499,7 +501,8 @@
 		}
 
 		// 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;
 	}
 
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 7f1434f..e8286aa 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -640,7 +640,7 @@
 		// Make sure not to replace a chunk inside a string that happens to match the bind marker
 		if ($c = preg_match_all("/'[^']*'/i", $sql, $matches))
 		{
-			$c = preg_match_all('/'.preg_quote($this->bind_marker).'/i',
+			$c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i',
 				str_replace($matches[0],
 					str_replace($this->bind_marker, str_repeat(' ', $ml), $matches[0]),
 					$sql, $c),
@@ -652,7 +652,7 @@
 				return $sql;
 			}
 		}
-		elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker).'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
+		elseif (($c = preg_match_all('/'.preg_quote($this->bind_marker, '/').'/i', $sql, $matches, PREG_OFFSET_CAPTURE)) !== $bind_count)
 		{
 			return $sql;
 		}
@@ -1007,13 +1007,13 @@
 			if (is_array($this->_escape_char))
 			{
 				$preg_ec = array(
-						preg_quote($this->_escape_char[0]), preg_quote($this->_escape_char[1]),
+						preg_quote($this->_escape_char[0], '/'), preg_quote($this->_escape_char[1], '/'),
 						$this->_escape_char[0], $this->_escape_char[1]
 						);
 			}
 			else
 			{
-				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char);
+				$preg_ec[0] = $preg_ec[1] = preg_quote($this->_escape_char, '/');
 				$preg_ec[2] = $preg_ec[3] = $this->_escape_char;
 			}
 		}
@@ -1172,7 +1172,7 @@
 		if (empty($_operators))
 		{
 			$_les = ($this->_like_escape_str !== '')
-				? '\s+'.preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)))
+				? '\s+'.preg_quote(trim(sprintf($this->_like_escape_str, $this->_like_escape_chr)), '/')
 				: '';
 			$_operators = array(
 				'\s*(?:<|>|!)?=\s*',		// =, <=, >=, !=
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 5ea9643..ed00510 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -2077,7 +2077,7 @@
 				for ($ci = 0, $cc = count($conditions); $ci < $cc; $ci++)
 				{
 					if (($op = $this->_get_operator($conditions[$ci])) === FALSE
-						OR ! preg_match('/^(\(?)(.*)('.preg_quote($op).')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches))
+						OR ! preg_match('/^(\(?)(.*)('.preg_quote($op, '/').')\s*(.*(?<!\)))?(\)?)$/i', $conditions[$ci], $matches))
 					{
 						continue;
 					}
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index 0232adf..2c26a36 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -110,13 +110,10 @@
 		// Internet Explorer-specific headers
 		if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE)
 		{
-			header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
-			header('Pragma: public');
+			header('Cache-Control: no-cache, no-store, must-revalidate');
 		}
-		else
-		{
-			header('Pragma: no-cache');
-		}
+
+		header('Pragma: no-cache');
 
 		exit($data);
 	}
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index de5bdec..dc77246 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -489,7 +489,7 @@
 			$separator = '_';
 		}
 
-		$q_separator = preg_quote($separator);
+		$q_separator = preg_quote($separator, '#');
 
 		$trans = array(
 				'&.+?;'			=> '',
diff --git a/system/libraries/User_agent.php b/system/libraries/User_agent.php
index ff596f0..3387d4a 100644
--- a/system/libraries/User_agent.php
+++ b/system/libraries/User_agent.php
@@ -466,7 +466,13 @@
 	 */
 	public function is_referral()
 	{
-		return ! empty($_SERVER['HTTP_REFERER']);
+		if (empty($_SERVER['HTTP_REFERER']))
+		{
+			return FALSE;
+		}
+
+		$referer = parse_url($_SERVER['HTTP_REFERER']);
+		return ! (empty($referer['host']) && strpos(config_item('base_url'), $referer['host']) !== FALSE);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 9def99c..c87aebd 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -223,6 +223,7 @@
    -  :doc:`Encryption Library <libraries/encryption>` changes include:
 	 -  Added support for hashing algorithms other than SHA1 and MD5.
 	 -  Removed previously deprecated ``sha1()`` method.
+   -  Changed :doc:`Language Library <libraries/language>` method ``load()`` to filter the language name with ``ctype_digit()``.
 
 -  Core
 
@@ -401,6 +402,10 @@
 -  Fixed a bug (#1766) - :doc:`Query Builder <database/query_builder>` didn't always take into account the *dbprefix* setting.
 -  Fixed a bug (#779) - :doc:`URI Class <libraries/uri>` didn't always trim slashes from the *uri_string* as shown in the documentation.
 -  Fixed a bug (#134) - :doc:`Database Caching <database/caching>` method ``delete_cache()`` didn't work in some cases due to *cachedir* not being initialized properly.
+-  Fixed a bug (#191) - :doc:`Loader Library <libraries/loader>` ignored attempts for (re)loading databases to ``get_instance()->db`` even when the old database connection is dead.
+-  Fixed a bug (#1255) - :doc:`User Agent Library <libraries/user_agent>` method ``is_referral()`` only checked if ``$_SERVER['HTTP_REFERER']`` exists.
+-  Fixed a bug (#1146) - :doc:`Download Helper <helpers/download_helper>` function ``force_download()`` incorrectly sent *Cache-Control* directives *pre-check* and *post-check* to Internet Explorer.
+-  Fixed a bug (#1811) - :doc:`URI Library <libraries/uri>` didn't properly cache segments for ``uri_to_assoc()`` and ``ruri_to_assoc()``.
 
 Version 2.1.3
 =============
diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst
index 6ca7291..5380d09 100644
--- a/user_guide_src/source/database/query_builder.rst
+++ b/user_guide_src/source/database/query_builder.rst
@@ -681,6 +681,35 @@
 
 .. note:: All values are escaped automatically producing safer queries.
 
+$this->db->replace()
+====================
+
+This method executes a REPLACE statement, which is basically the SQL
+standard for (optional) DELETE + INSERT, using *PRIMARY* and *UNIQUE*
+keys as the determining factor.
+In our case, it will save you from the need to implement complex
+logics with different combinations of  ``select()``, ``update()``,
+``delete()`` and ``insert()`` calls.
+
+Example::
+
+	$data = array(
+		'title' => 'My title',
+		'name'  => 'My Name',
+		'date'  => 'My date'
+	);
+
+	$this->db->replace('table', $data);
+
+	// Executes: REPLACE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date')
+
+In the above example, if we assume that the *title* field is our primary
+key, then if a row containing 'My title' as the *title* value, that row
+will be deleted with our new row data replacing it.
+
+Usage of the ``set()`` method is also allowed and all fields are
+automatically escaped, just like with ``insert()``.
+
 $this->db->set()
 ================
 
@@ -740,7 +769,6 @@
 	$this->db->set($object);
 	$this->db->insert('mytable');
 
-
 *************
 Updating Data
 *************
@@ -792,6 +820,7 @@
 You may also use the $this->db->set() function described above when
 performing updates.
 
+
 $this->db->update_batch()
 =========================
 
diff --git a/user_guide_src/source/libraries/language.rst b/user_guide_src/source/libraries/language.rst
index ec678cd..b231f14 100644
--- a/user_guide_src/source/libraries/language.rst
+++ b/user_guide_src/source/libraries/language.rst
@@ -54,7 +54,9 @@
 Where filename is the name of the file you wish to load (without the
 file extension), and language is the language set containing it (ie,
 english). If the second parameter is missing, the default language set
-in your application/config/config.php file will be used.
+in your *application/config/config.php* file will be used.
+
+.. note:: The *language* parameter can only consist of letters.
 
 Fetching a Line of Text
 =======================
@@ -67,8 +69,7 @@
 Where language_key is the array key corresponding to the line you wish
 to show.
 
-Note: This function simply returns the line. It does not echo it for
-you.
+.. note:: This method simply returns the line. It does not echo it.
 
 Using language lines as form labels
 -----------------------------------
diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst
index e7d2555..0555314 100644
--- a/user_guide_src/source/libraries/security.rst
+++ b/user_guide_src/source/libraries/security.rst
@@ -26,7 +26,7 @@
 To filter data through the XSS filter use this function:
 
 $this->security->xss_clean()
-=============================
+============================
 
 Here is an usage example::
 
@@ -56,7 +56,7 @@
 	}
 
 $this->security->sanitize_filename()
-=====================================
+====================================
 
 When accepting filenames from user input, it is best to sanitize them to
 prevent directory traversal and other security related issues. To do so,
@@ -76,16 +76,35 @@
 Cross-site request forgery (CSRF)
 =================================
 
-You can enable csrf protection by opening your
+You can enable CSRF protection by opening your
 application/config/config.php file and setting this::
 
 	$config['csrf_protection'] = TRUE;
 
-If you use the :doc:`form helper <../helpers/form_helper>` the
-form_open() function will automatically insert a hidden csrf field in
-your forms.
+If you use the :doc:`form helper <../helpers/form_helper>`, then
+``form_open()`` will automatically insert a hidden csrf field in
+your forms. If not, then you can use ``csrf_get_token_name()``
+and ``csrf_get_hash()``
 
-Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the CSRF cookie. The default regeneration of tokens provides stricter security but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You may alter this behavior by editing the following config parameter::
+::
+
+	$csrf = array(
+		'name' => $this->security->csrf_get_token_name(),
+		'hash' => $this->security->csrf_get_hash()
+	);
+
+	...
+
+	<input type="hidden" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
+
+Tokens may be either regenerated on every submission (default) or
+kept the same throughout the life of the CSRF cookie. The default
+regeneration of tokens provides stricter security, but may result
+in usability concerns as other tokens become invalid (back/forward
+navigation, multiple tabs/windows, asynchronous actions, etc). You
+may alter this behavior by editing the following config parameter
+
+::
 
 	$config['csrf_regeneration'] = TRUE;
 
@@ -95,3 +114,15 @@
 
 	$config['csrf_exclude_uris'] = array('api/person/add');
 
+$this->security->get_csrf_token_name()
+======================================
+
+Returns the CSRF token name, which is set by
+``$config['csrf_token_name']``.
+
+$this->security->get_csrf_hash()
+================================
+
+Returns the CSRF hash value. Useful in combination with
+``get_csrf_token_name()`` for manually building forms or 
+sending valid AJAX POST requests.
\ No newline at end of file