Merge branch 'patch-1' of https://github.com/has2k1/CodeIgniter into has2k1-patch-1

Conflicts:
	user_guide_src/source/changelog.rst
diff --git a/application/config/migration.php b/application/config/migration.php
index f568574..4fb027b 100644
--- a/application/config/migration.php
+++ b/application/config/migration.php
@@ -90,5 +90,4 @@
 $config['migration_path'] = APPPATH . 'migrations/';
 
 
-/* End of file migration.php */
-/* Location: ./application/config/migration.php */
\ No newline at end of file
+/* End of file migration.php */
\ No newline at end of file
diff --git a/application/config/user_agents.php b/application/config/user_agents.php
index 03cba9b..c3c7eae 100644
--- a/application/config/user_agents.php
+++ b/application/config/user_agents.php
@@ -174,6 +174,7 @@
 	'mobilexplorer'	=> "Mobile Explorer",
 	'operamini'		=> "Opera Mini",
 	'opera mini'	=> "Opera Mini",
+	'opera mobi'	=> "Opera Mini",
 
 	// Other
 	'digital paths'	=> "Digital Paths",
diff --git a/system/core/Common.php b/system/core/Common.php
index e43bb8d..b0921fe 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -419,6 +419,7 @@
 							415	=> 'Unsupported Media Type',
 							416	=> 'Requested Range Not Satisfiable',
 							417	=> 'Expectation Failed',
+							422	=> 'Unprocessable Entity',
 
 							500	=> 'Internal Server Error',
 							501	=> 'Not Implemented',
diff --git a/system/core/Input.php b/system/core/Input.php
index 946d929..3cbbe78 100755
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -740,7 +740,6 @@
 	}
 
 }
-// END Input class
 
 /* End of file Input.php */
 /* Location: ./system/core/Input.php */
diff --git a/system/core/Security.php b/system/core/Security.php
index ee4f0a0..ce3f7d3 100755
--- a/system/core/Security.php
+++ b/system/core/Security.php
@@ -95,7 +95,8 @@
 					'-moz-binding'		=> '[removed]',
 					'<!--'				=> '&lt;!--',
 					'-->'				=> '--&gt;',
-					'<![CDATA['			=> '&lt;![CDATA['
+					'<![CDATA['			=> '&lt;![CDATA[',
+					'<comment>'			=> '&lt;comment&gt;'
 	);
 
 	/**
@@ -498,15 +499,7 @@
 	{
 		if ($this->_xss_hash == '')
 		{
-			if (phpversion() >= 4.2)
-			{
-				mt_srand();
-			}
-			else
-			{
-				mt_srand(hexdec(substr(md5(microtime()), -8)) & 0x7fffffff);
-			}
-
+			mt_srand();
 			$this->_xss_hash = md5(time() + mt_rand(0, 1999999999));
 		}
 
@@ -520,6 +513,12 @@
 	 *
 	 * This function is 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
+	 * at the end of an entity most browsers will still interpret the entity
+	 * 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
 	 * @return	string
@@ -536,11 +535,6 @@
 			$charset = config_item('charset');
 		}
 
-		// The reason we are not using html_entity_decode() by itself is because
-		// while it is not technically correct to leave out the semicolon
-		// at the end of an entity most browsers will still interpret the entity
-		// correctly.  html_entity_decode() does not convert entities without
-		// semicolons, so we are left with our own little solution here. Bummer.
 		$str = html_entity_decode($str, ENT_COMPAT, $charset);
 		$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
 		return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
@@ -637,25 +631,45 @@
 	protected function _remove_evil_attributes($str, $is_image)
 	{
 		// All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns
-		$evil_attributes = array('on\w*', 'style', 'xmlns');
+		$evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction');
 
 		if ($is_image === TRUE)
 		{
 			/*
-			 * Adobe Photoshop puts XML metadata into JFIF images,
+			 * Adobe Photoshop puts XML metadata into JFIF images, 
 			 * including namespacing, so we have to allow this for images.
 			 */
 			unset($evil_attributes[array_search('xmlns', $evil_attributes)]);
 		}
