Merge pull request #3659 from bjjay/bjjay-patch-1

[ci skip] Correct  a comment link typo
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index 45c5c09..66b5803 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -405,7 +405,7 @@
 	 * @param	array	$config = array()
 	 * @return	void
 	 */
-	public function __construct($config = array())
+	public function __construct(array $config = array())
 	{
 		$this->charset = config_item('charset');
 
diff --git a/system/libraries/Form_validation.php b/system/libraries/Form_validation.php
index f161b40..9d16602 100644
--- a/system/libraries/Form_validation.php
+++ b/system/libraries/Form_validation.php
@@ -1151,9 +1151,7 @@
 			return FALSE;
 		}
 
-		return (MB_ENABLED === TRUE)
-			? ($val <= mb_strlen($str))
-			: ($val <= strlen($str));
+		return ($val <= mb_strlen($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1172,9 +1170,7 @@
 			return FALSE;
 		}
 
-		return (MB_ENABLED === TRUE)
-			? ($val >= mb_strlen($str))
-			: ($val >= strlen($str));
+		return ($val >= mb_strlen($str));
 	}
 
 	// --------------------------------------------------------------------
@@ -1193,9 +1189,7 @@
 			return FALSE;
 		}
 
-		return (MB_ENABLED === TRUE)
-			? (mb_strlen($str) === (int) $val)
-			: (strlen($str) === (int) $val);
+		return (mb_strlen($str) === (int) $val);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Session/Session.php b/system/libraries/Session/Session.php
index f3b819a..54d31ee 100644
--- a/system/libraries/Session/Session.php
+++ b/system/libraries/Session/Session.php
@@ -94,10 +94,7 @@
 			$this->_driver = 'database';
 		}
 
-		if (($class = $this->_ci_load_classes($this->_driver)) === FALSE)
-		{
-			return;
-		}
+		$class = $this->_ci_load_classes($this->_driver);
 
 		// Configuration ...
 		$this->_configure($params);
@@ -230,8 +227,7 @@
 
 			if ( ! class_exists('CI_'.$class, FALSE) && ! class_exists($class, FALSE))
 			{
-				log_message('error', "Session: Configured driver '".$driver."' was not found. Aborting.");
-				return FALSE;
+				throw new \UnexpectedValueException("Session: Configured driver '".$driver."' was not found. Aborting.");
 			}
 		}
 
diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php
index c96eecf..7f467fb 100644
--- a/tests/codeigniter/core/Security_test.php
+++ b/tests/codeigniter/core/Security_test.php
@@ -71,6 +71,47 @@
 		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless_string);
 	}
 
