Merge pull request #1436 from jjaffeux/tests-text-helper

Tests text helper
diff --git a/system/core/Input.php b/system/core/Input.php
index 73f46ba..b986c49 100755
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -383,7 +383,7 @@
 	 */
 	public function valid_ip($ip)
 	{
-		return (bool) filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
+		return (bool) filter_var($ip, FILTER_VALIDATE_IP);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/core/Output.php b/system/core/Output.php
index 0965671..5588ffe 100755
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -200,7 +200,7 @@
 	 * @param	string	extension of the file we're outputting
 	 * @return	void
 	 */
-	public function set_content_type($mime_type)
+	public function set_content_type($mime_type, $charset = NULL)
 	{
 		if (strpos($mime_type, '/') === FALSE)
 		{
@@ -218,7 +218,13 @@
 			}
 		}
 
-		$header = 'Content-Type: '.$mime_type;
+		if (empty($charset))
+		{
+			$charset = config_item('charset');
+		}
+
+		$header = 'Content-Type: '.$mime_type
+			.(empty($charset) ? NULL : '; charset='.strtolower($charset));
 
 		$this->headers[] = array($header, TRUE);
 		return $this;
@@ -364,7 +370,7 @@
 
 		if ($this->parse_exec_vars === TRUE)
 		{
-			$memory	= function_exists('memory_get_usage') ? round(memory_get_usage()/1024/1024, 2).'MB' : '0';
+			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';
 
 			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
 		}
diff --git a/system/database/DB_cache.php b/system/database/DB_cache.php
index 14f3c21..ba91103 100644
--- a/system/database/DB_cache.php
+++ b/system/database/DB_cache.php
@@ -99,7 +99,7 @@
 		$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
 		$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
 
-		if (FALSE === ($cachedata = read_file($filepath)))
+		if (FALSE === ($cachedata = file_get_contents($filepath)))
 		{
 			return FALSE;
 		}
diff --git a/system/database/drivers/mssql/mssql_forge.php b/system/database/drivers/mssql/mssql_forge.php
index 3708c22..e6227e1 100644
--- a/system/database/drivers/mssql/mssql_forge.php
+++ b/system/database/drivers/mssql/mssql_forge.php
@@ -70,7 +70,7 @@
 
 				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
diff --git a/system/database/drivers/sqlsrv/sqlsrv_forge.php b/system/database/drivers/sqlsrv/sqlsrv_forge.php
index 1529b2a..d8b5193 100644
--- a/system/database/drivers/sqlsrv/sqlsrv_forge.php
+++ b/system/database/drivers/sqlsrv/sqlsrv_forge.php
@@ -70,7 +70,7 @@
 
 				$sql .= "\n\t".$this->db->escape_identifiers($field).' '.$attributes['TYPE'];
 
-				if (array_key_exists('CONSTRAINT', $attributes))
+				if (stripos($attributes['TYPE'], 'INT') === FALSE && ! empty($attributes['CONSTRAINT']))
 				{
 					$sql .= '('.$attributes['CONSTRAINT'].')';
 				}
diff --git a/system/helpers/file_helper.php b/system/helpers/file_helper.php
index d53d986..be616f6 100644
--- a/system/helpers/file_helper.php
+++ b/system/helpers/file_helper.php
@@ -44,38 +44,15 @@
 	 *
 	 * Opens the file specfied in the path and returns it as a string.
 	 *
+	 * This function is DEPRECATED and should be removed in
+	 * CodeIgniter 3.1+. Use file_get_contents() instead.
+	 *
 	 * @param	string	path to file
 	 * @return	string
 	 */
 	function read_file($file)
 	{
-		if ( ! file_exists($file))
-		{
-			return FALSE;
-		}
-
-		if (function_exists('file_get_contents'))
-		{
-			return file_get_contents($file);
-		}
-
-		if ( ! $fp = @fopen($file, FOPEN_READ))
-		{
-			return FALSE;
-		}
-
-		flock($fp, LOCK_SH);
-
-		$data = '';
-		if (filesize($file) > 0)
-		{
-			$data =& fread($fp, filesize($file));
-		}
-
-		flock($fp, LOCK_UN);
-		fclose($fp);
-
-		return $data;
+		return @file_get_contents($file);
 	}
 }
 
diff --git a/system/helpers/form_helper.php b/system/helpers/form_helper.php
index 4109721..9846343 100644
--- a/system/helpers/form_helper.php
+++ b/system/helpers/form_helper.php
@@ -325,7 +325,10 @@
 			$selected = array($_POST[$name]);
 		}
 
-		if ($extra !== '') $extra = ' '.$extra;
+		if ($extra != '')
+		{
+			$extra = ' '.$extra;
+		}
 
 		$multiple = (count($selected) > 1 && strpos($extra, 'multiple') === FALSE) ? ' multiple="multiple"' : '';
 
@@ -378,7 +381,7 @@
 		{
 			$checked = $data['checked'];
 
-			if ($checked === FALSE)
+			if ($checked == FALSE)
 			{
 				unset($data['checked']);
 			}
@@ -388,7 +391,7 @@
 			}
 		}
 
-		if ($checked === TRUE)
+		if ($checked == TRUE)
 		{
 			$defaults['checked'] = 'checked';
 		}
@@ -702,7 +705,7 @@
 					return '';
 				}
 			}
-			elseif (($field === '' OR $value === '') OR ($field !== $value))
+			elseif (($field == '' OR $value == '') OR $field !== $value)
 			{
 				return '';
 			}
@@ -753,7 +756,7 @@
 					return '';
 				}
 			}
-			elseif (($field === '' OR $value === '') OR ($field !== $value))
+			elseif (($field == '' OR $value == '') OR $field !== $value)
 			{
 				return '';
 			}
@@ -806,7 +809,7 @@
 			}
 			else
 			{
-				if (($field === '' OR $value === '') OR ($field !== $value))
+				if (($field == '' OR $value == '') OR $field !== $value)
 				{
 					return '';
 				}
diff --git a/system/helpers/path_helper.php b/system/helpers/path_helper.php
index 1341054..fec4a1a 100644
--- a/system/helpers/path_helper.php
+++ b/system/helpers/path_helper.php
@@ -55,7 +55,7 @@
 		}
 
 		// Resolve the path
-		if (function_exists('realpath') && @realpath($path) !== FALSE)
+		if (@realpath($path) !== FALSE)
 		{
 			$path = realpath($path);
 		}
diff --git a/system/helpers/security_helper.php b/system/helpers/security_helper.php
index 6187a4a..3e6e914 100644
--- a/system/helpers/security_helper.php
+++ b/system/helpers/security_helper.php
@@ -77,6 +77,9 @@
 	/**
 	 * Hash encode a string
 	 *
+	 * This function is DEPRECATED and should be removed in
+	 * CodeIgniter 3.1+. Use hash() instead.
+	 *
 	 * @param	string
 	 * @param	string
 	 * @return	string
diff --git a/system/libraries/Cache/drivers/Cache_file.php b/system/libraries/Cache/drivers/Cache_file.php
index ce2c2b1..5170de8 100644
--- a/system/libraries/Cache/drivers/Cache_file.php
+++ b/system/libraries/Cache/drivers/Cache_file.php
@@ -71,7 +71,7 @@
 			return FALSE;
 		}
 
-		$data = unserialize(read_file($this->_cache_path.$id));
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
 
 		if (time() >  $data['time'] + $data['ttl'])
 		{
@@ -165,7 +165,7 @@
 			return FALSE;
 		}
 
-		$data = unserialize(read_file($this->_cache_path.$id));
+		$data = unserialize(file_get_contents($this->_cache_path.$id));
 
 		if (is_array($data))
 		{
diff --git a/system/libraries/Profiler.php b/system/libraries/Profiler.php
index aaac0c5..d96088c 100644
--- a/system/libraries/Profiler.php
+++ b/system/libraries/Profiler.php
@@ -402,7 +402,7 @@
 			."\n"
 			.'<legend style="color:#5a0099;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_memory_usage')."&nbsp;&nbsp;</legend>\n"
 			.'<div style="color:#5a0099;font-weight:normal;padding:4px 0 4px 0;">'
-			.((function_exists('memory_get_usage') && ($usage = memory_get_usage()) !== '') ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
+			.(($usage = memory_get_usage()) != '' ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
 			.'</div></fieldset>';
 	}
 
diff --git a/system/libraries/Unit_test.php b/system/libraries/Unit_test.php
index a87cf7e..70ad8dc 100644
--- a/system/libraries/Unit_test.php
+++ b/system/libraries/Unit_test.php
@@ -124,7 +124,7 @@
 
 		$this->results[] = $report;
 
-		return($this->report($this->result($report)));
+		return $this->report($this->result($report));
 	}
 
 	// --------------------------------------------------------------------
@@ -289,15 +289,11 @@
 	 */
 	protected function _backtrace()
 	{
-		if (function_exists('debug_backtrace'))
-		{
-			$back = debug_backtrace();
-			return array(
-					'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
-					'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
-				);
-		}
-		return array('file' => 'Unknown', 'line' => 'Unknown');
+		$back = debug_backtrace();
+		return array(
+				'file' => (isset($back[1]['file']) ? $back[1]['file'] : ''),
+				'line' => (isset($back[1]['line']) ? $back[1]['line'] : '')
+			);
 	}
 
 	// --------------------------------------------------------------------
