Commit 4b353c7b by Qiang Xue

Fixes #1297: CSRF not generated on error pages

parent 72dd86df
......@@ -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
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -69,7 +69,7 @@ class ErrorAction extends Action
public function run()
{
if (!($exception = Yii::$app->getErrorHandler()->exception)) {
if (($exception = Yii::$app->exception) === null) {
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