Merge pull request #2403 from groovenectar/loader-fix

Fix for extending classes in a subdirectory (e.g. drivers)
diff --git a/application/config/mimes.php b/application/config/mimes.php
index 6ff3812..32d10f6 100644
--- a/application/config/mimes.php
+++ b/application/config/mimes.php
@@ -49,7 +49,7 @@
 	'sea'	=>	'application/octet-stream',
 	'dll'	=>	'application/octet-stream',
 	'oda'	=>	'application/oda',
-	'pdf'	=>	array('application/pdf', 'application/x-download', 'binary/octet-stream'),
+	'pdf'	=>	array('application/pdf', 'application/force-download', 'application/x-download', 'binary/octet-stream'),
 	'ai'	=>	array('application/pdf', 'application/postscript'),
 	'eps'	=>	'application/postscript',
 	'ps'	=>	'application/postscript',
diff --git a/system/core/Common.php b/system/core/Common.php
index b4f0c38..cad340f 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -424,12 +424,12 @@
 	 * We use this as a simple mechanism to access the logging
 	 * class and send messages to be logged.
 	 *
-	 * @param	string
-	 * @param	string
-	 * @param	bool
+	 * @param	string	the error level: 'error', 'debug' or 'info'
+	 * @param	string	the error message
+	 * @param	bool	whether the error is a native PHP error
 	 * @return	void
 	 */
