优化插件项

This commit is contained in:
taoser 2022-11-20 21:56:09 +08:00
parent e81de0d307
commit 4ae7a3ea51
74 changed files with 3573 additions and 1262 deletions

View File

@ -12,6 +12,7 @@ use taoler\com\Api;
use app\common\lib\Zip;
use think\response\Json;
use app\admin\model\AuthRule;
use Symfony\Component\VarExporter\VarExporter;
class Addons extends AdminController
{
@ -27,7 +28,7 @@ class Addons extends AdminController
* 插件列表
* @return Json
*/
public function addonsList() :Json
public function addonsList()
{
$type = input('type');
@ -177,13 +178,13 @@ class Addons extends AdminController
}
//是否安装?
$addInstalledVersion = get_addons_info($data['name']);
// if(!empty($addInstalledVersion)){
// $verRes = version_compare($data['version'],$addInstalledVersion['version'],'>');
// if(!$verRes){
// return json(['code'=>-1,'msg'=>'不能降级,请选择正确版本']);
// }
// //$tpl_ver_res = version_compare($addInstalledVersion['template_version'], config('taoler.template_version'),'<');
// }
if(!empty($addInstalledVersion)){
$verRes = version_compare($data['version'],$addInstalledVersion['version'],'>');
if(!$verRes){
return json(['code'=>-1,'msg'=>'不能降级,请选择正确版本']);
}
//$tpl_ver_res = version_compare($addInstalledVersion['template_version'], config('taoler.template_version'),'<');
}
$file_url = $addons->addons_src;
//判断远程文件是否可用存在
@ -239,25 +240,18 @@ class Addons extends AdminController
SqlFile::dbExecute($sqlInstallFile);
}
//安装菜单
$menuFile = root_path().'addons/'.$data['name'].'/menu.php';
if(file_exists($menuFile)) {
include_once $menuFile;
$menu = Config::get('menu');
if(!empty($menu)){
if(isset($menu['is_nav']) && $menu['is_nav']==1){
$pid = 0;
}else{
$pid = AuthRule::where('name','addons')->value('id');
}
$menu_arr[] = $menu['menu'];
$this->addAddonMenu($menu_arr, (int)$pid,1);
$menu = get_addons_menu($data['name']);
if(!empty($menu)){
if(isset($menu['is_nav']) && $menu['is_nav']==1){
$pid = 0;
}else{
$pid = AuthRule::where('name','addons')->value('id');
}
$menu_arr[] = $menu['menu'];
$this->addAddonMenu($menu_arr, (int)$pid,1);
}
Files::delDirAndFile('../runtime/addons/');
Files::delDirAndFile('../runtime/addons/'.$data['name'] . DS);
return json(['code'=>0,'msg'=>'插件安装成功!']);
@ -265,21 +259,16 @@ class Addons extends AdminController
/**
* 卸载插件
*/
public function delete()
public function uninstall()
{
$name = input('name');
$addonsPath = '../addons/'.$name;
$staticPath = 'addons/'.$name;
//卸载菜单
$menuFile = root_path().'addons/'.$name.'/menu.php';
if(file_exists($menuFile)) {
include_once $menuFile;
$menu = Config::get('menu');
if(!empty($menu)){
$menu_arr[] = $menu['menu'];
$this->delAddonMenu($menu_arr);
}
$menu = get_addons_menu($name);
if(!empty($menu)){
$menu_arr[] = $menu['menu'];
// halt( $menu_arr);
$this->delAddonMenu($menu_arr);
}
//卸载插件数据库
@ -288,16 +277,30 @@ class Addons extends AdminController
SqlFile::dbExecute($sqlUninstallFile);
}
if (is_dir($staticPath)) {
Files::delDir($staticPath);
// 插件addons下目录
$addonsDir = root_path() . 'addons' . DS . $name . DS;
// 插件管理后台目录
$admin_controller = app_path() . 'controller' . DS . $name . DS;
$admin_model = app_path() . 'model' . DS . $name . DS;
$admin_view = app_path() . 'view' . DS . $name . DS;
$admin_validate = app_path() . 'validate' . DS . $name . DS;
// 插件静态资源目录
$addon_public = public_path() . 'addons' . DS . $name . DS;
try {
if(file_exists($addonsDir)) Files::delDir($addonsDir);
if(file_exists($admin_controller)) Files::delDir($admin_controller);
if(file_exists($admin_model)) Files::delDir($admin_model);
if(file_exists($admin_view)) Files::delDir($admin_view);
if(file_exists($admin_validate)) Files::delDir($admin_validate);
if(file_exists($addon_public)) Files::delDir($addon_public);
} catch (\Exception $e) {
return json(['code' => -1, 'msg' => $e->getMessage()]);
}
$res = Files::delDir($addonsPath);
if($res){
return json(['code'=>0,'msg'=>'卸载成功']);
} else {
return json(['code'=>-1,'msg'=>'卸载失败']);
}
return json(['code'=>0,'msg'=>'卸载成功']);
return json(['code' => 0, 'msg' => '插件卸载成功']);
}
//启用插件
@ -329,7 +332,7 @@ class Addons extends AdminController
$config = get_addons_config($name);
if(empty($config)) return json(['code'=>-1,'msg'=>'无配置项!']);
if(Request::isAjax()){
$params = Request::param('params/a');
$params = Request::param('params/a',[],'trim');
if ($params) {
foreach ($config as $k => &$v) {
if (isset($params[$k])) {
@ -359,7 +362,10 @@ class Addons extends AdminController
//模板引擎初始化
$view = ['formData'=>$config,'title'=>'title'];
View::assign($view);
return View::fetch();
$configFile = root_path() . 'addons' . DS . $name . DS . 'config.html';
$viewFile = is_file($configFile) ? $configFile : '';
return View::fetch($viewFile);
}
@ -396,7 +402,7 @@ class Addons extends AdminController
try {
$v['name'] = trim($v['name'],'/');
$menu_rule = AuthRule::withTrashed()->where('name',$v['name'])->find();
if($menu_rule){
if(!is_null($menu_rule)){
$menu_rule->delete(true);
if ($hasChild) {
$this->delAddonMenu($v['sublist']);

View File

@ -23,6 +23,7 @@ use think\facade\Session;
use think\facade\Cookie;
use taoser\SetArr;
use app\common\lib\SetArr as SetArrConf;
use think\response\Json;
class Set extends AdminController
{
@ -35,7 +36,6 @@ class Set extends AdminController
//网站设置显示
public function index()
{
$mailserver = MailServer::find(1);
$template = Files::getDirName('../view');
$email = Db::name('admin')->where('id',1)->value('email');
@ -44,7 +44,7 @@ class Set extends AdminController
$admin_map = array_search('admin',config('app.app_map'));
$index_map = $index_map ? $index_map : '';
$admin_map = $admin_map ? $admin_map : '';
View::assign(['sysInfo'=>$this->sysInfo,'mailserver'=>$mailserver,'template'=>$template,'email'=>$email,'index_map'=>$index_map,'admin_map'=>$admin_map]);
View::assign(['sysInfo'=>$this->sysInfo,'template'=>$template,'email'=>$email,'index_map'=>$index_map,'admin_map'=>$admin_map]);
// 域名绑定
if(!empty(config('app.domain_bind'))){
@ -98,69 +98,6 @@ class Set extends AdminController
return View::fetch('set/system/server');
}
/**邮箱设置
* parem $id
*/
public function email()
{
$mailserver = MailServer::find(1);
//邮箱配置
if(Request::isAjax()){
$data = Request::only(['host','port','mail','nickname','password']);
$res = $mailserver->save($data);
if($res){
return json(['code'=>0,'msg'=>'更新成功']);
} else {
return json(['code'=>-1,'msg'=>'更新失败']);
}
}
}
/**
* 发验证码
*
* @return void
*/
public function sendMailCode()
{
if(Request::isPost()){
$email = Request::param('email');
$code = mt_rand('1111','9999');
Cache::set('test_code',$code,600);
$result = mailto($email,'邮箱服务配置','Hi亲爱的管理员:</br>您正在配置您站点的邮箱服务配置成功后可以收到来自网站的发帖评论等即时信息。请在10分钟内把激活码填入激活码框内您的激活码为:'.$code);
if($result){
$res = ['code'=>0,'msg'=>'请去邮箱获取测试码'];
}else{
$res = ['code'=>-1,'msg'=>'邮箱配置错误或无服务能力,请排查!'];
}
}
return json($res);
}
/**
* 邮件激活
*
* @return void
*/
public function activeMailServer()
{
if(Request::isPost()){
$eCode = Request::param('code');
$sCode = Cache::get('test_code');
if($eCode == $sCode){
$result = Db::name('mail_server')->update(['id'=>1,'active'=>1]);
if($result){
$res = ['code'=>0,'msg'=>'邮箱服务激活成功'];
} else {
$res = ['code'=>-1,'msg'=>'激活服务出错!'];
}
}else{
$res = ['code'=>-1,'msg'=>'激活码错误!!!'];
}
}
return json($res);
}
/**基础服务配置
* parem $id
*/
@ -320,11 +257,10 @@ class Set extends AdminController
}
/**
* URL美化设置访问链接
*
* @return void
*/
/**
* URL美化设置访问链接
* @return Json
*/
public function setUrl()
{
$data = Request::only(['article_as','cate_as']);

View File

@ -2,45 +2,53 @@
{block name="body"}
<div class="layui-form" lay-filter="layuiadmin-form-addons" id="layuiadmin-form-addons" style="padding: 20px 30px 0 0;">
{foreach name="formData" item="vo" key="k"}
{php}$name = "params[".$k."]";{/php}
{switch name="$vo.type"}
{case value="text"}
{:form_input($name,'text',['label'=>$vo.title,'tip'=>$vo.tip],$vo.value)}
{/case}
{case value="textarea"}
{:form_textarea($name,['label'=>$vo.title,'tip'=>$vo.tip],$vo.value)}
{/case}
{case value="password"}
{:form_input($name,'password',['label'=>$vo.title,'tip'=>$vo.tip],$vo.value)}
{/case}
{case value="radio"}
{:form_radio($name,$vo.content,['label'=>$vo.title,'tip'=>$vo.tip],$vo.value)}
{/case}
{case value="select"}
{:form_select($name,$vo.content,['label'=>$vo.title,'verify'=>$vo.rule,'tip'=>$vo.tip,'search'=>1] ,[],$vo.value)}
{/case}
{case value="image"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tip'=>$vo.tip,'verify'=>$vo.rule,'type'=>'radio','num'=>'1','mime'=>'image'])}
{/case}
{case value="images"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tip'=>$vo.tip,'verify'=>$vo.rule,'type'=>'checkbox','num'=>$vo.num,'mime'=>'image'])}
{/case}
{case value="file"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tip'=>$vo.tip,'verify'=>$vo.rule,'type'=>'radio','num'=>$vo.num,'mime'=>'*'])}
{/case}
{case value="files"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tip'=>$vo.tip,'verify'=>$vo.rule,'type'=>'checkbox','num'=>$vo.num,'mime'=>'*'])}
{/case}
{case value="editor"}
{:form_editor($name,$name,2,['label'=>$vo.title,'tip'=>$vo.tip,'verify'=>$vo.rule])}
{/case}
{case value="array"}
{:form_arrays($name,['label'=>$vo.title,'tip'=>$vo.tip,'verify'=>$vo.rule],$vo.value?$vo.value:$vo.content)}
{/case}
{/switch}
{/foreach}
{foreach name="formData" item="vo" key="k"}
{php}$name = "params[".$k."]";{/php}
{switch name="$vo.type"}
{case value="text"}
{:form_input($name,'text',['label'=>$vo.title,'verify'=>$vo.rule,'tips'=>$vo.tips],$vo.value)}
{/case}
{case value="textarea"}
{:form_textarea($name,['label'=>$vo.title,'tips'=>$vo.tips],$vo.value)}
{/case}
{case value="password"}
{:form_input($name,'password',['label'=>$vo.title,'tips'=>$vo.tips],$vo.value)}
{/case}
{case value="radio"}
{:form_radio($name,$vo.content,['label'=>$vo.title,'tips'=>$vo.tips],$vo.value)}
{/case}
{case value="checkbox"}
{:form_checkbox($name, $vo.content,['label'=>$vo.title, 'verify' =>$vo.rule,'tips'=>$vo.tips,], $vo['value'])};
{/case}
{case value="switch"}
{:form_switch($name, $vo.content,['label'=>$vo.title, 'verify' =>$vo.rule,'tips'=>$vo.tips,], $vo['value'])};
{/case}
{case value="select"}
{:form_select($name,$vo.content,['label'=>$vo.title,'verify'=>$vo.rule,'tips'=>$vo.tips,'search'=>1] ,[],$vo.value)}
{/case}
{case value="selects"}
{:form_select($name,$vo.content,['label'=>$vo.title,'multipsle'=>1.,'verify'=>$vo.rule,'tips'=>$vo.tips,'search'=>1] ,[],$vo.value)}
{/case}
{case value="image"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tips'=>$vo.tips,'verify'=>$vo.rule,'type'=>'radio','num'=>'1','mime'=>'images'])}
{/case}
{case value="images"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tips'=>$vo.tips,'verify'=>$vo.rule,'type'=>'checkbox','num'=>$vo.num,'mime'=>'images'])}
{/case}
{case value="file"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tips'=>$vo.tips,'verify'=>$vo.rule,'type'=>'radio','num'=>$vo.num,'mime'=>'*'])}
{/case}
{case value="files"}
{:form_upload($name,$vo.value,['label'=>$vo.title,'tips'=>$vo.tips,'verify'=>$vo.rule,'type'=>'checkbox','num'=>$vo.num,'mime'=>'*'])}
{/case}
{case value="editor"}
{:form_editor($name,2,['label'=>$vo.title,'tips'=>$vo.tips,'verify'=>$vo.rule])}
{/case}
{case value="array"}
{:form_arrays($name,$vo.value?$vo.value:$vo.content,['label'=>$vo.title,'tips'=>$vo.tips,'verify'=>$vo.rule])}
{/case}
{/switch}
{/foreach}
<div class="layui-form-item layui-hide">
<input type="hidden" name="name" value="{:input('name')}">
<input type="button" lay-submit lay-filter="LAY-addons-config-submit" id="LAY-addons-config-submit" value="确认">
@ -48,4 +56,38 @@
</div>
{/block}
{block name="js"}
<script>
layui.config({
base: '/static/admin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'upload'], function(){
var $ = layui.$,upload = layui.upload,form = layui.form;
//上传头像
upload.render({
elem: '.upload-select'
,url: 'uploadImg'
,data: {type:'image'}
,accept: 'images'
,method: 'get'
,acceptMime: 'image/*'
,done: function(res){
$(this.item).prev("div").children("input").val(res.src);
if(res.code == 0){
layer.msg(res.msg,{
icon:6,
tiye:2000
});
} else {
layer.open({
title:"上传失败",
content:res.msg,
icon:5,
anim:6
});
}
}
});
})
</script>
{/block}

View File

@ -6,9 +6,7 @@
<div class="layui-card-body">
<form class="layui-form layui-card-header layuiadmin-card-header-auto">
<div class="layui-form-item">
<div class="layui-inline">
插件分类
</div>
<div class="layui-inline">插件分类</div>
<div class="layui-inline">
<select name="id" lay-filter="LAY-user-adminrole-type">
<option value="">全部插件</option>
@ -28,6 +26,7 @@
</div>
<div class="layui-btn-group" style="padding-bottom: 10px;">
<button class="layui-btn layui-btn-sm layuiadmin-btn-admin" data-type="add">离线安装</button>
<button class="layui-btn layui-btn-sm layuiadmin-btn-admin" data-type="user-info">用户信息</button>
</div>
</script>
@ -47,7 +46,6 @@
<option value="{{ item }}">{{ item }}</option>
{{# }); }}
</select>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="config"><i class="layui-icon layui-icon-set"></i>设置</a>
</script>
</form>
@ -61,13 +59,12 @@
<script>
var addonsIndex = "{:url('Addons/index')}",
addonsList = "{:url('Addons/addonsList')}",
addonsDelete = "{:url('Addons/delete')}",
addonsDelete = "{:url('Addons/uninstall')}",
addonsEdit = "{:url('Addons/edit')}";
var addonsStart = "{:url('Addons/start')}";
var addonsShut = "{:url('Addons/shutDown')}";
var addonsInstall = "{:url('Addons/install')}";
var addonsConfig = "{:url('Addons/config')}";
layui.config({
base: '/static/admin/' //静态资源所在路径
@ -82,7 +79,6 @@
form.render('select'); // 渲染所在容器内的 select 元素
//监听版本选择
form.on('select(versSelect)', function(obj){
console.log(111)
layer.tips(this.value + ' ' + this.name + ''+ obj.elem.checked, obj.othis);
});
@ -112,10 +108,7 @@
daType:"json",
success:function (data){
if (data.code == 0) {
layer.msg(data.msg,{
icon:6,
time:2000
});
layer.msg(data.msg,{icon:6,time:2000});
} else {
layer.open({
title:'添加失败',
@ -125,17 +118,16 @@
});
}
}
});
});
table.reload('addons-list'); //数据刷新
layer.close(index); //关闭弹层
});
submit.trigger('click');
});
submit.trigger('click');
}
});
}
}
$('.layui-btn.layuiadmin-btn-admin').on('click', function(){
var type = $(this).data('type');
active[type] ? active[type].call(this) : '';

View File

@ -69,7 +69,10 @@
</dl>
</dd>
{else /}
<dd><a lay-href="{:url($vo2.name)}">{$vo2.title}</a></dd>
<dd><a lay-href="{:url($vo2.name)}">
<i class="layui-icon {$vo2.icon}"></i>
<cite>{$vo2.title}</cite>
</a></dd>
{/if}
{/volist}
</dl>

View File

@ -16,47 +16,6 @@
</ul>
<div class="layui-tab-content">
{:hook('signadminhook')}
<!--div class="layui-tab-item layui-show">
<div class="layui-tab-content" style="padding: 20px 0;">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">连续签到</label>
<div class="layui-input-inline">
<select name="days">
<option value="1">1天</option>
<option value="2">2天</option>
<option value="3">3天</option>
<option value="5">5天</option>
<option value="7">7天</option>
<option value="10">10天</option>
<option value="20">20天</option>
<option value="100">100天</option>
<option value="365">365天</option>
</select>
</div>
<div class="layui-input-inline">
<input type="tel" name="score" lay-verify="required" placeholder="获得积分" autocomplete="off" class="layui-input">
</div>
<div class="layui-input-inline">
{if condition="checkRuleButton('Sign/add')"}
<input type="submit" class="layui-btn" lay-submit lay-filter="sign-rule-submit" id="sign-rule-submit" value="立即提交">
{else /}<input type="submit" class="layui-btn layui-btn-disabled" value="立即提交">{/if}
</div>
</div>
</div>
<div class="layui-form-item">
<table id="sign-rule" lay-filter="sign-rule"></table>
<script type="text/html" id="sign-rule-button">
{if condition="checkRuleButton('Sign/edit')"}
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a>
{else /}<a class="layui-btn layui-btn-normal layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-edit"></i>编辑</a>{/if}
{if condition="checkRuleButton('Sign/delete')"}
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
{else /}<a class="layui-btn layui-btn-danger layui-btn-xs layui-btn-disabled"><i class="layui-icon layui-icon-delete"></i>删除</a>{/if}
</script>
</div>
</div>
</div-->
<div class="layui-tab-item {if hook('signstatushook') == 0}layui-show{/if}">
<div class="layui-tab-content" style="padding: 20px 0;">
<div class="layui-form">
@ -110,9 +69,6 @@
{/block}
{block name="js"}
<script>
var signSignRule ="{:url('Sign/signRule')}";
var signDelete ="{:url('Sign/delete')}";
var signSignEdit ="{:url('Sign/signEdit')}";
var vipRule ="{:url('Vip/vipRule')}";
var vipDelete ="{:url('Vip/delete')}";
var vipEdit ="{:url('Vip/vipEdit')}";
@ -126,35 +82,6 @@
,table = layui.table
,form = layui.form;
//添加签到规则
form.on('submit(sign-rule-submit)',function(data){
var field = data.field;
$.ajax({
type:"post",
url: signAddAddons,
data:field,
daType:"json",
success:function (data){
if (data.code == 0) {
layer.msg(data.msg,{
icon:6,
time:2000
}, function(){
table.reload('sign-rule'); //数据刷新
});
} else {
layer.open({
title:'添加失败',
content:data.msg,
icon:5,
anim:6
});
}
}
});
return false;
});
//添加VIP规则
form.on('submit(vip-rule-submit)',function(data){
var field = data.field;

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,13 @@
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
use think\facade\Request;
use think\facade\Db;
use think\facade\Session;
use taoser\think\Auth;
define('DS', DIRECTORY_SEPARATOR);
// 应用公共文件
function mailto($to,$title,$content)
{
@ -17,6 +16,7 @@ function mailto($to,$title,$content)
try {
//Server settings
$mail->SMTPDebug = 0; // Enable verbose debug output
// $mail->SMTPDebug = SMTP::DEBUG_SERVER;
$mail->CharSet = 'utf-8'; //b
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = $mailserver['host']; // Specify main and backup SMTP servers
@ -24,6 +24,7 @@ try {
$mail->Username = $mailserver['mail']; // SMTP username
$mail->Password = $mailserver['password']; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
// $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
$mail->Port = $mailserver['port']; // TCP port to connect to
//Recipients
@ -306,3 +307,27 @@ function find_spider(){
return false;
}
if (!function_exists('__')) {
/**
* 获取语言变量值
* @param string $name 语言变量名
* @param array $vars 动态变量值
* @param string $lang 语言
* @return mixed
*/
function __($name, $vars = [], $lang = '')
{
if (is_numeric($name) || !$name) {
return $name;
}
if (!is_array($vars)) {
$vars = func_get_args();
array_shift($vars);
$lang = '';
}
return \think\facade\Lang::get($name, $vars, $lang);
}
}

View File

@ -223,7 +223,7 @@ class Article extends BaseController
}
$data = ['title'=>$title,'content'=>'评论通知','link'=>$link,'user_id'=>$sendId,'type'=>2]; //type=2为评论留言
Message::sendMsg($sendId,$receveId,$data);
if(Config::get('taoler.config.email_notice')) mailto($this->showUser(1)['email'],'评论审核通知','Hi亲爱的管理员:</br>用户'.$this->showUser($this->uid)['name'].'刚刚对 <b>'.$title.'</b> 发表了评论,请尽快处理。');
if(Config::get('taoler.config.email_notice')) hook('mailtohook',[$this->showUser(1)['email'],'评论审核通知','Hi亲爱的管理员:</br>用户'.$this->showUser($this->uid)['name'].'刚刚对 <b>'.$title.'</b> 发表了评论,请尽快处理。']);
$res = ['code'=>0, 'msg'=>$msg];
} else {
$res = ['code'=>-1, 'msg'=>'留言失败'];
@ -290,7 +290,7 @@ class Article extends BaseController
// 清除文章tag缓存
Cache::tag('tagArtDetail')->clear();
// 发提醒邮件
if(Config::get('taoler.config.email_notice')) mailto($this->showUser(1)['email'],'发帖审核通知','Hi亲爱的管理员:</br>用户'.$this->showUser($this->uid)['name'].'刚刚发表了 <b>'.$data['title'].'</b> 新的帖子,请尽快处理。');
if(Config::get('taoler.config.email_notice')) hook('mailtohook',[$this->showUser(1)['email'],'发帖审核通知','Hi亲爱的管理员:</br>用户'.$this->showUser($this->uid)['name'].'刚刚发表了 <b>'.$data['title'].'</b> 新的帖子,请尽快处理。']);
$link = $this->getRouteUrl((int)$aid, $cate_ename);
// 推送给百度收录接口

View File

@ -135,7 +135,7 @@ class Login extends BaseController
if ($result['code'] == 1) {
$res = ['code'=>0,'msg'=>$result['msg'],'url'=>(string) url('login/index')];
if(Config::get('taoler.config.email_notice')) mailto($this->showUser(1)['email'],'注册新用户通知','Hi亲爱的管理员:</br>新用户 <b>'.$data['name'].'</b> 刚刚注册了新的账号,请尽快处理。');
if(Config::get('taoler.config.email_notice')) hook('mailtohook',[$this->showUser(1)['email'],'注册新用户通知','Hi亲爱的管理员:</br>新用户 <b>'.$data['name'].'</b> 刚刚注册了新的账号,请尽快处理。']);
}else {
$res = ['code'=>-1,'msg'=>$result];
}
@ -164,7 +164,7 @@ class Login extends BaseController
Cache::set('code',$code,600);
Cache::set('userid',$user['id'],600);
$result = mailto($data['email'],'重置密码','Hi亲爱的'.$user['name'].':</br>您正在维护您的信息请在10分钟内验证您的验证码为:'.$code);
$result = hook('mailtohook',[$data['email'],'重置密码','Hi亲爱的'.$user['name'].':</br>您正在维护您的信息请在10分钟内验证您的验证码为:'.$code]);
if($result){
Cache::set('repass','postcode',60); //设置repass标志为1存入Cache
$res = ['code'=>0,'msg'=>'验证码已发送成功,请去邮箱查看!','url'=>(string) url('login/postcode')];
@ -247,7 +247,7 @@ class Login extends BaseController
$code = mt_rand('1111','9999');
Cache::set($email, $code, 600);
$result = mailto($email,'注册邮箱验证码','Hi亲爱的新用户:</br>您正在注册我们站点的新账户请在10分钟内验证您的验证码为:'.$code);
$result = hook('mailtohook',[$email,'注册邮箱验证码','Hi亲爱的新用户:</br>您正在注册我们站点的新账户请在10分钟内验证您的验证码为:'.$code]);
if($result == 1) {
$res = ['code' => 0, 'msg' => '验证码已发送成功,请去邮箱查看!'];
} else {

View File

@ -250,7 +250,7 @@ class User extends BaseController
$email = Request::param('email');
$url = Request::domain().Request::root().'/active/index?url='.time().md5($email).$this->uid;
$content = "Hi亲爱的{$this->showUser($this->uid)['name']}:</br>您正在进行邮箱激活请在10分钟内完成激活。 <a href='{$url}' target='_blank' >请点击进行激活</a> </br>若无法跳转请复制链接激活:{$url}";
$res = mailto($email,'邮箱激活',$content);
$res = hook('mailtohook',[$email,'邮箱激活',$content]);
if($res){
return json(['status'=>0]);
}else{

View File

@ -7,7 +7,7 @@
"thinkphp",
"ORM"
],
"homepage": "http://www.aieok.com/",
"homepage": "https://www.aieok.com/",
"license": "Apache-2.0",
"authors": [
{
@ -37,7 +37,8 @@
"guzzlehttp/guzzle": "7.0",
"php-di/php-di": "^6.4",
"workerman/phpsocket.io": "^1.1",
"jaeger/querylist": "^4.2"
"jaeger/querylist": "^4.2",
"symfony/var-exporter": "^5.4"
},
"require-dev": {
"symfony/var-dumper": "^4.2",

150
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c80928616d71c7770ef136acd370770e",
"content-hash": "775d0e3963da1506fb878faca1e62b31",
"packages": [
{
"name": "bacon/bacon-qr-code",
@ -304,16 +304,16 @@
},
{
"name": "endroid/qr-code",
"version": "4.5.0",
"version": "4.6.0",
"source": {
"type": "git",
"url": "https://github.com/endroid/qr-code.git",
"reference": "36681470bd10352b53bcb9731bdf2270e0d79b22"
"reference": "b60873b14e2ca7bf3c3746f5e032023095a7e05c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/endroid/qr-code/zipball/36681470bd10352b53bcb9731bdf2270e0d79b22",
"reference": "36681470bd10352b53bcb9731bdf2270e0d79b22",
"url": "https://api.github.com/repos/endroid/qr-code/zipball/b60873b14e2ca7bf3c3746f5e032023095a7e05c",
"reference": "b60873b14e2ca7bf3c3746f5e032023095a7e05c",
"shasum": ""
},
"require": {
@ -364,7 +364,7 @@
],
"support": {
"issues": "https://github.com/endroid/qr-code/issues",
"source": "https://github.com/endroid/qr-code/tree/4.5.0"
"source": "https://github.com/endroid/qr-code/tree/4.6.0"
},
"funding": [
{
@ -372,7 +372,7 @@
"type": "github"
}
],
"time": "2022-08-21T09:22:43+00:00"
"time": "2022-10-04T17:13:41+00:00"
},
{
"name": "firebase/php-jwt",
@ -920,16 +920,16 @@
},
{
"name": "league/flysystem",
"version": "1.1.9",
"version": "1.1.10",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "094defdb4a7001845300334e7c1ee2335925ef99"
"reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/094defdb4a7001845300334e7c1ee2335925ef99",
"reference": "094defdb4a7001845300334e7c1ee2335925ef99",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1",
"reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1",
"shasum": ""
},
"require": {
@ -1002,7 +1002,7 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/1.1.9"
"source": "https://github.com/thephpleague/flysystem/tree/1.1.10"
},
"funding": [
{
@ -1010,7 +1010,7 @@
"type": "other"
}
],
"time": "2021-12-09T09:40:50+00:00"
"time": "2022-10-04T09:16:37+00:00"
},
{
"name": "league/flysystem-cached-adapter",
@ -2130,16 +2130,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v4.4.44",
"version": "v4.4.46",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "f19951007dae942cc79b979c1fe26bfdfbeb54ed"
"reference": "90425fd98d1ecad98e4b2dca9f54f62069193b15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/f19951007dae942cc79b979c1fe26bfdfbeb54ed",
"reference": "f19951007dae942cc79b979c1fe26bfdfbeb54ed",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/90425fd98d1ecad98e4b2dca9f54f62069193b15",
"reference": "90425fd98d1ecad98e4b2dca9f54f62069193b15",
"shasum": ""
},
"require": {
@ -2199,7 +2199,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v4.4.44"
"source": "https://github.com/symfony/var-dumper/tree/v4.4.46"
},
"funding": [
{
@ -2215,24 +2215,98 @@
"type": "tidelift"
}
],
"time": "2022-07-20T09:59:04+00:00"
"time": "2022-09-03T23:07:25+00:00"
},
{
"name": "taoser/think-addons",
"version": "v1.0.3",
"name": "symfony/var-exporter",
"version": "v5.4.10",
"source": {
"type": "git",
"url": "https://github.com/taoser/think-addons.git",
"reference": "4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f"
"url": "https://github.com/symfony/var-exporter.git",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/taoser/think-addons/zipball/4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f",
"reference": "4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\VarExporter\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Allows exporting any serializable PHP data structure to plain PHP code",
"homepage": "https://symfony.com",
"keywords": [
"clone",
"construct",
"export",
"hydrate",
"instantiate",
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v5.4.10"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2022-05-27T12:56:18+00:00"
},
{
"name": "taoser/think-addons",
"version": "v1.0.6",
"source": {
"type": "git",
"url": "https://github.com/taoser/think-addons.git",
"reference": "e6e35bfd8b93dc469ebb5c5530ba350131bd7541"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/taoser/think-addons/zipball/e6e35bfd8b93dc469ebb5c5530ba350131bd7541",
"reference": "e6e35bfd8b93dc469ebb5c5530ba350131bd7541",
"shasum": ""
},
"require": {
"php": ">=7.1.0",
"symfony/var-exporter": "^5.4",
"topthink/framework": "^6.0",
"topthink/think-helper": "^3.0.0",
"topthink/think-view": "^1.0"
@ -2269,9 +2343,9 @@
"description": "The ThinkPHP6 Addons Package",
"support": {
"issues": "https://github.com/taoser/think-addons/issues",
"source": "https://github.com/taoser/think-addons/tree/v1.0.3"
"source": "https://github.com/taoser/think-addons/tree/v1.0.6"
},
"time": "2022-06-04T08:08:23+00:00"
"time": "2022-10-06T13:11:38+00:00"
},
{
"name": "taoser/think-auth",
@ -2368,16 +2442,16 @@
},
{
"name": "tightenco/collect",
"version": "v8.83.23",
"version": "v8.83.25",
"source": {
"type": "git",
"url": "https://github.com/tighten/collect.git",
"reference": "a4423c6ace6b54ba4f86c0ac9de588c57bc94d79"
"reference": "7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tighten/collect/zipball/a4423c6ace6b54ba4f86c0ac9de588c57bc94d79",
"reference": "a4423c6ace6b54ba4f86c0ac9de588c57bc94d79",
"url": "https://api.github.com/repos/tighten/collect/zipball/7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea",
"reference": "7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea",
"shasum": ""
},
"require": {
@ -2416,9 +2490,9 @@
],
"support": {
"issues": "https://github.com/tighten/collect/issues",
"source": "https://github.com/tighten/collect/tree/v8.83.23"
"source": "https://github.com/tighten/collect/tree/v8.83.25"
},
"time": "2022-08-22T17:50:04+00:00"
"time": "2022-08-22T17:55:07+00:00"
},
{
"name": "topthink/framework",
@ -2999,16 +3073,16 @@
},
{
"name": "workerman/workerman",
"version": "v4.1.0",
"version": "v4.1.3",
"source": {
"type": "git",
"url": "https://github.com/walkor/workerman.git",
"reference": "88ddf517e5c35bee072b2e453c4fcca0c6f1e59a"
"reference": "01028d8008c5691ec38c5f675fc13d76496a6db9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/walkor/workerman/zipball/88ddf517e5c35bee072b2e453c4fcca0c6f1e59a",
"reference": "88ddf517e5c35bee072b2e453c4fcca0c6f1e59a",
"url": "https://api.github.com/repos/walkor/workerman/zipball/01028d8008c5691ec38c5f675fc13d76496a6db9",
"reference": "01028d8008c5691ec38c5f675fc13d76496a6db9",
"shasum": ""
},
"require": {
@ -3058,7 +3132,7 @@
"type": "patreon"
}
],
"time": "2022-08-20T10:16:22+00:00"
"time": "2022-09-23T14:05:12+00:00"
},
{
"name": "yansongda/pay",

View File

@ -14,6 +14,11 @@ use think\Response;
class Api
{
/**
* @param $url
* @param $data
* @return mixed|\think\response\Json
*/
public static function urlPost($url, $data)
{
if($url == ''){

View File

@ -0,0 +1,18 @@
<?php
namespace taoler\com;
use think\Facade;
class FormHelper extends Facade
{
/**
* 获取当前Facade对应类名或者已经绑定的容器对象标识
* @access protected
* @return string
*/
protected static function getFacadeClass()
{
return 'taoler\com\FormHlp';
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,118 +5,6 @@ layui.define(['table', 'form'], function(exports){
,table = layui.table
,form = layui.form;
//签到规则
table.render({
elem: '#sign-rule',
url: signSignRule,
cols:[[
{type: 'numbers', fixed: 'left'},
{field: 'days',title: '天数'},
{field: 'score',title: '积分'},
{field: 'ctime',title: '时间'},
{title: '操作', width: 150, align:'center', toolbar: '#sign-rule-button'}
]]
,page: true
,limit: 10
,height: 'full-220'
,text: '对不起,加载出现异常!'
});
//监听工具条
table.on('tool(sign-rule)', function(obj){
var data = obj.data;
if(obj.event === 'del'){
layer.prompt({
formType: 1
,title: '敏感操作,请验证口令'
}, function(value, index){
layer.close(index);
layer.confirm('真的删除行么', function(index){
//obj.del();
$.ajax({
type:'post',
url:signDelete,
data:{id:data.id},
dataType:'json',
success:function(data){
if(data.code == 0){
layer.msg(data.msg,{
icon:6,
time:2000
});
} else {
layer.open({
title:'删除失败',
content:data.msg,
icon:5,
adim:6
})
}
}
});
table.reload('sign-rule');
layer.close(index);
});
});
} else if(obj.event === 'edit'){
var tr = $(obj.tr);
layer.open({
type: 2
,title: '编辑签到'
,content: signSignEdit +'?id='+ data.id
,maxmin: true
,area: ['350px', '300px']
,btn: ['确定', '取消']
,yes: function(index, layero){
var iframeWindow = window['layui-layer-iframe'+ index]
,submitID = 'LAY-user-sign-submit'
,submit = layero.find('iframe').contents().find('#'+ submitID);
//监听提交
iframeWindow.layui.form.on('submit('+ submitID +')', function(data){
var field = data.field; //获取提交的字段
//提交 Ajax 成功后,静态更新表格中的数据
$.ajax({
type:"post",
url:signSignEdit,
data:field,
daType:"json",
success:function (res){
if (res.code == 0) {
layer.msg(res.msg,{
icon:6,
time:2000
});
} else {
layer.open({
tiele:'修改失败',
content:res.msg,
icon:5,
anim:6
});
}
}
});
table.reload('sign-rule'); //数据刷新
layer.close(index); //关闭弹层
});
submit.trigger('click');
}
,success: function(layero, index){
}
});
}
});
//Vip规则
table.render({
elem: '#vip-rule',
@ -230,7 +118,5 @@ layui.define(['table', 'form'], function(exports){
}
});
exports('webset', {})
});

View File

@ -8,12 +8,12 @@ $baseDir = dirname($vendorDir);
return array(
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
'fe62ba7e10580d903cc46d808b5961a4' => $vendorDir . '/tightenco/collect/src/Collect/Support/helpers.php',

View File

@ -26,6 +26,7 @@ return array(
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'),
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'),
'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'),
'QL\\' => array($vendorDir . '/jaeger/querylist/src'),
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),

View File

@ -9,12 +9,12 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2
public static $files = array (
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
'35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
'25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
'fe62ba7e10580d903cc46d808b5961a4' => __DIR__ . '/..' . '/tightenco/collect/src/Collect/Support/helpers.php',
@ -74,6 +74,7 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2
'Symfony\\Polyfill\\Php80\\' => 23,
'Symfony\\Polyfill\\Php72\\' => 23,
'Symfony\\Polyfill\\Mbstring\\' => 26,
'Symfony\\Component\\VarExporter\\' => 30,
'Symfony\\Component\\VarDumper\\' => 28,
),
'Q' =>
@ -226,6 +227,10 @@ class ComposerStaticInit1b32198725235c8d6500c87262ef30c2
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
),
'Symfony\\Component\\VarExporter\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/var-exporter',
),
'Symfony\\Component\\VarDumper\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/var-dumper',

View File

@ -313,17 +313,17 @@
},
{
"name": "endroid/qr-code",
"version": "4.5.0",
"version_normalized": "4.5.0.0",
"version": "4.6.0",
"version_normalized": "4.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/endroid/qr-code.git",
"reference": "36681470bd10352b53bcb9731bdf2270e0d79b22"
"reference": "b60873b14e2ca7bf3c3746f5e032023095a7e05c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/endroid/qr-code/zipball/36681470bd10352b53bcb9731bdf2270e0d79b22",
"reference": "36681470bd10352b53bcb9731bdf2270e0d79b22",
"url": "https://api.github.com/repos/endroid/qr-code/zipball/b60873b14e2ca7bf3c3746f5e032023095a7e05c",
"reference": "b60873b14e2ca7bf3c3746f5e032023095a7e05c",
"shasum": ""
},
"require": {
@ -342,7 +342,7 @@
"roave/security-advisories": "Makes sure package versions with known security issues are not installed",
"setasign/fpdf": "Enables you to use the PDF writer"
},
"time": "2022-08-21T09:22:43+00:00",
"time": "2022-10-04T17:13:41+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -376,7 +376,7 @@
],
"support": {
"issues": "https://github.com/endroid/qr-code/issues",
"source": "https://github.com/endroid/qr-code/tree/4.5.0"
"source": "https://github.com/endroid/qr-code/tree/4.6.0"
},
"funding": [
{
@ -962,24 +962,18 @@
},
{
"name": "league/flysystem",
"version": "1.1.9",
"version_normalized": "1.1.9.0",
"version": "1.1.10",
"version_normalized": "1.1.10.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "094defdb4a7001845300334e7c1ee2335925ef99"
"reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/094defdb4a7001845300334e7c1ee2335925ef99",
"reference": "094defdb4a7001845300334e7c1ee2335925ef99",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1",
"reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
@ -1008,7 +1002,7 @@
"spatie/flysystem-dropbox": "Allows you to use Dropbox storage",
"srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications"
},
"time": "2021-12-09T09:40:50+00:00",
"time": "2022-10-04T09:16:37+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -1053,7 +1047,7 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/1.1.9"
"source": "https://github.com/thephpleague/flysystem/tree/1.1.10"
},
"funding": [
{
@ -2270,17 +2264,17 @@
},
{
"name": "symfony/var-dumper",
"version": "v4.4.44",
"version_normalized": "4.4.44.0",
"version": "v4.4.46",
"version_normalized": "4.4.46.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "f19951007dae942cc79b979c1fe26bfdfbeb54ed"
"reference": "90425fd98d1ecad98e4b2dca9f54f62069193b15"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/f19951007dae942cc79b979c1fe26bfdfbeb54ed",
"reference": "f19951007dae942cc79b979c1fe26bfdfbeb54ed",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/90425fd98d1ecad98e4b2dca9f54f62069193b15",
"reference": "90425fd98d1ecad98e4b2dca9f54f62069193b15",
"shasum": ""
},
"require": {
@ -2304,7 +2298,7 @@
"ext-intl": "To show region name in time zone dump",
"symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
},
"time": "2022-07-20T09:59:04+00:00",
"time": "2022-09-03T23:07:25+00:00",
"bin": [
"Resources/bin/var-dump-server"
],
@ -2342,7 +2336,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v4.4.44"
"source": "https://github.com/symfony/var-dumper/tree/v4.4.46"
},
"funding": [
{
@ -2361,27 +2355,104 @@
"install-path": "../symfony/var-dumper"
},
{
"name": "taoser/think-addons",
"version": "v1.0.3",
"version_normalized": "1.0.3.0",
"name": "symfony/var-exporter",
"version": "v5.4.10",
"version_normalized": "5.4.10.0",
"source": {
"type": "git",
"url": "https://github.com/taoser/think-addons.git",
"reference": "4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f"
"url": "https://github.com/symfony/var-exporter.git",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/taoser/think-addons/zipball/4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f",
"reference": "4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/8fc03ee75eeece3d9be1ef47d26d79bea1afb340",
"reference": "8fc03ee75eeece3d9be1ef47d26d79bea1afb340",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
},
"time": "2022-05-27T12:56:18+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\VarExporter\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Allows exporting any serializable PHP data structure to plain PHP code",
"homepage": "https://symfony.com",
"keywords": [
"clone",
"construct",
"export",
"hydrate",
"instantiate",
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v5.4.10"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"install-path": "../symfony/var-exporter"
},
{
"name": "taoser/think-addons",
"version": "v1.0.6",
"version_normalized": "1.0.6.0",
"source": {
"type": "git",
"url": "https://github.com/taoser/think-addons.git",
"reference": "e6e35bfd8b93dc469ebb5c5530ba350131bd7541"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/taoser/think-addons/zipball/e6e35bfd8b93dc469ebb5c5530ba350131bd7541",
"reference": "e6e35bfd8b93dc469ebb5c5530ba350131bd7541",
"shasum": ""
},
"require": {
"php": ">=7.1.0",
"symfony/var-exporter": "^5.4",
"topthink/framework": "^6.0",
"topthink/think-helper": "^3.0.0",
"topthink/think-view": "^1.0"
},
"time": "2022-06-04T08:08:23+00:00",
"time": "2022-10-06T13:11:38+00:00",
"type": "library",
"extra": {
"think": {
@ -2415,7 +2486,7 @@
"description": "The ThinkPHP6 Addons Package",
"support": {
"issues": "https://github.com/taoser/think-addons/issues",
"source": "https://github.com/taoser/think-addons/tree/v1.0.3"
"source": "https://github.com/taoser/think-addons/tree/v1.0.6"
},
"install-path": "../taoser/think-addons"
},
@ -2522,17 +2593,17 @@
},
{
"name": "tightenco/collect",
"version": "v8.83.23",
"version_normalized": "8.83.23.0",
"version": "v8.83.25",
"version_normalized": "8.83.25.0",
"source": {
"type": "git",
"url": "https://github.com/tighten/collect.git",
"reference": "a4423c6ace6b54ba4f86c0ac9de588c57bc94d79"
"reference": "7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tighten/collect/zipball/a4423c6ace6b54ba4f86c0ac9de588c57bc94d79",
"reference": "a4423c6ace6b54ba4f86c0ac9de588c57bc94d79",
"url": "https://api.github.com/repos/tighten/collect/zipball/7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea",
"reference": "7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea",
"shasum": ""
},
"require": {
@ -2544,7 +2615,7 @@
"nesbot/carbon": "^2.23.0",
"phpunit/phpunit": "^8.3"
},
"time": "2022-08-22T17:50:04+00:00",
"time": "2022-08-22T17:55:07+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -2573,7 +2644,7 @@
],
"support": {
"issues": "https://github.com/tighten/collect/issues",
"source": "https://github.com/tighten/collect/tree/v8.83.23"
"source": "https://github.com/tighten/collect/tree/v8.83.25"
},
"install-path": "../tightenco/collect"
},
@ -3282,17 +3353,17 @@
},
{
"name": "workerman/workerman",
"version": "v4.1.0",
"version_normalized": "4.1.0.0",
"version": "v4.1.3",
"version_normalized": "4.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/walkor/workerman.git",
"reference": "88ddf517e5c35bee072b2e453c4fcca0c6f1e59a"
"reference": "01028d8008c5691ec38c5f675fc13d76496a6db9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/walkor/workerman/zipball/88ddf517e5c35bee072b2e453c4fcca0c6f1e59a",
"reference": "88ddf517e5c35bee072b2e453c4fcca0c6f1e59a",
"url": "https://api.github.com/repos/walkor/workerman/zipball/01028d8008c5691ec38c5f675fc13d76496a6db9",
"reference": "01028d8008c5691ec38c5f675fc13d76496a6db9",
"shasum": ""
},
"require": {
@ -3301,7 +3372,7 @@
"suggest": {
"ext-event": "For better performance. "
},
"time": "2022-08-20T10:16:22+00:00",
"time": "2022-09-23T14:05:12+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {

View File

@ -3,7 +3,7 @@
'name' => 'taoser/taoler',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '846581c3abfa893a57d4ce930c2fa684dfd688af',
'reference' => '9f89482c951e9a44bf0e2e4bf91c7e7ccb0fc8dd',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -56,9 +56,9 @@
'dev_requirement' => false,
),
'endroid/qr-code' => array(
'pretty_version' => '4.5.0',
'version' => '4.5.0.0',
'reference' => '36681470bd10352b53bcb9731bdf2270e0d79b22',
'pretty_version' => '4.6.0',
'version' => '4.6.0.0',
'reference' => 'b60873b14e2ca7bf3c3746f5e032023095a7e05c',
'type' => 'library',
'install_path' => __DIR__ . '/../endroid/qr-code',
'aliases' => array(),
@ -137,9 +137,9 @@
'dev_requirement' => false,
),
'league/flysystem' => array(
'pretty_version' => '1.1.9',
'version' => '1.1.9.0',
'reference' => '094defdb4a7001845300334e7c1ee2335925ef99',
'pretty_version' => '1.1.10',
'version' => '1.1.10.0',
'reference' => '3239285c825c152bcc315fe0e87d6b55f5972ed1',
'type' => 'library',
'install_path' => __DIR__ . '/../league/flysystem',
'aliases' => array(),
@ -347,27 +347,36 @@
'dev_requirement' => false,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v4.4.44',
'version' => '4.4.44.0',
'reference' => 'f19951007dae942cc79b979c1fe26bfdfbeb54ed',
'pretty_version' => 'v4.4.46',
'version' => '4.4.46.0',
'reference' => '90425fd98d1ecad98e4b2dca9f54f62069193b15',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'dev_requirement' => false,
),
'symfony/var-exporter' => array(
'pretty_version' => 'v5.4.10',
'version' => '5.4.10.0',
'reference' => '8fc03ee75eeece3d9be1ef47d26d79bea1afb340',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-exporter',
'aliases' => array(),
'dev_requirement' => false,
),
'taoser/taoler' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '846581c3abfa893a57d4ce930c2fa684dfd688af',
'reference' => '9f89482c951e9a44bf0e2e4bf91c7e7ccb0fc8dd',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'taoser/think-addons' => array(
'pretty_version' => 'v1.0.3',
'version' => '1.0.3.0',
'reference' => '4329bb368fc87d7ca2fe0b2ac6e6e8d6bc13011f',
'pretty_version' => 'v1.0.6',
'version' => '1.0.6.0',
'reference' => 'e6e35bfd8b93dc469ebb5c5530ba350131bd7541',
'type' => 'library',
'install_path' => __DIR__ . '/../taoser/think-addons',
'aliases' => array(),
@ -392,9 +401,9 @@
'dev_requirement' => false,
),
'tightenco/collect' => array(
'pretty_version' => 'v8.83.23',
'version' => '8.83.23.0',
'reference' => 'a4423c6ace6b54ba4f86c0ac9de588c57bc94d79',
'pretty_version' => 'v8.83.25',
'version' => '8.83.25.0',
'reference' => '7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea',
'type' => 'library',
'install_path' => __DIR__ . '/../tightenco/collect',
'aliases' => array(),
@ -518,9 +527,9 @@
'dev_requirement' => false,
),
'workerman/workerman' => array(
'pretty_version' => 'v4.1.0',
'version' => '4.1.0.0',
'reference' => '88ddf517e5c35bee072b2e453c4fcca0c6f1e59a',
'pretty_version' => 'v4.1.3',
'version' => '4.1.3.0',
'reference' => '01028d8008c5691ec38c5f675fc13d76496a6db9',
'type' => 'library',
'install_path' => __DIR__ . '/../workerman/workerman',
'aliases' => array(),

View File

@ -51,6 +51,7 @@ $result = Builder::create()
->labelText('This is the label')
->labelFont(new NotoSans(20))
->labelAlignment(new LabelAlignmentCenter())
->validateResult(false)
->build();
```
@ -65,11 +66,12 @@ use Endroid\QrCode\Label\Label;
use Endroid\QrCode\Logo\Logo;
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
use Endroid\QrCode\Writer\PngWriter;
use Endroid\QrCode\Writer\ValidationException;
$writer = new PngWriter();
// Create QR code
$qrCode = QrCode::create('Data')
$qrCode = QrCode::create('Life is too short to be generating QR codes')
->setEncoding(new Encoding('UTF-8'))
->setErrorCorrectionLevel(new ErrorCorrectionLevelLow())
->setSize(300)
@ -87,6 +89,9 @@ $label = Label::create('Label')
->setTextColor(new Color(255, 0, 0));
$result = $writer->write($qrCode, $logo, $label);
// Validate the result
$writer->validateResult($result, 'Life is too short to be generating QR codes');
```
## Usage: working with results
@ -149,13 +154,14 @@ size can result in additional padding to compensate for the rounding difference.
And finally the encoding (default UTF-8 to support large character sets) can be
set to `ISO-8859-1` if possible to improve readability.
## Built-in validation reader
## Validating the generated QR code
You can enable the built-in validation reader (disabled by default) by calling
setValidateResult(true). This validation reader does not guarantee that the QR
code will be readable by all readers but it helps you provide a minimum level
of quality. Take note that the validator can consume quite amount of additional
resources and it should be installed separately only if you use it.
If you need to be extra sure the QR code you generated is readable and contains
the exact data you requested you can enable the validation reader, which is
disabled by default. You can do this either via the builder or directly on any
writer that supports validation. See the examples above.
Please note that validation affects performance so only use it in case of problems.
## Symfony integration

View File

@ -7,6 +7,7 @@ namespace Endroid\QrCode\Builder;
use Endroid\QrCode\Color\ColorInterface;
use Endroid\QrCode\Encoding\EncodingInterface;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelInterface;
use Endroid\QrCode\Exception\ValidationException;
use Endroid\QrCode\Label\Alignment\LabelAlignmentInterface;
use Endroid\QrCode\Label\Font\FontInterface;
use Endroid\QrCode\Label\Label;
@ -216,7 +217,7 @@ class Builder implements BuilderInterface
$writer = $this->options['writer'];
if ($this->options['validateResult'] && !$writer instanceof ValidatingWriterInterface) {
throw new \Exception('Unable to validate result with '.get_class($writer));
throw ValidationException::createForUnsupportedWriter(strval(get_class($writer)));
}
/** @var QrCode $qrCode */

View File

@ -44,6 +44,11 @@ final class Color implements ColorInterface
return 1 - $this->alpha / 127;
}
public function getHex(): string
{
return sprintf('#%02x%02x%02x', $this->red, $this->green, $this->blue);
}
public function toArray(): array
{
return [

View File

@ -16,6 +16,8 @@ interface ColorInterface
public function getOpacity(): float;
public function getHex(): string;
/** @return array<string, int> */
public function toArray(): array;
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Endroid\QrCode\Exception;
final class ValidationException extends \Exception
{
public static function createForUnsupportedWriter(string $writerClass): self
{
return new self(sprintf('Unable to validate the result: "%s" does not support validation', $writerClass));
}
public static function createForMissingPackage(string $packageName): self
{
return new self(sprintf('Please install "%s" or disable image validation', $packageName));
}
public static function createForIncompatiblePhpVersion(): self
{
return new self('The validator is not compatible with PHP 8 yet, see https://github.com/khanamiryan/php-qrcode-detector-decoder/pull/103');
}
public static function createForInvalidData(string $expectedData, string $actualData): self
{
return new self('The validation reader read "'.$actualData.'" instead of "'.$expectedData.'". Adjust your parameters to increase readability or disable validation.');
}
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer;
use Endroid\QrCode\Bacon\MatrixFactory;
use Endroid\QrCode\Label\LabelInterface;
use Endroid\QrCode\Logo\LogoInterface;
use Endroid\QrCode\QrCodeInterface;
@ -14,7 +15,10 @@ final class DebugWriter implements WriterInterface, ValidatingWriterInterface
{
public function write(QrCodeInterface $qrCode, LogoInterface $logo = null, LabelInterface $label = null, array $options = []): ResultInterface
{
return new DebugResult($qrCode, $logo, $label, $options);
$matrixFactory = new MatrixFactory();
$matrix = $matrixFactory->create($qrCode);
return new DebugResult($matrix, $qrCode, $logo, $label, $options);
}
public function validateResult(ResultInterface $result, string $expectedData): void

View File

@ -39,6 +39,6 @@ final class EpsWriter implements WriterInterface
}
}
return new EpsResult($lines);
return new EpsResult($matrix, $lines);
}
}

View File

@ -99,7 +99,7 @@ final class PdfWriter implements WriterInterface
$fpdf->Cell($matrix->getOuterSize(), 0, $label->getText(), 0, 0, 'C');
}
return new PdfResult($fpdf);
return new PdfResult($matrix, $fpdf);
}
private function addLogo(LogoInterface $logo, \FPDF $fpdf, float $x, float $y, float $size): void

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer;
use Endroid\QrCode\Bacon\MatrixFactory;
use Endroid\QrCode\Exception\ValidationException;
use Endroid\QrCode\ImageData\LabelImageData;
use Endroid\QrCode\ImageData\LogoImageData;
use Endroid\QrCode\Label\Alignment\LabelAlignmentLeft;
@ -110,7 +111,7 @@ final class PngWriter implements WriterInterface, ValidatingWriterInterface
imagesavealpha($targetImage, true);
}
$result = new PngResult($targetImage);
$result = new PngResult($matrix, $targetImage);
if ($logo instanceof LogoInterface) {
$result = $this->addLogo($logo, $result);
@ -174,7 +175,7 @@ final class PngWriter implements WriterInterface, ValidatingWriterInterface
imagedestroy($logoImageData->getImage());
}
return new PngResult($targetImage);
return new PngResult($result->getMatrix(), $targetImage);
}
private function addLabel(LabelInterface $label, PngResult $result): PngResult
@ -203,7 +204,7 @@ final class PngWriter implements WriterInterface, ValidatingWriterInterface
imagettftext($targetImage, $label->getFont()->getSize(), 0, $x, $y, $textColor, $label->getFont()->getPath(), $label->getText());
return new PngResult($targetImage);
return new PngResult($result->getMatrix(), $targetImage);
}
public function validateResult(ResultInterface $result, string $expectedData): void
@ -211,17 +212,16 @@ final class PngWriter implements WriterInterface, ValidatingWriterInterface
$string = $result->getString();
if (!class_exists(QrReader::class)) {
throw new \Exception('Please install khanamiryan/qrcode-detector-decoder or disable image validation');
throw ValidationException::createForMissingPackage('khanamiryan/qrcode-detector-decoder');
}
if (PHP_VERSION_ID >= 80000) {
throw new \Exception('The validator is not compatible with PHP 8 yet, see https://github.com/khanamiryan/php-qrcode-detector-decoder/pull/103');
throw ValidationException::createForIncompatiblePhpVersion();
}
$reader = new QrReader($string, QrReader::SOURCE_TYPE_BLOB);
if ($reader->text() !== $expectedData) {
throw new \Exception('Built-in validation reader read "'.$reader->text().'" instead of "'.$expectedData.'".
Adjust your parameters to increase readability or disable built-in validation.');
throw ValidationException::createForInvalidData($expectedData, strval($reader->text()));
}
}
}

View File

@ -4,8 +4,22 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Matrix\MatrixInterface;
abstract class AbstractResult implements ResultInterface
{
private MatrixInterface $matrix;
public function __construct(MatrixInterface $matrix)
{
$this->matrix = $matrix;
}
public function getMatrix(): MatrixInterface
{
return $this->matrix;
}
public function getDataUri(): string
{
return 'data:'.$this->getMimeType().';base64,'.base64_encode($this->getString());

View File

@ -8,19 +8,19 @@ use Endroid\QrCode\Matrix\MatrixInterface;
final class BinaryResult extends AbstractResult
{
private MatrixInterface $matrix;
public function __construct(MatrixInterface $matrix)
{
$this->matrix = $matrix;
parent::__construct($matrix);
}
public function getString(): string
{
$matrix = $this->getMatrix();
$binaryString = '';
for ($rowIndex = 0; $rowIndex < $this->matrix->getBlockCount(); ++$rowIndex) {
for ($columnIndex = 0; $columnIndex < $this->matrix->getBlockCount(); ++$columnIndex) {
$binaryString .= $this->matrix->getBlockValue($rowIndex, $columnIndex);
for ($rowIndex = 0; $rowIndex < $matrix->getBlockCount(); ++$rowIndex) {
for ($columnIndex = 0; $columnIndex < $matrix->getBlockCount(); ++$columnIndex) {
$binaryString .= $matrix->getBlockValue($rowIndex, $columnIndex);
}
$binaryString .= "\n";
}

View File

@ -7,27 +7,24 @@ namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Color\ColorInterface;
use Endroid\QrCode\Matrix\MatrixInterface;
/**
* Implementation of ResultInterface for printing a QR-Code on command line interface.
*/
class ConsoleResult extends AbstractResult
{
protected MatrixInterface $matrix;
protected string $colorEscapeCode;
public const twoblocks = [
private const TWO_BLOCKS = [
0 => ' ',
1 => "\xe2\x96\x80",
2 => "\xe2\x96\x84",
3 => "\xe2\x96\x88",
];
/**
* Ctor.
*/
public function __construct(MatrixInterface $matrix, ColorInterface $foreground, ColorInterface $background)
{
$this->matrix = $matrix;
private string $colorEscapeCode;
public function __construct(
MatrixInterface $matrix,
ColorInterface $foreground,
ColorInterface $background
) {
parent::__construct($matrix);
$this->colorEscapeCode = sprintf(
"\e[38;2;%d;%d;%dm\e[48;2;%d;%d;%dm",
$foreground->getRed(),
@ -46,28 +43,27 @@ class ConsoleResult extends AbstractResult
public function getString(): string
{
$side = $this->matrix->getBlockCount();
$marginLeft = $this->colorEscapeCode.self::twoblocks[0].self::twoblocks[0];
$marginRight = self::twoblocks[0].self::twoblocks[0]."\e[0m".PHP_EOL;
$marginVertical = $marginLeft.str_repeat(self::twoblocks[0], $side).$marginRight;
$matrix = $this->getMatrix();
ob_start();
echo $marginVertical; // margin-top
$side = $matrix->getBlockCount();
$marginLeft = $this->colorEscapeCode.self::TWO_BLOCKS[0].self::TWO_BLOCKS[0];
$marginRight = self::TWO_BLOCKS[0].self::TWO_BLOCKS[0]."\e[0m".PHP_EOL;
$marginVertical = $marginLeft.str_repeat(self::TWO_BLOCKS[0], $side).$marginRight;
$qrCodeString = $marginVertical;
for ($rowIndex = 0; $rowIndex < $side; $rowIndex += 2) {
echo $marginLeft; // margin-left
$qrCodeString .= $marginLeft;
for ($columnIndex = 0; $columnIndex < $side; ++$columnIndex) {
$combined = $this->matrix->getBlockValue($rowIndex, $columnIndex);
if (($rowIndex + 1) < $side) {
$combined |= $this->matrix->getBlockValue($rowIndex + 1, $columnIndex) << 1;
$combined = $matrix->getBlockValue($rowIndex, $columnIndex);
if ($rowIndex + 1 < $side) {
$combined |= $matrix->getBlockValue($rowIndex + 1, $columnIndex) << 1;
}
echo self::twoblocks[$combined];
$qrCodeString .= self::TWO_BLOCKS[$combined];
}
echo $marginRight; // margin-right
$qrCodeString .= $marginRight;
}
$qrCodeString .= $marginVertical;
echo $marginVertical; // margin-bottom
return (string) ob_get_clean();
return $qrCodeString;
}
}

View File

@ -6,6 +6,7 @@ namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Label\LabelInterface;
use Endroid\QrCode\Logo\LogoInterface;
use Endroid\QrCode\Matrix\MatrixInterface;
use Endroid\QrCode\QrCodeInterface;
final class DebugResult extends AbstractResult
@ -20,8 +21,15 @@ final class DebugResult extends AbstractResult
private bool $validateResult = false;
/** @param array<mixed> $options */
public function __construct(QrCodeInterface $qrCode, LogoInterface $logo = null, LabelInterface $label = null, array $options = [])
{
public function __construct(
MatrixInterface $matrix,
QrCodeInterface $qrCode,
LogoInterface $logo = null,
LabelInterface $label = null,
array $options = []
) {
parent::__construct($matrix);
$this->qrCode = $qrCode;
$this->logo = $logo;
$this->label = $label;

View File

@ -4,14 +4,18 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Matrix\MatrixInterface;
final class EpsResult extends AbstractResult
{
/** @var array<string> */
private array $lines;
/** @param array<string> $lines */
public function __construct(array $lines)
public function __construct(MatrixInterface $matrix, array $lines)
{
parent::__construct($matrix);
$this->lines = $lines;
}

View File

@ -4,12 +4,16 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Matrix\MatrixInterface;
final class PdfResult extends AbstractResult
{
private \FPDF $fpdf;
public function __construct(\FPDF $fpdf)
public function __construct(MatrixInterface $matrix, \FPDF $fpdf)
{
parent::__construct($matrix);
$this->fpdf = $fpdf;
}

View File

@ -4,14 +4,18 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Matrix\MatrixInterface;
final class PngResult extends AbstractResult
{
/** @var mixed */
private $image;
/** @param mixed $image */
public function __construct($image)
public function __construct(MatrixInterface $matrix, $image)
{
parent::__construct($matrix);
$this->image = $image;
}

View File

@ -4,8 +4,12 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Matrix\MatrixInterface;
interface ResultInterface
{
public function getMatrix(): MatrixInterface;
public function getString(): string;
public function getDataUri(): string;

View File

@ -4,13 +4,20 @@ declare(strict_types=1);
namespace Endroid\QrCode\Writer\Result;
use Endroid\QrCode\Matrix\MatrixInterface;
final class SvgResult extends AbstractResult
{
private \SimpleXMLElement $xml;
private bool $excludeXmlDeclaration;
public function __construct(\SimpleXMLElement $xml, bool $excludeXmlDeclaration = false)
{
public function __construct(
MatrixInterface $matrix,
\SimpleXMLElement $xml,
bool $excludeXmlDeclaration = false
) {
parent::__construct($matrix);
$this->xml = $xml;
$this->excludeXmlDeclaration = $excludeXmlDeclaration;
}

View File

@ -72,7 +72,7 @@ final class SvgWriter implements WriterInterface
}
}
$result = new SvgResult($xml, boolval($options[self::WRITER_OPTION_EXCLUDE_XML_DECLARATION]));
$result = new SvgResult($matrix, $xml, boolval($options[self::WRITER_OPTION_EXCLUDE_XML_DECLARATION]));
if ($logo instanceof LogoInterface) {
$this->addLogo($logo, $result, $options);

View File

@ -572,9 +572,9 @@ class Ftp extends AbstractFtpAdapter
private function getRawExecResponseCode($command)
{
$response = @ftp_raw($this->connection, trim($command));
$response = @ftp_raw($this->connection, trim($command)) ?: [];
return (int) preg_replace('/\D/', '', implode(' ', $response));
return (int) preg_replace('/\D/', '', implode(' ', (array) $response));
}
private function hasFtpConnection(): bool

2
vendor/services.php vendored
View File

@ -1,5 +1,5 @@
<?php
// This file is automatically generated at:2022-09-18 11:10:54
// This file is automatically generated at:2022-10-07 16:19:38
declare (strict_types = 1);
return array (
0 => 'taoser\\addons\\Service',

View File

@ -0,0 +1,12 @@
CHANGELOG
=========
5.1.0
-----
* added argument `array &$foundClasses` to `VarExporter::export()` to ease with preloading exported values
4.2.0
-----
* added the component

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Exception;
class ClassNotFoundException extends \Exception implements ExceptionInterface
{
public function __construct(string $class, \Throwable $previous = null)
{
parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous);
}
}

View File

@ -0,0 +1,16 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Exception;
interface ExceptionInterface extends \Throwable
{
}

View File

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Exception;
class NotInstantiableTypeException extends \Exception implements ExceptionInterface
{
public function __construct(string $type, \Throwable $previous = null)
{
parent::__construct(sprintf('Type "%s" is not instantiable.', $type), 0, $previous);
}
}

View File

@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter;
use Symfony\Component\VarExporter\Exception\ExceptionInterface;
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
use Symfony\Component\VarExporter\Internal\Hydrator;
use Symfony\Component\VarExporter\Internal\Registry;
/**
* A utility class to create objects without calling their constructor.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
final class Instantiator
{
/**
* Creates an object and sets its properties without calling its constructor nor any other methods.
*
* For example:
*
* // creates an empty instance of Foo
* Instantiator::instantiate(Foo::class);
*
* // creates a Foo instance and sets one of its properties
* Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]);
*
* // creates a Foo instance and sets a private property defined on its parent Bar class
* Instantiator::instantiate(Foo::class, [], [
* Bar::class => ['privateBarProperty' => $propertyValue],
* ]);
*
* Instances of ArrayObject, ArrayIterator and SplObjectStorage can be created
* by using the special "\0" property name to define their internal value:
*
* // creates an SplObjectStorage where $info1 is attached to $obj1, etc.
* Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]);
*
* // creates an ArrayObject populated with $inputArray
* Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]);
*
* @param string $class The class of the instance to create
* @param array $properties The properties to set on the instance
* @param array $privateProperties The private properties to set on the instance,
* keyed by their declaring class
*
* @throws ExceptionInterface When the instance cannot be created
*/
public static function instantiate(string $class, array $properties = [], array $privateProperties = []): object
{
$reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
if (Registry::$cloneable[$class]) {
$wrappedInstance = [clone Registry::$prototypes[$class]];
} elseif (Registry::$instantiableWithoutConstructor[$class]) {
$wrappedInstance = [$reflector->newInstanceWithoutConstructor()];
} elseif (null === Registry::$prototypes[$class]) {
throw new NotInstantiableTypeException($class);
} elseif ($reflector->implementsInterface('Serializable') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize'))) {
$wrappedInstance = [unserialize('C:'.\strlen($class).':"'.$class.'":0:{}')];
} else {
$wrappedInstance = [unserialize('O:'.\strlen($class).':"'.$class.'":0:{}')];
}
if ($properties) {
$privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties;
}
foreach ($privateProperties as $class => $properties) {
if (!$properties) {
continue;
}
foreach ($properties as $name => $value) {
// because they're also used for "unserialization", hydrators
// deal with array of instances, so we need to wrap values
$properties[$name] = [$value];
}
(Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance);
}
return $wrappedInstance[0];
}
}

View File

@ -0,0 +1,406 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Internal;
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class Exporter
{
/**
* Prepares an array of values for VarExporter.
*
* For performance this method is public and has no type-hints.
*
* @param array &$values
* @param \SplObjectStorage $objectsPool
* @param array &$refsPool
* @param int &$objectsCount
* @param bool &$valuesAreStatic
*
* @throws NotInstantiableTypeException When a value cannot be serialized
*/
public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic): array
{
$refs = $values;
foreach ($values as $k => $value) {
if (\is_resource($value)) {
throw new NotInstantiableTypeException(get_resource_type($value).' resource');
}
$refs[$k] = $objectsPool;
if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) {
$values[$k] = &$value; // Break hard references to make $values completely
unset($value); // independent from the original structure
$refs[$k] = $value = $values[$k];
if ($value instanceof Reference && 0 > $value->id) {
$valuesAreStatic = false;
++$value->count;
continue;
}
$refsPool[] = [&$refs[$k], $value, &$value];
$refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value);
}
if (\is_array($value)) {
if ($value) {
$value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
}
goto handle_value;
} elseif (!\is_object($value) || $value instanceof \UnitEnum) {
goto handle_value;
}
$valueIsStatic = false;
if (isset($objectsPool[$value])) {
++$objectsCount;
$value = new Reference($objectsPool[$value][0]);
goto handle_value;
}
$class = \get_class($value);
$reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class);
if ($reflector->hasMethod('__serialize')) {
if (!$reflector->getMethod('__serialize')->isPublic()) {
throw new \Error(sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class));
}
if (!\is_array($properties = $value->__serialize())) {
throw new \TypeError($class.'::__serialize() must return an array');
}
goto prepare_value;
}
$properties = [];
$sleep = null;
$proto = Registry::$prototypes[$class];
if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) {
// ArrayIterator and ArrayObject need special care because their "flags"
// option changes the behavior of the (array) casting operator.
[$arrayValue, $properties] = self::getArrayObjectProperties($value, $proto);
// populates Registry::$prototypes[$class] with a new instance
Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]);
} elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) {
// By implementing Serializable, SplObjectStorage breaks
// internal references; let's deal with it on our own.
foreach (clone $value as $v) {
$properties[] = $v;
$properties[] = $value[$v];
}
$properties = ['SplObjectStorage' => ["\0" => $properties]];
$arrayValue = (array) $value;
} elseif ($value instanceof \Serializable
|| $value instanceof \__PHP_Incomplete_Class
|| \PHP_VERSION_ID < 80200 && $value instanceof \DatePeriod
) {
++$objectsCount;
$objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0];
$value = new Reference($id);
goto handle_value;
} else {
if (method_exists($class, '__sleep')) {
if (!\is_array($sleep = $value->__sleep())) {
trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE);
$value = null;
goto handle_value;
}
$sleep = array_flip($sleep);
}
$arrayValue = (array) $value;
}
$proto = (array) $proto;
foreach ($arrayValue as $name => $v) {
$i = 0;
$n = (string) $name;
if ('' === $n || "\0" !== $n[0]) {
$c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass';
} elseif ('*' === $n[1]) {
$n = substr($n, 3);
$c = $reflector->getProperty($n)->class;
if ('Error' === $c) {
$c = 'TypeError';
} elseif ('Exception' === $c) {
$c = 'ErrorException';
}
} else {
$i = strpos($n, "\0", 2);
$c = substr($n, 1, $i - 1);
$n = substr($n, 1 + $i);
}
if (null !== $sleep) {
if (!isset($sleep[$n]) || ($i && $c !== $class)) {
continue;
}
$sleep[$n] = false;
}
if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) {
$properties[$c][$n] = $v;
}
}
if ($sleep) {
foreach ($sleep as $n => $v) {
if (false !== $v) {
trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE);
}
}
}
prepare_value:
$objectsPool[$value] = [$id = \count($objectsPool)];
$properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic);
++$objectsCount;
$objectsPool[$value] = [$id, $class, $properties, method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0)];
$value = new Reference($id);
handle_value:
if ($isRef) {
unset($value); // Break the hard reference created above
} elseif (!$valueIsStatic) {
$values[$k] = $value;
}
$valuesAreStatic = $valueIsStatic && $valuesAreStatic;
}
return $values;
}
public static function export($value, string $indent = '')
{
switch (true) {
case \is_int($value) || \is_float($value): return var_export($value, true);
case [] === $value: return '[]';
case false === $value: return 'false';
case true === $value: return 'true';
case null === $value: return 'null';
case '' === $value: return "''";
case $value instanceof \UnitEnum: return ltrim(var_export($value, true), '\\');
}
if ($value instanceof Reference) {
if (0 <= $value->id) {
return '$o['.$value->id.']';
}
if (!$value->count) {
return self::export($value->value, $indent);
}
$value = -$value->id;
return '&$r['.$value.']';
}
$subIndent = $indent.' ';
if (\is_string($value)) {
$code = sprintf("'%s'", addcslashes($value, "'\\"));
$code = preg_replace_callback("/((?:[\\0\\r\\n]|\u{202A}|\u{202B}|\u{202D}|\u{202E}|\u{2066}|\u{2067}|\u{2068}|\u{202C}|\u{2069})++)(.)/", function ($m) use ($subIndent) {
$m[1] = sprintf('\'."%s".\'', str_replace(
["\0", "\r", "\n", "\u{202A}", "\u{202B}", "\u{202D}", "\u{202E}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{202C}", "\u{2069}", '\n\\'],
['\0', '\r', '\n', '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', '\u{2069}', '\n"'."\n".$subIndent.'."\\'],
$m[1]
));
if ("'" === $m[2]) {
return substr($m[1], 0, -2);
}
if ('n".\'' === substr($m[1], -4)) {
return substr_replace($m[1], "\n".$subIndent.".'".$m[2], -2);
}
return $m[1].$m[2];
}, $code, -1, $count);
if ($count && str_starts_with($code, "''.")) {
$code = substr($code, 3);
}
return $code;
}
if (\is_array($value)) {
$j = -1;
$code = '';
foreach ($value as $k => $v) {
$code .= $subIndent;
if (!\is_int($k) || 1 !== $k - $j) {
$code .= self::export($k, $subIndent).' => ';
}
if (\is_int($k) && $k > $j) {
$j = $k;
}
$code .= self::export($v, $subIndent).",\n";
}
return "[\n".$code.$indent.']';
}
if ($value instanceof Values) {
$code = $subIndent."\$r = [],\n";
foreach ($value->values as $k => $v) {
$code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n";
}
return "[\n".$code.$indent.']';
}
if ($value instanceof Registry) {
return self::exportRegistry($value, $indent, $subIndent);
}
if ($value instanceof Hydrator) {
return self::exportHydrator($value, $indent, $subIndent);
}
throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', get_debug_type($value)));
}
private static function exportRegistry(Registry $value, string $indent, string $subIndent): string
{
$code = '';
$serializables = [];
$seen = [];
$prototypesAccess = 0;
$factoriesAccess = 0;
$r = '\\'.Registry::class;
$j = -1;
foreach ($value->classes as $k => $class) {
if (':' === ($class[1] ?? null)) {
$serializables[$k] = $class;
continue;
}
if (!Registry::$instantiableWithoutConstructor[$class]) {
if (is_subclass_of($class, 'Serializable') && !method_exists($class, '__unserialize')) {
$serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}';
} else {
$serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}';
}
if (is_subclass_of($class, 'Throwable')) {
$eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0";
$serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4);
}
continue;
}
$code .= $subIndent.(1 !== $k - $j ? $k.' => ' : '');
$j = $k;
$eol = ",\n";
$c = '['.self::export($class).']';
if ($seen[$class] ?? false) {
if (Registry::$cloneable[$class]) {
++$prototypesAccess;
$code .= 'clone $p'.$c;
} else {
++$factoriesAccess;
$code .= '$f'.$c.'()';
}
} else {
$seen[$class] = true;
if (Registry::$cloneable[$class]) {
$code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p';
} else {
$code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f';
$eol = '()'.$eol;
}
$code .= '('.substr($c, 1, -1).'))';
}
$code .= $eol;
}
if (1 === $prototypesAccess) {
$code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code);
}
if (1 === $factoriesAccess) {
$code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code);
}
if ('' !== $code) {
$code = "\n".$code.$indent;
}
if ($serializables) {
$code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')';
} else {
$code = '['.$code.']';
}
return '$o = '.$code;
}
private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string
{
$code = '';
foreach ($value->properties as $class => $properties) {
$code .= $subIndent.' '.self::export($class).' => '.self::export($properties, $subIndent.' ').",\n";
}
$code = [
self::export($value->registry, $subIndent),
self::export($value->values, $subIndent),
'' !== $code ? "[\n".$code.$subIndent.']' : '[]',
self::export($value->value, $subIndent),
self::export($value->wakeups, $subIndent),
];
return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')';
}
/**
* @param \ArrayIterator|\ArrayObject $value
* @param \ArrayIterator|\ArrayObject $proto
*/
private static function getArrayObjectProperties($value, $proto): array
{
$reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject';
$reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector);
$properties = [
$arrayValue = (array) $value,
$reflector->getMethod('getFlags')->invoke($value),
$value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator',
];
$reflector = $reflector->getMethod('setFlags');
$reflector->invoke($proto, \ArrayObject::STD_PROP_LIST);
if ($properties[1] & \ArrayObject::STD_PROP_LIST) {
$reflector->invoke($value, 0);
$properties[0] = (array) $value;
} else {
$reflector->invoke($value, \ArrayObject::STD_PROP_LIST);
$arrayValue = (array) $value;
}
$reflector->invoke($value, $properties[1]);
if ([[], 0, 'ArrayIterator'] === $properties) {
$properties = [];
} else {
if ('ArrayIterator' === $properties[2]) {
unset($properties[2]);
}
$properties = [$reflector->class => ["\0" => $properties]];
}
return [$arrayValue, $properties];
}
}

View File

@ -0,0 +1,152 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Internal;
use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class Hydrator
{
public static $hydrators = [];
public $registry;
public $values;
public $properties;
public $value;
public $wakeups;
public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups)
{
$this->registry = $registry;
$this->values = $values;
$this->properties = $properties;
$this->value = $value;
$this->wakeups = $wakeups;
}
public static function hydrate($objects, $values, $properties, $value, $wakeups)
{
foreach ($properties as $class => $vars) {
(self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects);
}
foreach ($wakeups as $k => $v) {
if (\is_array($v)) {
$objects[-$k]->__unserialize($v);
} else {
$objects[$v]->__wakeup();
}
}
return $value;
}
public static function getHydrator($class)
{
switch ($class) {
case 'stdClass':
return self::$hydrators[$class] = static function ($properties, $objects) {
foreach ($properties as $name => $values) {
foreach ($values as $i => $v) {
$objects[$i]->$name = $v;
}
}
};
case 'ErrorException':
return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException {
});
case 'TypeError':
return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error {
});
case 'SplObjectStorage':
return self::$hydrators[$class] = static function ($properties, $objects) {
foreach ($properties as $name => $values) {
if ("\0" === $name) {
foreach ($values as $i => $v) {
for ($j = 0; $j < \count($v); ++$j) {
$objects[$i]->attach($v[$j], $v[++$j]);
}
}
continue;
}
foreach ($values as $i => $v) {
$objects[$i]->$name = $v;
}
}
};
}
if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) {
throw new ClassNotFoundException($class);
}
$classReflector = new \ReflectionClass($class);
switch ($class) {
case 'ArrayIterator':
case 'ArrayObject':
$constructor = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']);
return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) {
foreach ($properties as $name => $values) {
if ("\0" !== $name) {
foreach ($values as $i => $v) {
$objects[$i]->$name = $v;
}
}
}
foreach ($properties["\0"] ?? [] as $i => $v) {
$constructor($objects[$i], $v);
}
};
}
if (!$classReflector->isInternal()) {
return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class);
}
if ($classReflector->name !== $class) {
return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name);
}
$propertySetters = [];
foreach ($classReflector->getProperties() as $propertyReflector) {
if (!$propertyReflector->isStatic()) {
$propertyReflector->setAccessible(true);
$propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']);
}
}
if (!$propertySetters) {
return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass');
}
return self::$hydrators[$class] = static function ($properties, $objects) use ($propertySetters) {
foreach ($properties as $name => $values) {
if ($setValue = $propertySetters[$name] ?? null) {
foreach ($values as $i => $v) {
$setValue($objects[$i], $v);
}
continue;
}
foreach ($values as $i => $v) {
$objects[$i]->$name = $v;
}
}
};
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Internal;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class Reference
{
public $id;
public $value;
public $count = 0;
public function __construct(int $id, $value = null)
{
$this->id = $id;
$this->value = $value;
}
}

View File

@ -0,0 +1,146 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Internal;
use Symfony\Component\VarExporter\Exception\ClassNotFoundException;
use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class Registry
{
public static $reflectors = [];
public static $prototypes = [];
public static $factories = [];
public static $cloneable = [];
public static $instantiableWithoutConstructor = [];
public $classes = [];
public function __construct(array $classes)
{
$this->classes = $classes;
}
public static function unserialize($objects, $serializables)
{
$unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector');
try {
foreach ($serializables as $k => $v) {
$objects[$k] = unserialize($v);
}
} finally {
ini_set('unserialize_callback_func', $unserializeCallback);
}
return $objects;
}
public static function p($class)
{
self::getClassReflector($class, true, true);
return self::$prototypes[$class];
}
public static function f($class)
{
$reflector = self::$reflectors[$class] ?? self::getClassReflector($class, true, false);
return self::$factories[$class] = \Closure::fromCallable([$reflector, 'newInstanceWithoutConstructor']);
}
public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null)
{
if (!($isClass = class_exists($class)) && !interface_exists($class, false) && !trait_exists($class, false)) {
throw new ClassNotFoundException($class);
}
$reflector = new \ReflectionClass($class);
if ($instantiableWithoutConstructor) {
$proto = $reflector->newInstanceWithoutConstructor();
} elseif (!$isClass || $reflector->isAbstract()) {
throw new NotInstantiableTypeException($class);
} elseif ($reflector->name !== $class) {
$reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, false, $cloneable);
self::$cloneable[$class] = self::$cloneable[$name];
self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name];
self::$prototypes[$class] = self::$prototypes[$name];
return self::$reflectors[$class] = $reflector;
} else {
try {
$proto = $reflector->newInstanceWithoutConstructor();
$instantiableWithoutConstructor = true;
} catch (\ReflectionException $e) {
$proto = $reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize') ? 'C:' : 'O:';
if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) {
$proto = null;
} else {
try {
$proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}');
} catch (\Exception $e) {
if (__FILE__ !== $e->getFile()) {
throw $e;
}
throw new NotInstantiableTypeException($class, $e);
}
if (false === $proto) {
throw new NotInstantiableTypeException($class);
}
}
}
if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !method_exists($class, '__sleep') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__serialize'))) {
try {
serialize($proto);
} catch (\Exception $e) {
throw new NotInstantiableTypeException($class, $e);
}
}
}
if (null === $cloneable) {
if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !method_exists($proto, '__wakeup') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize')))) {
throw new NotInstantiableTypeException($class);
}
$cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone');
}
self::$cloneable[$class] = $cloneable;
self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor;
self::$prototypes[$class] = $proto;
if ($proto instanceof \Throwable) {
static $setTrace;
if (null === $setTrace) {
$setTrace = [
new \ReflectionProperty(\Error::class, 'trace'),
new \ReflectionProperty(\Exception::class, 'trace'),
];
$setTrace[0]->setAccessible(true);
$setTrace[1]->setAccessible(true);
$setTrace[0] = \Closure::fromCallable([$setTrace[0], 'setValue']);
$setTrace[1] = \Closure::fromCallable([$setTrace[1], 'setValue']);
}
$setTrace[$proto instanceof \Exception]($proto, []);
}
return self::$reflectors[$class] = $reflector;
}
}

View File

@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter\Internal;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
class Values
{
public $values;
public function __construct(array $values)
{
$this->values = $values;
}
}

19
vendor/symfony/var-exporter/LICENSE vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2018-2022 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

38
vendor/symfony/var-exporter/README.md vendored Normal file
View File

@ -0,0 +1,38 @@
VarExporter Component
=====================
The VarExporter component allows exporting any serializable PHP data structure to
plain PHP code. While doing so, it preserves all the semantics associated with
the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`,
`__serialize`, `__unserialize`).
It also provides an instantiator that allows creating and populating objects
without calling their constructor nor any other methods.
The reason to use this component *vs* `serialize()` or
[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to
OPcache, the resulting code is significantly faster and more memory efficient
than using `unserialize()` or `igbinary_unserialize()`.
Unlike `var_export()`, this works on any serializable PHP value.
It also provides a few improvements over `var_export()`/`serialize()`:
* the output is PSR-2 compatible;
* the output can be re-indented without messing up with `\r` or `\n` in the data
* missing classes throw a `ClassNotFoundException` instead of being unserialized to
`PHP_Incomplete_Class` objects;
* references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator`
instances are preserved;
* `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes
throw an exception when being serialized (their unserialized version is broken
anyway, see https://bugs.php.net/76737).
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/var_exporter.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@ -0,0 +1,115 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarExporter;
use Symfony\Component\VarExporter\Exception\ExceptionInterface;
use Symfony\Component\VarExporter\Internal\Exporter;
use Symfony\Component\VarExporter\Internal\Hydrator;
use Symfony\Component\VarExporter\Internal\Registry;
use Symfony\Component\VarExporter\Internal\Values;
/**
* Exports serializable PHP values to PHP code.
*
* VarExporter allows serializing PHP data structures to plain PHP code (like var_export())
* while preserving all the semantics associated with serialize() (unlike var_export()).
*
* By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize().
*
* @author Nicolas Grekas <p@tchwork.com>
*/
final class VarExporter
{
/**
* Exports a serializable PHP value to PHP code.
*
* @param mixed $value The value to export
* @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise
* @param bool &$classes Classes found in the value are added to this list as both keys and values
*
* @throws ExceptionInterface When the provided value cannot be serialized
*/
public static function export($value, bool &$isStaticValue = null, array &$foundClasses = []): string
{
$isStaticValue = true;
if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) {
return Exporter::export($value);
}
$objectsPool = new \SplObjectStorage();
$refsPool = [];
$objectsCount = 0;
try {
$value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0];
} finally {
$references = [];
foreach ($refsPool as $i => $v) {
if ($v[0]->count) {
$references[1 + $i] = $v[2];
}
$v[0] = $v[1];
}
}
if ($isStaticValue) {
return Exporter::export($value);
}
$classes = [];
$values = [];
$states = [];
foreach ($objectsPool as $i => $v) {
[, $class, $values[], $wakeup] = $objectsPool[$v];
$foundClasses[$class] = $classes[] = $class;
if (0 < $wakeup) {
$states[$wakeup] = $i;
} elseif (0 > $wakeup) {
$states[-$wakeup] = [$i, array_pop($values)];
$values[] = [];
}
}
ksort($states);
$wakeups = [null];
foreach ($states as $k => $v) {
if (\is_array($v)) {
$wakeups[-$v[0]] = $v[1];
} else {
$wakeups[] = $v;
}
}
if (null === $wakeups[0]) {
unset($wakeups[0]);
}
$properties = [];
foreach ($values as $i => $vars) {
foreach ($vars as $class => $values) {
foreach ($values as $name => $v) {
$properties[$class][$name][$i] = $v;
}
}
}
if ($classes || $references) {
$value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups);
} else {
$isStaticValue = true;
}
return Exporter::export($value);
}
}

View File

@ -0,0 +1,32 @@
{
"name": "symfony/var-exporter",
"type": "library",
"description": "Allows exporting any serializable PHP data structure to plain PHP code",
"keywords": ["export", "serialize", "instantiate", "hydrate", "construct", "clone"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"symfony/var-dumper": "^4.4.9|^5.0.9|^6.0"
},
"autoload": {
"psr-4": { "Symfony\\Component\\VarExporter\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev"
}

8
vendor/taoser/think-addons/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
vendor/taoser/think-addons/.idea/modules.xml generated vendored Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/think-addons.iml" filepath="$PROJECT_DIR$/.idea/think-addons.iml" />
</modules>
</component>
</project>

4
vendor/taoser/think-addons/.idea/php.xml generated vendored Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpProjectSharedConfiguration" php_language_level="7.1" />
</project>

12
vendor/taoser/think-addons/.idea/think-addons.iml generated vendored Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="taoser\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
vendor/taoser/think-addons/.idea/vcs.xml generated vendored Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -28,7 +28,9 @@ php think addons:config
'testhook'=>'test' // 键为钩子名称,用于在业务中自定义钩子处理,值为实现该钩子的插件,
// 多个插件可以用数组也可以用逗号分割
],
'route' => [],
'route' => [
"/demo" => "demo/test/demo", // 键为请求中的路由地址,值为插件/控制器/方法
],
'service' => [],
];
```

View File

@ -12,7 +12,8 @@
"php": ">=7.1.0",
"topthink/framework": "^6.0",
"topthink/think-view": "^1.0",
"topthink/think-helper": "^3.0.0"
"topthink/think-helper": "^3.0.0",
"symfony/var-exporter": "^5.4"
},
"autoload": {
"psr-4": {

View File

@ -7,6 +7,7 @@ namespace taoser\addons;
use app\BaseController;
use think\App;
use think\helper\Str;
use think\facade\Lang;
use think\facade\Config;
use think\facade\View;

View File

@ -29,16 +29,14 @@ class Service extends \think\Service
// 自动载入插件
$this->autoload();
// 加载系统语言包
Lang::load([
$this->app->getRootPath() . '/vendor/taoser/think-addons/src/lang/zh-cn.php'
]);
$this->loadLang();
// 加载自定义路由
$this->loadRoutes();
// 加载插件事件
$this->loadEvent();
// 加载插件系统服务
$this->loadService();
//加载配置
// 加载配置
$this->loadConfig();
}
@ -67,7 +65,7 @@ class Service extends \think\Service
foreach ($val['rule'] as $k => $rule) {
[$addon, $controller, $action] = explode('/', $rule);
$rules[$k] = [
'addons' => $addon,
'addon' => $addon,
'controller' => $controller,
'action' => $action,
'indomain' => 1,
@ -88,7 +86,7 @@ class Service extends \think\Service
->name($key)
->completeMatch(true)
->append([
'addons' => $addon,
'addon' => $addon,
'controller' => $controller,
'action' => $action
]);
@ -97,6 +95,13 @@ class Service extends \think\Service
});
}
private function loadLang()
{
Lang::load([
$this->app->getRootPath() . '/vendor/taoser/think-addons/src/lang/zh-cn.php'
]);
}
/**
* 自定义路由文件
*/

View File

@ -10,6 +10,9 @@ use think\facade\Cache;
use think\helper\{
Str, Arr
};
use Symfony\Component\VarExporter\VarExporter;
define('DS', DIRECTORY_SEPARATOR);
\think\Console::starting(function (\think\Console $console) {
$console->addCommands([
@ -22,9 +25,7 @@ spl_autoload_register(function ($class) {
$class = ltrim($class, '\\');
//$dir = app()->getRootPath();
$app = new App();
$dir = $app::getRootPath();
$dir = App::getRootPath();
$namespace = 'addons';
if (strpos($class, $namespace) === 0) {
@ -41,12 +42,9 @@ spl_autoload_register(function ($class) {
include $dir;
return true;
}
return false;
}
return false;
});
if (!function_exists('hook')) {
@ -82,49 +80,6 @@ if (!function_exists('get_addons_info')) {
}
}
/**
* 设置基础配置信息
* @param string $name 插件名
* @param array $array 配置数据
* @return boolean
* @throws Exception
*/
if (!function_exists('set_addons_info')) {
function set_addons_info($name, $array)
{
$service = new Service(App::instance()); // 获取service 服务
$addons_path = $service->getAddonsPath();
// 插件列表
$file = $addons_path . $name . DIRECTORY_SEPARATOR . 'info.ini';
$addon = get_addons_instance($name);
$array = $addon->setInfo($name, $array);
$array['status'] ? $addon->enabled() : $addon->disabled();
if (!isset($array['name']) || !isset($array['title']) || !isset($array['version'])) {
throw new Exception("Failed to write plugin config");
}
$res = array();
foreach ($array as $key => $val) {
if (is_array($val)) {
$res[] = "[$key]";
foreach ($val as $k => $v)
$res[] = "$k = " . (is_numeric($v) ? $v : $v);
} else
$res[] = "$key = " . (is_numeric($val) ? $val : $val);
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, implode("\n", $res) . "\n");
fclose($handle);
//清空当前配置缓存
Config::set($array, "addon_{$name}_info");
Cache::delete('addonslist');
} else {
throw new Exception("File does not have write permission");
}
return true;
}
}
if (!function_exists('get_addons_instance')) {
/**
@ -181,45 +136,6 @@ if (!function_exists('get_addons_class')) {
}
}
if (!function_exists('get_addons_config')) {
/**
* 获取插件的配置
* @param string $name 插件名
* @return mixed|null
*/
function get_addons_config($name)
{
$addon = get_addons_instance($name);
if (!$addon) {
return [];
}
return $addon->getConfig($name);
}
}
if (!function_exists('set_addons_config')) {
function set_addons_config($name, $array)
{
$service = new Service(App::instance()); // 获取service 服务
$addons_path = $service->getAddonsPath();
// 插件列表
$file = $addons_path . $name . DIRECTORY_SEPARATOR . 'config.php';
if (!is_writable($file)) {
throw new \Exception(lang("addons.php File does not have write permission"));
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, "<?php\n\n" . "return " . var_export($array, TRUE) . ";");
fclose($handle);
} else {
throw new Exception(lang("File does not have write permission"));
}
return true;
}
}
if (!function_exists('addons_url')) {
/**
* 插件显示内容里生成访问插件的url
@ -264,3 +180,107 @@ if (!function_exists('addons_url')) {
}
}
if (!function_exists('set_addons_info')) {
/**
* 设置基础配置信息
* @param string $name 插件名
* @param array $array 配置数据
* @return boolean
* @throws Exception
*/
function set_addons_info($name, $array)
{
$service = new Service(App::instance()); // 获取service 服务
$addons_path = $service->getAddonsPath();
// 插件列表
$file = $addons_path . $name . DIRECTORY_SEPARATOR . 'info.ini';
$addon = get_addons_instance($name);
$array = $addon->setInfo($name, $array);
$array['status'] ? $addon->enabled() : $addon->disabled();
if (!isset($array['name']) || !isset($array['title']) || !isset($array['version'])) {
throw new Exception("Failed to write plugin config");
}
$res = array();
foreach ($array as $key => $val) {
if (is_array($val)) {
$res[] = "[$key]";
foreach ($val as $k => $v)
$res[] = "$k = " . (is_numeric($v) ? $v : $v);
} else
$res[] = "$key = " . (is_numeric($val) ? $val : $val);
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, implode("\n", $res) . "\n");
fclose($handle);
//清空当前配置缓存
Config::set($array, "addon_{$name}_info");
Cache::delete('addonslist');
} else {
throw new Exception("File does not have write permission");
}
return true;
}
}
if (!function_exists('get_addons_config')) {
/**
* 获取插件的配置
* @param string $name 插件名
* @return mixed|null
*/
function get_addons_config($name)
{
$addon = get_addons_instance($name);
if (!$addon) {
return [];
}
return $addon->getConfig($name);
}
}
if (!function_exists('set_addons_config')) {
/**
* 设置插件配置文件
* @param string $name
* @param array $array
* @return bool
* @throws Exception
*/
function set_addons_config(string $name, array $array)
{
$service = new Service(App::instance()); // 获取service 服务
$addons_path = $service->getAddonsPath();
// 插件列表
$file = $addons_path . $name . DIRECTORY_SEPARATOR . 'config.php';
if (!is_writable($file)) {
throw new \Exception(lang("addons.php File does not have write permission"));
}
if ($handle = fopen($file, 'w')) {
fwrite($handle, "<?php\n\n" . "return " . VarExporter::export($array) . ";\n");
fclose($handle);
} else {
throw new Exception(lang("File does not have write permission"));
}
return true;
}
}
if (!function_exists('get_addons_menu')) {
/**
* 获取插件菜单
* @param $name
* @return array|mixed
*/
function get_addons_menu($name)
{
$menu = app()->getRootPath() . 'addons' . DS . $name . DS . 'menu.php';
if(file_exists($menu)){
return include_once $menu;
}
return [];
}
}

View File

@ -94,60 +94,58 @@ class Http
*/
public static function input($recv_buffer, TcpConnection $connection)
{
static $input = array();
static $input = [];
if (!isset($recv_buffer[512]) && isset($input[$recv_buffer])) {
return $input[$recv_buffer];
}
$crlf_pos = \strpos($recv_buffer, "\r\n\r\n");
if (false === $crlf_pos) {
// Judge whether the package length exceeds the limit.
if ($recv_len = \strlen($recv_buffer) >= 16384) {
if (\strlen($recv_buffer) >= 16384) {
$connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true);
return 0;
}
return 0;
}
$head_len = $crlf_pos + 4;
$length = $crlf_pos + 4;
$method = \strstr($recv_buffer, ' ', true);
if ($method === 'GET' || $method === 'OPTIONS' || $method === 'HEAD' || $method === 'DELETE') {
if (!isset($recv_buffer[512])) {
$input[$recv_buffer] = $head_len;
if (\count($input) > 512) {
unset($input[key($input)]);
}
}
return $head_len;
} else if ($method !== 'POST' && $method !== 'PUT' && $method !== 'PATCH') {
if (!\in_array($method, ['GET', 'POST', 'OPTIONS', 'HEAD', 'DELETE', 'PUT', 'PATCH'])) {
$connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
return 0;
}
$header = \substr($recv_buffer, 0, $crlf_pos);
$length = false;
if ($pos = \strpos($header, "\r\nContent-Length: ")) {
$length = $head_len + (int)\substr($header, $pos + 18, 10);
$length = $length + (int)\substr($header, $pos + 18, 10);
$has_content_length = true;
} else if (\preg_match("/\r\ncontent-length: ?(\d+)/i", $header, $match)) {
$length = $head_len + $match[1];
$length = $length + $match[1];
$has_content_length = true;
} else {
$has_content_length = false;
if (false !== stripos($header, "\r\nTransfer-Encoding:")) {
$connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
return 0;
}
}
if ($length !== false) {
if (!isset($recv_buffer[512])) {
$input[$recv_buffer] = $length;
if (\count($input) > 512) {
unset($input[key($input)]);
}
}
if ($has_content_length) {
if ($length > $connection->maxPackageSize) {
$connection->close("HTTP/1.1 413 Request Entity Too Large\r\n\r\n", true);
return 0;
}
return $length;
}
$connection->close("HTTP/1.1 400 Bad Request\r\n\r\n", true);
return 0;
if (!isset($recv_buffer[512])) {
$input[$recv_buffer] = $length;
if (\count($input) > 512) {
unset($input[key($input)]);
}
}
return $length;
}
/**
@ -221,6 +219,7 @@ class Http
$file = $response->file['file'];
$offset = $response->file['offset'];
$length = $response->file['length'];
clearstatcache();
$file_size = (int)\filesize($file);
$body_len = $length > 0 ? $length : $file_size - $offset;
$response->withHeaders(array(

View File

@ -520,6 +520,9 @@ class Request
{
$file = [];
$boundary = "\r\n$boundary";
if (\strlen($this->_buffer) < $section_start_offset) {
return 0;
}
$section_end_offset = \strpos($this->_buffer, $boundary, $section_start_offset);
if (!$section_end_offset) {
return 0;

View File

@ -33,7 +33,7 @@ class Worker
*
* @var string
*/
const VERSION = '4.1.0';
const VERSION = '4.1.3';
/**
* Status starting.
@ -548,11 +548,13 @@ class Worker
{
static::checkSapiEnv();
static::init();
static::lock();
static::parseCommand();
static::daemonize();
static::initWorkers();
static::installSignal();
static::saveMasterPid();
static::lock(\LOCK_UN);
static::displayUI();
static::forkWorkers();
static::resetStd();
@ -629,24 +631,16 @@ class Worker
*
* @return void
*/
protected static function lock()
protected static function lock($flag = \LOCK_EX)
{
$fd = \fopen(static::$_startFile, 'r');
if ($fd && !flock($fd, LOCK_EX)) {
static::log('Workerman['.static::$_startFile.'] already running.');
exit;
static $fd;
if (\DIRECTORY_SEPARATOR !== '/') {
return;
}
$fd = $fd ?: \fopen(static::$pidFile . '.lock', 'a+');
if ($fd) {
flock($fd, $flag);
}
}
/**
* Unlock.
*
* @return void
*/
protected static function unlock()
{
$fd = \fopen(static::$_startFile, 'r');
$fd && flock($fd, \LOCK_UN);
}
/**

View File

@ -81,7 +81,7 @@
</a>
{if condition="$article.user.id eq $vo.user.id"}<span>({:lang('poster')})</span>{/if}
</div>
<div class="detail-hits"><span class="post-time" data="{$vo.create_time}"></span><span>{$vo.user.city}</span></div>
<div class="detail-hits"><span class="post-time" data="{$vo.create_time}"></span>{:hook('ipShow',$vo.user.city)}</div>
{if $vo.cai == 1}<i class="iconfont icon-caina" title="最佳答案"></i>{/if}
</div>
<div class="detail-body jieda-body photos">{$vo.content|raw}</div>

View File

@ -130,7 +130,7 @@
</a>
{if condition="$article.user.id eq $vo.user.id"}<span>({:lang('poster')})</span>{/if}
</div>
<div class="detail-hits"><span class="post-time" data="{$vo.create_time}"></span><span>{$vo.user.city}</span></div>
<div class="detail-hits"><span class="post-time" data="{$vo.create_time}"></span>{:hook('ipShow',$vo.user.city)}</div>
{if $vo.cai == 1}<i class="iconfont icon-caina" title="最佳答案"></i>{/if}
</div>
<div class="detail-body jieda-body photos">{$vo.content|raw}</div>

View File

@ -47,8 +47,8 @@
</div>
<div class="detail-hits">
<!--span style="padding-right: 10px; color: #FF7200">悬赏60飞吻</span-->
<span class="post-time" data="{$article.create_time}" style="padding-top: 5px;"></span>
<span>{$article.user.city}</span>
<span class="post-time" data="{$article.create_time}" style="padding-top: 5px;"></span>
{:hook('ipShow',$article.user.city)}
</div>
</div>
<hr>
@ -101,7 +101,7 @@
</a>
{if condition="$article.user.id eq $vo.user.id"}<span>({:lang('poster')})</span>{/if}
</div>
<div class="detail-hits"><span class="post-time" data="{$vo.create_time}"></span><span>{$vo.user.city}</span></div>
<div class="detail-hits"><span class="post-time" data="{$vo.create_time}"></span>{:hook('ipShow',$vo.user.city)}</span></div>
{if $vo.cai == 1}<i class="iconfont icon-caina" title="最佳答案"></i>{/if}
</div>
<div class="detail-body jieda-body photos">{$vo.content|raw}</div>

View File

@ -34,7 +34,7 @@
<p class="fly-home-info">
<i class="iconfont icon-kiss" title="飞吻"></i><span style="color: #FF7200;">{$u.point} {:lang('accumulate points')}</span>
<i class="iconfont icon-shijian"></i><span>{$u.create_time|date='Y-m-d'} {:lang('join')}</span>
<i class="iconfont icon-chengshi"></i><span>{:session('user_id') ? '来自'.$u.city: lang('log in to view')}</span>
<i class="iconfont icon-chengshi"></i>{if session('user_id')}<span>来自</span>{:hook('ipShow',$u.city)} {else /} lang('log in to view') {/if}
</p>
<p class="fly-home-sign">{$u.sign ? $u.sign|raw : lang('it is not signed yet')}</p>
</div>