Add CLI error templates and only send HTTP status headers for non-CLI requests (issue #1743)
diff --git a/application/views/errors/cli/error_404.php b/application/views/errors/cli/error_404.php
new file mode 100644
index 0000000..68ffdb3
--- /dev/null
+++ b/application/views/errors/cli/error_404.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Academic Free License version 3.0
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0) that is
+ * bundled with this package in the files license_afl.txt / license_afl.rst.
+ * It is also available through the world wide web at this URL:
+ * http://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+echo "\nERROR: ",
+	$heading,
+	"\n\n",
+	$message,
+	"\n\n";
\ No newline at end of file
diff --git a/application/views/errors/cli/error_db.php b/application/views/errors/cli/error_db.php
new file mode 100644
index 0000000..aca3a34
--- /dev/null
+++ b/application/views/errors/cli/error_db.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Academic Free License version 3.0
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0) that is
+ * bundled with this package in the files license_afl.txt / license_afl.rst.
+ * It is also available through the world wide web at this URL:
+ * http://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 3.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+echo "\nDatabase error: ",
+	$heading,
+	"\n\n",
+	$message,
+	"\n\n";
\ No newline at end of file
diff --git a/application/views/errors/cli/error_general.php b/application/views/errors/cli/error_general.php
new file mode 100644
index 0000000..1e5ffe5
--- /dev/null
+++ b/application/views/errors/cli/error_general.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * NOTICE OF LICENSE
+ *
+ * Licensed under the Academic Free License version 3.0
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0) that is
+ * bundled with this package in the files license_afl.txt / license_afl.rst.
+ * It is also available through the world wide web at this URL:
+ * http://opensource.org/licenses/AFL-3.0
+ * If you did not receive a copy of the license and are unable to obtain it
+ * through the world wide web, please send an email to
+ * licensing@ellislab.com so we can send you a copy immediately.
+ *
+ * @package		CodeIgniter
+ * @author		EllisLab Dev Team
+ * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
+ * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
+ * @link		http://codeigniter.com
+ * @since		Version 1.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+
+echo "\nERROR: ",
+	$heading,
+	"\n\n",
+	$message,
+	"\n\n";
\ No newline at end of file
diff --git a/application/views/errors/error_php.php b/application/views/errors/cli/error_php.php
similarity index 61%
copy from application/views/errors/error_php.php
copy to application/views/errors/cli/error_php.php
index c4e6b29..4dbc410 100644
--- a/application/views/errors/error_php.php
+++ b/application/views/errors/cli/error_php.php
@@ -21,39 +21,30 @@
  * @copyright	Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
  * @license		http://opensource.org/licenses/AFL-3.0 Academic Free License (AFL 3.0)
  * @link		http://codeigniter.com
- * @since		Version 1.0
+ * @since		Version 3.0
  * @filesource
  */
 defined('BASEPATH') OR exit('No direct script access allowed');
 ?>
 
-<div style="border:1px solid #990000;padding-left:20px;margin:0 0 10px 0;">
+A PHP Error was encountered
 
-<h4>A PHP Error was encountered</h4>
-
-<p>Severity: <?php echo $severity; ?></p>
-<p>Message:  <?php echo $message; ?></p>
-<p>Filename: <?php echo $filepath; ?></p>
-<p>Line Number: <?php echo $line; ?></p>
+Severity: <?php echo $severity;?>
+Message:  <?php echo $message;?>
+Filename: <?php echo $filepath;?>
+Line Number: <?php echo $line;?>
 
 <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
 
-	<p>Backtrace: </p>
-	<?php foreach(debug_backtrace() as $error): ?>
+Backtrace:
+	<?php foreach (debug_backtrace() as $error): ?>
+		<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
 
