[ci skip] Prepare 3.1.9 release
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index c5aab62..7b1dcc2 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -55,7 +55,7 @@
  * @var	string
  *
  */
-	const CI_VERSION = '3.1.9-dev';
+	const CI_VERSION = '3.1.9';
 
 /*
  * ------------------------------------------------------
diff --git a/system/libraries/Session/Session_driver.php b/system/libraries/Session/Session_driver.php
index bef5ee4..2fe30b8 100644
--- a/system/libraries/Session/Session_driver.php
+++ b/system/libraries/Session/Session_driver.php
@@ -113,6 +113,23 @@
 	// ------------------------------------------------------------------------
 
 	/**
+	 * PHP 5.x validate ID
+	 *
+	 * Enforces session.use_strict_mode on PHP 5.x (7+ does it by itself)
+	 *
+	 * @return	void
+	 */
+	public function php5_validate_id()
+	{
+		if (PHP_VERSION_ID < 70000 && isset($_COOKIE[$this->_config['cookie_name']]) && ! $this->validateId($_COOKIE[$this->_config['cookie_name']]))
+		{
+			unset($_COOKIE[$this->_config['cookie_name']]);
+		}
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
 	 * Cookie destroy
 	 *
 	 * Internal method to force removal of a cookie by the client
diff --git a/system/libraries/Session/drivers/Session_database_driver.php b/system/libraries/Session/drivers/Session_database_driver.php
index ae7a1b4..074accf 100644
--- a/system/libraries/Session/drivers/Session_database_driver.php
+++ b/system/libraries/Session/drivers/Session_database_driver.php
@@ -133,6 +133,8 @@
 			return $this->_fail();
 		}
 
+		$this->php5_validate_id();
+
 		return $this->_success;
 	}
 
@@ -340,6 +342,30 @@
 			: $this->_fail();
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Validate ID
+	 *
+	 * Checks whether a session ID record exists server-side,
+	 * to enforce session.use_strict_mode.
+	 *
+	 * @param	string	$id
+	 * @return	bool
+	 */
+	public function validateId($id)
+	{
+		// Prevent previous QB calls from messing with our queries
+		$this->_db->reset_query();
+
+		$this->_db->select('1')->from($this->_config['save_path'])->where('id', $id);
+		empty($this->_config['match_ip']) OR $this->_db->where('ip_address', $_SERVER['REMOTE_ADDR']);
+		$result = $this->_db->get();
+		empty($result) OR $result = $result->row();
+
+		return ! empty($result);
+	}
+
 	// ------------------------------------------------------------------------
 
 	/**
diff --git a/system/libraries/Session/drivers/Session_files_driver.php b/system/libraries/Session/drivers/Session_files_driver.php
index c6d789a..654f300 100644
--- a/system/libraries/Session/drivers/Session_files_driver.php
+++ b/system/libraries/Session/drivers/Session_files_driver.php
@@ -148,6 +148,8 @@
 			.$name // we'll use the session cookie name as a prefix to avoid collisions
 			.($this->_config['match_ip'] ? md5($_SERVER['REMOTE_ADDR']) : '');
 
+		$this->php5_validate_id();
+
 		return $this->_success;
 	}
 
@@ -392,6 +394,22 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Validate ID
+	 *
+	 * Checks whether a session ID record exists server-side,
+	 * to enforce session.use_strict_mode.
+	 *
+	 * @param	string	$id
+	 * @return	bool
+	 */
+	public function validateId($id)
+	{
+		return is_file($this->_file_path.$id);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Byte-safe strlen()
 	 *
 	 * @param	string	$str
diff --git a/system/libraries/Session/drivers/Session_memcached_driver.php b/system/libraries/Session/drivers/Session_memcached_driver.php
index b109738..7d8e390 100644
--- a/system/libraries/Session/drivers/Session_memcached_driver.php
+++ b/system/libraries/Session/drivers/Session_memcached_driver.php
@@ -145,6 +145,8 @@
 			return $this->_fail();
 		}
 
+		$this->php5_validate_id();
+
 		return $this->_success;
 	}
 
@@ -290,6 +292,23 @@
 		return $this->_success;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Validate ID
+	 *
+	 * Checks whether a session ID record exists server-side,
+	 * to enforce session.use_strict_mode.
+	 *
+	 * @param	string	$id
+	 * @return	bool
+	 */
+	public function validateId($id)
+	{
+		$this->_memcached-get($this->_key_prefix.$id);
+		return ($this->_memcached->getResultCode() === Memcached::RES_SUCCESS);
+	}
+
 	// ------------------------------------------------------------------------
 
 	/**
diff --git a/system/libraries/Session/drivers/Session_redis_driver.php b/system/libraries/Session/drivers/Session_redis_driver.php
index 413c30d..d7a5755 100644
--- a/system/libraries/Session/drivers/Session_redis_driver.php
+++ b/system/libraries/Session/drivers/Session_redis_driver.php
@@ -153,6 +153,8 @@
 			return $this->_success;
 		}
 
+		$this->php5_validate_id();
+
 		return $this->_fail();
 	}
 
@@ -310,6 +312,22 @@
 		return $this->_success;
 	}
 
+	// --------------------------------------------------------------------
+
+	/**
+	 * Validate ID
+	 *
+	 * Checks whether a session ID record exists server-side,
+	 * to enforce session.use_strict_mode.
+	 *
+	 * @param	string	$id
+	 * @return	bool
+	 */
+	public function validateId($id)
+	{
+		return (bool) $this->_redis->exists($this->_key_prefix.$id);
+	}
+
 	// ------------------------------------------------------------------------
 
 	/**
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 007e01c..5124809 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -5,11 +5,12 @@
 Version 3.1.9
 =============
 
-Release Date: Not Released
+Release Date: Jun 12, 2018
 
 - **Security**
 
    -  Updated :doc:`URL Helper <helpers/url_helper>` function :php:func:`auto_link()` to add ``rel="noopener"`` to generated links in order to prevent tab hijacking.
+   -  Fixed a possible session fixation vulnerability where the :doc:`Session Library <libraries/sessions>` enabled ``session.use_strict_mode`` but it didn't actually do anything (thanks to Aamer Shah, Prasanna Kumar).
 
 -  General Changes
 
diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py
index 7e1e520..e396217 100644
--- a/user_guide_src/source/conf.py
+++ b/user_guide_src/source/conf.py
@@ -48,9 +48,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '3.1.9-dev'
+version = '3.1.9'
 # The full version, including alpha/beta/rc tags.
-release = '3.1.9-dev'
+release = '3.1.9'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/user_guide_src/source/installation/downloads.rst b/user_guide_src/source/installation/downloads.rst
index 6147f4d..e2c764c 100644
--- a/user_guide_src/source/installation/downloads.rst
+++ b/user_guide_src/source/installation/downloads.rst
@@ -2,7 +2,7 @@
 Downloading CodeIgniter
 #######################
 
--  `CodeIgniter v3.1.9-dev (Current version) <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1-stable>`_
+-  `CodeIgniter v3.1.9 (Current version) <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.9>`_
 -  `CodeIgniter v3.1.8 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.8>`_
 -  `CodeIgniter v3.1.7 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.7>`_
 -  `CodeIgniter v3.1.6 <https://codeload.github.com/bcit-ci/CodeIgniter/zip/3.1.6>`_