+        // --------------------------------------------------------------------
+
+	public function test_xss_clean_string_array()
+	{
+		$harm_strings = array(
+			"Hello, i try to <script>alert('Hack');</script> your site",
+			"Simple clean string",
+			"Hello, i try to <script>alert('Hack');</script> your site"
+		);
+
+		$harmless_strings = $this->security->xss_clean($harm_strings);
+
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless_strings[0]);
+		$this->assertEquals("Simple clean string", $harmless_strings[1]);
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless_strings[2]);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_xss_clean_image_valid()
+	{
+		$harm_string = '<img src="test.png">';
+
+		$xss_clean_return = $this->security->xss_clean($harm_string, TRUE);
+
+		$this->assertTrue($xss_clean_return);
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_xss_clean_image_invalid()
+	{
+		$harm_string = '<img src=javascript:alert(String.fromCharCode(88,83,83))>';
+
+		$xss_clean_return = $this->security->xss_clean($harm_string, TRUE);
+
+		$this->assertFalse($xss_clean_return);
+	}
+
+	// --------------------------------------------------------------------
+
 	public function test_xss_clean_entity_double_encoded()
 	{
 		$input = '<a href="&#38&#35&#49&#48&#54&#38&#35&#57&#55&#38&#35&#49&#49&#56&#38&#35&#57&#55&#38&#35&#49&#49&#53&#38&#35&#57&#57&#38&#35&#49&#49&#52&#38&#35&#49&#48&#53&#38&#35&#49&#49&#50&#38&#35&#49&#49&#54&#38&#35&#53&#56&#38&#35&#57&#57&#38&#35&#49&#49&#49&#38&#35&#49&#49&#48&#38&#35&#49&#48&#50&#38&#35&#49&#48&#53&#38&#35&#49&#49&#52&#38&#35&#49&#48&#57&#38&#35&#52&#48&#38&#35&#52&#57&#38&#35&#52&#49">Clickhere</a>';
@@ -79,6 +120,22 @@
 
 	// --------------------------------------------------------------------
 
+	public function test_xss_clean_js_img_removal()
+	{
+		$input = '<img src="&#38&#35&#49&#48&#54&#38&#35&#57&#55&#38&#35&#49&#49&#56&#38&#35&#57&#55&#38&#35&#49&#49&#53&#38&#35&#57&#57&#38&#35&#49&#49&#52&#38&#35&#49&#48&#53&#38&#35&#49&#49&#50&#38&#35&#49&#49&#54&#38&#35&#53&#56&#38&#35&#57&#57&#38&#35&#49&#49&#49&#38&#35&#49&#49&#48&#38&#35&#49&#48&#50&#38&#35&#49&#48&#53&#38&#35&#49&#49&#52&#38&#35&#49&#48&#57&#38&#35&#52&#48&#38&#35&#52&#57&#38&#35&#52&#49">Clickhere';
+		$this->assertEquals('<img >', $this->security->xss_clean($input));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_xss_clean_sanitize_naughty_html()
+	{
+		$input = '<blink>';
+		$this->assertEquals('&lt;blink&gt;', $this->security->xss_clean($input));
+	}
+
+	// --------------------------------------------------------------------
+
 	public function test_remove_evil_attributes()
 	{
 		$this->assertEquals('<foo [removed]>', $this->security->remove_evil_attributes('<foo onAttribute="bar">', false));
@@ -103,6 +160,17 @@
 
 	// --------------------------------------------------------------------
 
+	public function test_get_random_bytes()
+	{
+		$length = "invalid";
+		$this->assertFalse($this->security->get_random_bytes($length));
+
+		$length = 10;
+		$this->assertNotEmpty($this->security->get_random_bytes($length));
+	}
+
+	// --------------------------------------------------------------------
+
 	public function test_entity_decode()
 	{
 		$encoded = '&lt;div&gt;Hello &lt;b&gt;Booya&lt;/b&gt;&lt;/div&gt;';
@@ -126,36 +194,55 @@
 
 		$this->assertEquals('foo', $safe_filename);
 	}
-        
-        // --------------------------------------------------------------------
+
+	// --------------------------------------------------------------------
 
 	public function test_strip_image_tags()
 	{
-                $imgtags = Array(
-                    '<img src="smiley.gif" alt="Smiley face" height="42" width="42">',
-                    '<img alt="Smiley face" height="42" width="42" src="smiley.gif">',
-                    '<img src="http://www.w3schools.com/images/w3schools_green.jpg">',
-                    '<img src="/img/sunset.gif" height="100%" width="100%">',
-                    '<img src="mdn-logo-sm.png" alt="MD Logo" srcset="mdn-logo-HD.png 2x, mdn-logo-small.png 15w, mdn-banner-HD.png 100w 2x" />',
-                    '<img sqrc="/img/sunset.gif" height="100%" width="100%">',
-                    '<img srqc="/img/sunset.gif" height="100%" width="100%">',
-                    '<img srcq="/img/sunset.gif" height="100%" width="100%">'
-                );
-                
-                $urls = Array(
-                    'smiley.gif',
-                    'smiley.gif',
-                    'http://www.w3schools.com/images/w3schools_green.jpg',
-                    '/img/sunset.gif',
-                    'mdn-logo-sm.png',
-                    '<img sqrc="/img/sunset.gif" height="100%" width="100%">',
-                    '<img srqc="/img/sunset.gif" height="100%" width="100%">',
-                    '<img srcq="/img/sunset.gif" height="100%" width="100%">'
-                );
-                
-                for($i = 0; $i < count($imgtags); $i++) 
-                {
-                    $this->assertEquals($urls[$i], $this->security->strip_image_tags($imgtags[$i]));
-                }
+		$imgtags = Array(
+			'<img src="smiley.gif" alt="Smiley face" height="42" width="42">',
+			'<img alt="Smiley face" height="42" width="42" src="smiley.gif">',
+			'<img src="http://www.w3schools.com/images/w3schools_green.jpg">',
+			'<img src="/img/sunset.gif" height="100%" width="100%">',
+			'<img src="mdn-logo-sm.png" alt="MD Logo" srcset="mdn-logo-HD.png 2x, mdn-logo-small.png 15w, mdn-banner-HD.png 100w 2x" />',
+			'<img sqrc="/img/sunset.gif" height="100%" width="100%">',
+			'<img srqc="/img/sunset.gif" height="100%" width="100%">',
+			'<img srcq="/img/sunset.gif" height="100%" width="100%">'
+		);
+
+		$urls = Array(
+			'smiley.gif',
+			'smiley.gif',
+			'http://www.w3schools.com/images/w3schools_green.jpg',
+			'/img/sunset.gif',
+			'mdn-logo-sm.png',
+			'<img sqrc="/img/sunset.gif" height="100%" width="100%">',
+			'<img srqc="/img/sunset.gif" height="100%" width="100%">',
+			'<img srcq="/img/sunset.gif" height="100%" width="100%">'
+		);
+
+		for($i = 0; $i < count($imgtags); $i++) 
+		{
+			$this->assertEquals($urls[$i], $this->security->strip_image_tags($imgtags[$i]));
+		}
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_csrf_set_hash()
+	{
+		// Set cookie for security test
+		$_COOKIE['ci_csrf_cookie'] = md5(uniqid(mt_rand(), TRUE));
+
+		// Set config for Security class
+		$this->ci_set_config('csrf_protection', TRUE);
+		$this->ci_set_config('csrf_token_name', 'ci_csrf_token');
+
+		// leave csrf_cookie_name as blank to test _csrf_set_hash function
+		$this->ci_set_config('csrf_cookie_name', '');
+
+		$this->security = new Mock_Core_Security();
+
+		$this->assertNotEmpty($this->security->get_csrf_hash());
 	}
 }
\ No newline at end of file
diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst
index 5f0979d..0c34760 100644
--- a/user_guide_src/source/libraries/encryption.rst
+++ b/user_guide_src/source/libraries/encryption.rst
@@ -2,6 +2,11 @@
 Encryption Library
 ##################
 
+.. important:: DO NOT use this or any other *encryption* library for
+	user password storage! Passwords must be *hashed* instead, and you
+	should do that via PHP's own `Password Hashing extension
+	<http://php.net/password>`_.
+
 The Encryption Library provides two-way data encryption. To do so in
 a cryptographically secure way, it utilizes PHP extensions that are
 unfortunately not always available on all systems.