X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fexception%2FMWExceptionHandler.php;h=b4e483bf53289f935f3d49a94b78d53f60fd1c9d;hb=e390198c4e4be7632b01173e42050061f1cc346a;hp=bd823b5e07c3ea6f6052518fb7fc27eb4fb3be61;hpb=0e56ff447bbb74df007f2573725baaa61ed2745c;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/exception/MWExceptionHandler.php b/includes/exception/MWExceptionHandler.php index bd823b5e07..b4e483bf53 100644 --- a/includes/exception/MWExceptionHandler.php +++ b/includes/exception/MWExceptionHandler.php @@ -35,12 +35,35 @@ class MWExceptionHandler { * @var string $reservedMemory */ protected static $reservedMemory; + /** + * Error types that, if unhandled, are fatal to the request. + * + * On PHP 7, these error types may be thrown as Error objects, which + * implement Throwable (but not Exception). + * + * On HHVM, these invoke the set_error_handler callback, similar to how + * (non-fatal) warnings and notices are reported, except that after this + * handler runs for fatal error tpyes, script execution stops! + * + * The user will be shown an HTTP 500 Internal Server Error. + * As such, these should be sent to MediaWiki's "fatal" or "exception" + * channel. Normally, the error handler logs them to the "error" channel. + * * @var array $fatalErrorTypes */ protected static $fatalErrorTypes = [ - E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, - /* HHVM's FATAL_ERROR level */ 16777217, + E_ERROR, + E_PARSE, + E_CORE_ERROR, + E_COMPILE_ERROR, + E_USER_ERROR, + + // E.g. "Catchable fatal error: Argument X must be Y, null given" + E_RECOVERABLE_ERROR, + + // HHVM's FATAL_ERROR constant + 16777217, ]; /** * @var bool $handledFatalCallback @@ -51,9 +74,32 @@ class MWExceptionHandler { * Install handlers with PHP. */ public static function installHandler() { + // This catches: + // * Exception objects that were explicitly thrown but not + // caught anywhere in the application. This is rare given those + // would normally be caught at a high-level like MediaWiki::run (index.php), + // api.php, or ResourceLoader::respond (load.php). These high-level + // catch clauses would then call MWExceptionHandler::logException + // or MWExceptionHandler::handleException. + // If they are not caught, then they are handled here. + // * Error objects (on PHP 7+), for issues that would historically + // cause fatal errors but may now be caught as Throwable (not Exception). + // Same as previous case, but more common to bubble to here instead of + // caught locally because they tend to not be safe to recover from. + // (e.g. argument TypeErorr, devision by zero, etc.) set_exception_handler( 'MWExceptionHandler::handleUncaughtException' ); + + // This catches: + // * Non-fatal errors (e.g. PHP Notice, PHP Warning, PHP Error) that do not + // interrupt execution in any way. We log these in the background and then + // continue execution. + // * Fatal errors (on HHVM in PHP5 mode) where PHP 7 would throw Throwable. set_error_handler( 'MWExceptionHandler::handleError' ); + // This catches: + // * Fatal error for which no Throwable is thrown (PHP 7), and no Error emitted (HHVM). + // This includes Out-Of-Memory and Timeout fatals. + // // Reserve 16k of memory so we can report OOM fatals self::$reservedMemory = str_repeat( ' ', 16384 ); register_shutdown_function( 'MWExceptionHandler::handleFatalError' ); @@ -192,10 +238,6 @@ class MWExceptionHandler { // behaviour given the null was not part of the code and is likely not // accounted for. switch ( $level ) { - case E_RECOVERABLE_ERROR: - $levelName = 'Error'; - $severity = LogLevel::ERROR; - break; case E_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: @@ -206,8 +248,12 @@ class MWExceptionHandler { $levelName = 'Notice'; $severity = LogLevel::ERROR; break; - case E_USER_WARNING: case E_USER_NOTICE: + // Used by wfWarn(), MWDebug::warning() + $levelName = 'Notice'; + $severity = LogLevel::WARNING; + break; + case E_USER_WARNING: // Used by wfWarn(), MWDebug::warning() $levelName = 'Warning'; $severity = LogLevel::WARNING; @@ -231,9 +277,9 @@ class MWExceptionHandler { self::logError( $e, 'error', $severity ); // If $wgPropagateErrors is true return false so PHP shows/logs the error normally. - // Ignore $wgPropagateErrors if the error should break execution, or track_errors is set + // Ignore $wgPropagateErrors if track_errors is set // (which means someone is counting on regular PHP error handling behavior). - return !( $wgPropagateErrors || $level == E_RECOVERABLE_ERROR || ini_get( 'track_errors' ) ); + return !( $wgPropagateErrors || ini_get( 'track_errors' ) ); } /** @@ -439,22 +485,6 @@ TXT; }, $trace ); } - /** - * Get the ID for this exception. - * - * The ID is saved so that one can match the one output to the user (when - * $wgShowExceptionDetails is set to false), to the entry in the debug log. - * - * @since 1.22 - * @deprecated since 1.27: Exception IDs are synonymous with request IDs. - * @param Exception|Throwable $e - * @return string - */ - public static function getLogId( $e ) { - wfDeprecated( __METHOD__, '1.27' ); - return WebRequest::getRequestId(); - } - /** * If the exception occurred in the course of responding to a request, * returns the requested URL. Otherwise, returns false.