Yii过滤器简介
过滤器是一段代码,可被配置在控制器动作执行之前或之后执行。例如, 访问控制过滤器将被执行以确保在执行请求的动作之前用户已通过身份验证;性能过滤器可用于测量控制器执行所用的时间。
一个动作可以有多个过滤器。过滤器执行顺序为它们出现在过滤器列表中的顺序。过滤器可以阻止动作及后面其他过滤器的执行。
过滤器有两种写法:
无论哪种过滤器,都必须在控制器中重写控制器的public function filters()方法,设置哪个过滤器对哪个动作起作用。
基于方法的过滤器
编写基于方法的过滤器,要经过三步:
在控制器中编写动作(Action);
在控制器中编写过滤器函数,函数名必须以filter为前缀,如:function filterAccessControl();
重写父类CController的filters()方法,定义过滤器与动作的关系;
实例:
<?php class UserController extends CController{ ** * 第一步:创建动作 */ function actionAdd(){ echo "actionAdd"; } /** * 第二步:创建基于方法的过滤器 */ public function filterAddFilter($filterChain) { echo "基于方法的过滤器UserController.filterAdd<br>"; $filterChain->run(); } /** * 第三步:重写父类CController的filters()方法,定义过滤器与动作的关系 * @see CController::filters() */ public function filters(){ return array( //定义过滤器与动作的关联关系 'addFilter + add', // array( // 'application.filters.TestFilter', // ), ); } }
自定义过滤器类
自定义过滤器类,需要单独写一个过滤器类,并继承CFilter类,重写CFilter类下的部分方法。大家可以看一下CFilter类的代码,该类代码不多,还是很容易看懂的。
自定义过滤器实例:
<?php class TestFilter extends CFilter{ /** * Performs the pre-action filtering. * @param CFilterChain $filterChain the filter chain that the filter is on. * @return boolean whether the filtering process should continue and the action * should be executed. */ protected function preFilter($filterChain) { echo "--->TestFilter.preFilter.<br>"; return true; } /** * Performs the post-action filtering. * @param CFilterChain $filterChain the filter chain that the filter is on. */ protected function postFilter($filterChain) { echo "--->TestFilter.postFilter.<br>"; } }
在控制器中注册该自定义过滤器与动作的绑定关系:
/** * 第三步:重写父类CController的filters()方法,定义过滤器与动作的关系 * @see CController::filters() */ ublic function filters(){ return array( //定义过滤器与动作的关联关系 'addFilter + add', array( 'application.filters.TestFilter', ), );
我自定义了一个过滤器:TestFilter,继承了CFilter类,重写了CFilter类的两个主要方法:preFilter(前控制器,在动作执行前运行)和postFilter(后控制器,在动作执行后运行)。
两种控制器的执行顺序
假设我将上面编写的自定义过滤器类与动作actionAdd绑定,那么,自定义过滤器继承自父类CFilter两个方法:preFilter和postFilter,与绑定的actionAdd之间的执行顺序是怎样的呢?
经过试验,执行顺序为:CFilter::preFilter--------->UserController::actionAdd--------->CFilter::postFilter。
也就是说,在动作执行前后都可以执行过滤操作。
那么文章开头说“过滤器可以阻止动作及后面其他过滤器的执行”是怎么做到的呢?
看了CFilter::preFilter的官方注释就知道了:
@return boolean whether the filtering process should continue and the action should be executed。
CFilter::preFilter函数默认return
true;即,默认执行后面的动作和后过滤器。如果在自定义过滤器类中,重写CFilter::preFilter方法,并return
false;就可以阻止后面的动作和过滤器执行了!
使用过滤器
过滤器本质上是一类特殊的 行为,所以使用过滤器和 使用 行为一样。 可以在控制器类中覆盖它的 yii\base\Controller::behaviors() 方法来申明过滤器,如下所示:
public function behaviors() { return [ [ 'class' => 'yii\filters\HttpCache', 'only' => ['index', 'view'], 'lastModified' => function ($action, $params) { $q = new \yii\db\Query(); return $q->from('user')->max('updated_at'); }, ], ]; }
控制器类的过滤器默认应用到该类的 所有 动作,你可以配置yii\base\ActionFilter::only属性明确指定控制器应用到哪些动作。 在上述例子中,HttpCache 过滤器只应用到index和view动作。 也可以配置yii\base\ActionFilter::except属性使一些动作不执行过滤器。
除了控制器外,可在 模块或应用主体 中申明过滤器。 申明之后,过滤器会应用到所属该模块或应用主体的 所有 控制器动作, 除非像上述一样配置过滤器的 yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 属性。
补充: 在模块或应用主体中申明过滤器,在yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 属性中使用路由 代替动作ID, 因为在模块或应用主体中只用动作ID并不能唯一指定到具体动作。.
当一个动作有多个过滤器时,根据以下规则先后执行:
预过滤
后过滤
创建过滤器
继承 yii\base\ActionFilter 类并覆盖 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法来创建动作的过滤器,前者在动作执行之前执行,后者在动作执行之后执行。 yii\base\ActionFilter::beforeAction() 返回值决定动作是否应该执行, 如果为false,之后的过滤器和动作不会继续执行。
下面的例子申明一个记录动作执行时间日志的过滤器。
namespace app\components; use Yii; use yii\base\ActionFilter; class ActionTimeFilter extends ActionFilter { private $_startTime; public function beforeAction($action) { $this->_startTime = microtime(true); return parent::beforeAction($action); } public function afterAction($action, $result) { $time = microtime(true) - $this->_startTime; Yii::trace("Action '{$action->uniqueId}' spent $time second."); return parent::afterAction($action, $result); } }
核心过滤器
Yii提供了一组常用过滤器,在yii\filters命名空间下,接下来我们简要介绍这些过滤器。
1.yii\filters\AccessControl
AccessControl提供基于yii\filters\AccessControl::rules规则的访问控制。 特别是在动作执行之前,访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则, 来决定允许还是拒绝请求动作的执行,如果没有规则符合,访问就会被拒绝。
如下示例表示表示允许已认证用户访问create 和 update 动作,拒绝其他用户访问这两个动作。
use yii\filters\AccessControl; public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'only' => ['create', 'update'], 'rules' => [ // 允许认证用户 [ 'allow' => true, 'roles' => ['@'], ], // 默认禁止其他用户 ], ], ]; }
2.认证方法过滤器
认证方法过滤器通过HTTP Basic Auth或OAuth 2 来认证一个用户,认证方法过滤器类在 yii\filters\auth 命名空间下。
如下示例表示可使用yii\filters\auth\HttpBasicAuth来认证一个用户,它使用基于HTTP基础认证方法的令牌。 注意为了可运行,yii\web\User::identityClass 类必须 实现 yii\web\IdentityInterface::findIdentityByAccessToken()方法。
use yii\filters\auth\HttpBasicAuth; public function behaviors() { return [ 'basicAuth' => [ 'class' => HttpBasicAuth::className(), ], ]; }
认证方法过滤器通常在实现RESTful API中使用。
3.yii\filters\ContentNegotiator
ContentNegotiator支持响应内容格式处理和语言处理。 通过检查 GET 参数和 Accept HTTP头部来决定响应内容格式和语言。
如下示例,配置ContentNegotiator支持JSON和XML响应格式和英语(美国)和德语。
use yii\filters\ContentNegotiator; use yii\web\Response; public function behaviors() { return [ [ 'class' => ContentNegotiator::className(), 'formats' => [ 'application/json' => Response::FORMAT_JSON, 'application/xml' => Response::FORMAT_XML, ], 'languages' => [ 'en-US', 'de', ], ], ]; }
在应用主体生命周期过程中检测响应格式和语言简单很多, 因此ContentNegotiator设计可被引导启动组件调用的过滤器。 如下例所示可以将它配置在应用主体配置。
use yii\filters\ContentNegotiator; use yii\web\Response; [ 'bootstrap' => [ [ 'class' => ContentNegotiator::className(), 'formats' => [ 'application/json' => Response::FORMAT_JSON, 'application/xml' => Response::FORMAT_XML, ], 'languages' => [ 'en-US', 'de', ], ], ], ];
补充: 如果请求中没有检测到内容格式和语言,使用formats和languages第一个配置项。
4.yii\filters\HttpCache
HttpCache利用Last-Modified 和 Etag HTTP头实现客户端缓存。例如:
use yii\filters\HttpCache; public function behaviors() { return [ [ 'class' => HttpCache::className(), 'only' => ['index'], 'lastModified' => function ($action, $params) { $q = new \yii\db\Query(); return $q->from('user')->max('updated_at'); }, ], ]; }
5.yii\filters\PageCache
PageCache实现服务器端整个页面的缓存。如下示例所示,PageCache应用在index动作, 缓存整个页面60秒或post表的记录数发生变化。它也会根据不同应用语言保存不同的页面版本。
use yii\filters\PageCache; use yii\caching\DbDependency; public function behaviors() { return [ 'pageCache' => [ 'class' => PageCache::className(), 'only' => ['index'], 'duration' => 60, 'dependency' => [ 'class' => DbDependency::className(), 'sql' => 'SELECT COUNT(*) FROM post', ], 'variations' => [ \Yii::$app->language, ] ], ]; }
6.yii\filters\RateLimiter
RateLimiter 根据 漏桶算法 来实现速率限制。
7.yii\filters\VerbFilter
VerbFilter检查请求动作的HTTP请求方式是否允许执行,如果不允许,会抛出HTTP 405异常。 如下示例,VerbFilter指定CRUD动作所允许的请求方式。
use yii\filters\VerbFilter; public function behaviors() { return [ 'verbs' => [ 'class' => VerbFilter::className(), 'actions' => [ 'index' => ['get'], 'view' => ['get'], 'create' => ['get', 'post'], 'update' => ['get', 'put', 'post'], 'delete' => ['post', 'delete'], ], ], ]; }
8.yii\filters\Cors
跨域资源共享 CORS 机制允许一个网页的许多资源(例如字体、JavaScript等) 这些资源可以通过其他域名访问获取。 特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制,由于同源安全策略该跨域请求会被网页浏览器禁止. CORS定义浏览器和服务器交互时哪些跨域请求允许和禁止。
yii\filters\Cors 应在 授权 / 认证 过滤器之前定义,以保证CORS头部被发送。
use yii\filters\Cors; use yii\helpers\ArrayHelper; public function behaviors() { return ArrayHelper::merge([ [ 'class' => Cors::className(), ], ], parent::behaviors()); }
Cors 可转为使用 cors 属性。
例如,允许来源为 http://www.myserver.net 和方式为 GET, HEAD 和 OPTIONS 的CORS如下:
use yii\filters\Cors; use yii\helpers\ArrayHelper; public function behaviors() { return ArrayHelper::merge([ [ 'class' => Cors::className(), 'cors' => [ 'Origin' => ['http://www.myserver.net'], 'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'], ], ], ], parent::behaviors()); }
可以覆盖默认参数为每个动作调整CORS 头部。例如,为login动作增加Access-Control-Allow-Credentials参数如下所示:
use yii\filters\Cors; use yii\helpers\ArrayHelper; public function behaviors() { return ArrayHelper::merge([ [ 'class' => Cors::className(), 'cors' => [ 'Origin' => ['http://www.myserver.net'], 'Access-Control-Request-Method' => ['GET', 'HEAD', 'OPTIONS'], ], 'actions' => [ 'login' => [ 'Access-Control-Allow-Credentials' => true, ] ] ], ], parent::behaviors()); }
本文向大家介绍详解PHP的Yii框架中日志的相关配置及使用,包括了详解PHP的Yii框架中日志的相关配置及使用的使用技巧和注意事项,需要的朋友参考一下 默认的日志是输出到protected/runtime/application.log 如果需要修改那么需要在main.php里面的 components 下面增加log配置,如下: 如果在某处调用了Yii::log("jdkshgds","info
此外,删除和添加一个新的规则可以吗?因为我们需要更新过滤器(总是在sql过滤器中添加一个额外的条件),基于可能在任何时间点发生的触发器?
本文向大家介绍PHP的Yii框架的常用日志操作总结,包括了PHP的Yii框架的常用日志操作总结的使用技巧和注意事项,需要的朋友参考一下 日志 Yii提供了一个高度自定义化和高扩展性的日志框架。根据使用场景的不同,你可以很容易的对各种消息就行记录、过滤、合并,比如说文本文件,数据库文件,邮件。 使用Yii的日志框架包含如下步骤: 调用日志记录的方法 在主应用的配置文件(例如basic下面的web.p
本文向大家介绍PHP的Yii框架入门使用教程,包括了PHP的Yii框架入门使用教程的使用技巧和注意事项,需要的朋友参考一下 安装 Yii 的安装由如下两步组成: 从 yiiframework.com 下载 Yii 框架。 将 Yii 压缩包解压至一个 Web 可访问的目录。 Tip|提示: 安装在 Web 目录不是必须的,每个 Yii 应用都有一个入口脚本,只有它才必须暴露给 Web 用户。其它
本文向大家介绍PHP的Yii框架的基本使用示例,包括了PHP的Yii框架的基本使用示例的使用技巧和注意事项,需要的朋友参考一下 在 Yii 自动生成的代码里,我们总能在 admin 的界面看到 CGridView 的身影。这是一个很好用的展示数据的表格控件,用的好可以明显地加快开发进度。下面就让我们来探索一下 CGridView 的基本使用吧: 简单起见,我们的代码就用 Yii demo
本文向大家介绍详解PHP的Yii框架中扩展的安装与使用,包括了详解PHP的Yii框架中扩展的安装与使用的使用技巧和注意事项,需要的朋友参考一下 扩展是专门设计的在 Yii 应用中随时可拿来使用的, 并可重发布的软件包。例如, yiisoft/yii2-debug 扩展在你的应用的每个页面底部添加一个方便用于调试的工具栏, 帮助你简单地抓取页面生成的情况。 你可以使用扩展来加速你的开发过程。 信息: