Commit 4b353c7b by Qiang Xue

Fixes #1297: CSRF not generated on error pages

parent 72dd86df
...@@ -22,14 +22,14 @@ return [ ...@@ -22,14 +22,14 @@ return [
], ],
``` ```
After it is done in case of error Yii will launch `SiteController::actionError()`. Since errors are converted to After it is done in case of error, Yii will launch `SiteController::actionError()`:
exceptions we can get exception from error handler:
```php ```php
public function actionError() public function actionError()
{ {
$exception = \Yii::$app->getErrorHandler()->exception; if (\Yii::$app->exception !== null) {
$this->render('myerror', ['message' => $exception->getMessage()]); return $this->render('error', ['exception' => \Yii::$app->exception]);
}
} }
``` ```
...@@ -48,7 +48,7 @@ public function actions() ...@@ -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 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 - `$name`: the error name
- `$message`: the error message - `$message`: the error message
......
...@@ -127,6 +127,11 @@ abstract class Application extends Module ...@@ -127,6 +127,11 @@ abstract class Application extends Module
* ~~~ * ~~~
*/ */
public $extensions = []; 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. * @var string Used to reserve memory for fatal error handler.
...@@ -487,6 +492,8 @@ abstract class Application extends Module ...@@ -487,6 +492,8 @@ abstract class Application extends Module
*/ */
public function handleException($exception) public function handleException($exception)
{ {
$this->exception = $exception;
// disable error capturing to avoid recursive errors while handling exceptions // disable error capturing to avoid recursive errors while handling exceptions
restore_error_handler(); restore_error_handler();
restore_exception_handler(); restore_exception_handler();
...@@ -574,6 +581,7 @@ abstract class Application extends Module ...@@ -574,6 +581,7 @@ abstract class Application extends Module
if (ErrorException::isFatalError($error)) { if (ErrorException::isFatalError($error)) {
$exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']); $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 // use error_log because it's too late to use Yii log
error_log($exception); error_log($exception);
......
...@@ -40,7 +40,7 @@ class ErrorHandler extends Component ...@@ -40,7 +40,7 @@ class ErrorHandler extends Component
/** /**
* @var string the route (e.g. 'site/error') to the controller action that will be used * @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 * 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. * will handle the error display.
*/ */
public $errorAction; public $errorAction;
...@@ -96,8 +96,6 @@ class ErrorHandler extends Component ...@@ -96,8 +96,6 @@ class ErrorHandler extends Component
$response->getHeaders()->removeAll(); $response->getHeaders()->removeAll();
if ($useErrorView && $this->errorAction !== null) { 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); $result = Yii::$app->runAction($this->errorAction);
if ($result instanceof Response) { if ($result instanceof Response) {
$response = $result; $response = $result;
......
...@@ -91,7 +91,7 @@ class Controller extends \yii\base\Controller ...@@ -91,7 +91,7 @@ class Controller extends \yii\base\Controller
public function beforeAction($action) public function beforeAction($action)
{ {
if (parent::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.')); throw new HttpException(400, Yii::t('yii', 'Unable to verify your data submission.'));
} }
return true; return true;
......
...@@ -69,7 +69,7 @@ class ErrorAction extends Action ...@@ -69,7 +69,7 @@ class ErrorAction extends Action
public function run() public function run()
{ {
if (!($exception = Yii::$app->getErrorHandler()->exception)) { if (($exception = Yii::$app->exception) === null) {
return ''; return '';
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment