Merge pull request #1479 from srtfisher/develop

A TTL of 0 will keep the cache persistant.
diff --git a/application/config/config.php b/application/config/config.php
index 7da889f..726e3a7 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -359,6 +359,18 @@
 
 /*
 |--------------------------------------------------------------------------
+| Minify
+|--------------------------------------------------------------------------
+|
+| Removes extra characters (usually unnecessary spaces) from your
+| output for faster page load speeds.  Makes your outputted HTML source
+| code less readable.
+|
+*/
+$config['minify_output'] = FALSE;
+
+/*
+|--------------------------------------------------------------------------
 | Master Time Reference
 |--------------------------------------------------------------------------
 |
@@ -398,5 +410,6 @@
 $config['proxy_ips'] = '';
 
 
+
 /* End of file config.php */
 /* Location: ./application/config/config.php */
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 15493af..4b1d6a8 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -68,7 +68,7 @@
 	'gtar'	=>	'application/x-gtar',
 	'gz'	=>	'application/x-gzip',
 	'gzip'  =>	'application/x-gzip',
-	'php'	=>	'application/x-httpd-php',
+	'php'	=>	array('application/x-httpd-php', 'application/php', 'application/x-php', 'text/php', 'text/x-php', 'application/x-httpd-php-source'),
 	'php4'	=>	'application/x-httpd-php',
 	'php3'	=>	'application/x-httpd-php',
 	'phtml'	=>	'application/x-httpd-php',
@@ -80,7 +80,8 @@
 	'tgz'	=>	array('application/x-tar', 'application/x-gzip-compressed'),
 	'xhtml'	=>	'application/xhtml+xml',
 	'xht'	=>	'application/xhtml+xml',
-	'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
+	'zip'	=>	array('application/x-zip', 'application/zip', 'application/x-zip-compressed', 'application/s-compressed', 'multipart/x-zip'),
+	'rar'	=>	array('application/x-rar', 'application/rar', 'application/x-rar-compressed'),
 	'mid'	=>	'audio/midi',
 	'midi'	=>	'audio/midi',
 	'mpga'	=>	'audio/mpeg',
diff --git a/system/core/Common.php b/system/core/Common.php
index 1708653..c309d41 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -431,6 +431,7 @@
 			300	=> 'Multiple Choices',
 			301	=> 'Moved Permanently',
 			302	=> 'Found',
+			303	=> 'See Other',
 			304	=> 'Not Modified',
 			305	=> 'Use Proxy',
 			307	=> 'Temporary Redirect',
@@ -462,18 +463,23 @@
 			505	=> 'HTTP Version Not Supported'
 		);
 
-		if ($code == '' OR ! is_numeric($code))
+		if (empty($code) OR ! is_numeric($code))
 		{
 			show_error('Status codes must be numeric', 500);
 		}
-		elseif (isset($stati[$code]) && $text === '')
-		{
-			$text = $stati[$code];
-		}
 
-		if ($text === '')
+		is_int($code) OR $code = (int) $code;
+
+		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;
diff --git a/system/core/Config.php b/system/core/Config.php
index 3de1bcb..4b4e5a7 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -225,25 +225,39 @@
 	 * Site URL
 	 * Returns base_url . index_page [. uri_string]
 	 *
-	 * @param	string	the URI string
+	 * @param	mixed	the 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');
 		}
 
+		$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;
+
+			if ($suffix !== '' && ($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;
 	}
 
 	// -------------------------------------------------------------
@@ -280,15 +294,7 @@
 		}
 		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;
diff --git a/system/core/Hooks.php b/system/core/Hooks.php
index 29fd882..afbf4b4 100644
--- a/system/core/Hooks.php
+++ b/system/core/Hooks.php
@@ -39,7 +39,7 @@
 class CI_Hooks {
 
 	/**
-	 * Determines wether hooks are enabled
+	 * Determines whether hooks are enabled
 	 *
 	 * @var bool
 	 */
@@ -53,7 +53,7 @@
 	public $hooks =	array();
 
 	/**
-	 * Determines wether hook is in progress, used to prevent infinte loops
+	 * Determines whether hook is in progress, used to prevent infinte loops
 	 *
 	 * @var bool
 	 */
diff --git a/system/core/Output.php b/system/core/Output.php
index 5588ffe..ed294f1 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -67,7 +67,14 @@
 	public $mimes =		array();
 
 	/**
-	 * Determines wether profiler is enabled
+	 * Mime-type for the current page
+	 *
+	 * @var string
+	 */
+	protected $mime_type		= 'text/html';
+
+	/**
+	 * Determines whether profiler is enabled
 	 *
 	 * @var book
 	 */
@@ -78,7 +85,7 @@
 	 *
 	 * @var bool
 	 */
-	protected $_zlib_oc =	FALSE;
+	protected $_zlib_oc =		FALSE;
 
 	/**
 	 * List of profiler sections
@@ -174,7 +181,7 @@
 	 * how to permit header data to be saved with the cache data...
 	 *
 	 * @param	string
-	 * @param 	bool
+	 * @param	bool
 	 * @return	void
 	 */
 	public function set_header($header, $replace = TRUE)
@@ -218,6 +225,8 @@
 			}
 		}
 
+		$this->mime_type = $mime_type;
+
 		if (empty($charset))
 		{
 			$charset = config_item('charset');
@@ -292,6 +301,12 @@
 	 */
 	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);
@@ -327,7 +342,7 @@
 	 * with any server headers and profile data. It also stops the
 	 * benchmark timer so the page rendering speed and memory usage can be shown.
 	 *
-	 * @param 	string
+	 * @param	string
 	 * @return	mixed
 	 */
 	public function _display($output = '')
@@ -353,6 +368,15 @@
 
 		// --------------------------------------------------------------------
 
+		// 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
@@ -450,7 +474,7 @@
 	/**
 	 * Write a Cache File
 	 *
-	 * @param 	string
+	 * @param	string
 	 * @return	void
 	 */
 	public function _write_cache($output)
@@ -493,6 +517,9 @@
 		@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);
 	}
 
 	// --------------------------------------------------------------------
@@ -500,8 +527,8 @@
 	/**
 	 * Update/serve a cached file
 	 *
-	 * @param 	object	config class
-	 * @param 	object	uri class
+	 * @param	object	config class
+	 * @param	object	uri class
 	 * @return	bool
 	 */
 	public function _display_cache(&$CFG, &$URI)
@@ -530,13 +557,22 @@
 			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 = trim(str_replace('TS--->', '', $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));
@@ -544,6 +580,135 @@
 		return TRUE;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Set the HTTP headers to match the server-side file cache settings
+	 * in order to reduce bandwidth.
+	 *
+	 * @param	int	timestamp of when the page was last modified
+	 * @param	int	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');
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Reduce excessive size of HTML content.
+	 *
+	 * @param	string
+	 * @param	string
+	 * @return	string
+	 */
+	public function minify($output, $type = 'text/html')
+	{
+		switch ($type)
+		{
+			case 'text/html':
+
+				$size_before = strlen($output);
+
+				// 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+}msU', '$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/URI.php b/system/core/URI.php
index a997525..6a8b1a5 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -278,7 +278,7 @@
 		{
 			// 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
-			if ( ! preg_match('|^['.str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-')).']+$|i', $str))
+			if ( ! preg_match('|^['.str_replace(array('\\-', '\-'), '-', preg_quote($this->config->item('permitted_uri_chars'), '-')).']+$|i', urldecode($str)))
 			{
 				show_error('The URI you submitted has disallowed characters.', 400);
 			}
@@ -302,9 +302,11 @@
 	 */
 	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));
 		}
 	}
 
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index d056bdb..28d665f 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -352,7 +352,7 @@
 			$error = $this->error();
 
 			// Log errors
-			log_message('error', 'Query error: '.$error['message']);
+			log_message('error', 'Query error: '.$error['message'] . ' - Invalid query: ' . $sql);
 
 			if ($this->db_debug)
 			{
diff --git a/system/database/DB_forge.php b/system/database/DB_forge.php
index 9b76392..91f9d56 100644
--- a/system/database/DB_forge.php
+++ b/system/database/DB_forge.php
@@ -231,7 +231,7 @@
 
 		if (($result = $this->db->query($sql)) !== FALSE && ! empty($this->db->data_cache['table_names']))
 		{
-			$this->db->data_cache['table_names'][] = $$this->db->dbprefix.$table;
+			$this->db->data_cache['table_names'][] = $this->db->dbprefix.$table;
 		}
 
 		return $result;
diff --git a/system/database/DB_query_builder.php b/system/database/DB_query_builder.php
index 488b294..531ca9e 100644
--- a/system/database/DB_query_builder.php
+++ b/system/database/DB_query_builder.php
@@ -324,10 +324,10 @@
 	 * @param	string
 	 * @param	string	the join condition
 	 * @param	string	the type of join
-	 * @param	string	wether not to try to escape identifiers
+	 * @param	string	whether not to try to escape identifiers
 	 * @return	object
 	 */
-	public function join($table, $cond, $type = '', $escape = TRUE)
+	public function join($table, $cond, $type = '', $escape = NULL)
 	{
 		if ($type !== '')
 		{
@@ -347,6 +347,8 @@
 		// in the protect_identifiers to know whether to add a table prefix
 		$this->_track_aliases($table);
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		// Split multiple conditions
 		if ($escape === TRUE && preg_match_all('/\sAND\s|\sOR\s/i', $cond, $m, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
 		{
@@ -381,7 +383,7 @@
 		}
 
 		// Assemble the JOIN statement
-		$this->qb_join[] = $join = $type.'JOIN '.$this->protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
+		$this->qb_join[] = $join = $type.'JOIN '.$table.' ON '.$cond;
 
 		if ($this->qb_caching === TRUE)
 		{
@@ -405,7 +407,7 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	public function where($key, $value = NULL, $escape = TRUE)
+	public function where($key, $value = NULL, $escape = NULL)
 	{
 		return $this->_where($key, $value, 'AND ', $escape);
 	}
@@ -423,7 +425,7 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	public function or_where($key, $value = NULL, $escape = TRUE)
+	public function or_where($key, $value = NULL, $escape = NULL)
 	{
 		return $this->_where($key, $value, 'OR ', $escape);
 	}
@@ -451,7 +453,7 @@
 		}
 
 		// If the escape value was not set will will base it on the global setting
-		$escape = $this->_protect_identifiers;
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
 
 		foreach ($key as $k => $v)
 		{
@@ -504,9 +506,9 @@
 	 * @param	array	The values searched on
 	 * @return	object
 	 */
-	public function where_in($key = NULL, $values = NULL)
+	public function where_in($key = NULL, $values = NULL, $escape = NULL)
 	{
-		return $this->_where_in($key, $values);
+		return $this->_where_in($key, $values, FALSE, 'AND ', $escape);
 	}
 
 	// --------------------------------------------------------------------
@@ -521,9 +523,9 @@
 	 * @param	array	The values searched on
 	 * @return	object
 	 */
-	public function or_where_in($key = NULL, $values = NULL)
+	public function or_where_in($key = NULL, $values = NULL, $escape = NULL)
 	{
-		return $this->_where_in($key, $values, FALSE, 'OR ');
+		return $this->_where_in($key, $values, FALSE, 'OR ', $escape);
 	}
 
 	// --------------------------------------------------------------------
@@ -538,9 +540,9 @@
 	 * @param	array	The values searched on
 	 * @return	object
 	 */
-	public function where_not_in($key = NULL, $values = NULL)
+	public function where_not_in($key = NULL, $values = NULL, $escape = NULL)
 	{
-		return $this->_where_in($key, $values, TRUE);
+		return $this->_where_in($key, $values, TRUE, 'AND ', $escape);
 	}
 
 	// --------------------------------------------------------------------
@@ -555,9 +557,9 @@
 	 * @param	array	The values searched on
 	 * @return	object
 	 */
-	public function or_where_not_in($key = NULL, $values = NULL)
+	public function or_where_not_in($key = NULL, $values = NULL, $escape = NULL)
 	{
-		return $this->_where_in($key, $values, TRUE, 'OR ');
+		return $this->_where_in($key, $values, TRUE, 'OR ', $escape);
 	}
 
 	// --------------------------------------------------------------------
@@ -573,7 +575,7 @@
 	 * @param	string
 	 * @return	object
 	 */
-	protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ')
+	protected function _where_in($key = NULL, $values = NULL, $not = FALSE, $type = 'AND ', $escape = NULL)
 	{
 		if ($key === NULL OR $values === NULL)
 		{
@@ -587,6 +589,8 @@
 			$values = array($values);
 		}
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		$not = ($not) ? ' NOT' : '';
 
 		foreach ($values as $value)
@@ -595,7 +599,7 @@
 		}
 
 		$prefix = (count($this->qb_where) === 0) ? '' : $type;
-		$this->qb_where[] = $where_in = $prefix.$this->protect_identifiers($key).$not.' IN ('.implode(', ', $this->qb_wherein).') ';
+		$this->qb_where[] = $where_in = $prefix.$this->protect_identifiers($key, FALSE, $escape).$not.' IN ('.implode(', ', $this->qb_wherein).') ';
 
 		if ($this->qb_caching === TRUE)
 		{
@@ -886,7 +890,7 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	public function having($key, $value = '', $escape = TRUE)
+	public function having($key, $value = '', $escape = NULL)
 	{
 		return $this->_having($key, $value, 'AND ', $escape);
 	}
@@ -903,7 +907,7 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	public function or_having($key, $value = '', $escape = TRUE)
+	public function or_having($key, $value = '', $escape = NULL)
 	{
 		return $this->_having($key, $value, 'OR ', $escape);
 	}
@@ -921,21 +925,22 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	protected function _having($key, $value = '', $type = 'AND ', $escape = TRUE)
+	protected function _having($key, $value = '', $type = 'AND ', $escape = NULL)
 	{
 		if ( ! is_array($key))
 		{
 			$key = array($key => $value);
 		}
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		foreach ($key as $k => $v)
 		{
 			$prefix = (count($this->qb_having) === 0) ? '' : $type;
 
-			if ($escape === TRUE)
-			{
-				$k = $this->protect_identifiers($k);
-			}
+			$k = $this->_has_operator($k)
+				? $this->protect_identifiers(substr($k, 0, strpos(rtrim($k), ' ')), FALSE, $escape).strchr(rtrim($k), ' ')
+				: $this->protect_identifiers($k, FALSE, $escape);
 
 			if ( ! $this->_has_operator($k))
 			{
@@ -968,7 +973,7 @@
 	 * @param	bool	enable field name escaping
 	 * @return	object
 	 */
-	public function order_by($orderby, $direction = '', $escape = TRUE)
+	public function order_by($orderby, $direction = '', $escape = NULL)
 	{
 		if (strtolower($direction) === 'random')
 		{
@@ -980,8 +985,9 @@
 			$direction = in_array(strtoupper(trim($direction)), array('ASC', 'DESC'), TRUE) ? ' '.$direction : ' ASC';
 		}
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
 
-		if ((strpos($orderby, ',') !== FALSE) && $escape === TRUE)
+		if ($escape === TRUE && strpos($orderby, ',') !== FALSE)
 		{
 			$temp = array();
 			foreach (explode(',', $orderby) as $part)
@@ -1055,14 +1061,16 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * The "set" function.  Allows key/value pairs to be set for inserting or updating
+	 * The "set" function.
+	 *
+	 * Allows key/value pairs to be set for inserting or updating
 	 *
 	 * @param	mixed
 	 * @param	string
 	 * @param	bool
 	 * @return	object
 	 */
-	public function set($key, $value = '', $escape = TRUE)
+	public function set($key, $value = '', $escape = NULL)
 	{
 		$key = $this->_object_to_array($key);
 
@@ -1071,16 +1079,12 @@
 			$key = array($key => $value);
 		}
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		foreach ($key as $k => $v)
 		{
-			if ($escape === FALSE)
-			{
-				$this->qb_set[$this->protect_identifiers($k)] = $v;
-			}
-			else
-			{
-				$this->qb_set[$this->protect_identifiers($k, FALSE, TRUE)] = $this->escape($v);
-			}
+			$this->qb_set[$this->protect_identifiers($k, FALSE, $escape)] = ($escape)
+				? $this->escape($v) : $v;
 		}
 
 		return $this;
@@ -1286,7 +1290,7 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	public function set_insert_batch($key, $value = '', $escape = TRUE)
+	public function set_insert_batch($key, $value = '', $escape = NULL)
 	{
 		$key = $this->_object_to_array_batch($key);
 
@@ -1295,6 +1299,8 @@
 			$key = array($key => $value);
 		}
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		$keys = array_keys($this->_object_to_array(current($key)));
 		sort($keys);
 
@@ -1326,7 +1332,7 @@
 
 		foreach ($keys as $k)
 		{
-			$this->qb_keys[] = $this->protect_identifiers($k);
+			$this->qb_keys[] = $this->protect_identifiers($k, FALSE, $escape);
 		}
 
 		return $this;
@@ -1725,7 +1731,7 @@
 	 * @param	bool
 	 * @return	object
 	 */
-	public function set_update_batch($key, $index = '', $escape = TRUE)
+	public function set_update_batch($key, $index = '', $escape = NULL)
 	{
 		$key = $this->_object_to_array_batch($key);
 
@@ -1734,6 +1740,8 @@
 			// @todo error
 		}
 
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
+
 		foreach ($key as $k => $v)
 		{
 			$index_set = FALSE;
@@ -1745,7 +1753,7 @@
 					$index_set = TRUE;
 				}
 
-				$clean[$this->protect_identifiers($k2)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
+				$clean[$this->protect_identifiers($k2, FALSE, $escape)] = ($escape === FALSE) ? $v2 : $this->escape($v2);
 			}
 
 			if ($index_set === FALSE)
diff --git a/system/database/drivers/mysql/mysql_forge.php b/system/database/drivers/mysql/mysql_forge.php
index d22454d..2ac75ba 100644
--- a/system/database/drivers/mysql/mysql_forge.php
+++ b/system/database/drivers/mysql/mysql_forge.php
@@ -62,7 +62,7 @@
 
 				$sql .= "\n\t".$this->db->escape_identifiers($field);
 
-				empty($attributes['NAME']) OR ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
+				empty($attributes['NAME']) OR $sql .= ' '.$this->db->escape_identifiers($attributes['NAME']).' ';
 
 				if ( ! empty($attributes['TYPE']))
 				{
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index ad9ac90..3d25b25 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -606,10 +606,7 @@
 		}
 
 		// If the escape value was not set will will base it on the global setting
-		if ( ! is_bool($escape))
-		{
-			$escape = $this->_protect_identifiers;
-		}
+		is_bool($escape) OR $escape = $this->_protect_identifiers;
 
 		foreach ($key as $k => $v)
 		{
diff --git a/system/helpers/date_helper.php b/system/helpers/date_helper.php
index 077a671..cafb6ba 100644
--- a/system/helpers/date_helper.php
+++ b/system/helpers/date_helper.php
@@ -304,13 +304,13 @@
 			$time = time();
 		}
 
-		return gmmktime(
-			date('G', $time),
-			date('i', $time),
-			date('s', $time),
-			date('n', $time),
-			date('j', $time),
-			date('Y', $time)
+		return mktime(
+			gmdate('G', $time),
+			gmdate('i', $time),
+			gmdate('s', $time),
+			gmdate('n', $time),
+			gmdate('j', $time),
+			gmdate('Y', $time)
 		);
 	}
 }
@@ -488,6 +488,10 @@
 		{
 			return 'Unknown';
 		}
+		elseif (empty($format))
+		{
+			$format = 'U';
+		}
 
 		// Date like: YYYYMM
 		if (preg_match('/^\d{6}$/i', $bad_date))
diff --git a/system/helpers/download_helper.php b/system/helpers/download_helper.php
index 5efbc49..09c4de5 100644
--- a/system/helpers/download_helper.php
+++ b/system/helpers/download_helper.php
@@ -46,7 +46,7 @@
 	 *
 	 * @param	string	filename
 	 * @param	mixed	the data to be downloaded
-	 * @param	bool	wether to try and send the actual file MIME type
+	 * @param	bool	whether to try and send the actual file MIME type
 	 * @return	void
 	 */
 	function force_download($filename = '', $data = '', $set_mime = FALSE)
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index 9846343..0c5d550 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -62,9 +62,11 @@
 		{
 			$action = $CI->config->site_url($action);
 		}
-
-		// If no action is provided then set to the current url
-		$action OR $action = $CI->config->site_url($CI->uri->uri_string());
+		elseif ( ! $action)
+		{
+			// If no action is provided then set to the current url
+			$action = $CI->config->site_url($CI->uri->uri_string());
+		}
 
 		$form = '<form action="'.$action.'"'._attributes_to_string($attributes, TRUE).">\n";
 
@@ -76,7 +78,7 @@
 
 		if (is_array($hidden) && count($hidden) > 0)
 		{
-			$form .= sprintf('<div style="display:none;">%s</div>', form_hidden($hidden));
+			$form .= '<div style="display:none;">'.form_hidden($hidden).'</div>';
 		}
 
 		return $form;
diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php
index 3e6e914..7fcb184 100644
--- a/system/helpers/security_helper.php
+++ b/system/helpers/security_helper.php
@@ -123,7 +123,7 @@
 	 */
 	function encode_php_tags($str)
 	{
-		return str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
+		return str_replace(array('<?', '?>'),  array('&lt;?', '?&gt;'), $str);
 	}
 }
 
diff --git a/system/helpers/url_helper.php b/system/helpers/url_helper.php
index 2bd41b0..40ce807 100644
--- a/system/helpers/url_helper.php
+++ b/system/helpers/url_helper.php
@@ -199,26 +199,33 @@
 
 		if ($attributes === FALSE)
 		{
-			return '<a href="javascript:void(0);" onclick="window.open(\''.$site_url."', '_blank');\">".$title.'</a>';
+			return '<a href="'.$site_url.'" onclick="window.open(\''.$site_url."', '_blank'); return false;\">".$title.'</a>';
 		}
 
 		if ( ! is_array($attributes))
 		{
-			$attributes = array();
+			$attributes = array($attributes);
+
+			// Ref: http://www.w3schools.com/jsref/met_win_open.asp
+			$window_name = '_blank';
+		}
+		elseif ( ! empty($attributes['window_name']))
+		{
+			$window_name = $attributes['window_name'];
+			unset($attributes['window_name']);
 		}
 
-		foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0', ) as $key => $val)
+		foreach (array('width' => '800', 'height' => '600', 'scrollbars' => 'yes', 'status' => 'yes', 'resizable' => 'yes', 'screenx' => '0', 'screeny' => '0') as $key => $val)
 		{
 			$atts[$key] = isset($attributes[$key]) ? $attributes[$key] : $val;
 			unset($attributes[$key]);
 		}
 
-		if ($attributes !== '')
-		{
-			$attributes = _parse_attributes($attributes);
-		}
+		$attributes = empty($attributes) ? '' : _parse_attributes($attributes);
 
-		return '<a href="javascript:void(0);" onclick="window.open(\''.$site_url."', '_blank', '"._parse_attributes($atts, TRUE)."');\"".$attributes.'>'.$title.'</a>';
+		return '<a href="'.$site_url
+			.'" onclick="window.open(\''.$site_url."', '".$window_name."', '"._parse_attributes($atts, TRUE)."'); return false;\""
+			.$attributes.'>'.$title.'</a>';
 	}
 }
 
diff --git a/system/libraries/Calendar.php b/system/libraries/Calendar.php
index 969a761..a49f171 100644
--- a/system/libraries/Calendar.php
+++ b/system/libraries/Calendar.php
@@ -155,7 +155,7 @@
 	public function generate($year = '', $month = '', $data = array())
 	{
 		// Set and validate the supplied month/year
-		if ($year === '')
+		if (empty($year))
 		{
 			$year  = date('Y', $this->local_time);
 		}
@@ -168,7 +168,7 @@
 			$year = '20'.$year;
 		}
 
-		if ($month === '')
+		if (empty($month))
 		{
 			$month = date('m', $this->local_time);
 		}
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index 6cbe032..fb1c69c 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -993,15 +993,19 @@
 	 * Minimum Length
 	 *
 	 * @param	string
-	 * @param	int
+	 * @param	string
 	 * @return	bool
 	 */
 	public function min_length($str, $val)
 	{
-		if (preg_match('/[^0-9]/', $val))
+		if ( ! is_numeric($val))
 		{
 			return FALSE;
 		}
+		else
+		{
+			$val = (int) $val;
+		}
 
 		return (MB_ENABLED === TRUE)
 			? ($val <= mb_strlen($str))
@@ -1014,15 +1018,19 @@
 	 * Max Length
 	 *
 	 * @param	string
-	 * @param	int
+	 * @param	string
 	 * @return	bool
 	 */
 	public function max_length($str, $val)
 	{
-		if (preg_match('/[^0-9]/', $val))
+		if ( ! is_numeric($val))
 		{
 			return FALSE;
 		}
+		else
+		{
+			$val = (int) $val;
+		}
 
 		return (MB_ENABLED === TRUE)
 			? ($val >= mb_strlen($str))
@@ -1035,15 +1043,19 @@
 	 * Exact Length
 	 *
 	 * @param	string
-	 * @param	int
+	 * @param	string
 	 * @return	bool
 	 */
 	public function exact_length($str, $val)
 	{
-		if (preg_match('/[^0-9]/', $val))
+		if ( ! is_numeric($val))
 		{
 			return FALSE;
 		}
+		else
+		{
+			$val = (int) $val;
+		}
 
 		return (MB_ENABLED === TRUE)
 			? (mb_strlen($str) === $val)
@@ -1370,7 +1382,7 @@
 	 */
 	public function encode_php_tags($str)
 	{
-		return str_replace(array('<?php', '<?PHP', '<?', '?>'),  array('&lt;?php', '&lt;?PHP', '&lt;?', '?&gt;'), $str);
+		return str_replace(array('<?', '?>'),  array('&lt;?', '?&gt;'), $str);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index d96088c..1e961f6 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -116,6 +116,12 @@
 	 */
 	public function set_sections($config)
 	{
+		if (isset($config['query_toggle_count']))
+		{
+			$this->_query_toggle_count = (int) $config['query_toggle_count'];
+			unset($config['query_toggle_count']);
+		}
+
 		foreach ($config as $method => $enable)
 		{
 			if (in_array($method, $this->_available_sections))
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index c96daaf..d381440 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -59,6 +59,7 @@
 	public $error_msg		= array();
 	public $mimes			= array();
 	public $remove_spaces		= TRUE;
+	public $detect_mime		= TRUE;
 	public $xss_clean		= FALSE;
 	public $temp_prefix		= 'temp_file_';
 	public $client_name		= '';
@@ -116,6 +117,7 @@
 					'image_size_str'		=> '',
 					'error_msg'			=> array(),
 					'remove_spaces'			=> TRUE,
+					'detect_mime'			=> TRUE,
 					'xss_clean'			=> FALSE,
 					'temp_prefix'			=> 'temp_file_',
 					'client_name'			=> ''
@@ -209,7 +211,13 @@
 		// Set the uploaded data as class variables
 		$this->file_temp = $_FILES[$field]['tmp_name'];
 		$this->file_size = $_FILES[$field]['size'];
-		$this->_file_mime_type($_FILES[$field]);
+
+		// Skip MIME type detection?
+		if ($this->detect_mime !== FALSE)
+		{
+			$this->_file_mime_type($_FILES[$field]);
+		}
+
 		$this->file_type = preg_replace('/^(.+?);.*$/', '\\1', $this->file_type);
 		$this->file_type = strtolower(trim(stripslashes($this->file_type), '"'));
 		$this->file_name = $this->_prep_filename($_FILES[$field]['name']);
@@ -990,7 +998,7 @@
 		 */
 		if (function_exists('finfo_file'))
 		{
-			$finfo = finfo_open(FILEINFO_MIME);
+			$finfo = @finfo_open(FILEINFO_MIME);
 			if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
 			{
 				$mime = @finfo_file($finfo, $file['tmp_name']);
@@ -1021,7 +1029,9 @@
 		 */
 		if (DIRECTORY_SEPARATOR !== '\\')
 		{
-			$cmd = 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1';
+			$cmd = function_exists('escapeshellarg')
+				? 'file --brief --mime '.escapeshellarg($file['tmp_name']).' 2>&1'
+				: 'file --brief --mime '.$file['tmp_name'].' 2>&1';
 
 			if (function_exists('exec'))
 			{
diff --git a/system/libraries/Zip.php b/system/libraries/Zip.php
index e0dc637..5c4c257 100644
--- a/system/libraries/Zip.php
+++ b/system/libraries/Zip.php
@@ -40,7 +40,7 @@
  * @author		EllisLab Dev Team
  * @link		http://codeigniter.com/user_guide/libraries/zip.html
  */
-class CI_Zip  {
+class CI_Zip {
 
 	/**
 	 * Zip data in string form
diff --git a/tests/codeigniter/helpers/date_helper_test.php b/tests/codeigniter/helpers/date_helper_test.php
index 1d397ac..8258c92 100644
--- a/tests/codeigniter/helpers/date_helper_test.php
+++ b/tests/codeigniter/helpers/date_helper_test.php
@@ -196,9 +196,9 @@
 	public function test_local_to_gmt()
 	{
 		$this->assertEquals(
-			gmmktime(
-				date('G', $this->time), date('i', $this->time), date('s', $this->time),
-				date('n', $this->time), date('j', $this->time), date('Y', $this->time)
+			mktime(
+				gmdate('G', $this->time), gmdate('i', $this->time), gmdate('s', $this->time),
+				gmdate('n', $this->time), gmdate('j', $this->time), gmdate('Y', $this->time)
 			),
 			local_to_gmt($this->time)
 		);
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 7748f9b..dd6fa46 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -30,9 +30,12 @@
    -  Added support for 3gp, 3g2, mp4, wmv, f4v, vlc Video files to mimes.php.
    -  Added support for m4a, aac, m4u, xspf, au, ac3, flac, ogg Audio files to mimes.php.
    -  Added support for kmz and kml (Google Earth) files to mimes.php.
-   -  Added support for ics Calendar files to mimes.php
+   -  Added support for ics Calendar files to mimes.php.
+   -  Added support for rar archives to mimes.php.
    -  Updated support for xml ('application/xml') and xsl ('application/xml', 'text/xsl') files in mimes.php.
    -  Updated support for doc files in mimes.php.
+   -  Updated support for php files in mimes.php.
+   -  Updated support for zip files in mimes.php.
    -  Added some more doctypes.
    -  Added Romanian and Greek characters in foreign_characters.php.
    -  Changed logger to only chmod when file is first created.
@@ -50,7 +53,10 @@
 
    -  :doc:`Date Helper <helpers/date_helper>` function now() now works with all timezone strings supported by PHP.
    -  ``create_captcha()`` accepts additional colors parameter, allowing for color customization.
-   -  ``url_title()`` will now trim extra dashes from beginning and end.
+   -  :doc:`URL Helper <helpers/url_helper>` changes include:
+	 - ``url_title()`` will now trim extra dashes from beginning and end.
+	 - ``anchor_popup()`` will now fill the "href" attribute with the URL and its JS code will return false instead.
+	 - Added JS window name support to ``anchor_popup()`` function.
    -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
    -  Changed ``humanize()`` to include a second param for the separator.
    -  Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
@@ -71,8 +77,7 @@
 	 - Renamed the Active Record class to Query Builder to remove confusion with the Active Record design pattern.
 	 - Added the ability to insert objects with insert_batch().
 	 - Added new methods that return the SQL string of queries without executing them: get_compiled_select(), get_compiled_insert(), get_compiled_update(), get_compiled_delete().
-	 - Added an optional order_by() parameter that allows to disable escaping (useful for custom fields).
-	 - Added an optional join() parameter that allows to disable escaping.
+	 - Added an optional parameter that allows to disable escaping (useful for custom fields) for methods join(), order_by(), where_in(), or_where_in(), where_not_in(), or_where_not_in().
 	 - Added support for join() with multiple conditions.
    -  Improved support for the MySQLi driver, including:
 	 - OOP style of the PHP extension is now used, instead of the procedural aliases.
@@ -161,12 +166,12 @@
 
 -  Core
 
-   -  Changed private functions in CI_URI to protected so MY_URI can override them.
+   -  Changed private methods in the :doc:`URI Library <libraries/uri>` to protected so MY_URI can override them.
    -  Removed CI_CORE boolean constant from CodeIgniter.php (no longer Reactor and Core versions).
-   -  Added method get_vars() to CI_Loader to retrieve all variables loaded with $this->load->vars().
+   -  Added method get_vars() to the :doc:`Loader Library <libraries/loader>` to retrieve all variables loaded with $this->load->vars().
    -  is_loaded() function from system/core/Commons.php now returns a reference.
    -  $config['rewrite_short_tags'] now has no effect when using PHP 5.4 as *<?=* will always be available.
-   -  Added method() to CI_Input to retrieve $_SERVER['REQUEST_METHOD'].
+   -  Added method() to the :doc:`Input Library <libraries/input>` to retrieve $_SERVER['REQUEST_METHOD'].
    -  Modified valid_ip() to use PHP's filter_var() in the :doc:`Input Library <libraries/input>`.
    -  Added support for HTTP-Only cookies with new config option ``cookie_httponly`` (default FALSE).
    -  Renamed method _call_hook() to call_hook() in the :doc:`Hooks Library <general/hooks>`.
@@ -174,6 +179,8 @@
    -  Added get_mimes() function to system/core/Commons.php to return the config/mimes.php array.
    -  Added a second argument to set_content_type() in the :doc:`Output Library <libraries/output>` that allows setting the document charset as well.
    -  $config['time_reference'] now supports all timezone strings supported by PHP.
+   -  Added support for HTTP code 303 ("See Other") in set_status_header().
+   -  Changed :doc:`Config Library <libraries/config>` method site_url() to accept an array as well.
 
 Bug fixes for 3.0
 ------------------
@@ -270,6 +277,12 @@
 -  Fixed a bug in protect_identifiers() where if passed along with the field names, operators got escaped as well.
 -  Fixed a bug (#10) - :doc:`URI Library <libraries/uri>` internal method _detect_uri() failed with paths containing a colon.
 -  Fixed a bug (#1387) - :doc:`Query Builder <database/query_builder>`'s from() method didn't escape table aliases.
+-  Fixed a bug (#520) - :doc:`Date Helper <helpers/date_helper>` function nice_date() failed when the optional second parameter is not passed.
+-  Fixed a bug (#167) - ``$config['permitted_uri_chars']`` didn't affect URL-encoded characters.
+-  Fixed a bug (#318) - :doc:`Profiling <general/profiling>` setting *query_toggle_count* was not settable as described in the manual.
+-  Fixed a bug (#938) - :doc:`Config Library <libraries/config>` method site_url() added a question mark to the URL string when query strings are enabled even if it already existed.
+-  Fixed a bug (#999) - :doc:`Config Library <libraries/config>` method site_url() always appended ``$config['url_suffix']`` to the end of the URL string, regardless of wether a query string exists in it.
+-  Fixed a bug where :doc:`URL Helper <helpers/url_helper>` function anchor_popup() ignored the attributes argument if it is not an array.
 
 Version 2.1.1
 =============
diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst
index d23efec..11dd783 100644
--- a/user_guide_src/source/database/queries.rst
+++ b/user_guide_src/source/database/queries.rst
@@ -21,11 +21,31 @@
 $this->db->simple_query();
 ===========================
 
-This is a simplified version of the $this->db->query() function. It ONLY
-returns TRUE/FALSE on success or failure. It DOES NOT return a database
-result set, nor does it set the query timer, or compile bind data, or
-store your query for debugging. It simply lets you submit a query. Most
-users will rarely use this function.
+This is a simplified version of the $this->db->query() method. It DOES
+NOT return a database result set, nor does it set the query timer, or
+compile bind data, or store your query for debugging. It simply lets you
+submit a query. Most users will rarely use this function.
+
+It returns whatever the database drivers' "execute" function returns.
+That typically is TRUE/FALSE on success or failure for write type queries
+such as INSERT, DELETE or UPDATE statements (which is what it really
+should be used for) and a resource/object on success for queries with
+fetchable results.
+
+::
+
+	if ($this->db->simple_query('YOUR QUERY'))
+	{
+		echo "Success!";
+	}
+	else
+	{
+		echo "Query failed!";
+	}
+
+.. note:: PostgreSQL's pg_exec() function always returns a resource on
+	success, even for write type queries. So take that in mind if
+	you're looking for a boolean value.
 
 ***************************************
 Working with Database prefixes manually
diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst
index 54e8df6..b86a0c8 100644
--- a/user_guide_src/source/database/query_builder.rst
+++ b/user_guide_src/source/database/query_builder.rst
@@ -603,9 +603,9 @@
 
 	/*
 	class Myclass {
-		var  $title = 'My Title';
-		var  $content = 'My Content';
-		var  $date = 'My Date';
+		public $title = 'My Title';
+		public $content = 'My Content';
+		public $date = 'My Date';
 	}
 	*/
 
@@ -730,9 +730,9 @@
 
 	/*
 	class Myclass {
-		var  $title = 'My Title';
-		var  $content = 'My Content';
-		var  $date = 'My Date';
+		public $title = 'My Title';
+		public $content = 'My Content';
+		public $date = 'My Date';
 	}
 	*/
 
@@ -766,9 +766,9 @@
 
 	/*
 	class Myclass {
-		var  $title = 'My Title';
-		var  $content = 'My Content';
-		var  $date = 'My Date';
+		public $title = 'My Title';
+		public $content = 'My Content';
+		public $date = 'My Date';
 	}
 	*/
 
diff --git a/user_guide_src/source/general/models.rst b/user_guide_src/source/general/models.rst
index 87f63e4..2e1e025 100644
--- a/user_guide_src/source/general/models.rst
+++ b/user_guide_src/source/general/models.rst
@@ -18,9 +18,9 @@
 
 	class Blog_model extends CI_Model {
 
-	    var $title   = '';
-	    var $content = '';
-	    var $date    = '';
+	    public $title   = '';
+	    public $content = '';
+	    public $date    = '';
 
 	    function __construct()
 	    {
diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst
index 1b7177f..b6dc2e9 100644
--- a/user_guide_src/source/helpers/date_helper.rst
+++ b/user_guide_src/source/helpers/date_helper.rst
@@ -247,16 +247,18 @@
 
 ::
 
-	$bad_time = 199605  // Should Produce: 1996-05-01
-	$better_time = nice_date($bad_time,'Y-m-d');
-	$bad_time = 9-11-2001 // Should Produce: 2001-09-11
-	$better_time = nice_date($human,'Y-m-d');
+	$bad_date = '199605';
+	// Should Produce: 1996-05-01
+	$better_date = nice_date($bad_date, 'Y-m-d');
+
+	$bad_date = '9-11-2001';
+	// Should Produce: 2001-09-11
+	$better_date = nice_date($bad_date, 'Y-m-d');
 
 timespan()
 ==========
 
 Formats a unix timestamp so that is appears similar to this
-
 ::
 
 	1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes
diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst
index e6d51b2..3c91fd5 100644
--- a/user_guide_src/source/helpers/url_helper.rst
+++ b/user_guide_src/source/helpers/url_helper.rst
@@ -168,19 +168,20 @@
 
 ::
 
-	$atts = array(               
-		'width'      => '800',               
-		'height'     => '600',               
-		'scrollbars' => 'yes',               
-		'status'     => 'yes',               
-		'resizable'  => 'yes',               
-		'screenx'    => '0',               
-		'screeny'    => '0'             
+	$atts = array(
+		'width'       => '800',
+		'height'      => '600',
+		'scrollbars'  => 'yes',
+		'status'      => 'yes',
+		'resizable'   => 'yes',
+		'screenx'     => '0',
+		'screeny'     => '0',
+		'window_name' => '_blank'
 	);
 
 	echo anchor_popup('news/local/123', 'Click Me!', $atts);
 
-Note: The above attributes are the function defaults so you only need to
+.. note:: The above attributes are the function defaults so you only need to
 set the ones that are different from what you need. If you want the
 function to use all of its defaults simply pass an empty array in the
 third parameter
@@ -189,6 +190,13 @@
 
 	echo anchor_popup('news/local/123', 'Click Me!', array());
 
+.. note:: The 'window_name' is not really an attribute, but an argument to
+	the JavaScript `window.open() <http://www.w3schools.com/jsref/met_win_open.asp>`
+	method, which accepts either a window name or a window target.
+
+.. note:: Any other attribute than the listed above will be parsed as an
+	HTML attribute to the anchor tag.
+
 mailto()
 ========
 
diff --git a/user_guide_src/source/libraries/config.rst b/user_guide_src/source/libraries/config.rst
index 08d9c29..6948963 100644
--- a/user_guide_src/source/libraries/config.rst
+++ b/user_guide_src/source/libraries/config.rst
@@ -175,7 +175,7 @@
 as to a stylesheet or image.
 
 The two functions above are normally accessed via the corresponding
-functions in the :doc:`URL Helper </helpers/url_helper>`.
+functions in the :doc:`URL Helper <helpers/url_helper>`.
 
 $this->config->system_url();
 *****************************
diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst
index 28bdca2..a381222 100644
--- a/user_guide_src/source/libraries/encryption.rst
+++ b/user_guide_src/source/libraries/encryption.rst
@@ -26,7 +26,7 @@
 anything that requires high security, like storing credit card numbers.
 
 To take maximum advantage of the encryption algorithm, your key should
-be 32 characters in length (128 bits). The key should be as random a
+be 32 characters in length (256 bits). The key should be as random a
 string as you can concoct, with numbers and uppercase and lowercase
 letters. Your key should **not** be a simple text string. In order to be
 cryptographically secure it needs to be as random as possible.
diff --git a/user_guide_src/source/libraries/file_uploading.rst b/user_guide_src/source/libraries/file_uploading.rst
index 414d84f..65cd5c7 100644
--- a/user_guide_src/source/libraries/file_uploading.rst
+++ b/user_guide_src/source/libraries/file_uploading.rst
@@ -215,6 +215,9 @@
                                                                        that can not be discerned by the person uploading it.
 **remove_spaces**            TRUE              TRUE/FALSE (boolean)    If set to TRUE, any spaces in the file name will be converted to
                                                                        underscores. This is recommended.
+**detect_mime**              TRUE              TRUE/FALSE (boolean)    If set to TRUE, a server side detection of the file type will be
+                                                                       performed to avoid code injection attacks. DO NOT disable this option
+                                                                       unless you have no other option as that would cause a security risk.
 ============================ ================= ======================= ======================================================================
 
 Setting preferences in a config file