-		<?php if(isset($error['file']) &&
-		         strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
-
-			<p style="margin-left:10px">
-			File: <?php echo $error['file'] ?><br />
-			Line: <?php echo $error['line'] ?><br />
-			Function: <?php echo $error['function'] ?>
-			</p>
+	File: <?php echo $error['file'];?>
+	Line: <?php echo $error['line'];?>
+	Function: <?php echo $error['function'];?>
 
 		<?php endif ?>
 
-	<?php endforeach ?></p>
-
-<?php endif ?>
-
-</div>
\ No newline at end of file
+	<?php endforeach ?>
+<?php endif ?>
\ No newline at end of file
diff --git a/application/views/errors/cli/index.html b/application/views/errors/cli/index.html
new file mode 100644
index 0000000..c942a79
--- /dev/null
+++ b/application/views/errors/cli/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/application/views/errors/error_404.php b/application/views/errors/html/error_404.php
similarity index 100%
rename from application/views/errors/error_404.php
rename to application/views/errors/html/error_404.php
diff --git a/application/views/errors/error_db.php b/application/views/errors/html/error_db.php
similarity index 100%
rename from application/views/errors/error_db.php
rename to application/views/errors/html/error_db.php
diff --git a/application/views/errors/error_general.php b/application/views/errors/html/error_general.php
similarity index 100%
rename from application/views/errors/error_general.php
rename to application/views/errors/html/error_general.php
diff --git a/application/views/errors/error_php.php b/application/views/errors/html/error_php.php
similarity index 90%
rename from application/views/errors/error_php.php
rename to application/views/errors/html/error_php.php
index c4e6b29..2267d98 100644
--- a/application/views/errors/error_php.php
+++ b/application/views/errors/html/error_php.php
@@ -38,11 +38,10 @@
 
 <?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
 
-	<p>Backtrace: </p>
-	<?php foreach(debug_backtrace() as $error): ?>
+	<p>Backtrace:</p>
+	<?php foreach (debug_backtrace() as $error): ?>
 
-		<?php if(isset($error['file']) &&
-		         strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
+		<?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
 
 			<p style="margin-left:10px">
 			File: <?php echo $error['file'] ?><br />
diff --git a/application/views/errors/html/index.html b/application/views/errors/html/index.html
new file mode 100644
index 0000000..c942a79
--- /dev/null
+++ b/application/views/errors/html/index.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+	<title>403 Forbidden</title>
+</head>
+<body>
+
+<p>Directory access is forbidden.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
index d7e5ed4..809dc02 100644
--- a/system/core/Exceptions.php
+++ b/system/core/Exceptions.php
@@ -91,7 +91,7 @@
 	public function log_exception($severity, $message, $filepath, $line)
 	{
 		$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
-		log_message('error', 'Severity: '.$severity.'  --> '.$message. ' '.$filepath.' '.$line);
+		log_message('error', 'Severity: '.$severity.' --> '.$message.' '.$filepath.' '.$line);
 	}
 
 	// --------------------------------------------------------------------
@@ -107,13 +107,21 @@
 	 */
 	public function show_404($page = '', $log_error = TRUE)
 	{
-		$heading = '404 Page Not Found';
-		$message = 'The page you requested was not found.';
+		if (is_cli())
+		{
+			$heading = 'Not Found';
+			$message = 'The controller/method pair you requested was not found.';
+		}
+		else
+		{
+			$heading = '404 Page Not Found';
+			$message = 'The page you requested was not found.';
+		}
 
 		// By default we log this, but allow a dev to skip it
 		if ($log_error)
 		{
-			log_message('error', '404 Page Not Found --> '.$page);
+			log_message('error', $heading.': '.$page);
 		}
 
 		echo $this->show_error($heading, $message, 'error_404', 404);
@@ -137,16 +145,24 @@
 	 */
 	public function show_error($heading, $message, $template = 'error_general', $status_code = 500)
 	{
-		set_status_header($status_code);
-
-		$message = '<p>'.implode('</p><p>', is_array($message) ? $message : array($message)).'</p>';
+		if (is_cli())
+		{
+			$message = "\t".(is_array($message) ? implode("\n\t", $message) : $message);
+			$template = 'cli'.DIRECTORY_SEPARATOR.$template;
+		}
+		else
+		{
+			set_status_header($status_code);
+			$message = '<p>'.(is_array($message) ? implode('</p><p>', $message) : $message).'</p>';
+			$template = 'html'.DIRECTORY_SEPARATOR.$template;
+		}
 
 		if (ob_get_level() > $this->ob_level + 1)
 		{
 			ob_end_flush();
 		}
 		ob_start();
-		include(VIEWPATH.'errors/'.$template.'.php');
+		include(VIEWPATH.'errors'.DIRECTORY_SEPARATOR.$template.'.php');
 		$buffer = ob_get_contents();
 		ob_end_clean();
 		return $buffer;
@@ -166,13 +182,22 @@
 	public function show_php_error($severity, $message, $filepath, $line)
 	{
 		$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
-		$filepath = str_replace('\\', '/', $filepath);
 
-		// For safety reasons we do not show the full file path
-		if (FALSE !== strpos($filepath, '/'))
+		// For safety reasons we don't show the full file path in non-CLI requests
+		if ( ! is_cli())
 		{
-			$x = explode('/', $filepath);
-			$filepath = $x[count($x)-2].'/'.end($x);
+			$filepath = str_replace('\\', '/', $filepath);
+			if (FALSE !== strpos($filepath, '/'))
+			{
+				$x = explode('/', $filepath);
+				$filepath = $x[count($x)-2].'/'.end($x);
+			}
+
+			$template = 'html'.DIRECTORY_SEPARATOR.'error_php';
+		}
+		else
+		{
+			$template = 'cli'.DIRECTORY_SEPARATOR.'error_php';
 		}
 
 		if (ob_get_level() > $this->ob_level + 1)
@@ -180,7 +205,7 @@
 			ob_end_flush();
 		}
 		ob_start();
-		include(VIEWPATH.'errors/error_php.php');
+		include(VIEWPATH.'errors'.DIRECTORY_SEPARATOR.$template.'.php');
 		$buffer = ob_get_contents();
 		ob_end_clean();
 		echo $buffer;
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 23fd958..93e75c2 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -55,6 +55,7 @@
    -  Changed environment defaults to report all errors in *development* and only fatal ones in *testing*, *production* but only display them in *development*.
    -  Updated *ip_address* database field lengths from 16 to 45 for supporting IPv6 address on :doc:`Trackback Library <libraries/trackback>` and :doc:`Captcha Helper <helpers/captcha_helper>`.
    -  Removed *cheatsheets* and *quick_reference* PDFs from the documentation.
+   -  Added support non-HTML error templates for CLI applications.
    -  Added availability checks where usage of dangerous functions like ``eval()`` and ``exec()`` is required.
    -  Added support for changing the file extension of log files using ``$config['log_file_extension']``.