From 26a605bf50058e3ce80aaf3e4171aa7d3d4adf29 Mon Sep 17 00:00:00 2001 From: Awilum Date: Mon, 7 Jan 2013 00:52:00 +0200 Subject: [PATCH] Core Improvements: Next Round #79 #80 --- engine/Core.php | 246 +--------------- engine/Security.php | 23 +- engine/Uri.php | 23 +- engine/_init.php | 55 ++-- index.php | 4 +- libraries/Gelato/ErrorHandler.php | 276 ++++++++++++++++++ libraries/Gelato/Gelato.php | 40 ++- .../Gelato/{docs => Resources/Docs}/README.md | 0 .../{docs => Resources/Docs}/changelog.txt | 0 .../{docs => Resources/Docs}/license.txt | 0 .../Resources/Views/Errors/exception.php | 225 ++++++++++++++ .../Resources/Views/Errors/production.php | 69 +++++ 12 files changed, 665 insertions(+), 296 deletions(-) create mode 100644 libraries/Gelato/ErrorHandler.php rename libraries/Gelato/{docs => Resources/Docs}/README.md (100%) rename libraries/Gelato/{docs => Resources/Docs}/changelog.txt (100%) rename libraries/Gelato/{docs => Resources/Docs}/license.txt (100%) create mode 100644 libraries/Gelato/Resources/Views/Errors/exception.php create mode 100644 libraries/Gelato/Resources/Views/Errors/production.php diff --git a/engine/Core.php b/engine/Core.php index 742fa76..1c4ec2a 100644 --- a/engine/Core.php +++ b/engine/Core.php @@ -1,7 +1,7 @@ 0) ob_end_clean(); - - // Send headers and output - @header('Content-Type: text/html; charset=UTF-8'); - @header('HTTP/1.1 500 Internal Server Error'); - - // Get highlighted code - $code = Core::highlightCode($exception->getFile(), $exception->getLine()); - - // Determine error type - if ($exception instanceof ErrorException) { - - $error_type = 'ErrorException: '; - - $codes = array ( - E_ERROR => 'Fatal Error', - E_PARSE => 'Parse Error', - E_COMPILE_ERROR => 'Compile Error', - E_COMPILE_WARNING => 'Compile Warning', - E_STRICT => 'Strict Mode Error', - E_NOTICE => 'Notice', - E_WARNING => 'Warning', - E_RECOVERABLE_ERROR => 'Recoverable Error', - /*E_DEPRECATED => 'Deprecated',*/ /* PHP 5.3 */ - E_USER_NOTICE => 'Notice', - E_USER_WARNING => 'Warning', - E_USER_ERROR => 'Error', - /*E_USER_DEPRECATED => 'Deprecated'*/ /* PHP 5.3 */ - ); - - $error_type .= in_array($exception->getCode(), array_keys($codes)) ? $codes[$exception->getCode()] : 'Unknown Error'; - } else { - $error_type = get_class($exception); - } - - // Show exception if core environment is DEVELOPMENT - if (Core::$environment == Core::DEVELOPMENT) { - - // Development - echo (" - - - - - Monstra - - - -
-

Monstra - ".$error_type."

-

".$exception->getMessage()."

-

Location

-

Exception thrown on line ".$exception->getLine()." in ".$exception->getFile()."

- "); - - if ( ! empty($code)) { - echo '
'; - foreach ($code as $line) { - echo '
' . $line['number'] . '' . $line['code'] . '
'; - } - echo '
'; - } - - echo '
'; - - } else { - - // Production - echo (" - - - - - Monstra - - - -
-

Oops!

-

An unexpected error has occurred.