-
+		
 		do {
-			$str = preg_replace(
-				"#<(/?[^><]+?)([^A-Za-z\-])(".implode('|', $evil_attributes).")(\s*=\s*)([\"][^>]*?[\"]|[\'][^>]*?[\']|[^>]*?)([\s><])([><]*)#i",
-				"<$1$6",
-				$str, -1, $count
-			);
-		} while ($count);
+			$count = 0;
+			$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);
+			
+			foreach ($matches as $attr)
+			{
+				$attribs[] = preg_quote($attr[0], '/');
+			}
+			
+			// find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes)
+			preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is",  $str, $matches, PREG_SET_ORDER);
 
+			foreach ($matches as $attr)
+			{
+				$attribs[] = preg_quote($attr[0], '/');
+			}
+
+			// 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);
+			}
+			
+		} while ($count);
+		
 		return $str;
 	}
 
@@ -877,4 +891,4 @@
 }
 
 /* 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/database/DB_driver.php b/system/database/DB_driver.php
index dd1b567..cc40ba4 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -522,6 +522,7 @@
 		}
 
 		$this->trans_begin($test_mode);
+		$this->_trans_depth += 1;
 	}
 
 	// --------------------------------------------------------------------
@@ -545,6 +546,10 @@
 			$this->_trans_depth -= 1;
 			return TRUE;
 		}
+		else
+		{
+			$this->_trans_depth = 0;
+		}
 
 		// The query() function will set this flag to FALSE in the event that a query failed
 		if ($this->_trans_status === FALSE)
diff --git a/system/database/drivers/mysql/mysql_result.php b/system/database/drivers/mysql/mysql_result.php
index 66f782d..29297b6 100644
--- a/system/database/drivers/mysql/mysql_result.php
+++ b/system/database/drivers/mysql/mysql_result.php
@@ -98,10 +98,10 @@
 		$retval = array();
 		while ($field = mysql_fetch_object($this->result_id))
 		{
-			preg_match('/([a-zA-Z]+)(\((\d+)\))?/i', $field->Type, $matches);
+			preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches);
 
-			$type = $matches[1];
-			$length = isset($matches[3]) ? (int) $matches[3] : NULL;
+			$type = (array_key_exists(1, $matches)) ? $matches[1] : NULL;
+			$length = (array_key_exists(2, $matches)) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
 
 			$F				= new stdClass();
 			$F->name		= $field->Field;
diff --git a/system/database/drivers/mysqli/mysqli_result.php b/system/database/drivers/mysqli/mysqli_result.php
index bfe500e..163788b 100644
--- a/system/database/drivers/mysqli/mysqli_result.php
+++ b/system/database/drivers/mysqli/mysqli_result.php
@@ -98,10 +98,10 @@
 		$retval = array();
 		while ($field = mysqli_fetch_object($this->result_id))
 		{
-			preg_match('/([a-zA-Z]+)(\((\d+)\))?/i', $field->Type, $matches);
+			preg_match('/([a-zA-Z]+)(\(\d+\))?/', $field->Type, $matches);
 
-			$type = $matches[1];
-			$length = isset($matches[3]) ? (int) $matches[3] : NULL;
+			$type = (array_key_exists(1, $matches)) ? $matches[1] : NULL;
+			$length = (array_key_exists(2, $matches)) ? preg_replace('/[^\d]/', '', $matches[2]) : NULL;
 
 			$F				= new stdClass();
 			$F->name		= $field->Field;
diff --git a/system/database/drivers/pdo/pdo_driver.php b/system/database/drivers/pdo/pdo_driver.php
index a66a16e..5f63a37 100644
--- a/system/database/drivers/pdo/pdo_driver.php
+++ b/system/database/drivers/pdo/pdo_driver.php
@@ -255,7 +255,11 @@
 		// Reset the transaction failure flag.
 		// If the $test_mode flag is set to TRUE transactions will be rolled back
 		// even if the queries produce a successful result.
+<<<<<<< HEAD
 		$this->_trans_failure = ($test_mode === TRUE) ? TRUE : FALSE;
+=======
+		$this->_trans_failure = (bool) ($test_mode === TRUE);
+>>>>>>> master
 
 		return $this->conn_id->beginTransaction();
 	}
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 6739db3..631b62e 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -418,11 +418,11 @@
 	 * @param	string
 	 * @return	void
 	 */
-	public function attach($filename, $disposition = 'attachment')
+	public function attach($filename, $disposition = '', $newname = NULL)
 	{
-		$this->_attach_name[] = $filename;
+		$this->_attach_name[] = array($filename, $newname);
 		$this->_attach_type[] = $this->_mime_types(pathinfo($filename, PATHINFO_EXTENSION));
-		$this->_attach_disp[] = $disposition; // Can also be 'inline'  Not sure if it matters
+		$this->_attach_disp[] = empty($disposition) ? 'attachment' : $disposition; // Can also be 'inline'  Not sure if it matters
 		return $this;
 	}
 
@@ -1151,8 +1151,9 @@
 
 		for ($i=0; $i < count($this->_attach_name); $i++)
 		{
-			$filename = $this->_attach_name[$i];
-			$basename = basename($filename);
+			$filename = $this->_attach_name[$i][0];
+			$basename = ( is_null($this->_attach_name[$i][1]) ? basename($filename) : $this->_attach_name[$i][1] );
+				
 			$ctype = $this->_attach_type[$i];
 
 			if ( ! file_exists($filename))
@@ -1692,12 +1693,7 @@
 	 */
 	protected function _smtp_connect()
 	{
-		$ssl = NULL;
-
-		if ($this->smtp_crypto == 'ssl')
-		{
-			$ssl = 'ssl://';
-		}
+		$ssl = ($this->smtp_crypto == 'ssl') ? 'ssl://' : NULL;
 
 		$this->_smtp_connect = fsockopen($ssl.$this->smtp_host,
 										$this->smtp_port,
@@ -1717,6 +1713,7 @@
 		{
 			$this->_send_command('hello');
 			$this->_send_command('starttls');
+
 			$crypto = stream_socket_enable_crypto($this->_smtp_connect, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT);
 
 			if ($crypto !== TRUE)
@@ -2112,4 +2109,4 @@
 // END CI_Email class
 
 /* End of file Email.php */
-/* Location: ./system/libraries/Email.php */
+/* Location: ./system/libraries/Email.php */
\ No newline at end of file
diff --git a/system/libraries/Pagination.php b/system/libraries/Pagination.php
index 7398c29..f470deb 100644
--- a/system/libraries/Pagination.php
+++ b/system/libraries/Pagination.php
@@ -298,11 +298,11 @@
 		if ($this->last_link !== FALSE AND ($this->cur_page + $this->num_links) < $num_pages)
 		{
 			$i = ($this->use_page_numbers) ? $num_pages : ($num_pages * $this->per_page) - $this->per_page;
-			
+
 			$output .= $this->last_tag_open.'<a '.$this->anchor_class.'href="'.$this->base_url.$this->prefix.$i.$this->suffix.'">'.$this->last_link.'</a>'.$this->last_tag_close;
 		}
 
-		// Kill double slashes.  Note: Sometimes we can end up with a double slash
+		// Kill double slashes. Note: Sometimes we can end up with a double slash
 		// in the penultimate link so we'll kill all double slashes.
 		$output = preg_replace("#([^:])//+#", "\\1/", $output);
 
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index 56062be..66e91c5 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -1033,7 +1033,7 @@
 	protected function _file_mime_type($file)
 	{
 		// Use if the Fileinfo extension, if available (only versions above 5.3 support the FILEINFO_MIME_TYPE flag)
-		if (is_php('5.3') && function_exists('finfo_file'))
+		if ( (float) substr(phpversion(), 0, 3) >= 5.3 && function_exists('finfo_file'))
 		{
 			$finfo = new finfo(FILEINFO_MIME_TYPE);
 			if ($finfo !== FALSE) // This is possible, if there is no magic MIME database file found on the system
@@ -1086,4 +1086,4 @@
 // END Upload Class
 
 /* End of file Upload.php */
-/* Location: ./system/libraries/Upload.php */
+/* Location: ./system/libraries/Upload.php */
\ No newline at end of file
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 1bd0976..979755c 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -35,8 +35,8 @@
 
 -  Database
 
-   -  Added new :doc:`Active Record <database/active_record>` methods that return 
-      the SQL string of queries without executing them: get_compiled_select(), 
+   -  Added new :doc:`Active Record <database/active_record>` methods that return
+      the SQL string of queries without executing them: get_compiled_select(),
       get_compiled_insert(), get_compiled_update(), get_compiled_delete().
 
 -  Libraries
@@ -44,6 +44,7 @@
    -  Added max_filename_increment config setting for Upload library.
    -  CI_Loader::_ci_autoloader() is now a protected method.
    -  Modified valid_ip() to use PHP's filter_var() when possible (>= PHP 5.2) in the :doc:`Form Validation library <libraries/form_validation>`.
+	 -  Added custom filename to Email::attach() as $this->email->attach($filename, $disposition, $newname)
 
 -  Core
 
@@ -57,9 +58,9 @@
 -  Unlink raised an error if cache file did not exist when you try to delete it.
 -  Fixed a bug (#181) where a mis-spelling was in the form validation
    language file.
+-  Fixed a bug (#159, #163) that mishandled Active Record nested transactions because _trans_depth was not getting incremented.
 -  Bug #419 - auto_link() now recognizes URLs that come after a word boundary.
 
-
 Version 2.1.0
 =============
 
@@ -155,7 +156,7 @@
 -  Fixed a bug (#60) - Added _file_mime_type() method to the :doc:`File Uploading Library <libraries/file_uploading>` in order to fix a possible MIME-type injection.
 -  Fixed a bug (#537) - Support for all wav type in browser.
 -  Fixed a bug (#576) - Using ini_get() function to detect if apc is enabled or not.
-<li>Fixed invalid date time format in <a href="helpers/date_helper.html">Date helper</a> and <a href="libraries/xmlrpc.html">XMLRPC library</a>.</li>
+-  Fixed invalid date time format in :doc:`Date helper <helpers/date_helper>` and :doc:`XMLRPC library <libraries/xmlrpc>`.
 
 Version 2.0.3
 =============
diff --git a/user_guide_src/source/helpers/string_helper.rst b/user_guide_src/source/helpers/string_helper.rst
index b8a69e0..dc70e46 100644
--- a/user_guide_src/source/helpers/string_helper.rst
+++ b/user_guide_src/source/helpers/string_helper.rst
@@ -58,7 +58,7 @@
 
 	echo increment_string('file', '_'); // "file_1"
 	echo increment_string('file', '-', 2); // "file-2"
-	echo increment_string('file-4'); // "file-5"
+	echo increment_string('file_4'); // "file_5"
 
 alternator()
 ============
diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst
index 7598992..27b704d 100644
--- a/user_guide_src/source/libraries/email.rst
+++ b/user_guide_src/source/libraries/email.rst
@@ -228,7 +228,11 @@
 	$this->email->attach('/path/to/photo2.jpg');
 	$this->email->attach('/path/to/photo3.jpg');
 
-	$this->email->send();
+If you'd like to change the disposition or add a custom file name, you can use the second and third paramaters. To use the default disposition (attachment), leave the second parameter blank. Here's an example::
+  
+	$this->email->attach('/path/to/photo1.jpg', 'inline');
+	$this->email->attach('/path/to/photo1.jpg', '', 'birthday.jpg');
+	
 
 $this->email->print_debugger()
 -------------------------------
diff --git a/user_guide_src/source/libraries/image_lib.rst b/user_guide_src/source/libraries/image_lib.rst
index 300cbef..14bd128 100644
--- a/user_guide_src/source/libraries/image_lib.rst
+++ b/user_guide_src/source/libraries/image_lib.rst
@@ -360,7 +360,7 @@
                                                                     image headers.
 **quality**             90%                 1 - 100%                Sets the quality of the image. The higher the quality the larger the
                                                                     file size.
-**padding**             None                A number                The amount of padding, set in pixels, that will be applied to the
+**wm_padding**          None                A number                The amount of padding, set in pixels, that will be applied to the
                                                                     watermark to set it away from the edge of your images.
 **wm_vrt_alignment**    bottom              top, middle, bottom     Sets the vertical alignment for the watermark image.
 **wm_hor_alignment**    center              left, center, right     Sets the horizontal alignment for the watermark image.