Add a real exception handler
Close #1590
Close #3200
diff --git a/application/views/errors/cli/error_exception.php b/application/views/errors/cli/error_exception.php
new file mode 100755
index 0000000..3314fa1
--- /dev/null
+++ b/application/views/errors/cli/error_exception.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014, British Columbia Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://codeigniter.com
+ * @since Version 3.0.0
+ * @filesource
+ */
+defined('BASEPATH') OR exit('No direct script access allowed');
+?>
+
+An uncaught Exception was encountered
+
+Type: <?php echo get_class($exception); ?>
+Message: <?php echo $message; ?>
+Filename: <?php echo $exception->getFile(); ?>
+Line Number: <?php echo $exception->getLine(); ?>
+
+<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
+
+Backtrace:
+ <?php foreach ($exception->getTrace() as $error): ?>
+ <?php if (isset($error['file']) && strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
+
+ File: <?php echo $error['file']; ?>
+ Line: <?php echo $error['line']; ?>
+ Function: <?php echo $error['function']; ?>
+
+ <?php endif ?>
+
+ <?php endforeach ?>
+<?php endif ?>
\ No newline at end of file
diff --git a/application/views/errors/html/error_exception.php b/application/views/errors/html/error_exception.php
new file mode 100755
index 0000000..2f3fe40
--- /dev/null
+++ b/application/views/errors/html/error_exception.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * CodeIgniter
+ *
+ * An open source application development framework for PHP 5.2.4 or newer
+ *
+ * This content is released under the MIT License (MIT)
+ *
+ * Copyright (c) 2014, British Columbia Institute of Technology
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @package CodeIgniter
+ * @author EllisLab Dev Team
+ * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
+ * @copyright Copyright (c) 2014, British Columbia Institute of Technology (http://bcit.ca/)
+ * @license http://opensource.org/licenses/MIT MIT License
+ * @link http://codeigniter.com
+ * @since Version 1.0.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;">
+
+<h4>An uncaught Exception was encountered</h4>
+
+<p>Type: <?php echo get_class($exception); ?></p>
+<p>Message: <?php echo $message; ?></p>
+<p>Filename: <?php echo $exception->getFile(); ?></p>
+<p>Line Number: <?php echo $exception->getLine(); ?></p>
+
+<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
+
+ <p>Backtrace:</p>
+ <?php foreach ($exception->getTrace() as $error): ?>
+
+ <?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>
+ <?php endif ?>
+
+ <?php endforeach ?>
+
+<?php endif ?>
+
+</div>
\ No newline at end of file
diff --git a/system/core/CodeIgniter.php b/system/core/CodeIgniter.php
index e3d3a1f..88e730b 100644
--- a/system/core/CodeIgniter.php
+++ b/system/core/CodeIgniter.php
@@ -132,7 +132,8 @@
* Define a custom error handler so we can log PHP errors
* ------------------------------------------------------
*/
- set_error_handler('_exception_handler');
+ set_error_handler('_error_handler');
+ set_exception_handler('_exception_handler');
register_shutdown_function('_shutdown_handler');
/*
diff --git a/system/core/Common.php b/system/core/Common.php
index 8bc9d01..4277ef5 100644
--- a/system/core/Common.php
+++ b/system/core/Common.php
@@ -570,17 +570,17 @@
// --------------------------------------------------------------------
-if ( ! function_exists('_exception_handler'))
+if ( ! function_exists('_error_handler'))
{
/**
- * Exception Handler
+ * Error Handler
*
- * This is the custom exception handler that is declared at the top
- * of CodeIgniter.php. The main reason we use this is to permit
+ * This is the custom error handler that is declared at the (relative)
+ * top of CodeIgniter.php. The main reason we use this is to permit
* PHP errors to be logged in our own log files since the user may
- * not have access to server logs. Since this function
- * effectively intercepts PHP errors, however, we also need
- * to display errors based on the current error_reporting level.
+ * not have access to server logs. Since this function effectively
+ * intercepts PHP errors, however, we also need to display errors
+ * based on the current error_reporting level.
* We do that with the use of a PHP error template.
*
* @param int $severity
@@ -589,7 +589,7 @@
* @param int $line
* @return void
*/
- function _exception_handler($severity, $message, $filepath, $line)
+ function _error_handler($severity, $message, $filepath, $line)
{
$is_error = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
@@ -632,6 +632,35 @@
// ------------------------------------------------------------------------
+if ( ! function_exists('_exception_handler'))
+{
+ /**
+ * Exception Handler
+ *
+ * Sends uncaught exceptions to the logger and displays them
+ * only if display_errors is On so that they don't show up in
+ * production environments.
+ *
+ * @param Exception $exception
+ * @return void
+ */
+ function _exception_handler($exception)
+ {
+ $_error =& load_class('Exceptions', 'core');
+ $_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
+
+ // Should we display the error?
+ if (ini_get('display_errors'))
+ {
+ $_error->show_exception($exception);
+ }
+
+ exit(1); // EXIT_ERROR
+ }
+}
+
+// ------------------------------------------------------------------------
+
if ( ! function_exists('_shutdown_handler'))
{
/**
diff --git a/system/core/Exceptions.php b/system/core/Exceptions.php
index 6324fba..0531a4e 100644
--- a/system/core/Exceptions.php
+++ b/system/core/Exceptions.php
@@ -187,6 +187,44 @@
// --------------------------------------------------------------------
+ public function show_exception(Exception $exception)
+ {
+ $templates_path = config_item('error_views_path');
+ if (empty($templates_path))
+ {
+ $templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR;
+ }
+
+ $message = $exception->getMessage();
+ if (empty($message))
+ {
+ $message = '(null)';
+ }
+
+ if (is_cli())
+ {
+ $templates_path .= 'cli'.DIRECTORY_SEPARATOR;
+ }
+ else
+ {
+ set_status_header(500);
+ $templates_path .= 'html'.DIRECTORY_SEPARATOR;
+ }
+
+ if (ob_get_level() > $this->ob_level + 1)
+ {
+ ob_end_flush();
+ }
+
+ ob_start();
+ include($templates_path.'error_exception.php');
+ $buffer = ob_get_contents();
+ ob_end_clean();
+ echo $buffer;
+ }
+
+ // --------------------------------------------------------------------
+
/**
* Native PHP error handler
*
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index 909c3bc..9d56748 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -42,9 +42,9 @@
Only entries in ``$autoload['libraries']`` are auto-loaded now.
- Removed previously deprecated EXT constant.
- Updated all classes to be written in PHP 5 style, with visibility declarations and no ``var`` usage for properties.
- - Moved error templates to *application/views/errors/*.
+ - Added an Exception handler.
+ - Moved error templates to *application/views/errors/* and made the path configurable via ``$config['error_views_path']``.
- Added support non-HTML error templates for CLI applications.
- - Made error templates path configurable using ``$config['error_views_path']``.
- Moved the Log class to *application/core/*
- Global config files are loaded first, then environment ones. Environment config keys overwrite base ones, allowing to only set the keys we want changed per environment.
- Changed detection of ``$view_folder`` so that if it's not found in the current path, it will now also be searched for under the application folder.
@@ -480,7 +480,8 @@
- Added function :func:`get_mimes()` to return the *application/config/mimes.php* array.
- Added support for HTTP code 303 ("See Other") in :func:`set_status_header()`.
- Removed redundant conditional to determine HTTP server protocol in :func:`set_status_header()`.
- - Changed ``_exception_handler()`` to respect php.ini *display_errors* setting.
+ - Renamed ``_exception_handler()`` to ``_error_handler()`` and replaced it with a real exception handler.
+ - Changed ``_error_handler()`` to respect php.ini *display_errors* setting.
- Added function :func:`is_https()` to check if a secure connection is used.
- Added function :func:`is_cli()` to replace the ``CI_Input::is_cli_request()`` method.
- Added function :func:`function_usable()` to work around a bug in `Suhosin <http://www.hardened-php.net/suhosin/>`.
@@ -547,7 +548,7 @@
- Removed ``CI_CORE`` boolean constant from *CodeIgniter.php* (no longer Reactor and Core versions).
- Added support for HTTP-Only cookies with new config option *cookie_httponly* (default FALSE).
- ``$config['time_reference']`` now supports all timezone strings supported by PHP.
- - Fatal PHP errors are now also passed to ``_exception_handler()``, so they can be logged.
+ - Fatal PHP errors are now also passed to ``_error_handler()``, so they can be logged.
Bug fixes for 3.0