-
- - - "); - } - - // Writes message to log - @file_put_contents(LOGS . DS . gmdate('Y_m_d') . '.log', - gmdate('Y/m/d H:i:s') . ' --- ' . '['.$error_type.']' . ' --- ' . $exception->getMessage() . ' --- ' . 'Exception thrown on line '.$exception->getLine().' in '.$exception->getFile() . "\n", - FILE_APPEND); - - exit(1); - } - - /** - * Converts errors to ErrorExceptions. - * - * @param integer $code The error code - * @param string $message The error message - * @param string $file The filename where the error occurred - * @param integer $line The line number where the error occurred - * @return boolean - */ - public static function errorHandler($code, $message, $file, $line) - { - // If isset error_reporting and $code then throw new error exception - if ((error_reporting() & $code) !== 0) { - throw new ErrorException($message, $code, 0, $file, $line); - } - - // Don't execute PHP internal error handler - return true; - } - - - - /** - * Returns an array of lines from a file. - * - * @param string $file File in which you want to highlight a line - * @param integer $line Line number to highlight - * @param integer $padding Number of padding lines - * @return array - */ - protected static function highlightCode($file, $line, $padding = 5) - { - // Is file readable ? - if ( ! is_readable($file)) { - return false; - } - - // Init vars - $lines = array(); - $current_line = 0; - - // Open file - $handle = fopen($file, 'r'); - - // Read file - while ( ! feof($handle)) { - - $current_line++; - - $temp = fgets($handle); - - if ($current_line > $line + $padding) { - break; // Exit loop after we have found what we were looking for - } - - if ($current_line >= ($line - $padding) && $current_line <= ($line + $padding)) { - - $lines[] = array ( - 'number' => str_pad($current_line, 4, ' ', STR_PAD_LEFT), - 'highlighted' => ($current_line === $line), - 'code' => Core::highlightString($temp), - ); - } - } - - // Close - fclose($handle); - - // Return lines - return $lines; - } - - - /** - * Highlight string - * - * @param string $string String - * @return string - */ - protected static function highlightString($string) - { - return str_replace(array("\n", '', '', '<?php ', '#$@r4!/*'), - array('', '', '', '', '/*'), - highlight_string(' $line + $padding) { + break; // Exit loop after we have found what we were looking for + } + + if ($currentLine >= ($line - $padding) && $currentLine <= ($line + $padding)) { + $lines[] = array + ( + 'number' => str_pad($currentLine, 4, ' ', STR_PAD_LEFT), + 'highlighted' => ($currentLine === $line), + 'code' => ErrorHandler::highlightString($temp), + ); + } + } + + fclose($handle); + + return $lines; + } + + /** + * Converts errors to ErrorExceptions. + * + * @param integer $code The error code + * @param string $message The error message + * @param string $file The filename where the error occurred + * @param integer $line The line number where the error occurred + * @return boolean + */ + public static function errorHandler($code, $message, $file, $line) + { + // If isset error_reporting and $code then throw new error exception + if ((error_reporting() & $code) !== 0) { + throw new ErrorException($message, $code, 0, $file, $line); + } + + // Don't execute PHP internal error handler + return true; + } + + /** + * Highlight string + * + * @param string $string String + * @return string + */ + protected static function highlightString($string) + { + $search = array("\r\n", "\n\r", "\r", "\n", '', '', '<?php ', '#$@r4!/*'); + $replace = array('', '', '', '', '', '', '', '/*'); + + return str_replace($search, $replace, highlight_string(' 0) { + foreach ($entry['args'] as $arg) { + ob_start(); + + var_dump($arg); + + $arg = htmlspecialchars(ob_get_contents()); + + ob_end_clean(); + + $arguments[] = $arg; + } + } + + // Location + + $location = array(); + + if (isset($entry['file'])) { + $location['file'] = $entry['file']; + $location['line'] = $entry['line']; + $location['code'] = static::highlightCode($entry['file'], $entry['line']); + } + + // Compile into array + + $trace[] = array + ( + 'function' => $function, + 'arguments' => $arguments, + 'location' => $location, + ); + } + + return $trace; + } + + /** + * Convert errors not caught by the errorHandler to ErrorExceptions. + */ + public static function fatalErrorHandler() + { + $e = error_get_last(); + + if ($e !== null && (error_reporting() & $e['type']) !== 0) { + ErrorHandler::exception(new ErrorException($e['message'], $e['type'], 0, $e['file'], $e['line'])); + + exit(1); + } + } + + /** + * Handles uncaught exceptions and returns a pretty error screen. + * + * @access public + * @param Exception $exception An exception object + */ + public static function exception($exception) + { + try { + // Empty output buffers + + while(ob_get_level() > 0) ob_end_clean(); + + // Get exception info + + $error['code'] = $exception->getCode(); + $error['message'] = $exception->getMessage(); + $error['file'] = $exception->getFile(); + $error['line'] = $exception->getLine(); + + // Determine error type + + if ($exception instanceof ErrorException) { + $error['type'] = 'ErrorException: '; + + $codes = array + ( + E_ERROR => 'Fatal Error', + E_PARSE => 'Parse Error', + E_COMPILE_ERROR => 'Compile Error', + E_COMPILE_WARNING => 'Compile Warning', + E_STRICT => 'Strict Mode Error', + E_NOTICE => 'Notice', + E_WARNING => 'Warning', + E_RECOVERABLE_ERROR => 'Recoverable Error', + /*E_DEPRECATED => 'Deprecated',*/ + E_USER_NOTICE => 'Notice', + E_USER_WARNING => 'Warning', + E_USER_ERROR => 'Error', + /*E_USER_DEPRECATED => 'Deprecated'*/ + ); + + $error['type'] .= in_array($error['code'], array_keys($codes)) ? $codes[$error['code']] : 'Unknown Error'; + } else { + $error['type'] = get_class($exception); + } + + // Write to error log + + /*if () { + Write here + }*/ + + // Send headers and output + @header('Content-Type: text/html; charset=UTF-8'); + + if (GELATO_DISPLAY_ERRORS) { + $error['backtrace'] = $exception->getTrace(); + + if ($exception instanceof ErrorException) { + $error['backtrace'] = array_slice($error['backtrace'], 1); //Remove call to error handler from backtrace + } + + $error['backtrace'] = static::formatBacktrace($error['backtrace']); + $error['highlighted'] = static::highlightCode($error['file'], $error['line']); + + Response::status(500); + include 'Resources/Templates/exception.php'; + } else { + Response::status(500); + include 'Resources/Templates/error.php'; + } + } catch (Exception $e) { + while(ob_get_level() > 0) ob_end_clean(); + + echo $e->getMessage() . ' in ' . $e->getFile() . ' (line ' . $e->getLine() . ').'; + } + + exit(1); + } +} diff --git a/libraries/Gelato/Gelato.php b/libraries/Gelato/Gelato.php index 63c6996..02bb78a 100644 --- a/libraries/Gelato/Gelato.php +++ b/libraries/Gelato/Gelato.php @@ -13,6 +13,18 @@ * @since 1.0.0 */ +/** + * The version of Gelato + */ +define('GELATO_VERSION', '1.0.0'); + +/** + * Display Gelato Errors or not ? + */ +if ( ! defined('GELATO_DISPLAY_ERRORS')) { + define('GELATO_DISPLAY_ERRORS', true); +} + /** * Should we use the Gelato Autoloader to ensure the dependancies are automatically * loaded? @@ -22,7 +34,27 @@ if ( ! defined('GELATO_AUTOLOADER')) { } /** - * Register autoload function + * Load Gelato Error Handler + */ +require_once __DIR__ . '/ErrorHandler.php'; + +/** + * Set Error Handler + */ +set_error_handler('ErrorHandler::errorHandler'); + +/** + * Set Fatal Error Handler + */ +register_shutdown_function('ErrorHandler::fatalErrorHandler'); + +/** + * Set Exception Handler + */ +set_exception_handler('ErrorHandler::exception'); + +/** + * Register Gelato Autoloader */ if (GELATO_AUTOLOADER) { spl_autoload_register(array('Gelato', 'autoload')); @@ -33,12 +65,6 @@ if (GELATO_AUTOLOADER) { */ class Gelato { - - /** - * The version of Gelato - */ - const VERSION = '1.0.0'; - /** * Registry of variables * diff --git a/libraries/Gelato/docs/README.md b/libraries/Gelato/Resources/Docs/README.md similarity index 100% rename from libraries/Gelato/docs/README.md rename to libraries/Gelato/Resources/Docs/README.md diff --git a/libraries/Gelato/docs/changelog.txt b/libraries/Gelato/Resources/Docs/changelog.txt similarity index 100% rename from libraries/Gelato/docs/changelog.txt rename to libraries/Gelato/Resources/Docs/changelog.txt diff --git a/libraries/Gelato/docs/license.txt b/libraries/Gelato/Resources/Docs/license.txt similarity index 100% rename from libraries/Gelato/docs/license.txt rename to libraries/Gelato/Resources/Docs/license.txt diff --git a/libraries/Gelato/Resources/Views/Errors/exception.php b/libraries/Gelato/Resources/Views/Errors/exception.php new file mode 100644 index 0000000..319e8a5 --- /dev/null +++ b/libraries/Gelato/Resources/Views/Errors/exception.php @@ -0,0 +1,225 @@ + + +
+ +
+ [] +Gelato +
+
+Message: + + +

+Location: (line ) + + + +

+
+ + class="highlighted"> + +
+ +
+ + +
+Backtrace + +
+ + + +
+Superglobals + +
+ + +
+Included Files + +
+ + + + +
+ + diff --git a/libraries/Gelato/Resources/Views/Errors/production.php b/libraries/Gelato/Resources/Views/Errors/production.php new file mode 100644 index 0000000..ee3d012 --- /dev/null +++ b/libraries/Gelato/Resources/Views/Errors/production.php @@ -0,0 +1,69 @@ + + + + +Error + + + + + + +
+

Error

+
+

Aw, snap! An error has occurred while processing your request.

+
+ +