Merge branch 'develop' of github.com:/EllisLab/CodeIgniter into load_config_units
diff --git a/system/core/Input.php b/system/core/Input.php
index 82482f2..ec935d5 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -390,31 +390,32 @@
 					}
 
 					// Convert the REMOTE_ADDR IP address to binary, if needed
-					if ( ! isset($ip, $convert_func))
+					if ( ! isset($ip, $sprintf))
 					{
 						if ($separator === ':')
 						{
 							// Make sure we're have the "full" IPv6 format
-							$ip = str_replace('::', str_repeat(':', 9 - substr_count($this->ip_address, ':')), $this->ip_address);
-							$convert_func = is_php('5.3')
-								? function ($value)
-									{
-										return str_pad(base_convert($value, 16, 2), 16, '0', STR_PAD_LEFT);
-									}
-								: create_function('$value', 'return str_pad(base_convert($value, 16, 2), 16, "0", STR_PAD_LEFT);');
+							$ip = explode(':',
+								str_replace('::',
+									str_repeat(':', 9 - substr_count($this->ip_address, ':')),
+									$this->ip_address
+								)
+							);
+
+							for ($i = 0; $i < 8; $i++)
+							{
+								$ip[$i] = intval($ip[$i], 16);
+							}
+
+							$sprintf = '%016b%016b%016b%016b%016b%016b%016b%016b';
 						}
 						else
 						{
-							$ip = $this->ip_address;
-							$convert_func = is_php('5.3')
-								? function ($value)
-									{
-										return str_pad(decbin($value), 8, '0', STR_PAD_LEFT);
-									}
-								: create_function('$value', 'return str_pad(decbin($value), 8, "0", STR_PAD_LEFT);');
+							$ip = explode('.', $this->ip_address);
+							$sprintf = '%08b%08b%08b%08b';
 						}
 
-						$ip = implode(array_map($convert_func, explode($separator, $ip)));
+						$ip = vsprintf($sprintf, $ip);
 					}
 
 					// Split the netmask length off the network address
@@ -423,12 +424,19 @@
 					// Again, an IPv6 address is most likely in a compressed form
 					if ($separator === ':')
 					{
-						$netaddr = str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr);
+						$netaddr = explode(':', str_replace('::', str_repeat(':', 9 - substr_count($netaddr, ':')), $netaddr));
+						for ($i = 0; $i < 8; $i++)
+						{
+							$netaddr[$i] = intval($netaddr[$i], 16);
+						}
+					}
+					else
+					{
+						$netaddr = explode('.', $netaddr);
 					}
 