-	function log_message($level = 'error', $message, $php_error = FALSE)
+	function log_message($level, $message, $php_error = FALSE)
 	{
 		static $_log, $_log_threshold;
 
diff --git a/system/core/Input.php b/system/core/Input.php
index 6690b7f..0ef8112 100644
--- a/system/core/Input.php
+++ b/system/core/Input.php
@@ -790,33 +790,32 @@
 	 */
 	public function request_headers($xss_clean = FALSE)
 	{
+		// If header is already defined, return it immediately
+		if ( ! empty($this->headers))
+		{
+			return $this->headers;
+		}
+
 		// In Apache, you can simply call apache_request_headers()
 		if (function_exists('apache_request_headers'))
 		{
-			$headers = apache_request_headers();
+			return $this->headers = apache_request_headers();
 		}
-		else
-		{
-			$headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
 
-			foreach ($_SERVER as $key => $val)
+		$this->headers['Content-Type'] = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : @getenv('CONTENT_TYPE');
+
+		foreach ($_SERVER as $key => $val)
+		{
+			if (sscanf($key, 'HTTP_%s', $header) === 1)
 			{
-				if (sscanf($key, 'HTTP_%s', $header) === 1)
-				{
-					$headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
-				}
+				// take SOME_HEADER and turn it into Some-Header
+				$header = str_replace('_', ' ', strtolower($header));
+				$header = str_replace(' ', '-', ucwords($header));
+
+				$this->headers[$header] = $this->_fetch_from_array($_SERVER, $key, $xss_clean);
 			}
 		}
 
-		// take SOME_HEADER and turn it into Some-Header
-		foreach ($headers as $key => $val)
-		{
-			$key = str_replace(array('_', '-'), ' ', strtolower($key));
-			$key = str_replace(' ', '-', ucwords($key));
-
-			$this->headers[$key] = $val;
-		}
-
 		return $this->headers;
 	}
 
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 8f76f9a..70a6b6f 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -658,7 +658,7 @@
 			return FALSE;
 		}
 
-		if ( ! class_exists('CI_Driver_Library'))
+		if ( ! class_exists('CI_Driver_Library', FALSE))
 		{
 			// We aren't instantiating an object here, just making the base class available
 			require BASEPATH.'libraries/Driver.php';
@@ -713,7 +713,7 @@
 	 *
 	 * Return a list of all package paths.
 	 *
-	 * @param	bool	$include_base	Whether to include BASEPATH (default: TRUE)
+	 * @param	bool	$include_base	Whether to include BASEPATH (default: FALSE)
 	 * @return	array
 	 */
 	public function get_package_paths($include_base = FALSE)
diff --git a/system/core/Log.php b/system/core/Log.php
index a84d3dc..e4d72b5 100644
--- a/system/core/Log.php
+++ b/system/core/Log.php
@@ -138,12 +138,12 @@
 	 *
 	 * Generally this function will be called using the global log_message() function
 	 *
-	 * @param	string	the error level
+	 * @param	string	the error level: 'error', 'debug' or 'info'
 	 * @param	string	the error message
 	 * @param	bool	whether the error is a native PHP error
 	 * @return	bool
 	 */
-	public function write_log($level = 'error', $msg, $php_error = FALSE)
+	public function write_log($level, $msg, $php_error = FALSE)
 	{
 		if ($this->_enabled === FALSE)
 		{
diff --git a/system/database/DB_driver.php b/system/database/DB_driver.php
index 9239dc1..593d78b 100644
--- a/system/database/DB_driver.php
+++ b/system/database/DB_driver.php
@@ -704,7 +704,7 @@
 	{
 		$driver = 'CI_DB_'.$this->dbdriver.'_result';
 
-		if ( ! class_exists($driver))
+		if ( ! class_exists($driver, FALSE))
 		{
 			include_once(BASEPATH.'database/DB_result.php');
 			include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');
diff --git a/system/helpers/captcha_helper.php b/system/helpers/captcha_helper.php
index 78e255a..f3b9c6c 100644
--- a/system/helpers/captcha_helper.php
+++ b/system/helpers/captcha_helper.php
@@ -51,7 +51,7 @@
 	 */
 	function create_captcha($data = '', $img_path = '', $img_url = '', $font_path = '')
 	{
-		$defaults = array('word' => '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200);
+		$defaults = array('word' => '', 'img_path' => '', 'img_url' => '', 'img_width' => '150', 'img_height' => '30', 'font_path' => '', 'expiration' => 7200, 'word_length' => 8, 'pool' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
 
 		foreach ($defaults as $key => $val)
 		{
@@ -95,9 +95,8 @@
 
 		if (empty($word))
 		{
-			$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
 			$word = '';
-			for ($i = 0, $mt_rand_max = strlen($pool) - 1; $i < 8; $i++)
+			for ($i = 0, $mt_rand_max = strlen($pool) - 1; $i < $word_length; $i++)
 			{
 				$word .= $pool[mt_rand(0, $mt_rand_max)];
 			}
diff --git a/system/libraries/Email.php b/system/libraries/Email.php
index a745d33..0c83a8b 100644
--- a/system/libraries/Email.php
+++ b/system/libraries/Email.php
@@ -1236,7 +1236,7 @@
 	/**
 	 * Build Final Body and attachments
 	 *
-	 * @return	void
+	 * @return	bool
 	 */
 	protected function _build_message()
 	{
@@ -1275,7 +1275,7 @@
 				if ($this->send_multipart === FALSE)
 				{
 					$hdr .= 'Content-Type: text/html; charset='.$this->charset.$this->newline
-						.'Content-Transfer-Encoding: quoted-printable';
+						.'Content-Transfer-Encoding: quoted-printable'.$this->newline.$this->newline;
 				}
 				else
 				{
@@ -1401,7 +1401,7 @@
 
 		$body .= implode($this->newline, $attachment).$this->newline.'--'.$this->_atc_boundary.'--';
 		$this->_finalbody = ($this->_get_protocol() === 'mail') ? $body : $hdr.$body;
-		return;
+		return TRUE;
 	}
 
 	// --------------------------------------------------------------------
@@ -1606,7 +1606,11 @@
 			return $result;
 		}
 
-		$this->_build_message();
+		if ($this->_build_message() === FALSE)
+		{
+			return FALSE;
+		}
+
 		$result = $this->_spool_email();
 
 		if ($result && $auto_clear)
@@ -1665,7 +1669,11 @@
 				$this->_bcc_array = $bcc;
 			}
 
-			$this->_build_message();
+			if ($this->_build_message() === FALSE)
+			{
+				return FALSE;
+			}
+
 			$this->_spool_email();
 		}
 	}
diff --git a/tests/README.md b/tests/README.md
index a5f89a2..3e32edc 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -17,6 +17,7 @@
 PHP Unit >= 3.5.6
 
 	pear channel-discover pear.phpunit.de
+	pear channel-discover pear.symfony.com
 	pear install phpunit/PHPUnit
 
 vfsStream
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index e75d0d5..ac2656e 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -147,6 +147,9 @@
 
 	public function test_driver()
 	{
+		// Call the autoloader, to include system/libraries/Driver.php
+		class_exists('CI_Driver_Library', TRUE);
+
 		// Create driver in VFS
 		$driver = 'unit_test_driver';
 		$dir = ucfirst($driver);
diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php
index 24d645a..0ccfe1e 100644
--- a/tests/mocks/core/common.php
+++ b/tests/mocks/core/common.php
@@ -178,7 +178,7 @@
 
 if ( ! function_exists('log_message'))
 {
-	function log_message($level = 'error', $message, $php_error = FALSE)
+	function log_message($level, $message, $php_error = FALSE)
 	{
 		return TRUE;
 	}
diff --git a/user_guide_src/source/_themes/eldocs/layout.html b/user_guide_src/source/_themes/eldocs/layout.html
index 51d61b8..7f2fe1a 100644
--- a/user_guide_src/source/_themes/eldocs/layout.html
+++ b/user_guide_src/source/_themes/eldocs/layout.html
@@ -81,7 +81,7 @@
 	{%- block content %}
 		<div id="table-contents">
 			<div class="toctree-wrapper compound">
-			{{ toctree(collapse=true) }}
+			{{ toctree }}
 			</div>
 		</div>
 
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 65e2107..38c6d05 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -105,6 +105,7 @@
    -  :doc:`Directory Helper <helpers/directory_helper>` :php:func:`directory_map()` will now append ``DIRECTORY_SEPARATOR`` to directory names in the returned array.
    -  :doc:`Language Helper <helpers/language_helper>` :php:func:`lang()` now accepts an optional list of additional HTML attributes.
    -  Deprecated the :doc:`Email Helper <helpers/email_helper>` as its ``valid_email()``, ``send_email()`` functions are now only aliases for PHP native functions ``filter_var()`` and ``mail()`` respectively.
+   -  :doc:`CAPTCHA Helper <helpers/captcha_helper>` :php:func:`create_captcha` added word_length and pool options for setting length of randomly generated captcha word, and what characters to select from.
 
 -  Database
 
@@ -496,7 +497,7 @@
 -  Fixed a bug (#78) - :doc:`Cart Library <libraries/cart>` didn't allow non-English letters in product names.
 -  Fixed a bug (#77) - :doc:`Database Class <database/index>` didn't properly handle the transaction "test mode" flag.
 -  Fixed a bug (#2380) - :doc:`URI Routing <general/routing>` method ``fetch_method()`` returned 'index' if the requested method name matches its controller name.
-
+-  Fixed a bug (#2388) - :doc:`Email Library <libraries/email>` used to ignore attachment errors, resulting in broken emails being sent.
 
 Version 2.1.3
 =============
diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst
index 79bd9b4..a133fdc 100644
--- a/user_guide_src/source/general/common_functions.rst
+++ b/user_guide_src/source/general/common_functions.rst
@@ -100,11 +100,11 @@
 log_message()
 =============
 
-.. php:function:: log_message($level = 'error', $message, $php_error = FALSE)
+.. php:function:: log_message($level, $message, $php_error = FALSE)
 
-	:param	string	$level: Log level
+	:param	string	$level: Log level: 'error', 'debug' or 'info'
 	:param	string	$message: Message to log
-	:param	bool	$php_error: Whether we're loggin a native PHP error message
+	:param	bool	$php_error: Whether we're logging a native PHP error message
 	:returns:	void
 
 This function is an alias for ``CI_Log::write_log()``. For more info,
diff --git a/user_guide_src/source/general/controllers.rst b/user_guide_src/source/general/controllers.rst
index 8cfb012..04f2327 100644
--- a/user_guide_src/source/general/controllers.rst
+++ b/user_guide_src/source/general/controllers.rst
@@ -214,7 +214,9 @@
 		echo $output;
 	}
 
-.. note:: Please note that your ``_output()`` method will receive the
+.. note::
+
+	Please note that your ``_output()`` method will receive the
 	data in its finalized state. Benchmark and memory usage data
 	will be rendered, cache files written (if you have caching
 	enabled), and headers will be sent (if you use that
diff --git a/user_guide_src/source/general/errors.rst b/user_guide_src/source/general/errors.rst
index a247c1b..f12d992 100644
--- a/user_guide_src/source/general/errors.rst
+++ b/user_guide_src/source/general/errors.rst
@@ -77,11 +77,11 @@
 log_message()
 =============
 
-.. php:function:: log_message($level = 'error', $message, $php_error = FALSE)
+.. php:function:: log_message($level, $message, $php_error = FALSE)
 
-	:param	string	$level: Log level
+	:param	string	$level: Log level: 'error', 'debug' or 'info'
 	:param	string	$message: Message to log
-	:param	bool	$php_error: Whether we're loggin a native PHP error message
+	:param	bool	$php_error: Whether we're logging a native PHP error message
 	:returns:	void
 
 This function lets you write messages to your log files. You must supply
diff --git a/user_guide_src/source/helpers/captcha_helper.rst b/user_guide_src/source/helpers/captcha_helper.rst
index 17462a8..ca24e01 100644
--- a/user_guide_src/source/helpers/captcha_helper.rst
+++ b/user_guide_src/source/helpers/captcha_helper.rst
@@ -62,7 +62,9 @@
 		'font_path'	=> './path/to/fonts/texb.ttf',
 		'img_width'	=> '150',
 		'img_height'	=> 30,
-		'expiration'	=> 7200
+		'expiration'	=> 7200,
+		'word_length'	=> 8,
+		'pool'	=> '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
 	);
 
 	$cap = create_captcha($vals);
@@ -79,6 +81,7 @@
 -  The **expiration** (in seconds) signifies how long an image will remain
    in the captcha folder before it will be deleted. The default is two
    hours.
+-  **word_length** defaults to 8, **pool** defaults to '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
 Adding a Database
 -----------------
diff --git a/user_guide_src/source/libraries/xmlrpc.rst b/user_guide_src/source/libraries/xmlrpc.rst
index b478a2d..a43c488 100644
--- a/user_guide_src/source/libraries/xmlrpc.rst
+++ b/user_guide_src/source/libraries/xmlrpc.rst
@@ -423,7 +423,7 @@
 	$parameters = $request->output_parameters();
 	$name = $parameters[0]['name'];
 	$size = $parameters[1]['size'];
-	$size = $parameters[1]['shape'];
+	$shape = $parameters[1]['shape'];
 
 **************************
 XML-RPC Function Reference