Moved all filter classes to namespace yii\filters

This commit is contained in:
Qiang Xue
2014-04-05 01:00:14 -04:00
parent 50e338127d
commit a15a3835c7
19 changed files with 54 additions and 42 deletions

View File

@@ -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.'));
}
}
}

View File

@@ -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);
}
}

View File

@@ -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)) . '"';
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}