-					// Convert to a binary form and finally compare
-					$netaddr = implode(array_map($convert_func, explode($separator, $netaddr)));
-					if (strncmp($ip, $netaddr, $masklen) === 0)
+					// Convert to binary and finally compare
+					if (strncmp($ip, vsprintf($sprintf, $netaddr), $masklen) === 0)
 					{
 						$this->ip_address = $spoof;
 						break;
diff --git a/system/database/drivers/mysqli/mysqli_driver.php b/system/database/drivers/mysqli/mysqli_driver.php
index f77176c..dc72ecc 100644
--- a/system/database/drivers/mysqli/mysqli_driver.php
+++ b/system/database/drivers/mysqli/mysqli_driver.php
@@ -69,7 +69,7 @@
 			? 'p:'.$this->hostname : $this->hostname;
 		$port = empty($this->port) ? NULL : $this->port;
 		$client_flags = ($this->compress === TRUE) ? MYSQLI_CLIENT_COMPRESS : 0;
-		$mysqli = new mysqli();
+		$mysqli = mysqli_init();
 
 		return @$mysqli->real_connect($hostname, $this->username, $this->password, $this->database, $port, NULL, $client_flags)
 			? $mysqli : FALSE;
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index fa1d5e9..08057f2 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -1754,47 +1754,6 @@
 	// --------------------------------------------------------------------
 
 	/**
-	 * Get IP
-	 *
-	 * @return	string
-	 */
-	protected function _get_ip()
-	{
-		if ($this->_IP !== FALSE)
-		{
-			return $this->_IP;
-		}
-
-		$cip = ( ! empty($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : FALSE;
-		$rip = ( ! empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : FALSE;
-		if ($cip) $this->_IP = $cip;
-		elseif ($rip) $this->_IP = $rip;
-		else
-		{
-			$fip = ( ! empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : FALSE;
-			if ($fip)
-			{
-				$this->_IP = $fip;
-			}
-		}
-
-		if (strpos($this->_IP, ',') !== FALSE)
-		{
-			$x = explode(',', $this->_IP);
-			$this->_IP = end($x);
-		}
-
-		if ( ! preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $this->_IP))
-		{
-			$this->_IP = '0.0.0.0';
-		}
-
-		return $this->_IP;
-	}
-
-	// --------------------------------------------------------------------
-
-	/**
 	 * Get Debug Message
 	 *
 	 * @return	string
diff --git a/system/libraries/Session/drivers/Session_cookie.php b/system/libraries/Session/drivers/Session_cookie.php
index fb62c7e..5bb1f7a 100755
--- a/system/libraries/Session/drivers/Session_cookie.php
+++ b/system/libraries/Session/drivers/Session_cookie.php
@@ -405,7 +405,7 @@
 		}
 
 		// Is the session current?
-		if (($session['last_activity'] + $this->sess_expiration) < $this->now)
+		if (($session['last_activity'] + $this->sess_expiration) < $this->now OR $session['last_activity'] > $this->now)
 		{
 			$this->sess_destroy();
 			return FALSE;
diff --git a/system/libraries/Session/drivers/Session_native.php b/system/libraries/Session/drivers/Session_native.php
index 8d5e515..6529d4c 100755
--- a/system/libraries/Session/drivers/Session_native.php
+++ b/system/libraries/Session/drivers/Session_native.php
@@ -107,7 +107,7 @@
 		// Check session expiration, ip, and agent
 		$now = time();
 		$destroy = FALSE;
-		if (isset($_SESSION['last_activity']) && ($_SESSION['last_activity'] + $expire) < $now)
+		if (isset($_SESSION['last_activity']) && (($_SESSION['last_activity'] + $expire) < $now OR $_SESSION['last_activity'] > $now))
 		{
 			// Expired - destroy
 			$destroy = TRUE;
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 145853a..f31781d 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -203,6 +203,7 @@
 	 -  Removed the second parameter (character limit) from internal method ``_prep_quoted_printable()`` as it is never used.
 	 -  Internal method ``_prep_quoted_printable()`` will now utilize the native ``quoted_printable_encode()``, ``imap_8bit()`` functions (if available) when CRLF is set to "\r\n".
 	 -  Default charset now relies on the global ``$config['charset']`` setting.
+	 -  Removed unused protected method ``_get_ip()`` (:doc:`Input Library <libraries/input>`'s ``ip_address()`` should be used anyway).
    -  :doc:`Pagination Library <libraries/pagination>` changes include:
 	 -  Added support for the anchor "rel" attribute.
 	 -  Added support for setting custom attributes.
@@ -360,7 +361,8 @@
 -  Fixed a bug (#1765) - :doc:`Database Library <database/index>` didn't properly detect connection errors for MySQLi.
 -  Fixed a bug (#1257) - :doc:`Query Builder <database/query_builder>` used to (unnecessarily) group FROM clause contents, which breaks certain queries and is invalid for some databases.
 -  Fixed a bug (#1709) - :doc:`Email <libraries/email>` headers were broken when using long email subjects and \r\n as CRLF.
--  Fixed a bug where MB_ENABLED was only declared if UTF8_ENABLED was set to TRUE.
+-  Fixed a bug where ``MB_ENABLED`` was only declared if ``UTF8_ENABLED`` was set to TRUE.
+-  Fixed a bug where the :doc:`Session Library <libraries/session>` accepted cookies with *last_activity* values being in the future.
 
 Version 2.1.3
 =============