diff --git a/system/libraries/Upload.php b/system/libraries/Upload.php
index c1e07de..1f6aeeb 100644
--- a/system/libraries/Upload.php
+++ b/system/libraries/Upload.php
@@ -694,7 +694,7 @@
 			return FALSE;
 		}
 
-		if (function_exists('realpath') && @realpath($this->upload_path) !== FALSE)
+		if (@realpath($this->upload_path) !== FALSE)
 		{
 			$this->upload_path = str_replace('\\', '/', realpath($this->upload_path));
 		}
@@ -815,17 +815,17 @@
 			return FALSE;
 		}
 
-		if (function_exists('memory_get_usage') && memory_get_usage() && ini_get('memory_limit'))
+		if (memory_get_usage() && ($memory_limit = ini_get('memory_limit')))
 		{
-			$current = ini_get('memory_limit') * 1024 * 1024;
+			$memory_limit *= 1024 * 1024;
 
 			// There was a bug/behavioural change in PHP 5.2, where numbers over one million get output
 			// into scientific notation. number_format() ensures this number is an integer
 			// http://bugs.php.net/bug.php?id=43053
 
-			$new_memory = number_format(ceil(filesize($file) + $current), 0, '.', '');
+			$memory_limit = number_format(ceil(filesize($file) + $memory_limit), 0, '.', '');
 
-			ini_set('memory_limit', $new_memory); // When an integer is used, the value is measured in bytes. - PHP.net
+			ini_set('memory_limit', $memory_limit); // When an integer is used, the value is measured in bytes. - PHP.net
 		}
 
 		// If the file being uploaded is an image, then we should have no problem with XSS attacks (in theory), but
@@ -849,14 +849,8 @@
 			// <a, <body, <head, <html, <img, <plaintext, <pre, <script, <table, <title
 			// title is basically just in SVG, but we filter it anyhow
 
-			if ( ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes))
-			{
-				return TRUE; // its an image, no "triggers" detected in the first 256 bytes, we're good
-			}
-			else
-			{
-				return FALSE;
-			}
+			// if its an image or no "triggers" detected in the first 256 bytes - we're good
+			return ! preg_match('/<(a|body|head|html|img|plaintext|pre|script|table|title)[\s>]/i', $opening_bytes);
 		}
 
 		if (($data = @file_get_contents($file)) === FALSE)
diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php
index cfc80c9..c9322c0 100644
--- a/tests/codeigniter/core/Input_test.php
+++ b/tests/codeigniter/core/Input_test.php
@@ -143,4 +143,19 @@
 		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $harm);
 		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless);
 	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_valid_ip()
+	{
+		$ip_v4 = '192.18.0.1';
+		$this->assertTrue($this->input->valid_ip($ip_v4));
+
+		$ip_v6 = array('2001:0db8:0000:85a3:0000:0000:ac1f:8001', '2001:db8:0:85a3:0:0:ac1f:8001', '2001:db8:0:85a3::ac1f:8001');
+		foreach($ip_v6 as $ip)
+		{
+			$this->assertTrue($this->input->valid_ip($ip));
+		}
+	}
+
 }
