PHP的Yii框架中過濾器相關(guān)的使用總結(jié)
Yii過濾器簡介
過濾器是一段代碼,可被配置在控制器動作執(zhí)行之前或之后執(zhí)行。例如, 訪問控制過濾器將被執(zhí)行以確保在執(zhí)行請求的動作之前用戶已通過身份驗(yàn)證;性能過濾器可用于測量控制器執(zhí)行所用的時(shí)間。
一個(gè)動作可以有多個(gè)過濾器。過濾器執(zhí)行順序?yàn)樗鼈兂霈F(xiàn)在過濾器列表中的順序。過濾器可以阻止動作及后面其他過濾器的執(zhí)行。
過濾器有兩種寫法:
- 基于方法的過濾器
- 基于自定義過濾器類的過濾器
無論哪種過濾器,都必須在控制器中重寫控制器的public function filters()方法,設(shè)置哪個(gè)過濾器對哪個(gè)動作起作用。
基于方法的過濾器
編寫基于方法的過濾器,要經(jīng)過三步:
在控制器中編寫動作(Action);
在控制器中編寫過濾器函數(shù),函數(shù)名必須以filter為前綴,如:function filterAccessControl();
重寫父類CController的filters()方法,定義過濾器與動作的關(guān)系;
實(shí)例:
<?php
class UserController extends CController{
**
* 第一步:創(chuàng)建動作
*/
function actionAdd(){
echo "actionAdd";
}
/**
* 第二步:創(chuàng)建基于方法的過濾器
*/
public function filterAddFilter($filterChain) {
echo "基于方法的過濾器UserController.filterAdd<br>";
$filterChain->run();
}
/**
* 第三步:重寫父類CController的filters()方法,定義過濾器與動作的關(guān)系
* @see CController::filters()
*/
public function filters(){
return array(
//定義過濾器與動作的關(guān)聯(lián)關(guān)系
'addFilter + add',
// array(
// 'application.filters.TestFilter',
// ),
);
}
}
自定義過濾器類
自定義過濾器類,需要單獨(dú)寫一個(gè)過濾器類,并繼承CFilter類,重寫CFilter類下的部分方法。大家可以看一下CFilter類的代碼,該類代碼不多,還是很容易看懂的。
自定義過濾器實(shí)例:
<?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>";
}
}
在控制器中注冊該自定義過濾器與動作的綁定關(guān)系:
/**
* 第三步:重寫父類CController的filters()方法,定義過濾器與動作的關(guān)系
* @see CController::filters()
*/
ublic function filters(){
return array(
//定義過濾器與動作的關(guān)聯(lián)關(guān)系
'addFilter + add',
array(
'application.filters.TestFilter',
),
);
我自定義了一個(gè)過濾器:TestFilter,繼承了CFilter類,重寫了CFilter類的兩個(gè)主要方法:preFilter(前控制器,在動作執(zhí)行前運(yùn)行)和postFilter(后控制器,在動作執(zhí)行后運(yùn)行)。
兩種控制器的執(zhí)行順序
假設(shè)我將上面編寫的自定義過濾器類與動作actionAdd綁定,那么,自定義過濾器繼承自父類CFilter兩個(gè)方法:preFilter和postFilter,與綁定的actionAdd之間的執(zhí)行順序是怎樣的呢?
經(jīng)過試驗(yàn),執(zhí)行順序?yàn)椋篊Filter::preFilter--------->UserController::actionAdd--------->CFilter::postFilter。
也就是說,在動作執(zhí)行前后都可以執(zhí)行過濾操作。
那么文章開頭說“過濾器可以阻止動作及后面其他過濾器的執(zhí)行”是怎么做到的呢?
看了CFilter::preFilter的官方注釋就知道了:
@return boolean whether the filtering process should continue and the action should be executed。
CFilter::preFilter函數(shù)默認(rèn)return
true;即,默認(rèn)執(zhí)行后面的動作和后過濾器。如果在自定義過濾器類中,重寫CFilter::preFilter方法,并return
false;就可以阻止后面的動作和過濾器執(zhí)行了!
使用過濾器
過濾器本質(zhì)上是一類特殊的 行為,所以使用過濾器和 使用 行為一樣。 可以在控制器類中覆蓋它的 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');
},
],
];
}
控制器類的過濾器默認(rèn)應(yīng)用到該類的 所有 動作,你可以配置yii\base\ActionFilter::only屬性明確指定控制器應(yīng)用到哪些動作。 在上述例子中,HttpCache 過濾器只應(yīng)用到index和view動作。 也可以配置yii\base\ActionFilter::except屬性使一些動作不執(zhí)行過濾器。
除了控制器外,可在 模塊或應(yīng)用主體 中申明過濾器。 申明之后,過濾器會應(yīng)用到所屬該模塊或應(yīng)用主體的 所有 控制器動作, 除非像上述一樣配置過濾器的 yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 屬性。
補(bǔ)充: 在模塊或應(yīng)用主體中申明過濾器,在yii\base\ActionFilter::only 和 yii\base\ActionFilter::except 屬性中使用路由 代替動作ID, 因?yàn)樵谀K或應(yīng)用主體中只用動作ID并不能唯一指定到具體動作。.
當(dāng)一個(gè)動作有多個(gè)過濾器時(shí),根據(jù)以下規(guī)則先后執(zhí)行:
預(yù)過濾
- 按順序執(zhí)行應(yīng)用主體中behaviors()列出的過濾器。
- 按順序執(zhí)行模塊中behaviors()列出的過濾器。
- 按順序執(zhí)行控制器中behaviors()列出的過濾器。
- 如果任意過濾器終止動作執(zhí)行,后面的過濾器(包括預(yù)過濾和后過濾)不再執(zhí)行。
- 成功通過預(yù)過濾后執(zhí)行動作。
后過濾
- 倒序執(zhí)行控制器中behaviors()列出的過濾器。
- 倒序執(zhí)行模塊中behaviors()列出的過濾器。
- 倒序執(zhí)行應(yīng)用主體中behaviors()列出的過濾器。
創(chuàng)建過濾器
繼承 yii\base\ActionFilter 類并覆蓋 yii\base\ActionFilter::beforeAction() 和/或 yii\base\ActionFilter::afterAction() 方法來創(chuàng)建動作的過濾器,前者在動作執(zhí)行之前執(zhí)行,后者在動作執(zhí)行之后執(zhí)行。 yii\base\ActionFilter::beforeAction() 返回值決定動作是否應(yīng)該執(zhí)行, 如果為false,之后的過濾器和動作不會繼續(xù)執(zhí)行。
下面的例子申明一個(gè)記錄動作執(zhí)行時(shí)間日志的過濾器。
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規(guī)則的訪問控制。 特別是在動作執(zhí)行之前,訪問控制會檢測所有規(guī)則并找到第一個(gè)符合上下文的變量(比如用戶IP地址、登錄狀態(tài)等等)的規(guī)則, 來決定允許還是拒絕請求動作的執(zhí)行,如果沒有規(guī)則符合,訪問就會被拒絕。
如下示例表示表示允許已認(rèn)證用戶訪問create 和 update 動作,拒絕其他用戶訪問這兩個(gè)動作。
use yii\filters\AccessControl;
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['create', 'update'],
'rules' => [
// 允許認(rèn)證用戶
[
'allow' => true,
'roles' => ['@'],
],
// 默認(rèn)禁止其他用戶
],
],
];
}
2.認(rèn)證方法過濾器
認(rèn)證方法過濾器通過HTTP Basic Auth或OAuth 2 來認(rèn)證一個(gè)用戶,認(rèn)證方法過濾器類在 yii\filters\auth 命名空間下。
如下示例表示可使用yii\filters\auth\HttpBasicAuth來認(rèn)證一個(gè)用戶,它使用基于HTTP基礎(chǔ)認(rèn)證方法的令牌。 注意為了可運(yùn)行,yii\web\User::identityClass 類必須 實(shí)現(xiàn) yii\web\IdentityInterface::findIdentityByAccessToken()方法。
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
return [
'basicAuth' => [
'class' => HttpBasicAuth::className(),
],
];
}
認(rèn)證方法過濾器通常在實(shí)現(xiàn)RESTful API中使用。
3.yii\filters\ContentNegotiator
ContentNegotiator支持響應(yīng)內(nèi)容格式處理和語言處理。 通過檢查 GET 參數(shù)和 Accept HTTP頭部來決定響應(yīng)內(nèi)容格式和語言。
如下示例,配置ContentNegotiator支持JSON和XML響應(yīng)格式和英語(美國)和德語。
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',
],
],
];
}
在應(yīng)用主體生命周期過程中檢測響應(yīng)格式和語言簡單很多, 因此ContentNegotiator設(shè)計(jì)可被引導(dǎo)啟動組件調(diào)用的過濾器。 如下例所示可以將它配置在應(yīng)用主體配置。
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',
],
],
],
];
補(bǔ)充: 如果請求中沒有檢測到內(nèi)容格式和語言,使用formats和languages第一個(gè)配置項(xiàng)。
4.yii\filters\HttpCache
HttpCache利用Last-Modified 和 Etag HTTP頭實(shí)現(xiàn)客戶端緩存。例如:
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實(shí)現(xiàn)服務(wù)器端整個(gè)頁面的緩存。如下示例所示,PageCache應(yīng)用在index動作, 緩存整個(gè)頁面60秒或post表的記錄數(shù)發(fā)生變化。它也會根據(jù)不同應(yīng)用語言保存不同的頁面版本。
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 根據(jù) 漏桶算法 來實(shí)現(xiàn)速率限制。
7.yii\filters\VerbFilter
VerbFilter檢查請求動作的HTTP請求方式是否允許執(zhí)行,如果不允許,會拋出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 機(jī)制允許一個(gè)網(wǎng)頁的許多資源(例如字體、JavaScript等) 這些資源可以通過其他域名訪問獲取。 特別是JavaScript's AJAX 調(diào)用可使用 XMLHttpRequest 機(jī)制,由于同源安全策略該跨域請求會被網(wǎng)頁瀏覽器禁止. CORS定義瀏覽器和服務(wù)器交互時(shí)哪些跨域請求允許和禁止。
yii\filters\Cors 應(yīng)在 授權(quán) / 認(rèn)證 過濾器之前定義,以保證CORS頭部被發(fā)送。
use yii\filters\Cors;
use yii\helpers\ArrayHelper;
public function behaviors()
{
return ArrayHelper::merge([
[
'class' => Cors::className(),
],
], parent::behaviors());
}
Cors 可轉(zhuǎn)為使用 cors 屬性。
- cors['Origin']: 定義允許來源的數(shù)組,可為['*'] (任何用戶) 或 ['http://www.myserver.net', 'http://www.myotherserver.com']. 默認(rèn)為 ['*'].
- cors['Access-Control-Request-Method']: 允許動作數(shù)組如 ['GET', 'OPTIONS', 'HEAD']. 默認(rèn)為 ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'].
- cors['Access-Control-Request-Headers']: 允許請求頭部數(shù)組,可為 ['*'] 所有類型頭部 或 ['X-Request-With'] 指定類型頭部. 默認(rèn)為 ['*'].
- cors['Access-Control-Allow-Credentials']: 定義當(dāng)前請求是否使用證書,可為 true, false 或 null (不設(shè)置). 默認(rèn)為null.
- cors['Access-Control-Max-Age']: 定義請求的有效時(shí)間,默認(rèn)為 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());
}
可以覆蓋默認(rèn)參數(shù)為每個(gè)動作調(diào)整CORS 頭部。例如,為login動作增加Access-Control-Allow-Credentials參數(shù)如下所示:
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());
}
相關(guān)文章
php+jQuery+Ajax實(shí)現(xiàn)點(diǎn)贊效果的方法(附源碼下載)
這篇文章主要介紹了php+jQuery+Ajax實(shí)現(xiàn)點(diǎn)贊效果的方法,結(jié)合實(shí)例形式詳細(xì)介紹了php結(jié)合jQuery的ajax無刷新提交實(shí)現(xiàn)點(diǎn)贊功能的具體步驟與相關(guān)技巧,需要的朋友可以參考下2015-12-12
PHP二維數(shù)組實(shí)現(xiàn)去除重復(fù)項(xiàng)的方法【保留各個(gè)鍵值】
這篇文章主要介紹了PHP二維數(shù)組實(shí)現(xiàn)去除重復(fù)項(xiàng)的方法,結(jié)合實(shí)例形式分析了php保留各個(gè)鍵值的情況下去除重復(fù)項(xiàng)的相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
php實(shí)現(xiàn)用戶在線時(shí)間統(tǒng)計(jì)詳解
php實(shí)現(xiàn)用戶在線時(shí)間統(tǒng)計(jì)詳解,需要的朋友可以參考下。2011-10-10
PHP中isset與array_key_exists的區(qū)別實(shí)例分析
這篇文章主要介紹了PHP中isset與array_key_exists的區(qū)別,較為詳細(xì)的分析了isset與array_key_exists使用中的區(qū)別,并實(shí)例分析其具體用法,需要的朋友可以參考下2015-06-06

