From 4b353c7bcea8b61592177c190ee6103f812e146c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sun, 24 Nov 2013 17:41:09 -0500 Subject: [PATCH] Fixes #1297: CSRF not generated on error pages --- docs/guide/error.md | 10 +++++----- framework/yii/base/Application.php | 8 ++++++++ framework/yii/base/ErrorHandler.php | 4 +--- framework/yii/web/Controller.php | 2 +- framework/yii/web/ErrorAction.php | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/guide/error.md b/docs/guide/error.md index f5aa615..d0418b4 100644 --- a/docs/guide/error.md +++ b/docs/guide/error.md @@ -22,14 +22,14 @@ return [ ], ``` -After it is done in case of error Yii will launch `SiteController::actionError()`. Since errors are converted to -exceptions we can get exception from error handler: +After it is done in case of error, Yii will launch `SiteController::actionError()`: ```php public function actionError() { - $exception = \Yii::$app->getErrorHandler()->exception; - $this->render('myerror', ['message' => $exception->getMessage()]); + if (\Yii::$app->exception !== null) { + return $this->render('error', ['exception' => \Yii::$app->exception]); + } } ``` @@ -48,7 +48,7 @@ public function actions() ``` After defining `actions` in `SiteController` as shown above you can create `views/site/error.php`. In the view there -are three varialbes available: +are three variables available: - `$name`: the error name - `$message`: the error message diff --git a/framework/yii/base/Application.php b/framework/yii/base/Application.php index dc363f1..d6409e8 100644 --- a/framework/yii/base/Application.php +++ b/framework/yii/base/Application.php @@ -127,6 +127,11 @@ abstract class Application extends Module * ~~~ */ public $extensions = []; + /** + * @var \Exception the exception that is being handled currently. When this is not null, + * it means the application is handling some exception and extra care should be taken. + */ + public $exception; /** * @var string Used to reserve memory for fatal error handler. @@ -487,6 +492,8 @@ abstract class Application extends Module */ public function handleException($exception) { + $this->exception = $exception; + // disable error capturing to avoid recursive errors while handling exceptions restore_error_handler(); restore_exception_handler(); @@ -574,6 +581,7 @@ abstract class Application extends Module if (ErrorException::isFatalError($error)) { $exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']); + $this->exception = $exception; // use error_log because it's too late to use Yii log error_log($exception); diff --git a/framework/yii/base/ErrorHandler.php b/framework/yii/base/ErrorHandler.php index c96ca5e..1014f71 100644 --- a/framework/yii/base/ErrorHandler.php +++ b/framework/yii/base/ErrorHandler.php @@ -40,7 +40,7 @@ class ErrorHandler extends Component /** * @var string the route (e.g. 'site/error') to the controller action that will be used * to display external errors. Inside the action, it can retrieve the error information - * by Yii::$app->errorHandler->exception. This property defaults to null, meaning ErrorHandler + * by Yii::$app->exception. This property defaults to null, meaning ErrorHandler * will handle the error display. */ public $errorAction; @@ -96,8 +96,6 @@ class ErrorHandler extends Component $response->getHeaders()->removeAll(); if ($useErrorView && $this->errorAction !== null) { - // disable CSRF validation so that errorAction can run in case the error is caused by CSRF validation failure - Yii::$app->getRequest()->enableCsrfValidation = false; $result = Yii::$app->runAction($this->errorAction); if ($result instanceof Response) { $response = $result; diff --git a/framework/yii/web/Controller.php b/framework/yii/web/Controller.php index 71e7793..5c68cdb 100644 --- a/framework/yii/web/Controller.php +++ b/framework/yii/web/Controller.php @@ -91,7 +91,7 @@ class Controller extends \yii\base\Controller public function beforeAction($action) { if (parent::beforeAction($action)) { - if ($this->enableCsrfValidation && !Yii::$app->getRequest()->validateCsrfToken()) { + if ($this->enableCsrfValidation && Yii::$app->exception === null && !Yii::$app->getRequest()->validateCsrfToken()) { throw new HttpException(400, Yii::t('yii', 'Unable to verify your data submission.')); } return true; diff --git a/framework/yii/web/ErrorAction.php b/framework/yii/web/ErrorAction.php index bdbb4c5..95f17be 100644 --- a/framework/yii/web/ErrorAction.php +++ b/framework/yii/web/ErrorAction.php @@ -69,7 +69,7 @@ class ErrorAction extends Action public function run() { - if (!($exception = Yii::$app->getErrorHandler()->exception)) { + if (($exception = Yii::$app->exception) === null) { return ''; }