From a15a3835c76f005f0f86b172454422a584037de7 Mon Sep 17 00:00:00 2001 From: Qiang Xue <qiang.xue@gmail.com> Date: Sat, 5 Apr 2014 01:00:14 -0400 Subject: [PATCH] Moved all filter classes to namespace `yii\filters` --- apps/advanced/backend/controllers/SiteController.php | 4 ++-- apps/advanced/frontend/controllers/SiteController.php | 7 ++++--- apps/basic/controllers/SiteController.php | 4 ++-- docs/guide/authorization.md | 12 ++++++------ docs/guide/controller.md | 6 +++--- docs/guide/performance.md | 4 ++-- docs/guide/rest.md | 8 +++++--- docs/guide/upgrade-from-v1.md | 4 ++-- docs/guide/url.md | 2 +- extensions/gii/generators/crud/default/controller.php | 2 +- framework/CHANGELOG.md | 1 + framework/base/ActionFilter.php | 2 +- framework/classes.php | 10 +++++----- framework/filters/AccessControl.php | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ framework/filters/AccessRule.php | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ framework/filters/HttpCache.php | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ framework/filters/PageCache.php | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ framework/filters/VerbFilter.php | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ framework/rest/Controller.php | 2 +- framework/web/AccessControl.php | 145 ------------------------------------------------------------------------------------------------------------------------------------------------- framework/web/AccessRule.php | 191 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- framework/web/HttpCache.php | 162 ------------------------------------------------------------------------------------------------------------------------------------------------------------------ framework/web/PageCache.php | 148 ---------------------------------------------------------------------------------------------------------------------------------------------------- framework/web/VerbFilter.php | 107 ----------------------------------------------------------------------------------------------------------- 24 files changed, 797 insertions(+), 785 deletions(-) create mode 100644 framework/filters/AccessControl.php create mode 100644 framework/filters/AccessRule.php create mode 100644 framework/filters/HttpCache.php create mode 100644 framework/filters/PageCache.php create mode 100644 framework/filters/VerbFilter.php delete mode 100644 framework/web/AccessControl.php delete mode 100644 framework/web/AccessRule.php delete mode 100644 framework/web/HttpCache.php delete mode 100644 framework/web/PageCache.php delete mode 100644 framework/web/VerbFilter.php diff --git a/apps/advanced/backend/controllers/SiteController.php b/apps/advanced/backend/controllers/SiteController.php index 2999218..db3259a 100644 --- a/apps/advanced/backend/controllers/SiteController.php +++ b/apps/advanced/backend/controllers/SiteController.php @@ -2,10 +2,10 @@ namespace backend\controllers; use Yii; -use yii\web\AccessControl; +use yii\filters\AccessControl; use yii\web\Controller; use common\models\LoginForm; -use yii\web\VerbFilter; +use yii\filters\VerbFilter; /** * Site controller diff --git a/apps/advanced/frontend/controllers/SiteController.php b/apps/advanced/frontend/controllers/SiteController.php index 5f58b58..1aae6fc 100644 --- a/apps/advanced/frontend/controllers/SiteController.php +++ b/apps/advanced/frontend/controllers/SiteController.php @@ -1,6 +1,7 @@ <?php namespace frontend\controllers; +use Yii; use common\models\LoginForm; use frontend\models\PasswordResetRequestForm; use frontend\models\ResetPasswordForm; @@ -9,8 +10,8 @@ use frontend\models\ContactForm; use yii\base\InvalidParamException; use yii\web\BadRequestHttpException; use yii\web\Controller; -use Yii; -use yii\web\VerbFilter; +use yii\filters\VerbFilter; +use yii\filters\AccessControl; /** * Site controller @@ -24,7 +25,7 @@ class SiteController extends Controller { return [ 'access' => [ - 'class' => \yii\web\AccessControl::className(), + 'class' => AccessControl::className(), 'only' => ['logout', 'signup'], 'rules' => [ [ diff --git a/apps/basic/controllers/SiteController.php b/apps/basic/controllers/SiteController.php index ebecd28..f959941 100644 --- a/apps/basic/controllers/SiteController.php +++ b/apps/basic/controllers/SiteController.php @@ -3,9 +3,9 @@ namespace app\controllers; use Yii; -use yii\web\AccessControl; +use yii\filters\AccessControl; use yii\web\Controller; -use yii\web\VerbFilter; +use yii\filters\VerbFilter; use app\models\LoginForm; use app\models\ContactForm; diff --git a/docs/guide/authorization.md b/docs/guide/authorization.md index 982ded0..91c943c 100644 --- a/docs/guide/authorization.md +++ b/docs/guide/authorization.md @@ -7,7 +7,7 @@ of controlling it. Access control basics --------------------- -Basic access control is very simple to implement using [[yii\web\AccessControl]]: +Basic access control is very simple to implement using [[yii\filters\AccessControl]]: ```php class SiteController extends Controller @@ -16,7 +16,7 @@ class SiteController extends Controller { return [ 'access' => [ - 'class' => \yii\web\AccessControl::className(), + 'class' => \yii\filters\AccessControl::className(), 'only' => ['login', 'logout', 'signup'], 'rules' => [ [ @@ -38,7 +38,7 @@ class SiteController extends Controller In the code above we're attaching access control behavior to a controller. Since there's `only` option specified, it will be applied to 'login', 'logout' and 'signup' actions only. A set of rules that are basically options for -[[yii\web\AccessRule]] reads as follows: +[[yii\filters\AccessRule]] reads as follows: - Allow all guest (not yet authenticated) users to access 'login' and 'signup' actions. - Allow authenticated users to access 'logout' action. @@ -46,7 +46,7 @@ will be applied to 'login', 'logout' and 'signup' actions only. A set of rules t Rules are checked one by one from top to bottom. If rule matches, action takes place immediately. If not, next rule is checked. If no rules matched access is denied. -[[yii\web\AccessRule]] is quite flexible and allows additionally to what was demonstrated checking IPs and request method +[[yii\filters\AccessRule]] is quite flexible and allows additionally to what was demonstrated checking IPs and request method (i.e. POST, GET). If it's not enough you can specify your own check via anonymous function: ```php @@ -56,7 +56,7 @@ class SiteController extends Controller { return [ 'access' => [ - 'class' => \yii\web\AccessControl::className(), + 'class' => \yii\filters\AccessControl::className(), 'only' => ['special-callback'], 'rules' => [ [ @@ -219,7 +219,7 @@ public function behaviors() { return [ 'access' => [ - 'class' => 'yii\web\AccessControl', + 'class' => 'yii\filters\AccessControl', 'except' => ['something'], 'rules' => [ [ diff --git a/docs/guide/controller.md b/docs/guide/controller.md index 634e936..12ac39d 100644 --- a/docs/guide/controller.md +++ b/docs/guide/controller.md @@ -199,7 +199,7 @@ public function behaviors() { return [ 'httpCache' => [ - 'class' => \yii\web\HttpCache::className(), + 'class' => \yii\filters\HttpCache::className(), 'only' => ['index'], 'lastModified' => function ($action, $params) { $q = new \yii\db\Query(); @@ -225,8 +225,8 @@ The return value of [[yii\base\ActionFilter::beforeAction()|beforeAction()]] det an action should be executed or not. If `beforeAction()` of a filter returns false, the filters after this one will be skipped and the action will not be executed. -The [authorization](authorization.md) section of this guide shows how to use the [[yii\web\AccessControl]] filter, -and the [caching](caching.md) section gives more details about the [[yii\web\PageCache]] and [[yii\web\HttpCache]] filters. +The [authorization](authorization.md) section of this guide shows how to use the [[yii\filters\AccessControl]] filter, +and the [caching](caching.md) section gives more details about the [[yii\filters\PageCache]] and [[yii\filters\HttpCache]] filters. These built-in filters are also good references when you learn to create your own filters. diff --git a/docs/guide/performance.md b/docs/guide/performance.md index c659a85..04c60d5 100644 --- a/docs/guide/performance.md +++ b/docs/guide/performance.md @@ -137,7 +137,7 @@ sending either `ETag` or `Last-Modified` header in your application response. If HTTP specification (most browsers are), content will be fetched only if it is different from what it was prevously. Forming proper headers is time consuming task so Yii provides a shortcut in form of controller filter -[[yii\web\HttpCache]]. Using it is very easy. In a controller you need to implement `behaviors` method like +[[yii\filters\HttpCache]]. Using it is very easy. In a controller you need to implement `behaviors` method like the following: ```php @@ -145,7 +145,7 @@ public function behaviors() { return [ 'httpCache' => [ - 'class' => \yii\web\HttpCache::className(), + 'class' => \yii\filters\HttpCache::className(), 'only' => ['list'], 'lastModified' => function ($action, $params) { $q = new Query(); diff --git a/docs/guide/rest.md b/docs/guide/rest.md index 6b43448..efc1005 100644 --- a/docs/guide/rest.md +++ b/docs/guide/rest.md @@ -13,7 +13,7 @@ In particular, Yii provides support for the following aspects regarding RESTful * Authentication; * Authorization; * Support for HATEOAS; -* Caching via `yii\web\HttpCache`; +* Caching via `yii\filters\HttpCache`; * Rate limiting; * Searching and filtering: TBD * Testing: TBD @@ -783,7 +783,7 @@ Accept: application/vnd.company.myapp-v1+json ``` Both methods have pros and cons, and there are a lot of debates about them. Below we describe a practical strategy -of API versioning that is a kind of mix of these two methods: +of API versioning that is kind of a mix of these two methods: * Put each major version of API implementation in a separate module whose ID is the major version number (e.g. `v1`, `v2`). Naturally, the API URLs will contain major version numbers. @@ -793,7 +793,9 @@ of API versioning that is a kind of mix of these two methods: For each module serving a major version, it should include the resource classes and the controller classes serving for that specific version. To better separate code responsibility, you may keep a common set of base resource and controller classes, and subclass them in each individual version module. Within the subclasses, -implement the concrete code such as `Model::fields()`. As a result, your code may be organized like the following: +implement the concrete code such as `Model::fields()`. + +Your code may be organized like the following: ``` api/ diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md index 56bc699..ceba3b0 100644 --- a/docs/guide/upgrade-from-v1.md +++ b/docs/guide/upgrade-from-v1.md @@ -318,7 +318,7 @@ Action Filters Action filters are implemented via behaviors now. You should extend from [[yii\base\ActionFilter]] to define a new filter. To use a filter, you should attach the filter class to the controller -as a behavior. For example, to use the [[yii\web\AccessControl]] filter, you should have the following +as a behavior. For example, to use the [[yii\filters\AccessControl]] filter, you should have the following code in a controller: ```php @@ -326,7 +326,7 @@ public function behaviors() { return [ 'access' => [ - 'class' => 'yii\web\AccessControl', + 'class' => 'yii\filters\AccessControl', 'rules' => [ ['allow' => true, 'actions' => ['admin'], 'roles' => ['@']], ], diff --git a/docs/guide/url.md b/docs/guide/url.md index f0c8b9d..40817ca 100644 --- a/docs/guide/url.md +++ b/docs/guide/url.md @@ -232,7 +232,7 @@ return [ ### Handling REST requests TBD: -- RESTful routing: [[yii\web\VerbFilter]], [[yii\web\UrlManager::$rules]] +- RESTful routing: [[yii\filters\VerbFilter]], [[yii\filters\UrlManager::$rules]] - Json API: - response: [[yii\web\Response::format]] - request: [[yii\web\Request::$parsers]], [[yii\web\JsonParser]] diff --git a/extensions/gii/generators/crud/default/controller.php b/extensions/gii/generators/crud/default/controller.php index 0ad80c9..0a00eb4 100644 --- a/extensions/gii/generators/crud/default/controller.php +++ b/extensions/gii/generators/crud/default/controller.php @@ -34,7 +34,7 @@ use <?= ltrim($generator->modelClass, '\\') ?>; use <?= ltrim($generator->searchModelClass, '\\') . (isset($searchModelAlias) ? " as $searchModelAlias" : "") ?>; use <?= ltrim($generator->baseControllerClass, '\\') ?>; use yii\web\NotFoundHttpException; -use yii\web\VerbFilter; +use yii\filters\VerbFilter; /** * <?= $controllerClass ?> implements the CRUD actions for <?= $modelClass ?> model. diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 9048645..536ada9 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -274,6 +274,7 @@ Yii Framework 2 Change Log - Chg: `Yii::$objectConfig` is removed. You should use `Yii::$container->set()` to configure default settings of classes. (qiangxue) - Chg: Removed `yii\grid\Column::getDataCellContent()` and renamed `yii\grid\DataColumn::getDataCellContent()` to `yii\grid\DataColumn::getDataCellValue()` (cebe) - Chg: `yii\log\Logger` is split into `yii\log\Logger` and `yii\log\Dispatcher`. (qiangxue) +- Chg: Moved all filter classes to namespace `yii\filters` (qiangxue) - New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul) - New #303: Added built-in support for REST API (qiangxue) - New #503: Added `yii\di\Container` and `yii\di\ServiceLocator` (qiangxue) diff --git a/framework/base/ActionFilter.php b/framework/base/ActionFilter.php index 72fed31..060bfaf 100644 --- a/framework/base/ActionFilter.php +++ b/framework/base/ActionFilter.php @@ -13,7 +13,7 @@ namespace yii\base; * An action filter will participate in the action execution workflow by responding to * the `beforeAction` and `afterAction` events triggered by modules and controllers. * - * Check implementation of [[\yii\web\AccessControl]], [[\yii\web\PageCache]] and [[\yii\web\HttpCache]] as examples on how to use it. + * Check implementation of [[\yii\filters\AccessControl]], [[\yii\filters\PageCache]] and [[\yii\filters\HttpCache]] as examples on how to use it. * * @author Qiang Xue <qiang.xue@gmail.com> * @since 2.0 diff --git a/framework/classes.php b/framework/classes.php index 0cd806d..68a61bb 100644 --- a/framework/classes.php +++ b/framework/classes.php @@ -227,8 +227,8 @@ return [ 'yii\validators\UrlValidator' => YII_PATH . '/validators/UrlValidator.php', 'yii\validators\ValidationAsset' => YII_PATH . '/validators/ValidationAsset.php', 'yii\validators\Validator' => YII_PATH . '/validators/Validator.php', - 'yii\web\AccessControl' => YII_PATH . '/web/AccessControl.php', - 'yii\web\AccessRule' => YII_PATH . '/web/AccessRule.php', + 'yii\filters\AccessControl' => YII_PATH . '/filters/AccessControl.php', + 'yii\filters\AccessRule' => YII_PATH . '/filters/AccessRule.php', 'yii\web\Application' => YII_PATH . '/web/Application.php', 'yii\web\AssetBundle' => YII_PATH . '/web/AssetBundle.php', 'yii\web\AssetConverter' => YII_PATH . '/web/AssetConverter.php', @@ -246,7 +246,7 @@ return [ 'yii\web\ForbiddenHttpException' => YII_PATH . '/web/ForbiddenHttpException.php', 'yii\web\GoneHttpException' => YII_PATH . '/web/GoneHttpException.php', 'yii\web\HeaderCollection' => YII_PATH . '/web/HeaderCollection.php', - 'yii\web\HttpCache' => YII_PATH . '/web/HttpCache.php', + 'yii\filters\HttpCache' => YII_PATH . '/filters/HttpCache.php', 'yii\web\HttpException' => YII_PATH . '/web/HttpException.php', 'yii\web\IdentityInterface' => YII_PATH . '/web/IdentityInterface.php', 'yii\web\JqueryAsset' => YII_PATH . '/web/JqueryAsset.php', @@ -257,7 +257,7 @@ return [ 'yii\web\MethodNotAllowedHttpException' => YII_PATH . '/web/MethodNotAllowedHttpException.php', 'yii\web\NotAcceptableHttpException' => YII_PATH . '/web/NotAcceptableHttpException.php', 'yii\web\NotFoundHttpException' => YII_PATH . '/web/NotFoundHttpException.php', - 'yii\web\PageCache' => YII_PATH . '/web/PageCache.php', + 'yii\filters\PageCache' => YII_PATH . '/filters/PageCache.php', 'yii\web\PrefixUrlRule' => YII_PATH . '/web/PrefixUrlRule.php', 'yii\web\Request' => YII_PATH . '/web/Request.php', 'yii\web\RequestParserInterface' => YII_PATH . '/web/RequestParserInterface.php', @@ -274,7 +274,7 @@ return [ 'yii\web\UrlRuleInterface' => YII_PATH . '/web/UrlRuleInterface.php', 'yii\web\User' => YII_PATH . '/web/User.php', 'yii\web\UserEvent' => YII_PATH . '/web/UserEvent.php', - 'yii\web\VerbFilter' => YII_PATH . '/web/VerbFilter.php', + 'yii\filters\VerbFilter' => YII_PATH . '/filters/VerbFilter.php', 'yii\web\View' => YII_PATH . '/web/View.php', 'yii\web\XmlResponseFormatter' => YII_PATH . '/web/XmlResponseFormatter.php', 'yii\web\YiiAsset' => YII_PATH . '/web/YiiAsset.php', diff --git a/framework/filters/AccessControl.php b/framework/filters/AccessControl.php new file mode 100644 index 0000000..e75b012 --- /dev/null +++ b/framework/filters/AccessControl.php @@ -0,0 +1,147 @@ +<?php +/** + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\filters; + +use Yii; +use yii\base\Action; +use yii\base\ActionFilter; +use yii\web\User; +use yii\web\ForbiddenHttpException; + +/** + * AccessControl provides simple access control based on a set of rules. + * + * AccessControl is an action filter. It will check its [[rules]] to find + * the first rule that matches the current context variables (such as user IP address, user role). + * The matching rule will dictate whether to allow or deny the access to the requested controller + * action. If no rule matches, the access will be denied. + * + * To use AccessControl, declare it in the `behaviors()` method of your controller class. + * For example, the following declarations will allow authenticated users to access the "create" + * and "update" actions and deny all other users from accessing these two actions. + * + * ~~~ + * public function behaviors() + * { + * return [ + * 'access' => [ + * 'class' => \yii\filters\AccessControl::className(), + * 'only' => ['create', 'update'], + * 'rules' => [ + * // deny all POST requests + * [ + * 'allow' => false, + * 'verbs' => ['POST'] + * ], + * // allow authenticated users + * [ + * 'allow' => true, + * 'roles' => ['@'], + * ], + * // everything else is denied + * ], + * ], + * ]; + * } + * ~~~ + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @since 2.0 + */ +class AccessControl extends ActionFilter +{ + /** + * @var callable a callback that will be called if the access should be denied + * to the current user. If not set, [[denyAccess()]] will be called. + * + * The signature of the callback should be as follows: + * + * ~~~ + * function ($rule, $action) + * ~~~ + * + * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. + * `$rule` will be `null` if access is denied because none of the rules matched. + */ + public $denyCallback; + /** + * @var array the default configuration of access rules. Individual rule configurations + * specified via [[rules]] will take precedence when the same property of the rule is configured. + */ + public $ruleConfig = ['class' => 'yii\filters\AccessRule']; + /** + * @var array a list of access rule objects or configuration arrays for creating the rule objects. + * If a rule is specified via a configuration array, it will be merged with [[ruleConfig]] first + * before it is used for creating the rule object. + * @see ruleConfig + */ + public $rules = []; + + + /** + * Initializes the [[rules]] array by instantiating rule objects from configurations. + */ + public function init() + { + parent::init(); + foreach ($this->rules as $i => $rule) { + if (is_array($rule)) { + $this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule)); + } + } + } + + /** + * This method is invoked right before an action is to be executed (after all possible filters.) + * You may override this method to do last-minute preparation for the action. + * @param Action $action the action to be executed. + * @return boolean whether the action should continue to be executed. + */ + public function beforeAction($action) + { + $user = Yii::$app->getUser(); + $request = Yii::$app->getRequest(); + /** @var AccessRule $rule */ + foreach ($this->rules as $rule) { + if ($allow = $rule->allows($action, $user, $request)) { + return true; + } elseif ($allow === false) { + if (isset($rule->denyCallback)) { + call_user_func($rule->denyCallback, $rule, $action); + } elseif (isset($this->denyCallback)) { + call_user_func($this->denyCallback, $rule, $action); + } else { + $this->denyAccess($user); + } + return false; + } + } + if (isset($this->denyCallback)) { + call_user_func($this->denyCallback, null, $action); + } else { + $this->denyAccess($user); + } + return false; + } + + /** + * Denies the access of the user. + * The default implementation will redirect the user to the login page if he is a guest; + * if the user is already logged, a 403 HTTP exception will be thrown. + * @param User $user the current user + * @throws ForbiddenHttpException if the user is already logged in. + */ + protected function denyAccess($user) + { + if ($user->getIsGuest()) { + $user->loginRequired(); + } else { + throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.')); + } + } +} diff --git a/framework/filters/AccessRule.php b/framework/filters/AccessRule.php new file mode 100644 index 0000000..316d396 --- /dev/null +++ b/framework/filters/AccessRule.php @@ -0,0 +1,194 @@ +<?php +/** + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\filters; + +use yii\base\Component; +use yii\base\Action; +use yii\web\User; +use yii\web\Request; +use yii\web\Controller; + +/** + * This class represents an access rule defined by the [[AccessControl]] action filter + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @since 2.0 + */ +class AccessRule extends Component +{ + /** + * @var boolean whether this is an 'allow' rule or 'deny' rule. + */ + public $allow; + /** + * @var array list of action IDs that this rule applies to. The comparison is case-sensitive. + * If not set or empty, it means this rule applies to all actions. + */ + public $actions; + /** + * @var array list of controller IDs that this rule applies to. The comparison is case-sensitive. + * If not set or empty, it means this rule applies to all controllers. + */ + public $controllers; + /** + * @var array list of roles that this rule applies to. Two special roles are recognized, and + * they are checked via [[User::isGuest]]: + * + * - `?`: matches a guest user (not authenticated yet) + * - `@`: matches an authenticated user + * + * Using additional role names requires RBAC (Role-Based Access Control), and + * [[User::checkAccess()]] will be called. + * + * If this property is not set or empty, it means this rule applies to all roles. + */ + public $roles; + /** + * @var array list of user IP addresses that this rule applies to. An IP address + * can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix. + * For example, '192.168.*' matches all IP addresses in the segment '192.168.'. + * If not set or empty, it means this rule applies to all IP addresses. + * @see Request::userIP + */ + public $ips; + /** + * @var array list of request methods (e.g. `GET`, `POST`) that this rule applies to. + * The request methods must be specified in uppercase. + * If not set or empty, it means this rule applies to all request methods. + * @see Request::requestMethod + */ + public $verbs; + /** + * @var callable a callback that will be called to determine if the rule should be applied. + * The signature of the callback should be as follows: + * + * ~~~ + * function ($rule, $action) + * ~~~ + * + * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. + * The callback should return a boolean value indicating whether this rule should be applied. + */ + public $matchCallback; + /** + * @var callable a callback that will be called if this rule determines the access to + * the current action should be denied. If not set, the behavior will be determined by + * [[AccessControl]]. + * + * The signature of the callback should be as follows: + * + * ~~~ + * function ($rule, $action) + * ~~~ + * + * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. + */ + public $denyCallback; + + /** + * Checks whether the Web user is allowed to perform the specified action. + * @param Action $action the action to be performed + * @param User $user the user object + * @param Request $request + * @return boolean|null true if the user is allowed, false if the user is denied, null if the rule does not apply to the user + */ + public function allows($action, $user, $request) + { + if ($this->matchAction($action) + && $this->matchRole($user) + && $this->matchIP($request->getUserIP()) + && $this->matchVerb($request->getMethod()) + && $this->matchController($action->controller) + && $this->matchCustom($action) + ) { + return $this->allow ? true : false; + } else { + return null; + } + } + + /** + * @param Action $action the action + * @return boolean whether the rule applies to the action + */ + protected function matchAction($action) + { + return empty($this->actions) || in_array($action->id, $this->actions, true); + } + + /** + * @param Controller $controller the controller + * @return boolean whether the rule applies to the controller + */ + protected function matchController($controller) + { + return empty($this->controllers) || in_array($controller->uniqueId, $this->controllers, true); + } + + /** + * @param User $user the user object + * @return boolean whether the rule applies to the role + */ + protected function matchRole($user) + { + if (empty($this->roles)) { + return true; + } + foreach ($this->roles as $role) { + if ($role === '?') { + if ($user->getIsGuest()) { + return true; + } + } elseif ($role === '@') { + if (!$user->getIsGuest()) { + return true; + } + } elseif ($user->checkAccess($role)) { + return true; + } + } + + return false; + } + + /** + * @param string $ip the IP address + * @return boolean whether the rule applies to the IP address + */ + protected function matchIP($ip) + { + if (empty($this->ips)) { + return true; + } + foreach ($this->ips as $rule) { + if ($rule === '*' || $rule === $ip || (($pos = strpos($rule, '*')) !== false && !strncmp($ip, $rule, $pos))) { + return true; + } + } + + return false; + } + + /** + * @param string $verb the request method + * @return boolean whether the rule applies to the request + */ + protected function matchVerb($verb) + { + return empty($this->verbs) || in_array($verb, $this->verbs, true); + } + + /** + * @param Action $action the action to be performed + * @return boolean whether the rule should be applied + */ + protected function matchCustom($action) + { + return empty($this->matchCallback) || call_user_func($this->matchCallback, $this, $action); + } +} diff --git a/framework/filters/HttpCache.php b/framework/filters/HttpCache.php new file mode 100644 index 0000000..5268144 --- /dev/null +++ b/framework/filters/HttpCache.php @@ -0,0 +1,162 @@ +<?php +/** + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\filters; + +use Yii; +use yii\base\ActionFilter; +use yii\base\Action; + +/** + * The HttpCache provides functionality for caching via HTTP Last-Modified and Etag headers. + * + * It is an action filter that can be added to a controller and handles the `beforeAction` event. + * + * To use AccessControl, declare it in the `behaviors()` method of your controller class. + * In the following example the filter will be applied to the `list`-action and + * the Last-Modified header will contain the date of the last update to the user table in the database. + * + * ~~~ + * public function behaviors() + * { + * return [ + * 'httpCache' => [ + * 'class' => \yii\filters\HttpCache::className(), + * 'only' => ['index'], + * 'lastModified' => function ($action, $params) { + * $q = new \yii\db\Query(); + * return $q->from('user')->max('updated_at'); + * }, + * // 'etagSeed' => function ($action, $params) { + * // return // generate etag seed here + * // } + * ], + * ]; + * } + * ~~~ + * + * @author Da:Sourcerer <webmaster@dasourcerer.net> + * @author Qiang Xue <qiang.xue@gmail.com> + * @since 2.0 + */ +class HttpCache extends ActionFilter +{ + /** + * @var callable a PHP callback that returns the UNIX timestamp of the last modification time. + * The callback's signature should be: + * + * ~~~ + * function ($action, $params) + * ~~~ + * + * where `$action` is the [[Action]] object that this filter is currently handling; + * `$params` takes the value of [[params]]. The callback should return a UNIX timestamp. + */ + public $lastModified; + /** + * @var callable a PHP callback that generates the Etag seed string. + * The callback's signature should be: + * + * ~~~ + * function ($action, $params) + * ~~~ + * + * where `$action` is the [[Action]] object that this filter is currently handling; + * `$params` takes the value of [[params]]. The callback should return a string serving + * as the seed for generating an Etag. + */ + public $etagSeed; + /** + * @var mixed additional parameters that should be passed to the [[lastModified]] and [[etagSeed]] callbacks. + */ + public $params; + /** + * @var string HTTP cache control header. If null, the header will not be sent. + */ + public $cacheControlHeader = 'max-age=3600, public'; + + /** + * This method is invoked right before an action is to be executed (after all possible filters.) + * You may override this method to do last-minute preparation for the action. + * @param Action $action the action to be executed. + * @return boolean whether the action should continue to be executed. + */ + public function beforeAction($action) + { + $verb = Yii::$app->getRequest()->getMethod(); + if ($verb !== 'GET' && $verb !== 'HEAD' || $this->lastModified === null && $this->etagSeed === null) { + return true; + } + + $lastModified = $etag = null; + if ($this->lastModified !== null) { + $lastModified = call_user_func($this->lastModified, $action, $this->params); + } + if ($this->etagSeed !== null) { + $seed = call_user_func($this->etagSeed, $action, $this->params); + $etag = $this->generateEtag($seed); + } + + $this->sendCacheControlHeader(); + $response = Yii::$app->getResponse(); + if ($etag !== null) { + $response->getHeaders()->set('Etag', $etag); + } + + if ($this->validateCache($lastModified, $etag)) { + $response->setStatusCode(304); + + return false; + } + + if ($lastModified !== null) { + $response->getHeaders()->set('Last-Modified', gmdate('D, d M Y H:i:s', $lastModified) . ' GMT'); + } + + return true; + } + + /** + * Validates if the HTTP cache contains valid content. + * @param integer $lastModified the calculated Last-Modified value in terms of a UNIX timestamp. + * If null, the Last-Modified header will not be validated. + * @param string $etag the calculated ETag value. If null, the ETag header will not be validated. + * @return boolean whether the HTTP cache is still valid. + */ + protected function validateCache($lastModified, $etag) + { + if ($lastModified !== null && (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < $lastModified)) { + return false; + } else { + return $etag === null || isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag; + } + } + + /** + * Sends the cache control header to the client + * @see cacheControl + */ + protected function sendCacheControlHeader() + { + session_cache_limiter('public'); + $headers = Yii::$app->getResponse()->getHeaders(); + $headers->set('Pragma'); + if ($this->cacheControlHeader !== null) { + $headers->set('Cache-Control', $this->cacheControlHeader); + } + } + + /** + * Generates an Etag from the given seed string. + * @param string $seed Seed for the ETag + * @return string the generated Etag + */ + protected function generateEtag($seed) + { + return '"' . base64_encode(sha1($seed, true)) . '"'; + } +} diff --git a/framework/filters/PageCache.php b/framework/filters/PageCache.php new file mode 100644 index 0000000..039fc89 --- /dev/null +++ b/framework/filters/PageCache.php @@ -0,0 +1,148 @@ +<?php +/** + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\filters; + +use Yii; +use yii\base\ActionFilter; +use yii\base\Action; +use yii\caching\Dependency; + +/** + * The PageCache provides functionality for whole page caching + * + * It is an action filter that can be added to a controller and handles the `beforeAction` event. + * + * To use PageCache, declare it in the `behaviors()` method of your controller class. + * In the following example the filter will be applied to the `list`-action and + * cache the whole page for maximum 60 seconds or until the count of entries in the post table changes. + * It also stores different versions of the page depended on the route ([[varyByRoute]] is true by default), + * the application language and user id. + * + * ~~~ + * public function behaviors() + * { + * return [ + * 'pageCache' => [ + * 'class' => \yii\filters\PageCache::className(), + * 'only' => ['list'], + * 'duration' => 60, + * 'dependency' => [ + * 'class' => 'yii\caching\DbDependency', + * 'sql' => 'SELECT COUNT(*) FROM post', + * ], + * 'variations' => [ + * Yii::$app->language, + * Yii::$app->user->id + * ] + * ], + * ]; + * } + * ~~~ + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @since 2.0 + */ +class PageCache extends ActionFilter +{ + /** + * @var boolean whether the content being cached should be differentiated according to the route. + * A route consists of the requested controller ID and action ID. Defaults to true. + */ + public $varyByRoute = true; + /** + * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. + */ + public $cache = 'cache'; + /** + * @var integer number of seconds that the data can remain valid in cache. + * Use 0 to indicate that the cached data will never expire. + */ + public $duration = 60; + /** + * @var array|Dependency the dependency that the cached content depends on. + * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. + * For example, + * + * ~~~ + * [ + * 'class' => 'yii\caching\DbDependency', + * 'sql' => 'SELECT MAX(lastModified) FROM Post', + * ] + * ~~~ + * + * would make the output cache depends on the last modified time of all posts. + * If any post has its modification time changed, the cached content would be invalidated. + */ + public $dependency; + /** + * @var array list of factors that would cause the variation of the content being cached. + * Each factor is a string representing a variation (e.g. the language, a GET parameter). + * The following variation setting will cause the content to be cached in different versions + * according to the current application language: + * + * ~~~ + * [ + * Yii::$app->language, + * ] + * ~~~ + */ + public $variations; + /** + * @var boolean whether to enable the fragment cache. You may use this property to turn on and off + * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). + */ + public $enabled = true; + /** + * @var \yii\base\View the view component to use for caching. If not set, the default application view component + * [[Application::view]] will be used. + */ + public $view; + + public function init() + { + parent::init(); + if ($this->view === null) { + $this->view = Yii::$app->getView(); + } + } + + /** + * This method is invoked right before an action is to be executed (after all possible filters.) + * You may override this method to do last-minute preparation for the action. + * @param Action $action the action to be executed. + * @return boolean whether the action should continue to be executed. + */ + public function beforeAction($action) + { + $properties = []; + foreach (['cache', 'duration', 'dependency', 'variations', 'enabled'] as $name) { + $properties[$name] = $this->$name; + } + $id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; + ob_start(); + ob_implicit_flush(false); + if ($this->view->beginCache($id, $properties)) { + return true; + } else { + Yii::$app->getResponse()->content = ob_get_clean(); + + return false; + } + } + + /** + * @inheritdoc + */ + public function afterAction($action, $result) + { + echo $result; + $this->view->endCache(); + + return ob_get_clean(); + } +} diff --git a/framework/filters/VerbFilter.php b/framework/filters/VerbFilter.php new file mode 100644 index 0000000..d2f3a65 --- /dev/null +++ b/framework/filters/VerbFilter.php @@ -0,0 +1,110 @@ +<?php +/** + * @link http://www.yiiframework.com/ + * @copyright Copyright (c) 2008 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +namespace yii\filters; + +use Yii; +use yii\base\ActionEvent; +use yii\base\Behavior; +use yii\web\Controller; +use yii\web\HttpException; +use yii\web\MethodNotAllowedHttpException; + +/** + * VerbFilter is an action filter that filters by HTTP request methods. + * + * It allows to define allowed HTTP request methods for each action and will throw + * an HTTP 405 error when the method is not allowed. + * + * To use VerbFilter, declare it in the `behaviors()` method of your controller class. + * For example, the following declarations will define a typical set of allowed + * request methods for REST CRUD actions. + * + * ~~~ + * public function behaviors() + * { + * return [ + * 'verbs' => [ + * 'class' => \yii\filters\VerbFilter::className(), + * 'actions' => [ + * 'index' => ['get'], + * 'view' => ['get'], + * 'create' => ['get', 'post'], + * 'update' => ['get', 'put', 'post'], + * 'delete' => ['post', 'delete'], + * ], + * ], + * ]; + * } + * ~~~ + * + * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 + * @author Carsten Brandt <mail@cebe.cc> + * @since 2.0 + */ +class VerbFilter extends Behavior +{ + /** + * @var array this property defines the allowed request methods for each action. + * For each action that should only support limited set of request methods + * you add an entry with the action id as array key and an array of + * allowed methods (e.g. GET, HEAD, PUT) as the value. + * If an action is not listed all request methods are considered allowed. + * + * You can use '*' to stand for all actions. When an action is explicitly + * specified, it takes precedence over the specification given by '*'. + * + * For example, + * + * ~~~ + * [ + * 'create' => ['get', 'post'], + * 'update' => ['get', 'put', 'post'], + * 'delete' => ['post', 'delete'], + * '*' => ['get'], + * ] + * ~~~ + */ + public $actions = []; + + /** + * Declares event handlers for the [[owner]]'s events. + * @return array events (array keys) and the corresponding event handler methods (array values). + */ + public function events() + { + return [Controller::EVENT_BEFORE_ACTION => 'beforeAction']; + } + + /** + * @param ActionEvent $event + * @return boolean + * @throws HttpException when the request method is not allowed. + */ + public function beforeAction($event) + { + $action = $event->action->id; + if (isset($this->actions[$action])) { + $verbs = $this->actions[$action]; + } elseif (isset($this->actions['*'])) { + $verbs = $this->actions['*']; + } else { + return $event->isValid; + } + + $verb = Yii::$app->getRequest()->getMethod(); + $allowed = array_map('strtoupper', $verbs); + if (!in_array($verb, $allowed)) { + $event->isValid = false; + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 + Yii::$app->getResponse()->getHeaders()->set('Allow', implode(', ', $allowed)); + throw new MethodNotAllowedHttpException('Method Not Allowed. This url can only handle the following request methods: ' . implode(', ', $allowed) . '.'); + } + + return $event->isValid; + } +} diff --git a/framework/rest/Controller.php b/framework/rest/Controller.php index 12c5ff2..8cdd1d6 100644 --- a/framework/rest/Controller.php +++ b/framework/rest/Controller.php @@ -13,7 +13,7 @@ use yii\web\Response; use yii\web\UnauthorizedHttpException; use yii\web\UnsupportedMediaTypeHttpException; use yii\web\TooManyRequestsHttpException; -use yii\web\VerbFilter; +use yii\filters\VerbFilter; use yii\web\ForbiddenHttpException; /** diff --git a/framework/web/AccessControl.php b/framework/web/AccessControl.php deleted file mode 100644 index da3d63b..0000000 --- a/framework/web/AccessControl.php +++ /dev/null @@ -1,145 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\web; - -use Yii; -use yii\base\Action; -use yii\base\ActionFilter; - -/** - * AccessControl provides simple access control based on a set of rules. - * - * AccessControl is an action filter. It will check its [[rules]] to find - * the first rule that matches the current context variables (such as user IP address, user role). - * The matching rule will dictate whether to allow or deny the access to the requested controller - * action. If no rule matches, the access will be denied. - * - * To use AccessControl, declare it in the `behaviors()` method of your controller class. - * For example, the following declarations will allow authenticated users to access the "create" - * and "update" actions and deny all other users from accessing these two actions. - * - * ~~~ - * public function behaviors() - * { - * return [ - * 'access' => [ - * 'class' => \yii\web\AccessControl::className(), - * 'only' => ['create', 'update'], - * 'rules' => [ - * // deny all POST requests - * [ - * 'allow' => false, - * 'verbs' => ['POST'] - * ], - * // allow authenticated users - * [ - * 'allow' => true, - * 'roles' => ['@'], - * ], - * // everything else is denied - * ], - * ], - * ]; - * } - * ~~~ - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @since 2.0 - */ -class AccessControl extends ActionFilter -{ - /** - * @var callable a callback that will be called if the access should be denied - * to the current user. If not set, [[denyAccess()]] will be called. - * - * The signature of the callback should be as follows: - * - * ~~~ - * function ($rule, $action) - * ~~~ - * - * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. - * `$rule` will be `null` if access is denied because none of the rules matched. - */ - public $denyCallback; - /** - * @var array the default configuration of access rules. Individual rule configurations - * specified via [[rules]] will take precedence when the same property of the rule is configured. - */ - public $ruleConfig = ['class' => 'yii\web\AccessRule']; - /** - * @var array a list of access rule objects or configuration arrays for creating the rule objects. - * If a rule is specified via a configuration array, it will be merged with [[ruleConfig]] first - * before it is used for creating the rule object. - * @see ruleConfig - */ - public $rules = []; - - - /** - * Initializes the [[rules]] array by instantiating rule objects from configurations. - */ - public function init() - { - parent::init(); - foreach ($this->rules as $i => $rule) { - if (is_array($rule)) { - $this->rules[$i] = Yii::createObject(array_merge($this->ruleConfig, $rule)); - } - } - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $user = Yii::$app->getUser(); - $request = Yii::$app->getRequest(); - /** @var AccessRule $rule */ - foreach ($this->rules as $rule) { - if ($allow = $rule->allows($action, $user, $request)) { - return true; - } elseif ($allow === false) { - if (isset($rule->denyCallback)) { - call_user_func($rule->denyCallback, $rule, $action); - } elseif (isset($this->denyCallback)) { - call_user_func($this->denyCallback, $rule, $action); - } else { - $this->denyAccess($user); - } - return false; - } - } - if (isset($this->denyCallback)) { - call_user_func($this->denyCallback, null, $action); - } else { - $this->denyAccess($user); - } - return false; - } - - /** - * Denies the access of the user. - * The default implementation will redirect the user to the login page if he is a guest; - * if the user is already logged, a 403 HTTP exception will be thrown. - * @param User $user the current user - * @throws ForbiddenHttpException if the user is already logged in. - */ - protected function denyAccess($user) - { - if ($user->getIsGuest()) { - $user->loginRequired(); - } else { - throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.')); - } - } -} diff --git a/framework/web/AccessRule.php b/framework/web/AccessRule.php deleted file mode 100644 index 50a074a..0000000 --- a/framework/web/AccessRule.php +++ /dev/null @@ -1,191 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\web; - -use yii\base\Component; -use yii\base\Action; - -/** - * This class represents an access rule defined by the [[AccessControl]] action filter - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @since 2.0 - */ -class AccessRule extends Component -{ - /** - * @var boolean whether this is an 'allow' rule or 'deny' rule. - */ - public $allow; - /** - * @var array list of action IDs that this rule applies to. The comparison is case-sensitive. - * If not set or empty, it means this rule applies to all actions. - */ - public $actions; - /** - * @var array list of controller IDs that this rule applies to. The comparison is case-sensitive. - * If not set or empty, it means this rule applies to all controllers. - */ - public $controllers; - /** - * @var array list of roles that this rule applies to. Two special roles are recognized, and - * they are checked via [[User::isGuest]]: - * - * - `?`: matches a guest user (not authenticated yet) - * - `@`: matches an authenticated user - * - * Using additional role names requires RBAC (Role-Based Access Control), and - * [[User::checkAccess()]] will be called. - * - * If this property is not set or empty, it means this rule applies to all roles. - */ - public $roles; - /** - * @var array list of user IP addresses that this rule applies to. An IP address - * can contain the wildcard `*` at the end so that it matches IP addresses with the same prefix. - * For example, '192.168.*' matches all IP addresses in the segment '192.168.'. - * If not set or empty, it means this rule applies to all IP addresses. - * @see Request::userIP - */ - public $ips; - /** - * @var array list of request methods (e.g. `GET`, `POST`) that this rule applies to. - * The request methods must be specified in uppercase. - * If not set or empty, it means this rule applies to all request methods. - * @see Request::requestMethod - */ - public $verbs; - /** - * @var callable a callback that will be called to determine if the rule should be applied. - * The signature of the callback should be as follows: - * - * ~~~ - * function ($rule, $action) - * ~~~ - * - * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. - * The callback should return a boolean value indicating whether this rule should be applied. - */ - public $matchCallback; - /** - * @var callable a callback that will be called if this rule determines the access to - * the current action should be denied. If not set, the behavior will be determined by - * [[AccessControl]]. - * - * The signature of the callback should be as follows: - * - * ~~~ - * function ($rule, $action) - * ~~~ - * - * where `$rule` is this rule, and `$action` is the current [[Action|action]] object. - */ - public $denyCallback; - - /** - * Checks whether the Web user is allowed to perform the specified action. - * @param Action $action the action to be performed - * @param User $user the user object - * @param Request $request - * @return boolean|null true if the user is allowed, false if the user is denied, null if the rule does not apply to the user - */ - public function allows($action, $user, $request) - { - if ($this->matchAction($action) - && $this->matchRole($user) - && $this->matchIP($request->getUserIP()) - && $this->matchVerb($request->getMethod()) - && $this->matchController($action->controller) - && $this->matchCustom($action) - ) { - return $this->allow ? true : false; - } else { - return null; - } - } - - /** - * @param Action $action the action - * @return boolean whether the rule applies to the action - */ - protected function matchAction($action) - { - return empty($this->actions) || in_array($action->id, $this->actions, true); - } - - /** - * @param Controller $controller the controller - * @return boolean whether the rule applies to the controller - */ - protected function matchController($controller) - { - return empty($this->controllers) || in_array($controller->uniqueId, $this->controllers, true); - } - - /** - * @param User $user the user object - * @return boolean whether the rule applies to the role - */ - protected function matchRole($user) - { - if (empty($this->roles)) { - return true; - } - foreach ($this->roles as $role) { - if ($role === '?') { - if ($user->getIsGuest()) { - return true; - } - } elseif ($role === '@') { - if (!$user->getIsGuest()) { - return true; - } - } elseif ($user->checkAccess($role)) { - return true; - } - } - - return false; - } - - /** - * @param string $ip the IP address - * @return boolean whether the rule applies to the IP address - */ - protected function matchIP($ip) - { - if (empty($this->ips)) { - return true; - } - foreach ($this->ips as $rule) { - if ($rule === '*' || $rule === $ip || (($pos = strpos($rule, '*')) !== false && !strncmp($ip, $rule, $pos))) { - return true; - } - } - - return false; - } - - /** - * @param string $verb the request method - * @return boolean whether the rule applies to the request - */ - protected function matchVerb($verb) - { - return empty($this->verbs) || in_array($verb, $this->verbs, true); - } - - /** - * @param Action $action the action to be performed - * @return boolean whether the rule should be applied - */ - protected function matchCustom($action) - { - return empty($this->matchCallback) || call_user_func($this->matchCallback, $this, $action); - } -} diff --git a/framework/web/HttpCache.php b/framework/web/HttpCache.php deleted file mode 100644 index 8e85e7a..0000000 --- a/framework/web/HttpCache.php +++ /dev/null @@ -1,162 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\web; - -use Yii; -use yii\base\ActionFilter; -use yii\base\Action; - -/** - * The HttpCache provides functionality for caching via HTTP Last-Modified and Etag headers. - * - * It is an action filter that can be added to a controller and handles the `beforeAction` event. - * - * To use AccessControl, declare it in the `behaviors()` method of your controller class. - * In the following example the filter will be applied to the `list`-action and - * the Last-Modified header will contain the date of the last update to the user table in the database. - * - * ~~~ - * public function behaviors() - * { - * return [ - * 'httpCache' => [ - * 'class' => \yii\web\HttpCache::className(), - * 'only' => ['index'], - * 'lastModified' => function ($action, $params) { - * $q = new \yii\db\Query(); - * return $q->from('user')->max('updated_at'); - * }, - * // 'etagSeed' => function ($action, $params) { - * // return // generate etag seed here - * // } - * ], - * ]; - * } - * ~~~ - * - * @author Da:Sourcerer <webmaster@dasourcerer.net> - * @author Qiang Xue <qiang.xue@gmail.com> - * @since 2.0 - */ -class HttpCache extends ActionFilter -{ - /** - * @var callable a PHP callback that returns the UNIX timestamp of the last modification time. - * The callback's signature should be: - * - * ~~~ - * function ($action, $params) - * ~~~ - * - * where `$action` is the [[Action]] object that this filter is currently handling; - * `$params` takes the value of [[params]]. The callback should return a UNIX timestamp. - */ - public $lastModified; - /** - * @var callable a PHP callback that generates the Etag seed string. - * The callback's signature should be: - * - * ~~~ - * function ($action, $params) - * ~~~ - * - * where `$action` is the [[Action]] object that this filter is currently handling; - * `$params` takes the value of [[params]]. The callback should return a string serving - * as the seed for generating an Etag. - */ - public $etagSeed; - /** - * @var mixed additional parameters that should be passed to the [[lastModified]] and [[etagSeed]] callbacks. - */ - public $params; - /** - * @var string HTTP cache control header. If null, the header will not be sent. - */ - public $cacheControlHeader = 'max-age=3600, public'; - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $verb = Yii::$app->getRequest()->getMethod(); - if ($verb !== 'GET' && $verb !== 'HEAD' || $this->lastModified === null && $this->etagSeed === null) { - return true; - } - - $lastModified = $etag = null; - if ($this->lastModified !== null) { - $lastModified = call_user_func($this->lastModified, $action, $this->params); - } - if ($this->etagSeed !== null) { - $seed = call_user_func($this->etagSeed, $action, $this->params); - $etag = $this->generateEtag($seed); - } - - $this->sendCacheControlHeader(); - $response = Yii::$app->getResponse(); - if ($etag !== null) { - $response->getHeaders()->set('Etag', $etag); - } - - if ($this->validateCache($lastModified, $etag)) { - $response->setStatusCode(304); - - return false; - } - - if ($lastModified !== null) { - $response->getHeaders()->set('Last-Modified', gmdate('D, d M Y H:i:s', $lastModified) . ' GMT'); - } - - return true; - } - - /** - * Validates if the HTTP cache contains valid content. - * @param integer $lastModified the calculated Last-Modified value in terms of a UNIX timestamp. - * If null, the Last-Modified header will not be validated. - * @param string $etag the calculated ETag value. If null, the ETag header will not be validated. - * @return boolean whether the HTTP cache is still valid. - */ - protected function validateCache($lastModified, $etag) - { - if ($lastModified !== null && (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) || @strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < $lastModified)) { - return false; - } else { - return $etag === null || isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag; - } - } - - /** - * Sends the cache control header to the client - * @see cacheControl - */ - protected function sendCacheControlHeader() - { - session_cache_limiter('public'); - $headers = Yii::$app->getResponse()->getHeaders(); - $headers->set('Pragma'); - if ($this->cacheControlHeader !== null) { - $headers->set('Cache-Control', $this->cacheControlHeader); - } - } - - /** - * Generates an Etag from the given seed string. - * @param string $seed Seed for the ETag - * @return string the generated Etag - */ - protected function generateEtag($seed) - { - return '"' . base64_encode(sha1($seed, true)) . '"'; - } -} diff --git a/framework/web/PageCache.php b/framework/web/PageCache.php deleted file mode 100644 index 633b403..0000000 --- a/framework/web/PageCache.php +++ /dev/null @@ -1,148 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\web; - -use Yii; -use yii\base\ActionFilter; -use yii\base\Action; -use yii\caching\Dependency; - -/** - * The PageCache provides functionality for whole page caching - * - * It is an action filter that can be added to a controller and handles the `beforeAction` event. - * - * To use PageCache, declare it in the `behaviors()` method of your controller class. - * In the following example the filter will be applied to the `list`-action and - * cache the whole page for maximum 60 seconds or until the count of entries in the post table changes. - * It also stores different versions of the page depended on the route ([[varyByRoute]] is true by default), - * the application language and user id. - * - * ~~~ - * public function behaviors() - * { - * return [ - * 'pageCache' => [ - * 'class' => \yii\web\PageCache::className(), - * 'only' => ['list'], - * 'duration' => 60, - * 'dependency' => [ - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT COUNT(*) FROM post', - * ], - * 'variations' => [ - * Yii::$app->language, - * Yii::$app->user->id - * ] - * ], - * ]; - * } - * ~~~ - * - * @author Qiang Xue <qiang.xue@gmail.com> - * @since 2.0 - */ -class PageCache extends ActionFilter -{ - /** - * @var boolean whether the content being cached should be differentiated according to the route. - * A route consists of the requested controller ID and action ID. Defaults to true. - */ - public $varyByRoute = true; - /** - * @var string the application component ID of the [[\yii\caching\Cache|cache]] object. - */ - public $cache = 'cache'; - /** - * @var integer number of seconds that the data can remain valid in cache. - * Use 0 to indicate that the cached data will never expire. - */ - public $duration = 60; - /** - * @var array|Dependency the dependency that the cached content depends on. - * This can be either a [[Dependency]] object or a configuration array for creating the dependency object. - * For example, - * - * ~~~ - * [ - * 'class' => 'yii\caching\DbDependency', - * 'sql' => 'SELECT MAX(lastModified) FROM Post', - * ] - * ~~~ - * - * would make the output cache depends on the last modified time of all posts. - * If any post has its modification time changed, the cached content would be invalidated. - */ - public $dependency; - /** - * @var array list of factors that would cause the variation of the content being cached. - * Each factor is a string representing a variation (e.g. the language, a GET parameter). - * The following variation setting will cause the content to be cached in different versions - * according to the current application language: - * - * ~~~ - * [ - * Yii::$app->language, - * ] - * ~~~ - */ - public $variations; - /** - * @var boolean whether to enable the fragment cache. You may use this property to turn on and off - * the fragment cache according to specific setting (e.g. enable fragment cache only for GET requests). - */ - public $enabled = true; - /** - * @var \yii\base\View the view component to use for caching. If not set, the default application view component - * [[Application::view]] will be used. - */ - public $view; - - public function init() - { - parent::init(); - if ($this->view === null) { - $this->view = Yii::$app->getView(); - } - } - - /** - * This method is invoked right before an action is to be executed (after all possible filters.) - * You may override this method to do last-minute preparation for the action. - * @param Action $action the action to be executed. - * @return boolean whether the action should continue to be executed. - */ - public function beforeAction($action) - { - $properties = []; - foreach (['cache', 'duration', 'dependency', 'variations', 'enabled'] as $name) { - $properties[$name] = $this->$name; - } - $id = $this->varyByRoute ? $action->getUniqueId() : __CLASS__; - ob_start(); - ob_implicit_flush(false); - if ($this->view->beginCache($id, $properties)) { - return true; - } else { - Yii::$app->getResponse()->content = ob_get_clean(); - - return false; - } - } - - /** - * @inheritdoc - */ - public function afterAction($action, $result) - { - echo $result; - $this->view->endCache(); - - return ob_get_clean(); - } -} diff --git a/framework/web/VerbFilter.php b/framework/web/VerbFilter.php deleted file mode 100644 index 06e13ba..0000000 --- a/framework/web/VerbFilter.php +++ /dev/null @@ -1,107 +0,0 @@ -<?php -/** - * @link http://www.yiiframework.com/ - * @copyright Copyright (c) 2008 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\web; - -use Yii; -use yii\base\ActionEvent; -use yii\base\Behavior; - -/** - * VerbFilter is an action filter that filters by HTTP request methods. - * - * It allows to define allowed HTTP request methods for each action and will throw - * an HTTP 405 error when the method is not allowed. - * - * To use VerbFilter, declare it in the `behaviors()` method of your controller class. - * For example, the following declarations will define a typical set of allowed - * request methods for REST CRUD actions. - * - * ~~~ - * public function behaviors() - * { - * return [ - * 'verbs' => [ - * 'class' => \yii\web\VerbFilter::className(), - * 'actions' => [ - * 'index' => ['get'], - * 'view' => ['get'], - * 'create' => ['get', 'post'], - * 'update' => ['get', 'put', 'post'], - * 'delete' => ['post', 'delete'], - * ], - * ], - * ]; - * } - * ~~~ - * - * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 - * @author Carsten Brandt <mail@cebe.cc> - * @since 2.0 - */ -class VerbFilter extends Behavior -{ - /** - * @var array this property defines the allowed request methods for each action. - * For each action that should only support limited set of request methods - * you add an entry with the action id as array key and an array of - * allowed methods (e.g. GET, HEAD, PUT) as the value. - * If an action is not listed all request methods are considered allowed. - * - * You can use '*' to stand for all actions. When an action is explicitly - * specified, it takes precedence over the specification given by '*'. - * - * For example, - * - * ~~~ - * [ - * 'create' => ['get', 'post'], - * 'update' => ['get', 'put', 'post'], - * 'delete' => ['post', 'delete'], - * '*' => ['get'], - * ] - * ~~~ - */ - public $actions = []; - - /** - * Declares event handlers for the [[owner]]'s events. - * @return array events (array keys) and the corresponding event handler methods (array values). - */ - public function events() - { - return [Controller::EVENT_BEFORE_ACTION => 'beforeAction']; - } - - /** - * @param ActionEvent $event - * @return boolean - * @throws HttpException when the request method is not allowed. - */ - public function beforeAction($event) - { - $action = $event->action->id; - if (isset($this->actions[$action])) { - $verbs = $this->actions[$action]; - } elseif (isset($this->actions['*'])) { - $verbs = $this->actions['*']; - } else { - return $event->isValid; - } - - $verb = Yii::$app->getRequest()->getMethod(); - $allowed = array_map('strtoupper', $verbs); - if (!in_array($verb, $allowed)) { - $event->isValid = false; - // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.7 - Yii::$app->getResponse()->getHeaders()->set('Allow', implode(', ', $allowed)); - throw new MethodNotAllowedHttpException('Method Not Allowed. This url can only handle the following request methods: ' . implode(', ', $allowed) . '.'); - } - - return $event->isValid; - } -} -- libgit2 0.27.1