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并不能唯一指定到具体动作。.
当一个动作有多个过滤器时,根据以下规则先后执行:

预过滤

  • 按顺序执行应用主体中behaviors()列出的过滤器。
  • 按顺序执行模块中behaviors()列出的过滤器。
  • 按顺序执行控制器中behaviors()列出的过滤器。
  • 如果任意过滤器终止动作执行,后面的过滤器(包括预过滤和后过滤)不再执行。
  • 成功通过预过滤后执行动作。

后过滤

  • 倒序执行控制器中behaviors()列出的过滤器。
  • 倒序执行模块中behaviors()列出的过滤器。
  • 倒序执行应用主体中behaviors()列出的过滤器。

创建过滤器

继承 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 属性。

  • cors['Origin']: 定义允许来源的数组,可为['*'] (任何用户) 或 ['http://www.myserver.net', 'http://www.myotherserver.com']. 默认为 ['*'].
  • cors['Access-Control-Request-Method']: 允许动作数组如 ['GET', 'OPTIONS', 'HEAD']. 默认为 ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'].
  • cors['Access-Control-Request-Headers']: 允许请求头部数组,可为 ['*'] 所有类型头部 或 ['X-Request-With'] 指定类型头部. 默认为 ['*'].
  • cors['Access-Control-Allow-Credentials']: 定义当前请求是否使用证书,可为 true, false 或 null (不设置). 默认为null.
  • cors['Access-Control-Max-Age']: 定义请求的有效时间,默认为 86400.

例如,允许来源为 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框架中过滤器相关的使用总结的更多相关文章

  1. 从iOS应用程序发送帖子到PHP脚本不工作…简单的解决方案就像

    我之前已经做了好几次了但是由于某些原因我无法通过这个帖子…我尝试了设置为_POST且没有的变量的PHP脚本……当它们未设置为发布时它工作精细.这是我的iOS代码:这里是PHP的一大块,POST变量不在正确的位置?我想这对于更有经验的开发人员来说是一个相当简单的答案,感谢您的帮助!解决方法$_POST是一个数组,而不是一个函数.您需要使用方括号来访问数组索引:

  2. swift学习2 元组 tuples

    swift中出现了一种新的数据结构,非常牛掰的元组tuples如果懂PHP的猿,会发现这个元组和PHP的数组非常类似,同样是可以默认不指定key,也可以指定key目前的学习疑问是,如何进行元组的遍历?

  3. 尝试使用swift mailer,gmail smtp,php发送邮件

    这里是我的代码:在运行时出现此错误…

  4. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  5. jQuery的Cookie封装,与PHP交互的简单实现

    下面小编就为大家带来一篇jQuery的Cookie封装,与PHP交互的简单实现。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  6. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  7. 如何在PHP环境中使用ProtoBuf数据格式

    这篇文章主要介绍了如何在PHP环境中使用ProtoBuf数据格式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

  8. PHP rsa加密解密算法原理解析

    这篇文章主要介绍了PHP rsa加密解密算法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

  9. PHP cookie与session会话基本用法实例分析

    这篇文章主要介绍了PHP cookie与session会话基本用法,结合实例形式分析了PHP cookie与session会话基本存储、设置、删除等相关使用方式,需要的朋友可以参考下

  10. PHP 匿名函数与注意事项详细介绍

    这篇文章主要介绍了PHP 匿名函数与注意事项详细介绍的相关资料,匿名函数是PHP5.3引进来了,php5.3不但引进了匿名函数还有更多更好多新的特性了,下面我们一起来了解一下PHP匿名函数与注意事项详解,需要的朋友可以参考下

随机推荐

  1. PHP个人网站架设连环讲(一)

    先下一个OmnihttpdProffesinalV2.06,装上就有PHP4beta3可以用了。PHP4给我们带来一个简单的方法,就是使用SESSION(会话)级变量。但是如果不是PHP4又该怎么办?我们可以假设某人在15分钟以内对你的网页的请求都不属于一个新的人次,这样你可以做个计数的过程存在INC里,在每一个页面引用,访客第一次进入时将访问时间送到cookie里。以后每个页面被访问时都检查cookie上次访问时间值。

  2. PHP函数学习之PHP函数点评

    PHP函数使用说明,应用举例,精简点评,希望对您学习php有所帮助

  3. ecshop2.7.3 在php5.4下的各种错误问题处理

    将方法内的函数,分拆为2个部分。这个和gd库没有一点关系,是ecshop程序的问题。会出现这种问题,不外乎就是当前会员的session或者程序对cookie的处理存在漏洞。进过本地测试,includes\modules\integrates\ecshop.php这个整合自身会员的类中没有重写integrate.php中的check_cookie()方法导致,验证cookie时返回的username为空,丢失了登录状态,在ecshop.php中重写了此方法就可以了。把他加到ecshop.php的最后面去就可

  4. NT IIS下用ODBC连接数据库

    $connection=intodbc_connect建立数据库连接,$query_string="查询记录的条件"如:$query_string="select*fromtable"用$cur=intodbc_exec检索数据库,将记录集放入$cur变量中。再用while{$var1=odbc_result;$var2=odbc_result;...}读取odbc_exec()返回的数据集$cur。最后是odbc_close关闭数据库的连接。odbc_result()函数是取当前记录的指定字段值。

  5. PHP使用JpGraph绘制折线图操作示例【附源码下载】

    这篇文章主要介绍了PHP使用JpGraph绘制折线图操作,结合实例形式分析了php使用JpGraph的相关操作技巧与注意事项,并附带源码供读者下载参考,需要的朋友可以参考下

  6. zen_cart实现支付前生成订单的方法

    这篇文章主要介绍了zen_cart实现支付前生成订单的方法,结合实例形式详细分析了zen_cart支付前生成订单的具体步骤与相关实现技巧,需要的朋友可以参考下

  7. Thinkphp5框架实现获取数据库数据到视图的方法

    这篇文章主要介绍了Thinkphp5框架实现获取数据库数据到视图的方法,涉及thinkPHP5数据库配置、读取、模型操作及视图调用相关操作技巧,需要的朋友可以参考下

  8. PHP+jquery+CSS制作头像登录窗(仿QQ登陆)

    本篇文章介绍了PHP结合jQ和CSS制作头像登录窗(仿QQ登陆),实现了类似QQ的登陆界面,很有参考价值,有需要的朋友可以了解一下。

  9. 基于win2003虚拟机中apache服务器的访问

    下面小编就为大家带来一篇基于win2003虚拟机中apache服务器的访问。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. Yii2中组件的注册与创建方法

    这篇文章主要介绍了Yii2之组件的注册与创建的实现方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

返回
顶部