CI_URI changes related to the 'permitted_uri_chars' setting

 - Initialize and cache the value in the class constructor instead of searching for it every time
 - Removed the preg_quote() call from _filter_uri() to allow more fine-tuning from configuration
 - Renamed _filter_uri() to filter_uri() - it was public anyway and using it cannot break anything

Related: issue #2799
diff --git a/system/core/URI.php b/system/core/URI.php
index 5e4c80a..3d6d202 100644
--- a/system/core/URI.php
+++ b/system/core/URI.php
@@ -70,6 +70,15 @@
 	public $rsegments =	array();
 
 	/**
+	 * Permitted URI chars
+	 *
+	 * PCRE character group allowed in URI segments
+	 *
+	 * @var	string
+	 */
+	protected $_permitted_uri_chars;
+
+	/**
 	 * Class constructor
 	 *
 	 * Simply globalizes the $RTR object. The front
@@ -81,6 +90,12 @@
 	public function __construct()
 	{
 		$this->config =& load_class('Config', 'core');
+
+		if ($this->config->item('enable_query_strings') !== TRUE OR is_cli())
+		{
+			$this->_permitted_uri_chars = $this->config->item('permitted_uri_chars');
+		}
+
 		log_message('debug', 'URI Class Initialized');
 	}
 
@@ -303,23 +318,19 @@
 	 * @param	string	$str
 	 * @return	string
 	 */
-	public function _filter_uri($str)
+	public function filter_uri($str)
 	{
-		if ($str !== '' && $this->config->item('permitted_uri_chars') != '' && $this->config->item('enable_query_strings') === FALSE)
+		if ( ! empty($str) && ! empty($this->_permitted_uri_chars) && ! preg_match('/^['.$this->_permitted_uri_chars.']+$/i', $str))
 		{
-			// 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))
-			{
-				show_error('The URI you submitted has disallowed characters.', 400);
-			}
+			show_error('The URI you submitted has disallowed characters.', 400);
 		}
 
 		// Convert programatic characters to entities and return
 		return str_replace(
-					array('$',     '(',     ')',     '%28',   '%29'), // Bad
-					array('$', '(', ')', '(', ')'), // Good
-					$str);
+			array('$',     '(',     ')',     '%28',   '%29'),	// Bad
+			array('$', '(', ')', '(', ')'),	// Good
+			$str
+		);
 	}
 
 	// --------------------------------------------------------------------
@@ -365,7 +376,7 @@
 		foreach (explode('/', preg_replace('|/*(.+?)/*$|', '\\1', $this->uri_string)) as $val)
 		{
 			// Filter segments for security
-			$val = trim($this->_filter_uri($val));
+			$val = trim($this->filter_uri($val));
 
 			if ($val !== '')
 			{