Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Yii Framework 2 Change Log
- Bug #20764: Fix `@return` annotation for `Model::rules()` (mspirkov)
- Bug #20697: `loadTableIndexes()` includes LOB indexes with `NULL` column names, causing `strpos()` deprecation on PHP `8.1+` (terabytesoftw)
- Chg #20757: Remove dead code for PHP < 7.4 in `Security` (WarLikeLaux)
- Enh #20780: Add configurable `ErrorHandler::$fallbackExceptionMessage` property (WarLikeLaux)


2.0.54 January 09, 2026
Expand Down
21 changes: 20 additions & 1 deletion framework/base/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ abstract class ErrorHandler extends Component
* @since 2.0.36
*/
public $silentExitOnException;
/**
* @var string|callable the message displayed to end users when an error occurs while handling another error.
* This message is only shown when [[YII_DEBUG]] is `false`.
* If a callable is provided, it will be called with two arguments: the current exception and the previous exception.
* The callable must return a string.
*
* ```php
* 'errorHandler' => [
* 'fallbackExceptionMessage' => function ($exception, $previousException) {
* return 'Error: ' . $exception->getMessage();
* },
* ],
* ```
*
* @since 2.0.55
*/
public $fallbackExceptionMessage = 'An internal server error occurred.';

/**
* @var string|null Used to reserve memory for fatal error handler.
Expand Down Expand Up @@ -188,7 +205,9 @@ protected function handleFallbackExceptionMessage($exception, $previousException
}
$msg .= "\n\$_SERVER = " . VarDumper::export($_SERVER);
} else {
echo 'An internal server error occurred.';
echo is_callable($this->fallbackExceptionMessage)
? call_user_func($this->fallbackExceptionMessage, $exception, $previousException)
: $this->fallbackExceptionMessage;
}
error_log($msg);
if (defined('HHVM_VERSION')) {
Expand Down
51 changes: 51 additions & 0 deletions tests/framework/web/ErrorHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,57 @@ public function testHtmlEncodeWithUnicodeSequence(): void

$this->assertSame($expected, $handler->htmlEncode($text));
}

public function testFallbackExceptionMessageDefault(): void
{
$handler = Yii::$app->getErrorHandler();

$this->assertSame('An internal server error occurred.', $handler->fallbackExceptionMessage);
}

public function testFallbackExceptionMessageCustom(): void
{
$this->destroyApplication();
$this->mockWebApplication([
'controllerNamespace' => 'yiiunit\\data\\controllers',
'components' => [
'errorHandler' => [
'class' => 'yiiunit\framework\web\ErrorHandler',
'errorView' => '@yiiunit/data/views/errorHandler.php',
'exceptionView' => '@yiiunit/data/views/errorHandlerForAssetFiles.php',
'fallbackExceptionMessage' => 'Service temporarily unavailable.',
],
],
]);

$handler = Yii::$app->getErrorHandler();

$this->assertSame('Service temporarily unavailable.', $handler->fallbackExceptionMessage);
}

public function testFallbackExceptionMessageCallable(): void
{
$this->destroyApplication();
$this->mockWebApplication([
'controllerNamespace' => 'yiiunit\\data\\controllers',
'components' => [
'errorHandler' => [
'class' => 'yiiunit\framework\web\ErrorHandler',
'errorView' => '@yiiunit/data/views/errorHandler.php',
'exceptionView' => '@yiiunit/data/views/errorHandlerForAssetFiles.php',
'fallbackExceptionMessage' => function ($exception, $previousException) {
return 'Error: ' . $exception->getMessage();
},
],
],
]);

$handler = Yii::$app->getErrorHandler();

$this->assertIsCallable($handler->fallbackExceptionMessage);
$result = call_user_func($handler->fallbackExceptionMessage, new \RuntimeException('test'), new \RuntimeException('prev'));
$this->assertSame('Error: test', $result);
}
}

class ErrorHandler extends \yii\web\ErrorHandler
Expand Down
Loading