关于yii2:开源项目一个干净简约基于vue3yii2轻度改造的后台框架

Yaa 疾速助你CURD开发! 示例图 环境要求PHP >= 7.3Composer >= 2Node.js >= 14PHP 启用扩大fileinfoimagemagickexif链接https://yaa.speaks.life/admin账号:admin明码:123456Yaa文档地址github✨ 个性 界面清新、简洁⚒️ 原生框架轻度革新、不附带任何臃肿第三方库✨ 自带祝愿光环加持,助你效率晋升1000X 装置composer create-project umono/yaa-yii2 疾速上手出现数据表格(以用户表)为例: vue 文件<template> <TableData :subHeight="240" :search="search" ref="tables" @view="openModal({ id: $event.id, isEdit: false }, 'formModal')" @edit="openModal({ id: $event.id, isEdit: true }, 'formModal')" url="admin/api/user/index" :handle="_handleBtn"> <!-- 搜寻条件开始 --> <n-input v-model:value="search.nickName" filterable placeholder="用户昵称" /> <n-input v-model:value="search.name" filterable placeholder="姓名" /> <n-input v-model:value="search.phone" filterable placeholder="手机号码" /> <!-- 搜寻条件完结 --> </TableData></template><script lang="ts">import TableData from "@/components/common/TableData.vue";export default defineComponent({ name: "USER", components: { TableData }, setup() { // 搜寻条件参数 // 在开发中尽量应用search参数蕴含所有条件 let search = reactive({ name: '', } as any) return { search } },})</script>php 文件<?php namespace app\modules\backend\api\controllers; use app\modules\backend\api\Controller; use app\modules\backend\api\models\other\User; class UserController extends Controller { // 数据列表 public function actionIndex() { $get = $this->get; $andWhere = [ ['like', 'nickName', $get['nickName'] ?? ''], ['like', 'name', $get['name'] ?? ''], ['like', 'phone', $get['phone'] ?? ''], ]; return User::page()->andWhere($andWhere)->toTableDataArray(); } // 创立、批改、删除 // ... } 倡议如果您在应用的过程中碰到问题,能够先通过 issues 看看有没有相似的 bug 或者倡议。 ...

December 20, 2022 · 1 min · jiezi

关于yii2:Yii2-controller-传值给layout

在yii2中,咱们通过上面的办法,将controller的数组传递给view public function actionIndex() { $data = ['xx' => 'yy']; return $this->render($this->action->id,$data); }在view文件中就能够应用$xx变量了,这个变量的值是’yy’. 当初咱们想给layout外面传递,怎么办呢?上面是原理: 在yii/base/Controller.php中能够看到如下代码: public function render($view, $params = []) { $content = $this->getView()->render($view, $params, $this); return $this->renderContent($content); }查找renderContent()办法 public function renderContent($content) { $layoutFile = $this->findLayoutFile($this->getView()); if ($layoutFile !== false) { return $this->getView()->renderFile($layoutFile, ['content' => $content], $this); } return $content; }能够看到,咱们只有重写renderContent()办法,在这个办法的内容局部: [‘content’ => $content]在这个数组中,增加上咱们的想要的其余的数组,譬如: [‘content’ => $content, ‘tt’ => ‘terry’]咱们就能够在layout外面应用$tt变量了。也就是将controller中的变量传递给layout。 在fecify中就采纳了这个技术点,把 controller 传值给layout,解决了难题,心愿能够帮忙大家。

August 24, 2022 · 1 min · jiezi

关于yii2:Yii2-ElasticSearch-aggregate-group

我想要统计的是country_code 呈现的次数,通过yii2的ElasticSearch扩大,下面的例子满足我的须要。业务场景:在fecify商城中,应用elasticSearch搜寻,进行aggregate group操作,代码如下: public function actionCountry(){ $size = 5000; $name = 'country_code'; $type = 'terms'; $options = [ 'field' => 'country_code', 'size' => $size, ]; $data = WholeCountryData::find() //->limit(5000) //->offset(0) ->asArray() ->addAgg($name, $type, $options) ->createCommand() ->search(); $agg_data = $data['aggregations']; $buckets = $agg_data['country_code']['buckets']; //var_dump($agg_data);exit; $country_code_arr = \yii\helpers\BaseArrayHelper::getColumn($buckets,'key'); var_dump($country_code_arr);}

August 23, 2022 · 1 min · jiezi

关于yii2:yii2核心验证-时间验证

['expiration_range_0', 'date', 'timestampAttribute' => 'expiration_range_0', 'format' => 'php: Y-m-d', 'defaultTimeZone' => \Yii::$app->timeZone],['expiration_range_1', 'date', 'timestampAttribute' => 'expiration_range_1', 'format' => 'php: Y-m-d', 'defaultTimeZone' => \Yii::$app->timeZone],须要留神工夫格局,默认timestampAttribute 属性转化是UTC,无论是否在Yii->$app->timeZone,还是 Yii->$app->commoment->formatter设置defaultTimeZone、timeZine 都有效;必须在验证条目下来设置 还有就是转换工夫戳时的时区,否者有偏差;所以我的项目中必须查看时区;

April 26, 2022 · 1 min · jiezi

关于yii2:关于yii框架-updateAll-多次更新不生效

AdvModel::updateAll($row,['id'=>1]); //返回 1;AdvModel::updateAll($row,['id'=>1]); //返回 0; 换成上面的 $advModel->attributes = $row; $advModel->save();//true; $advModel->save();//true; 用save()代替

February 21, 2022 · 1 min · jiezi

关于yii2:Yii2框架基础模板使用多组用户增加admin

首先配置文件新增一组,copy user组件即可 属性可调整 'components' => [ //其余... 'user' => [ 'identityClass' => 'app\models\User', 'enableAutoLogin' => true, ], 'admin' => [ 'class' => 'yii\web\User', 'identityClass' => 'app\admin\models\Admin', 'enableAutoLogin' => true, 'loginUrl' => 'admin/default/xxx',//admin的登录页 'identityCookie' => ['name' => '_admin_identity', 'httpOnly' => true], //这5个我的项目必须配置 否则会和user登录状态发生冲突 'idParam' => '__admin_id', 'authKeyParam' => '__admin_authKey', 'authTimeoutParam' => '__admin_expire', 'absoluteAuthTimeoutParam' => '__admin_absoluteExpire', 'returnUrlParam' => '__admin_returnUrl', ],在控制器,假如咱们减少了一个admin模块 <?phpnamespace app\admin\controllers;use Yii;use yii\web\Controller;use yii\filters\AccessControl;class DefaultController extends Controller{ public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), /* * 这里的user必须要指定 components 里的后盾用户组组件名称admin * 否则默认会判断前台用户组user * 如果你取了其余名字就填写你自定义的名字 */ 'user' => 'admin', 'only' => ['index', 'signup'], 'rules' => [ [//不须要登录就能够拜访的办法 'allow' => true, 'actions' => ['login', 'signup'], 'roles' => ['?'], ], [//必须登录才能够拜访的办法 'allow' => true, 'actions' => ['index'], 'roles' => ['@'], ], ], ], ]; } public function actionIndex() { if( Yii::$app->admin->isGuest ){ return 'admin没有登陆,如果设置了AccessControl,其实压根拜访不到这里就会被重定向到管理员登陆界面'; } $identity = Yii::$app->admin->identity; return 'Your username : ' . $identity->username; } //admin登录 实在业务代码会简单一些 public function actionLogin() { $identity = \app\admin\models\Admin::findByUsername('demo'); return Yii::$app->admin->login($identity) ? 'admin登陆胜利' : '登陆失败' ; } //admin退出 public function actionLogout() { return Yii::$app->admin->logout() ? 'admin 登出胜利' : '登出失败' ; }}除了admin,你也能够设定其余用户组件,比方供应商,商户须要独立用户表都能够用这种办法 ...

November 11, 2021 · 1 min · jiezi

关于yii2:yii2问题

1.Yii2 验证码不显示} else { ob_clean(); //Add this line, can solve this problem. Or add in other suitable places $this->setHttpHeaders(); Yii::$app->response->format = Response::FORMAT_RAW; return $this->renderImage($this->getVerifyCode()); }

December 17, 2020 · 1 min · jiezi

关于yii2:yii2-读写分离模式下强制读主库

yii2 配置读写主动读写拆散时,在一些场景下可能须要强制读主库。以及 createCommand 的 in 查问参数绑定实现办法。 强制读主库yii2 配置读写主动主从拆散时,在一些场景下可能须要强制读主库。这时咱们能够应用 \yii\db\Connection 的 useMaster 办法来操作,该办法会将 enableSlaves 模式在本次查问会话中敞开,查问实现后继而复原。 /** @var $users User[] */$users = User::getDb()->useMaster(function($db) use ($ids) { /** @var $db \yii\db\Connection */ return $db->createCommand("SELECT * FROM " . User::tableName() . " where find_in_set(`id`, :ids) AND `is_del`=:is_del", [ ':ids' => implode(',', $ids), ':is_del' => Base::NOT_DELETED, ])->queryAll(\PDO::FETCH_OBJ);});createCommand IN 查问createCommand 构建 sql 时可能会遇到 IN 查问的场景,yii2 貌似不反对,能够应用 find_in_set 来代替。 $db->createCommand("SELECT * FROM `users` WHERE `id` in(:ids)", [':ids' => [1, 2, 3]]);$db->createCommand("SELECT * FROM `users` WHERE `id` in(:ids)", [':ids' => implode(",", [1, 2, 3])]);会被解析成 ...

November 27, 2020 · 1 min · jiezi

Yii2-composer安装慢的解决办法

在yii中引用php的开源项目用composer已经很方便了,引用前端的开源项目也有composer的插件fxp-asset和Asset Packagist 以前yii默认采用前者,现在新的yii2模版默认采用后者,后者的作者就很厉害了,貌似是个重度yii用户,看来是被fxp-asset的执行缓慢给弄急眼了,所以自己搞了个更新的方法。言归正传:所以更快速的安装方式就是 Asset Packagist https://asset-packagist.org 其实就是2步: 在config中关闭fxp-asset的调用在源列表中加入asset-packagist库的配置"config": { "process-timeout": 1800, "fxp-asset": { "enabled": false } }, "repositories": [ { "type": "composer", "url": "https://asset-packagist.org" }]需要注意的是,yii在yii\base\Application 中定义vendor路径的时候也定义了bower和npm路径: /** * Sets the directory that stores vendor files. * @param string $path the directory that stores vendor files. */ public function setVendorPath($path) { $this->_vendorPath = Yii::getAlias($path); Yii::setAlias('@vendor', $this->_vendorPath); Yii::setAlias('@bower', $this->_vendorPath . DIRECTORY_SEPARATOR . 'bower'); Yii::setAlias('@npm', $this->_vendorPath . DIRECTORY_SEPARATOR . 'npm'); }这就和asset-packagist的默认安装路径有了差别解决办法:重新定义yii中的bower和npm路径 ...

September 10, 2019 · 1 min · jiezi

openadmyii2admin模块化开发骨架

introduceopenadm/yii2-admin 基于yii2-extension包管理和adminlte2主题构建的admin项目,包括了基础的用户管理,RBAC管理,扩展管理等核心功能。 去OpenADM(https://openadm.com)查看更多 SourceSource https://gitee.com/openadm/yii2-admin.git InstallationThe preferred way to install this extension is through composer. Either run php composer.phar require --prefer-dist openadm/yii2-admin "*"or add "openadm/yii2-admin": "*"to the require section of your composer.json file. UsageOnce the extension is installed, simply use it in your code by : Migrate DB./yii migrate --migrationPath=@openadm/admin/migrations./yii migrate all -p=@tecnocen/oauth2server/migrations/tablesscreenshots

July 6, 2019 · 1 min · jiezi

YII2项目中重写PhpStorm中对方法function的注释代码

1说明Yii2默认的可访问的路由都是action开头的,但是当项目多了action名称变长了,每次都要转换大小写对action进行全局的搜索,很是不方便,所以重写了phpstorm对function注释的工具,这样我们写好action方法的时候只要输入/**然后再按一个回车就可以出现以下代码了,如下图,自动对action进行了拆分,这样就能愉快的搜索了 2操作步骤·依次打开File->Settings->Editor->File and Code Templates(或者使用快捷键ctrl+shift+s)·找到界面右侧的Includes,再点击PHP Function Doc Comment,接着把以下代码复制进去,点击apply->ok即可 3、配置代码/*** @note: #if($NAME.length()>6) #set($formatAction = '') #if($NAME.substring(0,6) == 'action') #set($len = $NAME.length()) #set($actionName = $NAME.substring(6,$len)) #set($actionLen = ${len} - 6 - 1) #foreach($start in [0..$actionLen]) #set($end = ${start} + 1) #set($tmpStr = $actionName.substring($start,$end)) #if($tmpStr.toUpperCase() == $tmpStr) #set($tmpLowerStr = $tmpStr.toLowerCase()) #if($start != 0) #set($formatAction = "${formatAction}-") #end #set($formatAction = "${formatAction}${tmpLowerStr}") #else #set($formatAction = "${formatAction}${tmpStr}") #end #end * @action $formatAction #else * @func $NAME #end#else * @func $NAME #end${PARAM_DOC}#if (${TYPE_HINT} != "void") * @return ${TYPE_HINT}#end${THROWS_DOC}*/4、相关网站http://velocity.apache.org/en...https://wizardforcel.gitbooks... ...

July 3, 2019 · 1 min · jiezi

Yii授权之基于角色的存取控制-RBAC

一:基本概念 角色是 权限 的集合 (例如:建贴、改贴)。一个角色 可以指派给一个或者多个用户。要检查某用户是否有一个特定的权限, 系统会检查该包含该权限的角色是否指派给了该用户。 可以用一个规则 rule 与一个角色或者权限关联。一个规则用一段代码代表, 规则的执行是在检查一个用户是否满足这个角色或者权限时进行的。例如,"改帖" 的权限 可以使用一个检查该用户是否是帖子的创建者的规则。权限检查中,如果该用户 不是帖子创建者,那么他(她)将被认为不具有 "改帖"的权限。 角色和权限都可以按层次组织。特定情况下,一个角色可能由其他角色或权限构成, 而权限又由其他的权限构成。Yii 实现了所谓的 局部顺序 的层次结构,包含更多的特定的 树 的层次。 一个角色可以包含一个权限,反之则不行。(译者注:可理解为角色在上方,权限在下方,从上到下如果碰到权限那么再往下不能出现角色) 二:配置 RBAC 在开始定义授权数据和执行存取检查之前,需要先配置应用组件 yiibaseApplication::authManager 。 Yii 提供了两套授权管理器: yiirbacPhpManager 和 yiirbacDbManager。前者使用 PHP 脚本存放授权数据, 而后者使用数据库存放授权数据。 如果你的应用不要求大量的动态角色和权限管理, 你可以考虑使用前者 1:使用yiirbacPhpManager return [ // ... 'components' => [ 'authManager' => [ 'class' => 'yii\rbac\PhpManager', ], // ... ],];配置完成之后你就可以通过Yii::$app->authManager来访问 authManager yiirbacPhpManager 默认将 RBAC 数据保存在 @app/rbac 目录下的文件中。 如果权限层次数据在运行时会被修改,需确保WEB服务器进程对该目录和其中的文件有写权限。 2:使用yiirbacDbManager (1)配置yiirbacDbManager ...

June 29, 2019 · 1 min · jiezi

Yii-使用JWT

了解JWT可以参考:了解JWT 一:下载JWT拓展 在JWT官网中我们可以看到很多php版本的JWT,选择一个JWT进行下载 这里我选择的是lcobucci/jwt,使用composer进行下载 lcobucci/jwt的composer地址:https://packagist.org/package... composer require lcobucci/jwt "^3.3.0" #这里我下载的是3.3.0版本二:lcobucci/jwt使用 lcobucci/jwt使用方法可以参考下载下来的README.md文件(vendor/lcobucci/jwt/README.md) 1:生成JWT $request = Yii::$app->getRequest();$signer = new Sha256();//使用Sha256加密,常用加密方式有Sha256,Sha384,Sha512$time = time();$tokenBuilder = (new Builder()) ->issuedBy($request->getHostInfo()) // 设置发行人 ->permittedFor(isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '') // 设置接收 ->identifiedBy(Yii::$app->security->generateRandomString(10), true) // 设置id ->issuedAt($time) // 设置生成token的时间 ->canOnlyBeUsedAfter($time) // 设置token使用时间(实时使用) ->expiresAt($time + 3600); //设置token过期时间//定义自己所需字段$user = ['user_name' => '测试', 'user_no' => '001'];$tokenBuilder->withClaim('user', $user);$tokenBuilder->withClaim('ceshi', '测试字段');//使用Sha256加密生成token对象,该对象的字符串形式为一个JWT字符串$token = $tokenBuilder->getToken($signer, new Key('jwt_secret'));echo (string) $token;2:对JWT进行校验 在正常的开发环境下,我们将生成的JWT字符串传到前端,当前端调用其他接口时,将我们所给的JWT传递到后台,我们后台需要对前端传来的JWT字符串进行校验 下面的$token为我们获取到的前端传递的JWT $token = (new Parser())->parse($token);//数据校验$data = new ValidationData(); // 使用当前时间来校验数据if (!$token->validate($data)) { //数据校验失败 return '数据校验失败';}//token校验$signer = new Sha256();//生成JWT时使用的加密方式if (!$token->verify($signer, new Key('jwt_secret'))) { //token校验失败 return 'token校验失败';}echo '校验成功';3:获取JWT的相关信息 ...

June 24, 2019 · 2 min · jiezi

Yii-实现阿里云短信发送

一:安装saviorlv/yii2-dysms拓展 composer地址:https://packagist.org/package... composer require "saviorlv/yii2-dysms"二:saviorlv/yii2-dysms拓展配置 'components' => [ .....'aliyun' => [ 'class' => 'saviorlv\aliyun\Sms', 'accessKeyId' => 'XXXXXX',//阿里云accessKeyId 'accessKeySecret' => 'XXXXXX'//阿里云accessKeySecret], ....]三:实现短信发送 1:单条短信发送 // 单条发送$response = \Yii::$app->aliyun->sendSms( "短信签名", // 短信签名 "SMS_5002925", // 短信模板编号 "18551773287", // 短信接收者 //模板变量 [ "code"=>"12345", "product"=>"dsd" ], //发送短信流水号,选填 "123");2:多条短信发送 //批量发送(签名、手机号、模板字段 数组长度必须相等)$response = \Yii::$app->aliyun->sendBatchSms( // 短信签名 [ '短信签名', '短信签名' ], "SMS_5002925", // 短信模板编号 // 短信接收者 [ '18551773287', '17600827397' ], //模板变量 [ [ "code"=>"12345", "product"=>"测试" ], [ "code"=>"12345", "product"=>"测试" ], ], //发送短信流水号,选填 "123");根据如上就可以实现阿里云短信发送 ...

June 21, 2019 · 1 min · jiezi

Yii-使用interventionimage拓展实现图像处理

一:安装intervention/image拓展 composer require intervention/image二:上传文件 \Intervention\Image\ImageManagerStatic::make($_FILES['file']['tmp_name'])->save('upload.jpg');//file为上传表单的name名\Intervention\Image\ImageManagerStatic::make($_FILES['file']['tmp_name'])->resize(300, 200)->save('upload.jpg');//file为上传表单的name名,并将上传的图片压缩成300,200同时实现单图上传和多图上传 if ($_FILES['file']) { $image = $_FILES['file']['tmp_name']; if (is_array($image)) { //多图上传 foreach ($image as $key => $item) { \Intervention\Image\ImageManagerStatic::make($item)->save($key.'upload.jpg'); } } else { //单图上传 \Intervention\Image\ImageManagerStatic::make($image)->save('upload.jpg'); }}三:添加水印 1:添加文字水印 添加文字水印主要使用到text方法 text方法参数说明 x(可选) x定义第一个字符的基点。默认值:0 y(可选) y定义第一个字符的基点。默认值:0 callback(可选) 关闭字体对象的回调,回调可配置: (1)file:配置水印字体(2)size:配置水印大小(3)color:配置水印颜色(4)align:配置水印水平对齐方式(5)valign:配置是垂直对齐方式(6)angle:配置水印旋转角度例: //水印ImageManagerStatic::make('upload.jpg')->text('水印文字',20,30,function($font){ //配置水印字体 $font->file(\Yii::getAlias('@webroot') . '/simsun.ttc'); //配置水印大小 $font->size(30); //配置水印颜色 $font->color('#fff'); //配置水印水平居左( left, right and center) $font->align('left'); //配置水印垂直居下(top, bottom and middle) $font->valign('bottom'); //配置水印旋转角度 $font->angle(45);})->save('uploadWater.jpg');2:添加图片水印 添加图片水印主要使用到insert方法 insert方法参数说明: ...

June 21, 2019 · 1 min · jiezi

yii2缓存写入失败问题排查记录

问题今天遇到了一个很奇怪的bug,只有同事的手机登录系统一直失败,其他人的都正常。 发现原因在确认代码逻辑没问题后,发现是yii2写入缓存失败的问题。我们yii2的缓存组件是使用文件组件,进入缓存所在的文件夹,发现有少数几个文件夹拥有者是root,而不是运行php-fpm的apache,而这几个文件夹的权限为775,所以apache没有写入的权限。 解决问题使用chmod赋值777权限后,写入正常。那么是什么导致这几个root文件的生成的呢?因为我们用了定时任务执行commonds,但是指定的用户是root,所以才出现了这个问题。把crontab里的用户指定改成apache,这问题就解决了。 防范于未然如果是有人登陆并手动执行了commonds的话,也可能会生成apache操作不了的文件,所以让运维把所有登陆用户和apache放在一个组里,这个问题就完全解决了。

June 20, 2019 · 1 min · jiezi

深入理解控制反转IoC和依赖注入DI

容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描述(类、接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” 、“依赖注入(DI)”。本文就从这里开始。IoC 容器, laravel 的核心Laravel 的核心就是一个 IoC 容器,根据文档,称其为“服务容器”,顾名思义,该容器提供了整个框架中需要的一系列服务。作为初学者,很多人会在这一个概念上犯难,因此,我打算从一些基础的内容开始讲解,通过理解面向对象开发中依赖的产生和解决方法,来逐渐揭开“依赖注入”的面纱,逐渐理解这一神奇的设计理念。 本文一大半内容都是通过举例来让读者去理解什么是 IoC(控制反转) 和 DI(依赖注入),通过理解这些概念,来更加深入。更多关于 laravel 服务容器的用法建议阅读文档即可。 IoC 容器诞生的故事讲解 IoC 容器有很多的文章,我之前也写过。但现在我打算利用当下的灵感重新来过,那么开始吧。 超人和超能力,依赖的产生!面向对象编程,有以下几样东西无时不刻的接触:接口、类还有对象。这其中,接口是类的原型,一个类必须要遵守其实现的接口;对象则是一个类实例化后的产物,我们称其为一个实例。当然这样说肯定不利于理解,我们就实际的写点中看不中用的代码辅助学习。 怪物横行的世界,总归需要点超级人物来摆平。我们把一个“超人”作为一个类, class Superman {}我们可以想象,一个超人诞生的时候肯定拥有至少一个超能力,这个超能力也可以抽象为一个对象,为这个对象定义一个描述他的类吧。一个超能力肯定有多种属性、(操作)方法,这个尽情的想象,但是目前我们先大致定义一个只有属性的“超能力”,至于能干啥,我们以后再丰富: class Power { /** * 能力值 */ protected $ability; /** * 能力范围或距离 */ protected $range; public function __construct($ability, $range) { $this->ability = $ability; $this->range = $range; }}这时候我们回过头,修改一下之前的“超人”类,让一个“超人”创建的时候被赋予一个超能力: class Superman{ protected $power; public function __construct() { $this->power = new Power(999, 100); }}这样的话,当我们创建一个“超人”实例的时候,同时也创建了一个“超能力”的实例,但是,我们看到了一点,“超人”和“超能力”之间不可避免的产生了一个依赖。 所谓“依赖”,就是 “我若依赖你,我就不能离开你”。在一个贯彻面向对象编程的项目中,这样的依赖随处可见。少量的依赖并不会有太过直观的影响,我们随着这个例子逐渐铺开,让大家慢慢意识到,当依赖达到一个量级时,是怎样一番噩梦般的体验。当然,我也会自然而然的讲述如何解决问题。 ...

May 24, 2019 · 4 min · jiezi

Yii-modules模块配置

在开发过程中,一个项目中,项目的功能可能会分为多个模块,例如,如果我们的项目为电商的管理控制系统的话,这时候我们的项目可能就会分为销售模块,采购模块,财务模块等等,这时候我们如果可以将项目按照一个个模块区分开来,在一个目录下专门写指定模块的代码,这样的话,我们的项目结构是不是就什么的清楚明了呢?在Yii中,我们可以使用modules来实现代码模块话 一:modules配置 在配置文件中main.php配置 //这里我配置了一个销售的模块和采购模块'modules' => [ 'sell'=> [ 'class' => 'frontend\modules\sell\Module', ], 'purchase'=> [ 'class' => 'frontend\modules\purchase\Module', ], ],二:创建模块目录(这里我只创建sell模块,其他模块创建方式相同) 上面我配置的modules实在frontend中,所有在frontend目录下创建一个modules目录,然后在modules目录下创建一个sell目录,在sell目录下有如下文件及文件夹 1:module.php(模块入口文件) <?phpnamespace frontend\modules\sell;class Module extends \common\components\Module{ public $controllerNamespace = 'frontend\modules\sell\controllers';}2:controllers目录 此目录下放置的是此模块所有的控制器方法 3:models目录 此目录放置的是此模块所需的模型 4:view目录 此目录放置的是此模块的视图文件 sell目录下文件结构如下: 根据如上方法我们就完成了modules配置使用

May 14, 2019 · 1 min · jiezi

yii2-的-restful-api-路由实例

yii\rest\UrlRule使用yii\rest\UrlRule来自动映射控制器的 restful 路由,简单快捷,缺点是必须得按规定好的方法名去写业务。 映射的规则如下,当然,你可以修改源码为你的习惯: public $patterns = [ 'PUT,PATCH {id}' => 'update', 'DELETE {id}' => 'delete', 'GET,HEAD {id}' => 'view', 'POST' => 'create', 'GET,HEAD' => 'index', '{id}' => 'options', '' => 'options',];除了被限制了HTTP动词对应的方法名外,其他都很好用,比如pluralize是多么的优雅啊,可以自动解析单词的复数,laravel的话要一个个的去写,反而有些不方便了 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'enableStrictParsing' => true, 'rules' => [ [ 'class' => 'yii\rest\UrlRule', 'controller' => [ 'v1/user', 'v1/news', 'routeAlias' => 'v1/box' ], 'pluralize' => true ], ]]自定义路由注意我路由里很刻意的用了复数模式,但很鸡肋,因为一些单词的复数并不是简单的加个 s 就可以了。 ...

May 13, 2019 · 1 min · jiezi

yii2-开发-api-接口时优雅的处理全局异常

前言:个人觉得,学习或温习一套Web框架,在快速阅读一遍文档后,应从路由,控制器,请求/响应对象,数据模型(Logic,Dao,Entity),全局异常处理几个方面下手,这几项了解后,框架上手就游刃有余了。然后我比较喜欢在开工前整理好框架的全局异常处理,方便写 api时错误的统一响应。 在api接口的开发过程中,我们需要对用户数据进行严格的校验,防止非法输入对服务产生安全问题,在开发过程中,我比较喜欢即时的以抛出异常的方式中断请求的处理,并以全局异常处理器格式化处理后统一返回给客户端。 今天就把 yii2 自带的全局异常处理器改写至对 api 友好(yii2的 yii\web\HttpException默认对 web 请求友好,都是以text/html的方式返回错误描述,对api不友好,api当然是json)。 注册异常处理器yii2也是以 controller/action 的方式定义一个异常处理器的,我们可以在 components=>errorHandler中自定义。 # config/web.php'components' => [ 'errorHandler' => [ 'errorAction' => 'exception/handler' ]]异常处理器定义相应的异常处理器,app\actions\ErrorApiAction 继承 yii\web\ErrorAction,可以拿到yii2为我们整理好的全局异常。 # controllers/ExceptionController.php<?phpnamespace app\controllers;use yii\web\Controller;class ExceptionController extends Controller{ /** * 为 actionHandler 挂载独立的 action * @return array */ public function actions() { return [ 'handler' => [ 'class' => 'app\actions\ErrorApiAction', ] ]; }}对api友好的错误异常处理器,这里我也只是简单的把响应格式改了一下,异常的上下文还是用yii2自带的处理的。 #actions/ErrorApiAction.php<?php/** * @author wangzhijian@styd.com * @date 2019-5-13 17:20:10 * Api 全局错误异常处理器 */namespace app\actions;use Yii;use yii\web\ErrorAction;use yii\web\Response;class ErrorApiAction extends ErrorAction{ public function run() { // 根据异常类型设定相应的响应码 Yii::$app->getResponse()->setStatusCodeByException($this->exception); // json 格式返回 Yii::$app->getResponse()->format = Response::FORMAT_JSON; // 返回的内容数据 return [ 'msg' => $this->exception->getMessage(), 'err' => $this->exception->getCode() ]; }}异常实体主要是简单的把状态码的传递封装一下,用更容易理解的类名来代理传递。exceptions/HttpException.php ...

May 13, 2019 · 1 min · jiezi

YII2项目常用技能知识总结

1、不通过日志获取AR执行的原生SQL语句和打印变量数据 $query = User::find() ->select(['username'])->where(['id'=>[1,2,3,4])// get the AR raw sql in YII2$commandQuery = clone $query;echo $commandQuery->createCommand()->getRawSql();$users = $query->all();打印变量数据可以这样写: //引用命名空间use yii\helpers\VarDumper;//使用VarDumper::dump($var);//使用2 第二个参数是数组的深度 第三个参数是是否显示代码高亮(默认不显示)VarDumper::dump($var, 10 ,true);2、从数据库二维数组中返回一维数组并配合rules验证规则实现分类数据过滤。 普通返回表记录的二维数组 Member::find()->select('userid')->asArray()->all();Array( [0] => Array ( [userid] => 1 ) [1] => Array ( [userid] => 2 ) [2] => Array ( [userid] => 3 ))返回字段的一维数组 Member::find()->select('userid')->asArray()->column();或者:\yii\helpers\ArrayHelper::getColumn(Member::find()->all(), 'userid')Array( [0] => 1 [1] => 2 [2] => 3)返回一维数组配合验证规则验证数据正确性,如分类catid正确分为只有1-4,但是在devTools打开修改catid为5,提交同样会到数据库,此时rules验证规则如下: ['catid', 'in', 'range' => category::find()->select('id')->asArray()->column()],当然,这个也可以通过下面这样子写,一样的: ...

May 6, 2019 · 3 min · jiezi

Yii2自定义组件编辑器无法自动提示超简单解决方案来了

组件配置return [ 'components' => [ 'redisWorm'=>[ 'class' => 'yii\redis\Connection', 'hostname' => '127.0.0.1', 'port' => 6379, 'database' => 0, ], ],];新增_ide_helper.php<?php/** 组件提示,无任何实际功能 * Class Yii */class Yii{ /** * @var MyApplication */ public static $app;}/** 自定义应用组件 * Class MyApplication */class MyApplication{ /** components redisWorm */ /** @var yii\redis\Connection */ public $redisWorm ; /** @var \common\models\SourceList */ public $source;}具体路径如下 代码使用 当我们用 Ctrl+鼠标 指上去的时候,编辑器已经能正确提示了!

April 27, 2019 · 1 min · jiezi

Yii2中使用phpunit进行测试

Yii2中使用phpunit进行测试安装 phpunit , 将 phpunit 命令添加到环境变量中 ;(详情请参照phpunit官网)进入到项目文件夹中,新建 test 文件夹, test 和 vendor,backend 同级。(可以自行定义目录结构)将 phpunit.phar 放入 test 文件夹中 。(方便测试代码中的断言调试)(可省)新建 index.php , 具体内容如下 :<?php//定义模式defined(‘YII_DEBUG’) or define(‘YII_DEBUG’, true);defined(‘YII_ENV’) or define(‘YII_ENV’, ‘dev’);//引入文件require DIR . ‘/../vendor/autoload.php’;require DIR . ‘/../vendor/yiisoft/yii2/Yii.php’;require DIR . ‘/../common/config/bootstrap.php’;//配置信息,这里默认使用的为后台配置,可自行修改$config = yii\helpers\ArrayHelper::merge( //配置信息,数据库信息 require DIR . ‘/../common/config/main.php’, require DIR . ‘/../common/config/main-local.php’, require DIR . ‘/../backend/config/main.php’);//(new yii\web\Application($config))->run() ;//注册框架基本服务,不运行框架(new yii\web\Application($config)) ;//所有测试文件 以 Test.php结尾 eg: UnitTest.php//所有测试方法 以 test开头 eg: testPay()//测试 以index.php为运行组件运行测试文件//window + R 输入 cmd ;//进入到项目中的test文件夹//运行:phpunit –bootstrap ./index.php demo/UnitTest//解释:使用 phpunit 以 index.php 为组件,运行 demo 文件夹下的 UnitTest.php 中的所有测试代码目录结构如下 : ...

March 13, 2019 · 1 min · jiezi

Yii2 设置 分类型分日期保存日志

直接上代码:’log’ => [ ’traceLevel’ => YII_DEBUG ? 3 : 0, ’targets’ => [ [ ‘class’ => ‘yii\log\FileTarget’, ’levels’ => [’error’], ’logFile’ => ‘@runtime/logs/’.date(‘Ym’).’/app.error.log’, ], [ ‘class’ => ‘yii\log\FileTarget’, ’levels’ => [‘warning’], ’logFile’ => ‘@runtime/logs/’.date(‘Ym’).’/app.warning.log’, ], ],],

March 4, 2019 · 1 min · jiezi

YII2+AdminLET开源通用后台管理系统源码

GitHub地址:https://github.com/jianyan74/…演示地址:http://demo2.rageframe.com/ba…账号:demo密码:123456什么都不说先上思维导图 系统截图

January 17, 2019 · 1 min · jiezi

Yii2.0 RESTful API 之版本控制

Yii2.0 RESTful API 之版本控制之前我写过两篇关于 Yii2.0 RESTful API 如何搭建,以及 认证 等处理,但是没有涉及到版本管理,今天就来谈谈版本管理如何实现。索性就从头开始一步一步搭建吧,但是关于一些概念以及使用本篇就不一一解释了,可以参考 第一篇 Yii2.0 RESTful API 基础配置教程 进行配置安装Yii2.0通过 Composer 安装这是安装Yii2.0的首选方法。如果你还没有安装 Composer,你可以按照这里的说明进行安装。安装完 Composer,运行下面的命令来安装 Composer Asset 插件:composer global require “fxp/composer-asset-plugin:^1.2.0"安装高级的应用程序模板,运行下面的命令:composer create-project yiisoft/yii2-app-advanced yii-api 2.0.14拷贝backend目录,命名为api打开api\config\main.php 修改id,controllerNamespace:return [ ‘id’ => ‘app-api’, ‘basePath’ => dirname(DIR), ‘controllerNamespace’ => ‘api\controllers’,]初始化高级模板在初始化之前不妨先看下这篇文章cd advancedphp init打开common\config\main.php开启url路由美化规则’urlManager’ => [ ’enablePrettyUrl’ => true, ‘showScriptName’ => false, ‘rules’ => [ ],],打开common\config\bootstrap.php添加以下别名Yii::setAlias(’@api’, dirname(dirname(DIR)) . ‘/api’);ok,以上工作准备完毕,接下来进入正题,关于版本更多介绍可以参考 权威指南 ,这里不过多解释(PS:主要我也不会……)我的理解:Yii2 的版本你可以理解为不同的模块,每一个版本就是一个新的模块,比如常见的v1,v2等。模块的搭建关于如何生成模块,我们可以使用GII来进行生成.配置 GII打开 api/config/main-local.php 文件 修改如下:if (!YII_ENV_TEST) { // configuration adjustments for ‘dev’ environment $config[‘bootstrap’][] = ‘debug’; $config[‘modules’][‘debug’] = [ ‘class’ => ‘yii\debug\Module’, ]; $config[‘bootstrap’][] = ‘gii’; $config[‘modules’][‘gii’] = [ ‘class’ => ‘yii\gii\Module’, ‘allowedIPs’ => [‘127.0.0.1’, ‘’] ];}我这里因为使用的是 Homestead ,默认是不允许访问 GII 的,所以得加上 ‘allowedIPs’ => [‘127.0.0.1’, ‘’] ,否则会出现 Forbidden (#403), 你可以根据自己的需要来进行配置,或者不配置生成Modules浏览器中输入 http://your host/gii ,可以看到 Module Generator ,点击 StartModules Class 中输入:api\modules\v1\ModuleModule ID 中输入v1,(一般会自动输入)点击 Preview最后点击 Generate 进行生成配置模块打开 api/config/main.php 文件,修改 modules’modules’ => [ ‘v1’=>[ ‘class’=>‘api\modules\v1\Module’, ],],接着修改 urlManager’urlManager’ => [ ’enablePrettyUrl’ => true, ’enableStrictParsing’ => true, ‘showScriptName’ => false, ‘rules’ => [ [‘class’ => ‘yii\rest\UrlRule’, ‘controller’ => ‘v1/default’, ’extraPatterns’=>[ ‘GET index’=>‘index’, ], ], ],],基于以上,Yii2.0 RESTFul API 就实现了版本管理,我们可以通过如下地址进行访问:http://localhost/v1/defaults多说一点,我上方的地址是已经映射到api/web目录,请根据自己的实际情况进行配置打开刚生成的 modules 文件目录,可以看到里面存在一个 v1 的目录,可以看到该目录还有一个controllers,以及一个 views 目录,我们刚才访问的 defaults 其实就是这两个文件,和传统的web项目一样控制器渲染视图好了,你可能知道了,我们以后的控制器代码就放到 modules/v1/controllers 里了刚才仅仅是默认GII为我们生成的代码,因为我们是API,所以 views 目录,我们一般情况下用不到。新建一个 rest 的控制器在 modules\v1\controllers 下新建 UserController<?phpnamespace api\modules\v1\controllers;use yii\rest\Controller;/** * User controller for the v1 module /class UserController extends Controller{ /* * @return string */ public function actionIndex() { return ’this is v1/user’; }}修改 api/config/main.php 中的urlManager’urlManager’ => [ ’enablePrettyUrl’ => true, ’enableStrictParsing’ => true, ‘showScriptName’ => false, ‘rules’ => [ [‘class’ => ‘yii\rest\UrlRule’, ‘controller’ => ‘v1/default’, ’extraPatterns’=>[ ‘GET index’=>‘index’, ], ], [‘class’ => ‘yii\rest\UrlRule’, ‘controller’ => ‘v1/user’, ’extraPatterns’=>[ ‘GET index’=>‘index’, ], ], ],],试着访问下http://localhost/v1/users/indexok,以上就是 Yii2.0 版本管理的实现方式格式化响应修改 api/config/main.php 在components 数组中添加 response’response’ => [ ‘class’ => ‘yii\web\Response’, ‘on beforeSend’ => function ($event) { $response = $event->sender; $response->data = [ ‘success’ => $response->isSuccessful, ‘code’ => $response->getStatusCode(), ‘message’ => $response->statusText, ‘data’ => $response->data, ]; $response->statusCode = 200; },],至此关于 Yii2.0 RESTFul API 我一共完成了 3 篇文章,分别为:Yii2.0 RESTful API 基础配置教程Yii2.0 RESTful API 认证教程Yii2.0 RESTful API 之版本控制写得实在不怎么样,您如果看了有收获,不妨留言给个评论,或者您觉得写得有问题,或者不明白,也可以留言,我们可以一块探讨研究。 ...

January 9, 2019 · 2 min · jiezi

Yii2.0 RESTful API 之速率限制

Yii2.0 RESTful API 之速率限制什么是速率限制?权威指南翻译过来为限流,为防止滥用,你应该考虑对您的 API 限流。 例如,您可以限制每个用户 10 分钟内最多调用 API 100 次。 如果在规定的时间内接收了一个用户大量的请求,将返回响应状态代码 429 (这意味着过多的请求)。要启用速率限制,首先需要实现认证类,而关于认证的章节我在 Yii2.0 RESTful API 认证教程 进行了详细的阐述,本篇就不过多介绍,再次基础上进行操作启用速率限制翻阅权威指南,我们可以看到要启用速率限制首先 认证类 需要继承 yiifiltersRateLimitInterface生成两个关键字段php yii migrate/create add_allowance_and_allowance_updated_at_to_user修改 刚才的迁移文件/** * {@inheritdoc} /public function safeUp(){ $this->addColumn(‘user’, ‘allowance’, $this->integer()); $this->addColumn(‘user’, ‘allowance_updated_at’, $this->integer());}/* * {@inheritdoc} */public function safeDown(){ $this->dropColumn(‘user’, ‘allowance’); $this->dropColumn(‘user’, ‘allowance_updated_at’);}执行迁移php yii migrate编写认证类,并继承 RateLimitInterfacenamespace api\models;use Yii;use yii\base\NotSupportedException;use yii\behaviors\TimestampBehavior;use yii\db\ActiveRecord;use yii\filters\RateLimitInterface;use yii\web\IdentityInterface;class User extends ActiveRecord implements IdentityInterface,RateLimitInterface{ . . .}实现 RateLimitInterface 所需要的方法public function getRateLimit($request, $action){ return [1, 1]; // $rateLimit requests per second}public function loadAllowance($request, $action){ return [$this->allowance, $this->allowance_updated_at];}public function saveAllowance($request, $action, $allowance, $timestamp){ $this->allowance = $allowance; $this->allowance_updated_at = $timestamp; $this->save();}控制器中实现调用use yii\filters\auth\CompositeAuth;use yii\filters\auth\HttpBearerAuth;use yii\filters\auth\QueryParamAuth;use yii\filters\RateLimiter;public function behaviors(){ $behaviors = parent::behaviors(); $behaviors[‘rateLimiter’] = [ ‘class’ => RateLimiter::className(), ’enableRateLimitHeaders’ => true, ]; $behaviors[‘authenticator’] = [ ‘class’ => CompositeAuth::className(), ‘authMethods’ => [ //Http::className(), HttpBearerAuth::className(), QueryParamAuth::className(), ], ]; //$behaviors[‘rateLimiter’][’enableRateLimitHeaders’] = true; return $behaviors;}ok,请求下你的 action,多次请求如果出现 429,那么表示速率限制启用成功以上就是关于 Yii2.0 速率限制的使用,速率限制需要和认证配合着使用,关于认证的,查阅Yii2.0 RESTful API 认证教程 ,这篇文章,推荐您,先看完认证,先做完认证的功能,然后在启用速率限制 关于 Yii2.0 RESTFul API到此我觉得就结束了,核心功能就是这些,剩下的就是具体的实战了,多练、多敲,一共四篇文章,分别为:Yii2.0 RESTful API 基础配置教程Yii2.0 RESTful API 认证教程Yii2.0 RESTful API 之版本控制Yii2.0 RESTful API 之速率限制 ...

January 9, 2019 · 1 min · jiezi

在yii2应用中,使用imagine库生成分享图实战。

这个需求现在特别常见,比如生成小程序分享图、生成朋友圈分享图等等,一般是文字 + 二维码 + 背景模板。今天我们使用imagine来完成这件事情,并作用于网站的面试题模块。我规划的分享图布局如下在这里面题目标题、日期和二维码是需要替换的,其他部分均可以做到背景图中。准备阶段为了让这件事情能实现,我们需要准备一些东西imagine图片库二维码生成库一个好看的字体一张海报(自行用PS处理)imagineimagine 支持三种底层的图像处理库(GD、Imagick和Gmagick),GD是最老的图片库,自然处理能力也不如另外两种,本次我使用Imagick作为底层支持,关于PHP如何安装Imagick扩展可参考 https://www.cnblogs.com/aini5…我们知道imagine的安装可以使用composer,我们首先安装它composer require imagine/imagine安装完以后你可以在yii2的 vendor/imagine/imagine 内找到它,如果没有请检查环境的composer环境(尽量不要使用镜像,否则可能出现无法获取最新版本问题)。因为imagine需要的PHP环境是5.3+,因此只要你的yii2可以运行,imagine一般都是没问题的。二维码在这张分享图上我计划放一个二维码,它含有的是此次面试题的URL,这样分享到朋友圈或群的时候,大家通过长按二维码就能访问到,为了每个图片只反映一个主题,关于面试题的订阅等需求均放到目标页面,分享图只做一个事情。在yii2中生成二维码有很成熟的库 —— qrcode-library ,使用它可以生成不同尺寸、内容及样式的二维码,强烈推荐。qrcode-library的安装也非常简单,依然是composer。composer require 2amigos/qrcode-library同样安装后我们应该在 vendor/2amigos/qrcode-library 文件夹内找到它。找一种字体为了让样式好看,我决定找一个字体,然后写到分享图上,网上字体下载的网站太多太多,我选择下载微软雅黑,再熟悉不管的字体了。写入标题通过上面都准备完成,我们接下来思考分享图的生成逻辑,其实就是贴水印,文字的水印、图片水印,就是这样。我做的图片背景模板尺寸是500750,看下图。当然这张图我们后面还要写话并填充内容,图中白色的矩形区域我计划防止标题内容,因为面试题标题长度一般都不长,我预留的3行的高度足够用了。现在假设标题为 【请使用PHP循环出本周一到本周日】,我们需要打开背景图然后做手脚,开始实际编码。use Imagine\Imagick\Imagine;public function actionShare($id){ $imagine = new Imagine(); $image = $imagine->open(Yii::getAlias("@webroot")."/images/task-bg.jpg"); //VarDumper::dump($image,10,true);}通过dump可以看到正确打开了。imagine和image对象都正常输出了。接下来的主要工作就是写入标题开始第一次写入写入标题等价于为一个图片添加文本水印,这里面涉及的问题如下文本内容是什么用什么字体字号大小字体颜色从哪个坐标开始注:imagine和笛卡尔坐标系不同,详情见 文档先说说字体库,虽然微软雅黑是win系列的标配,但是服务器上不一定有,我使用的是centos系统,需要下载和指定,在上一部分我们已经下载了字体,现在我将其放到yii2应用的fonts文件夹下,这样可以通过如下代码访问它。Yii::getAlias(’@app’)."/fonts/yahei.ttf";除非你的页面需要此字体,否则不推荐将字体放到web目录下,这样可以有效防止其他人通过浏览器访问。接下来我们初步实现一下,接着上面的代码。use Imagine\Imagick\Imagine;use Imagine\Image\Palette\RGB;use Imagine\Image\Point;public function actionShare($id){ $imagine = new Imagine(); $image = $imagine->open(Yii::getAlias("@webroot")."/images/task-bg.jpg"); $palette = new RGB(); $color = $palette->color(“000000”); $point = new Point(0,0); $font = $imagine->font(Yii::getAlias(’@app’)."/fonts/yahei.ttf",12,$color); $image->draw()->text(“请使用PHP循环出本周一到本周日”,$font,$point); $image->show(‘jpg’); }在讲解上面代码之前,我们先看看结果。得到了我们要的结果,接下来说说逻辑。在 imagine 中如果为一个图片增加文本水印,它属于绘制功能,要调用draw的text方法,我们先看看这个方法的声明。text(string $string, AbstractFont $font, PointInterface $position, int $angle = 0, int $width = null)这就是你刚刚代码中的 $image->draw()->text(); 部分。它有几个重要的参数,比如文字内容、字体、起始坐标,内容弧度等。因此我们做的一起就是为这个函数准备参数值,内容、字体、坐标。use Imagine\Image\Palette\RGB;use Imagine\Image\Point;这些类都是为了最终调用 text 方法做准备的。比如我们听过RGB类定义颜色类$palette = new RGB();$color = $palette->color(“000000”);比如我们需要通过font方法得到字体类对象$font = $imagine->font(Yii::getAlias(’@app’)."/fonts/yahei.ttf",12,$color);比如我们通过Point来定义坐标对象$point = new Point(0,0);好了,虽然到现在我们实现了标题的写入,但是位置和大小都不理想,接下来优化。字体大小坐标位置之前是12,现在我们设置为24,坐标从[0,0]改为[44,230]$point = new Point(44,230);$font = $imagine->font(Yii::getAlias(’@app’)."/fonts/yahei.ttf",24,$color);看下效果很高兴,现在为止大小和位置都调整的不错,但是新的问题来了,我的标题内容超过了一行,其他部分没有换行而是被切掉了,怎么办???内容超过边界问题的处理怎么处理这个问题?在imagine 1.0.0+已经提供了一个自动换行的函数,你只需要升级版本即可,用法非常简单,如下。$font = $imagine->font(Yii::getAlias(’@app’)."/fonts/yahei.ttf",24,$color);$text = $font->wrapText(“请使用PHP循环出本周一到本周日”,400);wrapText方法的第二个参数代表文本最大长度,超过了即为换行,然后将wrapText作用后的$text再传给 image->draw()->text(); 即可。但是,在此文章并不适用,wrapText对中文的支持并不好,因此我们需要另想办法,虽然如此,我们还是有必要看看wrapText的实现原理。// vendor/imagine/imagine/src/Image/FontInterface.php:59public function wrapText($string, $maxWidth, $angle = 0){ $words = explode(’ ‘, $string); foreach ($words as $word) { if ($currentLine === null) { $currentLine = $word; } else { $testLine = $currentLine . ’ ’ . $word; $testbox = $this->box($testLine, $angle); if ($testbox->getWidth() <= $maxWidth) { $currentLine = $testLine; } else { $lines[] = $currentLine; $currentLine = $word; } } } ….. return implode("\n", $lines); }你看到了wrapText的实现是通过空格来实现单词的划分,因此这个算法只适用于英文,最后通过计算宽度,通过换行符实现最后效果。那对中文怎么办?没关系,从官方wrapText的方法我们可以改造出子的方法,只不过每个词的话不不再是空格,我进行了如下改造。$lines = array();$maxWidth = 420;$currentLine = null;$text = “请使用PHP循环出本周一到本周日”;for($i = 0;$i < mb_strlen($text,‘UTF-8’);$i++){ $word = mb_substr($text,$i,1,‘UTF-8’); if ($currentLine === null) { $currentLine = $word; } else { $testLine = $currentLine.$word; $testbox = $font->box($testLine, 0); if ($testbox->getWidth() <= $maxWidth) { $currentLine = $testLine; } else { $lines[] = $currentLine; $currentLine = $word; } }}if ($currentLine !== null) { $lines[] = $currentLine;}$text = implode("\n", $lines);思路就是首先获得整个字符串的长度N,然后从0到N-1遍历,得到每个字(中英文),然后将这些字放到一个测试行testLine中,并通过$font->box方法得到测试行的宽度,超过了我们最大宽度则重新设置测试行,一次又一次,最后lines数组里就是每一行,且他们都没有超过边界maxWidth。最后使用换行符再将lines数组拼凑回字符串,ok,看效果。更好的行间距刚刚我们解决了溢出问题,但是现在每行的间距太小了,这样大大影响了体验,这小节我们将做出一个合适的行间距,但是你知道当我们将文本划到图片的时候,是无法设置行边距的。这一切要从坐标开始研究。因此我计划取消上面将lines数组重新拼凑成字符串的代码,保留每一行,然后指定每一行的具体Y坐标。$height = $font->box($model->title)->getHeight();// 获得字的高度。$model->title 就是输出的内容$lines = array();$currentLine = null;for($i = 0;$i < mb_strlen($model->title,‘UTF-8’);$i++){ $word = mb_substr($model->title,$i,1,‘UTF-8’); if ($currentLine === null) { $currentLine = $word; } else { $testLine = $currentLine.$word; $testbox = $font->box($testLine, 0); if ($testbox->getWidth() <= 420) { $currentLine = $testLine; } else { $lines[] = $currentLine; $currentLine = $word; } }}if ($currentLine !== null) { $lines[] = $currentLine;}// 获得lines数组foreach($lines as $key=>$value){ $point = new Point(40,($key == 0 ? 230 : (230 + ($height + 10)$key))); $image->draw()->text($value,$font,$point,0);}$image->show(‘jpg’);行间距我留了10px,再看看效果。写入时间(坐标自动计算)通过上面的方法实现时间的写入并不复杂,不过我决定换一个思路,时间的写入我们并不打算直接指定坐标,而是通过计算而来,这个方法将非常适合于让一些文字居中的情形。写入的内容很简单 2018-09-28,就是一个日期。继续扩展上面的代码,主要是计算X坐标。Y坐标400.use Imagine\Image\Point\Center;$dateText = date(‘Y-m-d’,$model->publish_date);$dateFont = $imagine->font(Yii::getAlias(’@app’)."/fonts/yahei.ttf",12,$color);$dateBox = $dateFont->box($dateText);$dateCenterPosition = new Center($dateBox);$image->draw()->text($dateText,$dateFont,new Point(($image->getSize()->getWidth()/2 - $dateCenterPosition->getX()),420));之所以这样写是为了让大家熟悉Center类,我们可以将一个字体的盒子放到Center中,然后获取中间点坐标。写入二维码离成功越来越近了,接下来我们写入二维码,这其实是两步。生成二维码写入二维码到分享图写入二维码使用 qrcode-library 生成二维码非常简单,我们还是先贴代码use Da\QrCode\QrCode;$qrCode = (new QrCode(Yii::$app->urlManager->createAbsoluteUrl([’/task/detail’,‘id’=>$id])))->setSize(180)->setMargin(10);$path = Yii::getAlias(’@webroot’).’/uploads/tmp/’.Yii::$app->security->generateRandomString().’.jpg’;$qrCode->writeFile($path);在合理其实有点瑕疵,使用QrCode生成的二维码比较简单,但是只支持生成Uri、服务器文件及流,但是无法返回资源,因此我们必须将其保存下来后在使用 imagine 来读取,否则就可以直接使用 imagine 的read方法了。总之上面的代码通过为QrCode对象传入URL地址来生成二维码,同时使用writeFile将其存到服务器。写入二维码到分享图将二维码写入分享图需要使用imagine库的paste方法,这也是我们做图片水印的方法。$water = $imagine->open($path);$image->paste($water,new Point(150,520));通过 open 方法读取一个文件返回image对象,通过paste将其贴到$image图像上。最后我们看到了要的效果小结分享图的细节太多太多,这一切还需要优化,本篇希望对你能起到抛砖引玉的作用,如果你有好的库也欢迎留言。阿北哥ya https://nai8.me ...

September 29, 2018 · 2 min · jiezi

同一个系统内使用curl模拟post请求如何不被csrf拦截方案

关于csrf的原理和在yii2内的运行建议先看之前发的一篇文 https://nai8.me/article/383本篇我们要做一个事情,就是在同一个yii2应用中,某个action使用curl模拟表单提交到另一个action,但是你我都知道在yii2内如果发送post请求,需要经过csrf验证,那么使用curl模拟的时候如何通过csrf那?我们来实现。模拟POST在这里我使用yii2官方的http客户端扩展,模拟一个post请求很简单,如下代码。$client = new Client([ ’transport’ => ‘yii\httpclient\CurlTransport’,]);$response = $client->createRequest() ->setMethod(‘POST’) ->setUrl(‘https://xxx.com/demo/csrf-post.html') ->setData([ ‘username’=>‘abei2017’, ‘_csrf’=>Yii::$app->request->getCsrfToken() ])->send();echo $response->getContent();以上使我们最先想到的,提交一组数据到某个url,但是这样并不能得到预想的结果。原因之所以被yii2的csrf拦截,主要是因为使用curl模拟POST请求的时候没有奖cookie中的 _csrf 也一起发送给服务器端。这个cookie值将用于csrf的具体验证工作,那就简单了。$client = new Client([ ’transport’ => ‘yii\httpclient\CurlTransport’,]);$response = $client->createRequest() ->setMethod(‘POST’) ->setUrl(‘https://xxx.com/demo/csrf-post.html') ->setCookies([ [’name’ => ‘_csrf’, ‘value’ => urlencode($_COOKIE[’_csrf’])], ]) ->setData([ ‘username’=>‘abei2017’, ‘_csrf’=>Yii::$app->request->getCsrfToken() ])->send();echo $response->getContent();ok,之所以没有使用yii2内置的cookie功能,主要是因为yii2在设置cookie的时候默认是进行加密的,而获取时候会自动解密。如果使用yii2内置cookie组件获取,则获取是解密后的,再用来模拟就会出问题,我们需要使用curl发送一个经过加密的cookie。当然如果你也可以配置yii2文件将cookie的加密解密去掉。大功告成。

September 26, 2018 · 1 min · jiezi

在yii2中,让你action参数支持POST数据的小方法

我们先来看一段代码class RaController extends Controller { public $enableCsrfValidation = false; public function actionSay($username = ‘’,$city = ‘’){ echo “{$username} 来自 {$city}”; }}这里actionSay对应的url为index.php?r=ra/say,而 $username 和 $city 值的获取来自于url的参数,比如index.php?r=ra/say&username=abei2017&city=洛阳总结 在yii2中,action参数都是来自于GET。但是有的时候你可能需要让action的参数来自于POST请求,怎么办?重载runAction即可,yii2为控制器提供了runAction方法,它负责生成一个具体的Action对象并传递参数,我们可以通过复写它来实现,你可以看下yii2的生命周期来对其进行更好的了解。那就开始干吧~,对上面的代码复写runActionclass RaController extends Controller { public $enableCsrfValidation = false; public function runAction($id, $params = []){ $params = ArrayHelper::merge(Yii::$app->request->post(),$params); return parent::runAction($id, $params); } public function actionSay($username = ‘’,$city = ‘’){ echo “{$username} 来自 {$city}”; }}复写了runAction后,它将作用于此控制器的所有action,当然你也可以通过runAction的$id来作用于某个action。比如public function runAction($id, $params = []){ if($id == ‘say’){ $params = ArrayHelper::merge(Yii::$app->request->post(),$params); } return parent::runAction($id, $params);}现在去试试吧,对say动作提交POST数据username和city,成功接收。 ...

September 26, 2018 · 1 min · jiezi