\ No newline at end of file
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 74de512..801f0e4 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -44,19 +44,21 @@
 
 -  Helpers
 
-   -  create_captcha() accepts additional colors parameter, allowing for color customization
-   -  url_title() will now trim extra dashes from beginning and end.
+   -  ``create_captcha()`` accepts additional colors parameter, allowing for color customization.
+   -  ``url_title()`` will now trim extra dashes from beginning and end.
    -  Added XHTML Basic 1.1 doctype to :doc:`HTML Helper <helpers/html_helper>`.
-   -  Changed humanize() to include a second param for the separator.
+   -  Changed ``humanize()`` to include a second param for the separator.
    -  Refactored ``plural()`` and ``singular()`` to avoid double pluralization and support more words.
    -  Added an optional third parameter to ``force_download()`` that enables/disables sending the actual file MIME type in the Content-Type header (disabled by default).
    -  Added an optional third parameter to ``timespan()`` that constrains the number of time units displayed.
-   -  Added a work-around in force_download() for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
-   -  form_dropdown() will now also take an array for unity with other form helpers.
-   -  set_realpath() can now also handle file paths as opposed to just directories.
-   -  do_hash() now uses PHP's native hash() function, supporting more algorithms.
-   -  Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html.
-   -  Removed deprecated helper function ``js_insert_smiley()`` from smiley helper.
+   -  Added a work-around in ``force_download()`` for a bug Android <= 2.1, where the filename extension needs to be in uppercase.
+   -  ``form_dropdown()`` will now also take an array for unity with other form helpers.
+   -  ``do_hash()`` now uses PHP's native ``hash()`` function (supporting more algorithms) and is deprecated.
+   -  Removed previously deprecated helper function ``js_insert_smiley()`` from smiley helper.
+   -  :doc:`File Helper <helpers/file_helper>` changes include:
+	 - ``set_realpath()`` can now also handle file paths as opposed to just directories.
+	 - Added an optional paramater to ``delete_files()`` to enable it to skip deleting files such as .htaccess and index.html.
+	 - ``read_file()`` is now a deprecated alias of ``file_get_contents()``.
 
 -  Database
 
@@ -135,7 +137,8 @@
    -  Allowed for setting table class defaults in a config file.
    -  Added a Wincache driver to the :doc:`Caching Library <libraries/caching>`.
    -  Added dsn (delivery status notification) option to the :doc:`Email Library <libraries/email>`.
-   -  Enabled public access to Email library's set_header() for adding additional headers to e-mails. Original function _set_header() now renamed to set_header().
+   -  Input library now supports IPv6.
+   -  Renamed method _set_header() to set_header() and made it public to enable adding custom headers in the :doc:`Email Library <libraries/email>`.
 
 -  Core
 
@@ -150,6 +153,7 @@
    -  Renamed method _call_hook() to call_hook() in the :doc:`Hooks Library <general/hooks>`.
    -  Added get_content_type() method to the :doc:`Output Library <libraries/output>`.
    -  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.
 
 Bug fixes for 3.0
 ------------------
@@ -168,7 +172,7 @@
 -  Fixed a bug (#797) - timespan() was using incorrect seconds for year and month.
 -  Fixed a bug in CI_Cart::contents() where if called without a TRUE (or equal) parameter, it would fail due to a typo.
 -  Fixed a bug (#696) - make oci_execute() calls inside num_rows() non-committing, since they are only there to reset which row is next in line for oci_fetch calls and thus don't need to be committed.
--  Fixed a bug (#406) - sqlsrv DB driver not returning resource on ``db_pconnect()``.
+-  Fixed a bug (#406) - SQLSRV DB driver not returning resource on ``db_pconnect()``.
 -  Fixed a bug in CI_Image_lib::gd_loaded() where it was possible for the script execution to end or a PHP E_WARNING message to be emitted.
 -  Fixed a bug in the :doc:`Pagination library <libraries/pagination>` where when use_page_numbers=TRUE previous link and page 1 link did not have the same url.
 -  Fixed a bug (#561) - Errors in :doc:`XML-RPC Library <libraries/xmlrpc>` were not properly escaped.
@@ -226,10 +230,12 @@
 -  Fixed a bug (#121) - ``CI_DB_result::row()`` returned an array when there's no actual result to be returned.
 -  Fixed a bug (#319) - SQLSRV's affected_rows() method failed due to a scrollable cursor being created for write-type queries.
 -  Fixed a bug (#356) - PostgreSQL driver didn't have an _update_batch() method, which resulted in fatal error being triggered when update_batch() is used with it.
--  Fixed a bug (#862) - create_table() failed on SQLSRV/MSSQL when used with 'IF NOT EXISTS'.
+-  Fixed a bug (#784, #862) - :doc:`Database Forge <database/forge>` method ``create_table()`` failed on SQLSRV/MSSQL when used with 'IF NOT EXISTS'.
 -  Fixed a bug (#1419) - libraries/Driver.php had a static variable that was causing an error.
 -  Fixed a bug (#1411) - the :doc:`Email library <libraries/email>` used its own short list of MIMEs instead the one from config/mimes.php.
 -  Fixed a bug where the magic_quotes_runtime setting wasn't turned off for PHP 5.3 (where it is indeed deprecated, but not non-existent).
+-  Fixed a bug (#666) - :doc:`Output library <libraries/output>`'s set_content_type() method didn't set the document charset.
+-  Fixed a bug (#784, #861) - :doc:`Database Forge <database/forge>` method ``create_table()`` used to accept constraints for MSSQL/SQLSRV integer-type columns.
 
 Version 2.1.1
 =============
diff --git a/user_guide_src/source/helpers/file_helper.rst b/user_guide_src/source/helpers/file_helper.rst
index bfc271e..60c5aa9 100644
--- a/user_guide_src/source/helpers/file_helper.rst
+++ b/user_guide_src/source/helpers/file_helper.rst
@@ -32,6 +32,9 @@
 	controller or view files. CodeIgniter uses a front controller so paths
 	are always relative to the main site index.
 
+.. note:: This function is DEPRECATED. Use the native ``file_get_contents()``
+	instead.
+
 If your server is running an `open_basedir` restriction this function might not work if you are trying to access a file above the calling script.
 
 write_file('path', $data)
diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst
index b1bcf2b..ec0be28 100644
--- a/user_guide_src/source/helpers/security_helper.rst
+++ b/user_guide_src/source/helpers/security_helper.rst
@@ -43,8 +43,10 @@
 	$str = do_hash($str); // SHA1
 	$str = do_hash($str, 'md5'); // MD5
 
-.. note:: This function was formerly named dohash(), which has been
-	removed in favor of `do_hash()`.
+.. note:: This function was formerly named ``dohash()``, which has been
+	removed in favor of ``do_hash()``.
+
+.. note:: This function is DEPRECATED. Use the native ``hash()`` instead.
 
 strip_image_tags()
 ==================
diff --git a/user_guide_src/source/helpers/string_helper.rst b/user_guide_src/source/helpers/string_helper.rst
index 2d23fb0..19500aa 100644
--- a/user_guide_src/source/helpers/string_helper.rst
+++ b/user_guide_src/source/helpers/string_helper.rst
@@ -36,8 +36,7 @@
 -  **unique**: Encrypted with MD5 and uniqid(). Note: The length
    parameter is not available for this type. Returns a fixed length 32
    character string.
--  **sha1**: An encrypted random number based on do_hash() from the
-   :doc:`security helper <security_helper>`.
+-  **sha1**: An encrypted random number based on ``sha1()``.
 
 Usage example
 
diff --git a/user_guide_src/source/libraries/output.rst b/user_guide_src/source/libraries/output.rst
index baceaae..0472d14 100644
--- a/user_guide_src/source/libraries/output.rst
+++ b/user_guide_src/source/libraries/output.rst
@@ -49,6 +49,10 @@
 .. important:: Make sure any non-mime string you pass to this method
 	exists in config/mimes.php or it will have no effect.
 
+You can also set the character set of the document, by passing a second argument::
+
+	$this->output->set_content_type('css', 'utf-8');
+
 $this->output->get_content_type();
 ==========================================