first commit
This commit is contained in:
151
extend/system/File.php
Normal file
151
extend/system/File.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace system;
|
||||
|
||||
/**
|
||||
* 文件操作类
|
||||
* @author meystack
|
||||
*/
|
||||
class File
|
||||
{
|
||||
|
||||
/**
|
||||
* 递归创建文件夹
|
||||
* @param string $dirs
|
||||
*/
|
||||
public static function mkDirs(string $dirs)
|
||||
{
|
||||
if (!is_dir($dirs)) {
|
||||
self::mkDirs(dirname($dirs));
|
||||
mkdir($dirs, 0755);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归删除文件夹
|
||||
* @param string $dirs
|
||||
* @return mixed
|
||||
*/
|
||||
public static function rmDirs(string $dirs)
|
||||
{
|
||||
if (!is_dir($dirs)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$files = scandir($dirs);
|
||||
foreach ($files as $file) {
|
||||
if ($file == '.' || $file == '..') {
|
||||
continue;
|
||||
}
|
||||
if (is_dir($dirs . '/' . $file)) {
|
||||
self::rmDirs($dirs . '/' . $file);
|
||||
} else {
|
||||
unlink($dirs . '/' . $file);
|
||||
}
|
||||
}
|
||||
rmdir($dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前文件夹大小
|
||||
* @param string $dirs
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getDirSize(string $dirs)
|
||||
{
|
||||
$handle = opendir($dirs);
|
||||
$size = 0;
|
||||
while (false !== ($FolderOrFile = readdir($handle))) {
|
||||
if ($FolderOrFile != "." && $FolderOrFile != "..") {
|
||||
if (is_dir("$dirs/$FolderOrFile")) {
|
||||
$size += self::getDirSize("$dirs/$FolderOrFile");
|
||||
} else {
|
||||
$size += filesize("$dirs/$FolderOrFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
return $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件夹文件列表
|
||||
* @param string $dirs
|
||||
* @return array
|
||||
*/
|
||||
public static function getDirFile(string $dirs): array
|
||||
{
|
||||
$handle = opendir($dirs);
|
||||
$file = [];
|
||||
while (false !== ($FolderOrFile = readdir($handle))) {
|
||||
if ($FolderOrFile != "." && $FolderOrFile != "..") {
|
||||
if (is_dir("$dirs/$FolderOrFile")) {
|
||||
$file[] = self::getDirFile("$dirs/$FolderOrFile");
|
||||
} else {
|
||||
$file[] = "$dirs/$FolderOrFile";
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 [app, public] 的路径
|
||||
* @param string $name
|
||||
* @return array
|
||||
*/
|
||||
public static function getCopyDirs(string $name): array
|
||||
{
|
||||
return [
|
||||
plugin_path($name) . 'app',
|
||||
plugin_path($name) . 'public'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件比较
|
||||
* @param $source
|
||||
* @param $destFileOrPath
|
||||
* @param string $prefix
|
||||
* @param bool $onlyFiles
|
||||
* @return mixed
|
||||
*/
|
||||
public static function mutexCompare($source, $destFileOrPath, string $prefix = '', bool $onlyFiles = false): array
|
||||
{
|
||||
$list = [];
|
||||
$destFileOrPath = $destFileOrPath ?: root_path();
|
||||
if (!is_array($source) && is_file($source) && is_file($destFileOrPath)) {
|
||||
return md5_file($source) !== md5_file($destFileOrPath);
|
||||
}
|
||||
|
||||
foreach ($source as $filesPath) {
|
||||
if (is_dir($filesPath)) {
|
||||
$files = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($filesPath, \FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if ($file->isFile()) {
|
||||
$filePath = $file->getPathname();
|
||||
$appPath = str_replace($prefix, '', $filePath);
|
||||
$destPath = $destFileOrPath . $appPath;
|
||||
if ($onlyFiles) {
|
||||
if (is_file($destPath)) {
|
||||
if (md5_file($filePath) != md5_file($destPath)) {
|
||||
$list[] = $appPath;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$list[] = $appPath;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
659
extend/system/Form.php
Normal file
659
extend/system/Form.php
Normal file
@@ -0,0 +1,659 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin 极速开发框架 [基于WebMan开发]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin.net High Speed Development Framework
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: meystack <coolsec@foxmail.com> Apache2 License
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace system;
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 表单生成器
|
||||
* SAPHP框架专用
|
||||
*/
|
||||
|
||||
class Form extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return 'system\FormBuilder';
|
||||
}
|
||||
}
|
||||
|
||||
class FormBuilder
|
||||
{
|
||||
|
||||
/**
|
||||
* Item宽度
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $width = 100;
|
||||
|
||||
/**
|
||||
* 标签宽度
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $labelwidth = 110;
|
||||
|
||||
/**
|
||||
* 公用属性
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $attrs = [
|
||||
'type',
|
||||
'name',
|
||||
'min',
|
||||
'max',
|
||||
'maxlength',
|
||||
'required',
|
||||
'readonly',
|
||||
'disabled',
|
||||
'placeholder',
|
||||
];
|
||||
|
||||
public $replace = [];
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* 表单类型
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $formtype = true;
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return object|FormBuilder|null
|
||||
*/
|
||||
public static function instance(array $options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始生成元素
|
||||
*
|
||||
* @param array $data
|
||||
* @param bool $formType
|
||||
* @return string
|
||||
*/
|
||||
public function itemElem(array $data = [], bool $formType = true): string
|
||||
{
|
||||
|
||||
$this->formtype = $formType;
|
||||
|
||||
if ($data['tag'] == 'tab') {
|
||||
return $this->tab($data);
|
||||
}
|
||||
|
||||
if ($data['tag'] == 'grid') {
|
||||
return $this->grid($data);
|
||||
}
|
||||
|
||||
$itemHtml = '<div class="layui-form-item" ';
|
||||
|
||||
if (isset($data['width']) && $data['width']) {
|
||||
if ($data['width'] != $this->width) {
|
||||
$itemHtml .= 'style="width:' . $data['width'] . '%;"';
|
||||
}
|
||||
}
|
||||
|
||||
$itemHtml .= '>' . PHP_EOL;
|
||||
if (isset($data['label'])) {
|
||||
$itemHtml .= $this->label($data['label'], $data) . PHP_EOL;
|
||||
}
|
||||
|
||||
$itemHtml .= $this->block($data) . PHP_EOL;
|
||||
$itemHtml .= '</div>' . PHP_EOL;
|
||||
|
||||
return $itemHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成Label标签
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function label(string $text, array $data = []): string
|
||||
{
|
||||
$label = '<label class="layui-form-label';
|
||||
if ($data['labelhide']) {
|
||||
$label .= ' layui-hide';
|
||||
}
|
||||
|
||||
$label .= '"';
|
||||
if ($data['labelwidth'] && $data['labelwidth'] != $this->labelwidth) {
|
||||
$label .= ' style="width:' . $data['labelwidth'] . 'px;"';
|
||||
}
|
||||
$label .= '>';
|
||||
if (isset($data['required']) && $data['required']) {
|
||||
$label .= '<font color="red">* </font>';
|
||||
}
|
||||
|
||||
return $label .= $text . '</label>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BLOCK区块
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function block(array $data = []): string
|
||||
{
|
||||
$block = '<div class="layui-input-block"';
|
||||
|
||||
if (isset($data['labelhide'])) {
|
||||
if ($data['labelhide']) {
|
||||
$style = 'margin-left:0';
|
||||
} else {
|
||||
if ($data['labelwidth'] && $data['labelwidth'] != $this->labelwidth) {
|
||||
$style = 'margin-left:' . ($data['labelwidth'] + 30) . 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($style)) {
|
||||
$block .= ' style="' . $style . '"';
|
||||
}
|
||||
|
||||
$block .= '>';
|
||||
$block .= call_user_func([Form::instance(), $data['tag']], $data);
|
||||
$block .= '</div>';
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取input
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function input(array $data = []): string
|
||||
{
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
return '<input class="layui-input" ' . $this->attributes($data) . $value . ' >';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多行编辑
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function textarea(array $data = []): string
|
||||
{
|
||||
$value = $this->formtype ? '{$data.' . $data['name'] . '}' : '';
|
||||
return '<textarea class="layui-textarea"' . $this->attributes($data) . ' >' . $value . '</textarea>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单选框
|
||||
*
|
||||
* @param array $data
|
||||
* @return string|string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function radio(array $data = [])
|
||||
{
|
||||
return $this->radioCheckSelect($data,'radio');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多选框
|
||||
*
|
||||
* @param array $data
|
||||
* @return string|string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function checkbox(array $data = [])
|
||||
{
|
||||
if (!$this->formtype) {
|
||||
throw new \Exception('多选框不支持生成内置表单');
|
||||
}
|
||||
return $this->radioCheckSelect($data,'checkbox','[]');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下拉框
|
||||
*
|
||||
* @param array $data
|
||||
* @return string|string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function select(array $data = [])
|
||||
{
|
||||
return $this->radioCheckSelect($data,'select');
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证选项
|
||||
*
|
||||
* @param array $options
|
||||
* @return string|string[]|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function validOptions(array $options = [])
|
||||
{
|
||||
if (!is_array($options) || !$options) {
|
||||
throw new \Exception("Options is Empty", 1);
|
||||
}
|
||||
|
||||
$export = var_exports($options, true);
|
||||
return preg_replace('/\s+/', '', $export);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取PHP代码
|
||||
*
|
||||
* @param [type] $argc
|
||||
* @param [type] $options
|
||||
* @return string
|
||||
*/
|
||||
public function getVarPHPList($argc = null, $options = null): string
|
||||
{
|
||||
return PHP_EOL . "<php>$$argc = $options;</php>";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $type
|
||||
* @param string $attr
|
||||
* @return string|string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function radioCheckSelect(array $data = [], string $type = '', string $attr = '' )
|
||||
{
|
||||
$options = $this->validOptions($data['options']);
|
||||
$varName = ucfirst($data['name']).'_LIST';
|
||||
$getAttr = $this->attributes($data,$attr);
|
||||
$varHtml = $this->getVarPHPList($varName, $options);
|
||||
$varHtml .= read_file($this->getHtmlTpl($type));
|
||||
|
||||
$this->replace = [
|
||||
'varlist' => $varName,
|
||||
'field' => $data['name'],
|
||||
'attributes' => $getAttr,
|
||||
];
|
||||
|
||||
foreach ($this->replace as $key => $value) {
|
||||
$varHtml = str_replace("{%$key%}", $value, $varHtml);
|
||||
}
|
||||
|
||||
return $varHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function date(array $data = []): string
|
||||
{
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
return '<input class="layui-input" lay-datetime="" ' . $this->attributes($data) . $value . ' >';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取颜色选择器
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function colorpicker(array $data = []): string
|
||||
{
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
|
||||
if (!$this->formtype) {
|
||||
throw new \Exception('颜色选择器不支持生成内置表单');
|
||||
}
|
||||
|
||||
return <<<Eof
|
||||
<input class="layui-input layui-hide" {$this->attributes($data)} {$value} >
|
||||
<div lay-colorpicker="{$data['name']}"></div>
|
||||
Eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取滑块
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function slider(array $data = []): string
|
||||
{
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
return <<<Eof
|
||||
<input class="layui-input layui-hide" name="{$data['name']}" {$value} >
|
||||
<div class="lay-slider" lay-slider="{$data['name']}" {$this->attributes($data)} ></div>
|
||||
Eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取评分
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function rate(array $data = []): string
|
||||
{
|
||||
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
|
||||
if (!$this->formtype) {
|
||||
throw new \Exception("评分组件不支持生成内置表单");
|
||||
}
|
||||
|
||||
return <<<Eof
|
||||
<input class="layui-input layui-hide" name="{$data['name']}" {$value} >
|
||||
<div lay-rate="{$data['name']}" {$this->attributes($data)} ></div>
|
||||
Eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取开关
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function switch(array $data = []): string
|
||||
{
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
$param = '$data.' . $data['name'];
|
||||
return <<<Eof
|
||||
<input type="hidden" type="checkbox" name="{$data['name']}" value="0" />
|
||||
<input type="checkbox" name="{$data['name']}" value="1" <eq name="{$param}" value="1" > checked </eq> lay-skin="switch" />
|
||||
Eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取级联选择器
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function cascader(array $data = [])
|
||||
{
|
||||
if (!$this->formtype) {
|
||||
throw new \Exception("级联选择器不支持生成内置表单");
|
||||
}
|
||||
$value = 'value="{$data.' . $data['name'] . '}"';
|
||||
return <<<Eof
|
||||
<input type="text" id="{$data['name']}" class="layui-hide" lay-cascader="" {$this->attributes($data)} {$value} />
|
||||
Eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取富文本
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function editor(array $data = []): string
|
||||
{
|
||||
if (!$this->formtype) {
|
||||
throw new \Exception("富文本不支持生成内置表单");
|
||||
}
|
||||
// 非INPUT表单 值
|
||||
$value = '{$data.' . $data['name'] . '}';
|
||||
return <<<Eof
|
||||
<textarea id="{$data['name']}" {$data['editorType']} class="layui-hide" {$this->attributes($data)} type="layui-textarea" >{$value}</textarea>
|
||||
Eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传模板
|
||||
*
|
||||
* @param array $data
|
||||
* @return false|string|string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function upload(array $data = [])
|
||||
{
|
||||
|
||||
if (!$this->formtype && ($data['uploadtype'] == 'multiple' || $data['uploadtype'] == 'images')) {
|
||||
throw new \Exception("上传组件仅支持 File类型 生成内置表单");
|
||||
}
|
||||
|
||||
$value = $this->formtype ? '{$data.' . $data['name'] . '}' : '';
|
||||
$varHtml = read_file($this->getHtmlTpl($data['uploadtype']));
|
||||
$this->replace = [
|
||||
'value' => $value,
|
||||
'field' => $data['name'],
|
||||
'accept' => $data['data_accept'],
|
||||
'size' => (string)$data['data_size'],
|
||||
];
|
||||
|
||||
foreach ($this->replace as $key => $value) {
|
||||
$varHtml = str_replace("{%$key%}", $value, $varHtml);
|
||||
}
|
||||
|
||||
return $varHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取TAGS模板
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function tags(array $data = []): string
|
||||
{
|
||||
$value = 'value="{$data.' . $data['name'] . '}"';
|
||||
return '<input type="text" lay-tags="" id="' . $data['name'] . '" name="' . $data['name'] .'" '. $value .' class="layui-input" >';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JSON模板
|
||||
*
|
||||
* @param array $data
|
||||
* @return false|string|string[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function json(array $data = [])
|
||||
{
|
||||
if (!$this->formtype) {
|
||||
throw new \Exception("JSON组件不支持生成内置表单");
|
||||
}
|
||||
|
||||
$value = $this->formtype ? 'value="{$data.' . $data['name'] . '}"' : '';
|
||||
$jsonHtml = read_file($this->getHtmlTpl($data['tag']));
|
||||
|
||||
$this->replace = [
|
||||
'value' => $value,
|
||||
'field' => $data['name'],
|
||||
];
|
||||
|
||||
foreach ($this->replace as $key => $value) {
|
||||
$jsonHtml = str_replace("{%$key%}", $value, $jsonHtml);
|
||||
}
|
||||
|
||||
return $jsonHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提示器
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function tips(array $data = []): string
|
||||
{
|
||||
return '<div class="layui-input-inline"><i class="layui-icon layui-icon-about" lay-tips="' . $data['msg'] . '" data-offset="' . $data['offset'] . '"></i></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取便签
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function note(array $data = []): string
|
||||
{
|
||||
return '<blockquote class="layui-elem-quote">' . $data['textarea'] . '</blockquote>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取横线
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function subtraction(array $data = []): string
|
||||
{
|
||||
return '<hr class="' . $data['border'] . '">';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取行高
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function space(array $data = []): string
|
||||
{
|
||||
return '<div style="height:' . $data['height'] . 'px;"></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取选项卡
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function tab(array $data = []): string
|
||||
{
|
||||
$tabHtml = '<div id="layui-tab" id="' . $data['name'] . '" class="layui-tab layui-tab-brief">';
|
||||
$tabHtml .= '<ul class="layui-tab-title">';
|
||||
$tabContent = '';
|
||||
foreach ($data['options'] as $key => $option) {
|
||||
$tabHtml .= '<li class="' . ($option['checked'] ? 'layui-this' : '') . '">' . $option['title'] . '</li>';
|
||||
$tabContent .= '<div class="layui-tab-item ' . ($option['checked'] ? 'layui-show ' : '') . '" data-index="' . $key . '">';
|
||||
|
||||
foreach ($data['children'][$key] as $children) {
|
||||
foreach ($children as $elem) {
|
||||
$tabContent .= $this->itemElem($elem);
|
||||
}
|
||||
}
|
||||
|
||||
$tabContent .= '</div>';
|
||||
}
|
||||
|
||||
$tabHtml .= '</ul>';
|
||||
$tabHtml .= '<div class="layui-tab-content">' . $tabContent . '</div>';
|
||||
$tabHtml .= '</div>';
|
||||
return $tabHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取布局组件
|
||||
*
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function grid(array $data = []): string
|
||||
{
|
||||
$gridHtml = '<div class="layui-form-item layui-row" >';
|
||||
$col = 12 / $data['column'];
|
||||
for ($key=0; $key < $data['column']; $key++) {
|
||||
|
||||
$gridHtml .= '<div class="layui-col-md' .$col. ' layui-grid-' .$key. '" data-index="' .$key. '">';
|
||||
|
||||
foreach ($data['children'][$key] as $children) {
|
||||
foreach ($children as $elem) {
|
||||
$gridHtml .= $this->itemElem($elem);
|
||||
}
|
||||
}
|
||||
|
||||
$gridHtml .= '</div>';
|
||||
}
|
||||
|
||||
$gridHtml .= '</div>';
|
||||
|
||||
return $gridHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表单属性
|
||||
*
|
||||
* @param array $data
|
||||
* @param string $suffix
|
||||
* @return string
|
||||
*/
|
||||
public function attributes(array $data = [], string $suffix = ''): string
|
||||
{
|
||||
$vars = [];
|
||||
foreach ($data as $key => $elem) {
|
||||
if (array_search($key, $this->attrs)) {
|
||||
|
||||
if (!$elem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 单独处理NAME值
|
||||
if ($key == 'name') {
|
||||
$elem .= $suffix;
|
||||
}
|
||||
|
||||
$vars[] = $key . '="' . $elem . '"';
|
||||
} else {
|
||||
if (strstr($key, 'lay_') || strstr($key, 'data_')) {
|
||||
$_key = str_replace('_', '-', $key);
|
||||
$vars[] = $_key . '="' . $elem . '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count($vars) > 0 ? ' ' . implode(' ', $vars) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板文件
|
||||
*
|
||||
* @param [type] $name
|
||||
* @return string
|
||||
*/
|
||||
protected function getHtmlTpl($name): string
|
||||
{
|
||||
return __DIR__ . DIRECTORY_SEPARATOR . 'form' . DIRECTORY_SEPARATOR . $name . '.html';
|
||||
}
|
||||
}
|
||||
105
extend/system/Http.php
Normal file
105
extend/system/Http.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace system;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
/**
|
||||
* Http 请求类
|
||||
*/
|
||||
class Http
|
||||
{
|
||||
/**
|
||||
* PC/Mobile 标识
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $agent = [
|
||||
'Opera/9.80 (Android 2.3.4; Linux; Opera Mobi/build-1107180945; U; en-GB) Presto/2.8.149 Version/11.10',
|
||||
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
|
||||
];
|
||||
|
||||
/**
|
||||
* 发送一个POST请求
|
||||
* @param string $url
|
||||
* @param array $params
|
||||
* @param bool $agent
|
||||
* @param array $options
|
||||
* @param $header
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function post(string $url, array $params = [], bool $agent = true, array $options = [], $header = '')
|
||||
{
|
||||
$req = self::request($url, $params, $agent, 'POST', $options, $header);
|
||||
return $req['ret'] ? $req['msg'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送一个GET请求
|
||||
* @param string $url
|
||||
* @param array $params
|
||||
* @param bool $agent
|
||||
* @param array $options
|
||||
* @param $header
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function get(string $url, array $params = [], bool $agent = true, array $options = [], $header = [])
|
||||
{
|
||||
$req = self::request($url, $params, $agent, 'GET', $options, $header);
|
||||
return $req['ret'] ? $req['msg'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $params
|
||||
* @param bool $agent
|
||||
* @param string $method
|
||||
* @param array $options
|
||||
* @param array $header
|
||||
* @return array
|
||||
*/
|
||||
public static function request(string $url, array $params, bool $agent, string $method = 'GET', array $options = [], array $header = []): array
|
||||
{
|
||||
try {
|
||||
$client = self::getClient($agent, $options, $header);
|
||||
$response = $client->request($method, $url, $params ? ['query' => $params] : [])->getBody()->getContents();
|
||||
if (!empty($response)) {
|
||||
return ['ret' => true, 'msg' => $response];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
return ['ret' => false, 'msg' => $e->getMessage()];
|
||||
}
|
||||
|
||||
return ['ret' => false, 'msg' => $response];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取访问客户端
|
||||
* @param bool $agent
|
||||
* @param array $options
|
||||
* @param array $header
|
||||
* @return mixed
|
||||
*/
|
||||
private static function getClient(bool $agent, array $options = [], array $header = [])
|
||||
{
|
||||
if (empty($options)) {
|
||||
$options = [
|
||||
'timeout' => 60,
|
||||
'connect_timeout' => 60,
|
||||
'verify' => false,
|
||||
'http_errors' => false,
|
||||
'headers' => [
|
||||
'X-REQUESTED-WITH' => 'XMLHttpRequest',
|
||||
'Referer' => dirname(request()->url()),
|
||||
'User-Agent' => self::$agent[$agent]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($header)) {
|
||||
$options['headers'] = array_merge($options['headers'], $header);
|
||||
}
|
||||
|
||||
return new Client($options);
|
||||
}
|
||||
|
||||
}
|
||||
146
extend/system/Random.php
Normal file
146
extend/system/Random.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin 极速开发框架 [基于WebMan开发]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin.net High Speed Development Framework
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: meystack <coolsec@foxmail.com> Apache2 License
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace system;
|
||||
|
||||
class Random
|
||||
{
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return self
|
||||
*/
|
||||
|
||||
public static function instance(array $options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成大小写字母
|
||||
*
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function alpha(int $length = 6): string
|
||||
{
|
||||
return self::Generate('alpha', $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成纯数字
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function number(int $length = 6): string
|
||||
{
|
||||
return self::Generate('number', $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成小写字母
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function lower(int $length = 6): string
|
||||
{
|
||||
return self::Generate('lower', $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成大写字母
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function upper(int $length = 6): string
|
||||
{
|
||||
return self::Generate('upper', $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下划线随机
|
||||
*
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function alphaDash(int $length = 6): string
|
||||
{
|
||||
return self::Generate('alphaDash', $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成数字+字母
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function alphaNum(int $length = 6): string
|
||||
{
|
||||
return self::Generate('alphaNum', $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机字符
|
||||
* @param string $type
|
||||
* @param integer $length
|
||||
* @return string
|
||||
*/
|
||||
public static function Generate(string $type = 'alpha', int $length = 6): string
|
||||
{
|
||||
$config = [
|
||||
'number' => '1234567890',
|
||||
'lower' => 'abcdefghijklmnopqrstuvwxyz',
|
||||
'upper' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'alpha' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'alphaDash' => '_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'alphaNum' => '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
];
|
||||
|
||||
$letter = str_shuffle($config[$type]);
|
||||
return substr($letter, 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成订单ID
|
||||
*
|
||||
* @param boolean $other
|
||||
* @return string
|
||||
*/
|
||||
public static function orderId(bool $other = false): string
|
||||
{
|
||||
if (!$other) {
|
||||
return date('Ymd') . str_pad((string)mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
|
||||
} else {
|
||||
return date('Ymd') . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
121
extend/system/ZipArchives.php
Normal file
121
extend/system/ZipArchives.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin 极速开发框架 [基于WebMan开发]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
|
||||
// +----------------------------------------------------------------------
|
||||
// | swiftAdmin.net High Speed Development Framework
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: meystack <coolsec@foxmail.com> Apache2 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace system;
|
||||
|
||||
use FilesystemIterator;
|
||||
|
||||
/**
|
||||
* 文件压缩类
|
||||
* @author meystack
|
||||
* @version 1.0
|
||||
*/
|
||||
class ZipArchives
|
||||
{
|
||||
/**
|
||||
* 解压文件
|
||||
* @param string $fileName
|
||||
* @param string $filePath
|
||||
* @param string $search
|
||||
* @param bool $delete
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function unzip(string $fileName, string $filePath = '', string $search = '', bool $delete = false)
|
||||
{
|
||||
if (!is_file($fileName) && preg_match('/^[a-z]{3,32}/', $fileName)) {
|
||||
$fileName = plugin_path() . $fileName . '.zip';
|
||||
}
|
||||
|
||||
if (!is_file($fileName)) {
|
||||
throw new \Exception(__('解压文件不存在'), -113);
|
||||
}
|
||||
|
||||
$fileStream = '';
|
||||
$filePath = $filePath ?: plugin_path();
|
||||
$zip = new \ZipArchive();
|
||||
if ($zip->open($fileName) !== TRUE) {
|
||||
throw new \Exception(__("访问解压文件失败"), -114);
|
||||
}
|
||||
try {
|
||||
if (!empty($search)) {
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$filePath = str_replace('\\','/',$zip->getNameIndex($i));
|
||||
$fileName = explode('/', $filePath);
|
||||
if (end($fileName) == $search) {
|
||||
$fileStream = $zip->getFromIndex($i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!is_dir($filePath)) {
|
||||
@mkdir($filePath, 0755, true);
|
||||
}
|
||||
$zip->extractTo($filePath);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("解压 " . $fileName . " 包失败", -115);
|
||||
} finally {
|
||||
$zip->close();
|
||||
if ($delete && !$search) {
|
||||
unlink($fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return $search ? $fileStream : $filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩文件夹
|
||||
* @param string $fileName
|
||||
* @param string $filePath
|
||||
* @param string $rootPath
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function compression(string $fileName, string $filePath, string $rootPath = ''): bool
|
||||
{
|
||||
$zip = new \ZipArchive();
|
||||
try {
|
||||
|
||||
@unlink($fileName);
|
||||
$zip->open($fileName, \ZipArchive::CREATE);
|
||||
$files = new \RecursiveIteratorIterator(
|
||||
new \RecursiveDirectoryIterator($filePath, FilesystemIterator::SKIP_DOTS),
|
||||
\RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
// 默认为插件目录
|
||||
$rootPath = $rootPath ?: plugin_path();
|
||||
foreach ($files as $fileinfo) {
|
||||
if ($fileinfo->isFile()) {
|
||||
// 过滤冗余文件
|
||||
$filePath = str_replace('\\','/',$fileinfo->getRealPath());
|
||||
if (!in_array($fileinfo->getFilename(), ['.git', '.vscode', 'Thumbs.db'])) {
|
||||
$zip->addFile($filePath, str_replace($rootPath, '', $filePath));
|
||||
}
|
||||
} else {
|
||||
$localDir = str_replace('\\','/',$fileinfo->getPathName());
|
||||
$localDir = str_replace($rootPath, '', $localDir);
|
||||
$zip->addEmptyDir($localDir);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception("压缩 " . $fileName . " 包失败", -115);
|
||||
} finally {
|
||||
$zip->close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
92
extend/system/exception.tpl
Normal file
92
extend/system/exception.tpl
Normal file
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>系统发生错误</title>
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
<style>
|
||||
body{color:#333;margin:0;padding:0 20px 20px;min-height:100%;background:#edf1f4;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:"Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",微软雅黑,Arial,sans-serif}
|
||||
h1{margin:10px 0 0;font-size:28px;font-weight:500;line-height:32px}
|
||||
h2{color:#4288ce;font-weight:400;padding:6px 0;margin:6px 0 0;font-size:18px;border-bottom:1px solid #eee}
|
||||
h3{margin:12px;font-size:16px;font-weight:bold}
|
||||
abbr{cursor:help;text-decoration:underline;text-decoration-style:dotted}
|
||||
a{color:#868686;cursor:pointer}
|
||||
a:hover{text-decoration:underline}
|
||||
.line-error{background:#f8cbcb}
|
||||
.echo table{width:100%}
|
||||
.echo pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border:0;border-radius:3px;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace}
|
||||
.echo pre > pre{padding:0;margin:0}
|
||||
.exception{margin-top:20px}
|
||||
.exception .message{padding:12px;border:1px solid #ddd;border-bottom:0 none;line-height:18px;font-size:16px;border-top-left-radius:4px;border-top-right-radius:4px;font-family:Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif}
|
||||
.exception .code{float:left;text-align:center;color:#fff;margin-right:12px;padding:16px;border-radius:4px;background:#999}
|
||||
.exception .source-code{padding:6px;border:1px solid #ddd;background:#f9f9f9;overflow-x:auto}
|
||||
.exception .source-code pre{margin:0}
|
||||
.exception .source-code pre ol{margin:0;color:#4288ce;display:inline-block;min-width:100%;box-sizing:border-box;font-size:14px;font-family:"Century Gothic",Consolas,"Liberation Mono",Courier,Verdana,serif;padding-left:<?php echo (isset($source) && !empty($source)) ? parse_padding($source):40;?>px}
|
||||
.exception .source-code pre li{border-left:1px solid #ddd;height:18px;line-height:18px}
|
||||
.exception .source-code pre code{color:#333;height:100%;display:inline-block;border-left:1px solid #fff;font-size:14px;font-family:Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif}
|
||||
.exception .trace{padding:6px;border:1px solid #ddd;border-top:0 none;line-height:16px;font-size:14px;font-family:Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif}
|
||||
.exception .trace h2:hover{text-decoration:underline;cursor:pointer}
|
||||
.exception .trace ol{margin:12px}
|
||||
.exception .trace ol li{padding:2px 4px}
|
||||
.exception div:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px}
|
||||
.exception-var table{width:100%;margin:12px 0;box-sizing:border-box;table-layout:fixed;word-wrap:break-word}
|
||||
.exception-var table caption{text-align:left;font-size:16px;font-weight:bold;padding:6px 0}
|
||||
.exception-var table caption small{font-weight:300;display:inline-block;margin-left:10px;color:#ccc}
|
||||
.exception-var table tbody{font-size:13px;font-family:Consolas,"Liberation Mono",Courier,"微软雅黑",serif}
|
||||
.exception-var table td{padding:0 6px;vertical-align:top;word-break:break-all}
|
||||
.exception-var table td:first-child{width:28%;font-weight:bold;white-space:nowrap}
|
||||
.exception-var table td pre{margin:0}
|
||||
.copyright{margin-top:24px;padding:12px 0;border-top:1px solid #eee}
|
||||
pre.prettyprint .pln{color:#000}
|
||||
pre.prettyprint .str{color:#080}
|
||||
pre.prettyprint .kwd{color:#008}
|
||||
pre.prettyprint .com{color:#800}
|
||||
pre.prettyprint .typ{color:#606}
|
||||
pre.prettyprint .lit{color:#066}
|
||||
pre.prettyprint .pun,pre.prettyprint .opn,pre.prettyprint .clo{color:#660}
|
||||
pre.prettyprint .tag{color:#008}
|
||||
pre.prettyprint .atn{color:#606}
|
||||
pre.prettyprint .atv{color:#080}
|
||||
pre.prettyprint .dec,pre.prettyprint .var{color:#606}
|
||||
pre.prettyprint .fun{color:red}
|
||||
.exception-container{border-radius:5px;text-align:center;box-shadow:0 0 30px rgba(99,99,99,0.06);padding:50px;background-color:#fff;width:100%;left:50%;top:50%;max-width:456px;position:absolute;margin-top:-280px;margin-left:-280px}
|
||||
.exception-container .head-line{transition:color .2s linear;font-size:40px;line-height:60px;letter-spacing:-1px;color:#777}
|
||||
.exception-container .subheader{transition:color .2s linear;font-size:26px;line-height:46px;color:#494949}
|
||||
.exception-container .hr{height:1px;background-color:#eee;width:80%;max-width:350px;margin:23px auto}
|
||||
.exception-container .context{transition:color .2s linear;font-size:16px;line-height:27px;color:#aaa}
|
||||
.exception-container .buttons-container{margin-top:35px;overflow:hidden}
|
||||
.exception-container .buttons-container a{transition:text-indent .2s ease-out,color .2s linear,background-color .2s linear;text-indent:0px;font-size:14px;text-transform:uppercase;text-decoration:none;color:#fff;background-color:#1890ff;border-radius:10px;padding:10px 10px;text-align:center;display:inline-block;overflow:hidden;position:relative;width:40%;margin:0px 8px 0px 8px}
|
||||
.status-ico{width:72px;height:72px;line-height:72px;font-size:42px;color:#fff;text-align:center;border-radius:50%;display:inline-block;margin-bottom:24px;background-color:#52c41a!important}
|
||||
.status-error{background-color:#ff4d4f!important}
|
||||
@media screen and (max-width:580px){padding:30px 5%}
|
||||
.head-line{font-size:36px}
|
||||
.subheader{font-size:27px;line-height:37px}
|
||||
.hr{margin:30px auto;width:215px}
|
||||
}@media screen and (max-width:450px){padding:30px}
|
||||
.head-line{font-size:32px}
|
||||
.hr{margin:25px auto;width:180px}
|
||||
.context{font-size:15px;line-height:22px}
|
||||
.context p:nth-child(n+2){margin-top:10px}
|
||||
.buttons-container{margin-top:29px}
|
||||
.buttons-container a{float:none !important;width:65%;margin:0 auto;font-size:13px;padding:9px 0}
|
||||
.buttons-container a:nth-child(2){margin-top:12px}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="exception-container">
|
||||
<div class="head-line"><span class="status-ico status-error">X</span></div>
|
||||
<div class="subheader">服务器异常</div>
|
||||
<div class="hr"></div>
|
||||
<div class="context">
|
||||
<p>你可以返回上一页重试,或直接向我们反馈错误报告</p>
|
||||
</div>
|
||||
<div class="buttons-container">
|
||||
<a href="/">返回主页</a>
|
||||
<a href="/">反馈错误</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
10
extend/system/form/checkbox.html
Normal file
10
extend/system/form/checkbox.html
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
<volist name="{%varlist%}" id="vo">
|
||||
<input type="checkbox" {%attributes%} value="{$vo.value}" title="{$vo.title}"
|
||||
<if (isset($data['id']) && $data['id']) >
|
||||
<in name="$vo.value" value="$data.{%field%}">checked</in>
|
||||
<else/>
|
||||
<eq name="$vo.checked" value="true">checked</eq>
|
||||
</if>
|
||||
>
|
||||
</volist>
|
||||
8
extend/system/form/file.html
Normal file
8
extend/system/form/file.html
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
<input type="text" name="{%field%}" value="{%value%}" class="layui-input layui-input-upload {%field%}" >
|
||||
<button type="button" class="layui-btn" lay-upload="{%field%}" data-type="normal" data-accept="{%accept%}" data-size="{%size%}">
|
||||
<i class="layui-icon layui-icon-upload"></i> 上传
|
||||
</button>
|
||||
<button type="button" class="layui-btn ml10" lay-choose="{%field%}" data-type="file" >
|
||||
<i class="layui-icon layui-icon-windows"></i> 选择
|
||||
</button>
|
||||
24
extend/system/form/images.html
Normal file
24
extend/system/form/images.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<input class="layui-input layui-input-upload {%field%}" name="{%field%}" value="{%value%}">
|
||||
<button type="button" class="layui-btn" lay-choose="{%field%}" data-type="images" >
|
||||
<i class="layui-icon layui-icon-windows"></i> 选择
|
||||
</button>
|
||||
<div class="clear"></div>
|
||||
<notempty name="$data['{%field%}']" >
|
||||
<div class="layui-upload-drag layui-uplpad-image mt10" lay-upload="{%field%}" data-type="images" data-accept="{%accept%}" data-size="{%size%}">
|
||||
<i class="layui-icon layui-icon-upload layui-hide"></i>
|
||||
<p class="layui-hide">点击上传,或将文件拖拽到此处</p>
|
||||
<div >
|
||||
<hr><img src="{%value%}" class="layui-upload-dragimg {%field%}" alt="上传成功后渲染" >
|
||||
<span class="layui-badge layui-upload-clear">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
<else/>
|
||||
<div class="layui-upload-drag layui-uplpad-image mt10" lay-upload="{%field%}" data-type="images" data-accept="{%accept%}" data-size="{%size%}">
|
||||
<i class="layui-icon layui-icon-upload"></i>
|
||||
<p>点击上传,或将文件拖拽到此处</p>
|
||||
<div class="layui-hide">
|
||||
<hr><img src="{%value%}" class="layui-upload-dragimg {%field%}" alt="上传成功后渲染" >
|
||||
<span class="layui-badge layui-upload-clear">删除</span>
|
||||
</div>
|
||||
</div>
|
||||
</notempty>
|
||||
21
extend/system/form/json.html
Normal file
21
extend/system/form/json.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>变量值</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<notempty name="data.{%field%}">
|
||||
<volist name="data.{%field%}" id="vo" key="i">
|
||||
<tr>
|
||||
<td><input type="text" class="layui-input" name="{%field%}[key][]" value="{$key}" ></td>
|
||||
<td><input type="text" class="layui-input" name="{%field%}[value][]" value="{$vo}"></td>
|
||||
<td><i class="layui-icon fa-times" data-name="{%field%}" onclick="layui.admin.resetInput(this);"></i></td>
|
||||
</tr>
|
||||
</volist>
|
||||
</notempty>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="button" class="layui-btn layui-btn-normal layui-jsonvar-add" data-name="{%field%}">追加</button>
|
||||
25
extend/system/form/multiple.html
Normal file
25
extend/system/form/multiple.html
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
<div class="layui-imagesbox">
|
||||
|
||||
<!-- // 循环输出代码 -->
|
||||
<notempty name="$data['{%field%}']" >
|
||||
<volist name="$data['{%field%}']" id="vo">
|
||||
<div class="layui-input-inline layui-uplpad-image">
|
||||
<img src="{$vo.src}" lay-image-hover >
|
||||
<input type="text" name="{%field%}[{$key}][src]" class="layui-hide" value="{$vo.src}" >
|
||||
<input type="text" name="{%field%}[{$key}][title]" class="layui-input" value="{$vo.title}" placeholder="图片简介">
|
||||
<span class="layui-badge layui-badge-red" data-name="{%field%}" onclick="layui.admin.resetInput(this,'images');">删除</span>
|
||||
</div>
|
||||
</volist>
|
||||
</notempty>
|
||||
<div class="layui-input-inline layui-uplpad-image">
|
||||
<div class="layui-upload-drag" lay-upload="{%field%}" data-type="multiple" data-accept="{%accept%}" data-size="{%size%}">
|
||||
<i class="layui-icon layui-icon-upload"></i>
|
||||
<p>点击上传,或将文件拖拽到此处</p>
|
||||
<div class="layui-hide"></div>
|
||||
</div>
|
||||
<button type="button" class="layui-btn layui-btn-xs layui-btn-fluid" lay-choose="{%field%}" data-name="{%field%}" data-type="multiple">
|
||||
<i class="layui-icon layui-icon-windows"></i> 选择
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
10
extend/system/form/radio.html
Normal file
10
extend/system/form/radio.html
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
<volist name="{%varlist%}" id="vo">
|
||||
<input type="radio" {%attributes%} value="{$vo.value}" title="{$vo.title}"
|
||||
<if (isset($data['id']) && $data['id']) >
|
||||
<eq name="$vo.value" value="$data.{%field%}">checked</eq>
|
||||
<else/>
|
||||
<eq name="$vo.checked" value="true">checked</eq>
|
||||
</if>
|
||||
>
|
||||
</volist>
|
||||
13
extend/system/form/select.html
Normal file
13
extend/system/form/select.html
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
<select {%attributes%} >
|
||||
<volist name="{%varlist%}" id="vo">
|
||||
<option value="{$vo.value}"
|
||||
<if (isset($data['id']) && $data['id']) >
|
||||
<in name="$vo.value" value="$data.{%field%}">selected</in>
|
||||
<else/>
|
||||
<eq name="$vo.checked" value="true">selected</eq>
|
||||
</if>
|
||||
>{$vo.title}</option>
|
||||
</volist>
|
||||
</select>
|
||||
146
extend/system/third/gitee.php
Normal file
146
extend/system/third/gitee.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace system\third;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
/**
|
||||
* Gitee登录类
|
||||
*/
|
||||
|
||||
class gitee
|
||||
{
|
||||
|
||||
const GET_AUTH_CODE_URL = "https://gitee.com/oauth/authorize";
|
||||
const GET_ACCESS_TOKEN_URL = "https://gitee.com/oauth/token";
|
||||
const GET_USERINFO_URL = "https://gitee.com/api/v5/user";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* Http实例
|
||||
* @var Object
|
||||
*/
|
||||
protected $http = null;
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if ($config = saenv('gitee')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
$this->http = new Client();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*/
|
||||
public function login() {
|
||||
return redirect($this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录地址
|
||||
*/
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$state = hash('sha256',uniqid((string)mt_rand()));
|
||||
session('state', $state);
|
||||
$queryarr = array(
|
||||
"response_type" => "code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
// "scope" => 'user_info',
|
||||
"state" => $state,
|
||||
);
|
||||
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function getUserInfo(array $params = []): array
|
||||
{
|
||||
$params = $params ? $params : input();
|
||||
if ((isset($params['state']) && $params['state'] == session('state') && isset($params['code']))) {
|
||||
|
||||
// 获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
|
||||
// 获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
];
|
||||
|
||||
$ret = $this->http->get(self::GET_USERINFO_URL.'?'.http_build_query($queryarr))->getBody()->getContents();
|
||||
$userinfo = json_decode($ret, true);
|
||||
|
||||
if (!$userinfo || !is_array($userinfo)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$userinfo['avatar'] = isset($userinfo['avatar_url']) ? $userinfo['avatar_url'] : '';
|
||||
$userinfo['avatar'] = str_replace('http://','https://',$userinfo['avatar']);
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'userinfo' => $userinfo,
|
||||
'id' => $userinfo['id'],
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
if (!$code) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$queryarr = array(
|
||||
"grant_type" => "authorization_code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"client_secret" => $this->config['app_key'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"code" => $code,
|
||||
);
|
||||
|
||||
|
||||
try {
|
||||
$params = $this->http->post(self::GET_ACCESS_TOKEN_URL,['query'=>$queryarr])->getBody()->getContents();
|
||||
} catch (\Throwable $th) {
|
||||
if (strstr($th->getMessage(),'error_description')) {
|
||||
throw new \Exception('登录已过期,请重新登录');
|
||||
}
|
||||
}
|
||||
|
||||
return $params ? json_decode($params,true): [];
|
||||
}
|
||||
}
|
||||
154
extend/system/third/qq.php
Normal file
154
extend/system/third/qq.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace system\third;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
/**
|
||||
* QQ登录类
|
||||
*/
|
||||
|
||||
class qq
|
||||
{
|
||||
|
||||
const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";
|
||||
const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
|
||||
const GET_USERINFO_URL = "https://graph.qq.com/user/get_user_info";
|
||||
const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* Http实例
|
||||
* @var Object
|
||||
*/
|
||||
protected $http = null;
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if ($config = saenv('qq')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
$this->http = new Client();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*/
|
||||
public function login() {
|
||||
return redirect($this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录地址
|
||||
*/
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$state = hash('sha256',uniqid((string)mt_rand()));
|
||||
session('state', $state);
|
||||
$queryarr = array(
|
||||
"response_type" => "code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"scope" => 'get_user_info',
|
||||
"state" => $state,
|
||||
);
|
||||
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr);
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getUserInfo($params = [])
|
||||
{
|
||||
$params = $params ? $params : input();
|
||||
if (isset($params['access_token']) || (isset($params['state']) && $params['state'] == session('state') && isset($params['code']))) {
|
||||
|
||||
//获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
$openid = $this->getOpenId($access_token);
|
||||
//获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
"oauth_consumer_key" => $this->config['app_id'],
|
||||
"openid" => $openid,
|
||||
];
|
||||
|
||||
$ret = $this->http->get(self::GET_USERINFO_URL.'?'.http_build_query($queryarr))->getBody()->getContents();
|
||||
$userinfo = (array)json_decode($ret, true);
|
||||
if (!$userinfo || !isset($userinfo['ret']) || $userinfo['ret'] !== 0) {
|
||||
return [];
|
||||
}
|
||||
$userinfo = $userinfo ? $userinfo : [];
|
||||
$userinfo['avatar'] = isset($userinfo['figureurl_qq_2']) ? $userinfo['figureurl_qq_2'] : '';
|
||||
$userinfo['avatar'] = str_replace('http://','https://',$userinfo['avatar']);
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'openid' => $openid,
|
||||
'userinfo' => $userinfo
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string $code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
if (!$code) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$queryarr = array(
|
||||
"grant_type" => "authorization_code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"client_secret" => $this->config['app_key'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"code" => $code,
|
||||
);
|
||||
|
||||
$ret = $this->http->get(self::GET_ACCESS_TOKEN_URL.'?'.http_build_query($queryarr))->getBody()->getContents();
|
||||
$params = [];
|
||||
parse_str($ret, $params);
|
||||
return $params ? $params : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取open_id
|
||||
* @param string $access_token
|
||||
* @return string
|
||||
*/
|
||||
private function getOpenId($access_token = '')
|
||||
{
|
||||
$response = $this->http->get(self::GET_OPENID_URL.'?access_token='.$access_token)->getBody()->getContents();
|
||||
if (strpos($response, "callback") !== false) {
|
||||
$lpos = strpos($response, "(");
|
||||
$rpos = strrpos($response, ")");
|
||||
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
|
||||
}
|
||||
$user = (array)json_decode($response, true);
|
||||
return isset($user['openid']) ? $user['openid'] : '';
|
||||
}
|
||||
}
|
||||
133
extend/system/third/weibo.php
Normal file
133
extend/system/third/weibo.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace system\third;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
/**
|
||||
* 微博登录类
|
||||
*/
|
||||
|
||||
class weibo
|
||||
{
|
||||
|
||||
const GET_AUTH_CODE_URL = "https://api.weibo.com/oauth2/authorize";
|
||||
const GET_ACCESS_TOKEN_URL = "https://api.weibo.com/oauth2/access_token";
|
||||
const GET_USERINFO_URL = "https://api.weibo.com/2/users/show.json";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* Http实例
|
||||
* @var Object
|
||||
*/
|
||||
protected $http = null;
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if ($config = saenv('weibo')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
|
||||
$this->http = new Client();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*/
|
||||
public function login() {
|
||||
return redirect($this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录地址
|
||||
*/
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$state = hash('sha256',uniqid((string)mt_rand()));
|
||||
session('state', $state);
|
||||
$queryarr = array(
|
||||
"response_type" => "code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"state" => $state,
|
||||
);
|
||||
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getUserInfo($params = [])
|
||||
{
|
||||
$params = $params ? $params : input();
|
||||
if (isset($params['access_token']) || (isset($params['state']) && $params['state'] == session('state') && isset($params['code']))) {
|
||||
//获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
$uid = isset($data['uid']) ? $data['uid'] : '';
|
||||
//获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
"uid" => $uid,
|
||||
];
|
||||
$ret = $this->http->get(self::GET_USERINFO_URL.'?'.http_build_query($queryarr))->getBody()->getContents();
|
||||
$userinfo = (array)json_decode($ret, true);
|
||||
if (!$userinfo || isset($userinfo['error_code'])) {
|
||||
return [];
|
||||
}
|
||||
$userinfo = $userinfo ? $userinfo : [];
|
||||
$userinfo['nickname'] = isset($userinfo['screen_name']) ? $userinfo['screen_name'] : '';
|
||||
$userinfo['avatar'] = isset($userinfo['profile_image_url']) ? $userinfo['profile_image_url'] : '';
|
||||
$userinfo['avatar'] = str_replace('http://','https://',$userinfo['avatar']);
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'openid' => $uid,
|
||||
'userinfo' => $userinfo
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
if (!$code) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$queryarr = array(
|
||||
"grant_type" => "authorization_code",
|
||||
"client_id" => $this->config['app_id'],
|
||||
"client_secret" => $this->config['app_key'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"code" => $code,
|
||||
);
|
||||
|
||||
$response = $this->http->post(self::GET_ACCESS_TOKEN_URL,['query'=>$queryarr])->getBody()->getContents();
|
||||
$ret = (array)json_decode($response, true);
|
||||
return $ret ? $ret : [];
|
||||
}
|
||||
}
|
||||
143
extend/system/third/weixin.php
Normal file
143
extend/system/third/weixin.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace system\third;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
/**
|
||||
* 微信登录类
|
||||
*/
|
||||
|
||||
class weixin
|
||||
{
|
||||
const GET_AUTH_CODE_URL = "https://open.weixin.qq.com/connect/qrconnect";
|
||||
const GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
|
||||
const GET_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo";
|
||||
|
||||
/**
|
||||
* 配置信息
|
||||
* @var array
|
||||
*/
|
||||
private $config = [];
|
||||
|
||||
/**
|
||||
* Http实例
|
||||
* @var Object
|
||||
*/
|
||||
protected $http = null;
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if ($config = saenv('weixin')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
|
||||
$this->http = new Client();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*/
|
||||
public function login() {
|
||||
return redirect($this->getAuthorizeUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录地址
|
||||
*/
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$state = hash('sha256',uniqid((string)mt_rand()));
|
||||
session('state', $state);
|
||||
$queryarr = array(
|
||||
"response_type" => "code",
|
||||
"appid" => $this->config['app_id'],
|
||||
"redirect_uri" => $this->config['callback'],
|
||||
"scope" => 'snsapi_login,',
|
||||
"state" => $state,
|
||||
);
|
||||
|
||||
request()->isMobile() && $queryarr['display'] = 'mobile';
|
||||
$url = self::GET_AUTH_CODE_URL . '?' . http_build_query($queryarr);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
public function getUserInfo($params = [])
|
||||
{
|
||||
$params = $params ? $params : input();
|
||||
if (isset($params['access_token']) || (isset($params['state']) && $params['state'] == session('state') && isset($params['code']))) {
|
||||
|
||||
//获取access_token
|
||||
$data = isset($params['code']) ? $this->getAccessToken($params['code']) : $params;
|
||||
|
||||
$access_token = isset($data['access_token']) ? $data['access_token'] : '';
|
||||
$refresh_token = isset($data['refresh_token']) ? $data['refresh_token'] : '';
|
||||
$expires_in = isset($data['expires_in']) ? $data['expires_in'] : 0;
|
||||
if ($access_token) {
|
||||
$openid = isset($data['openid']) ? $data['openid'] : '';
|
||||
$unionid = isset($data['unionid']) ? $data['unionid'] : '';
|
||||
if (stripos($data['scope'], 'snsapi_login') !== false) {
|
||||
//获取用户信息
|
||||
$queryarr = [
|
||||
"access_token" => $access_token,
|
||||
"openid" => $openid,
|
||||
"lang" => 'zh_CN'
|
||||
];
|
||||
|
||||
$ret = $this->http->get(self::GET_USERINFO_URL.'?'.http_build_query($queryarr))->getBody()->getContents();
|
||||
$userinfo = (array)json_decode($ret, true);
|
||||
if (!$userinfo || isset($userinfo['errcode'])) {
|
||||
return [];
|
||||
}
|
||||
$userinfo = $userinfo ? $userinfo : [];
|
||||
$userinfo['avatar'] = isset($userinfo['headimgurl']) ? $userinfo['headimgurl'] : '';
|
||||
$userinfo['avatar'] = str_replace('http://','https://',$userinfo['avatar']);
|
||||
} else {
|
||||
$userinfo = [];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'access_token' => $access_token,
|
||||
'refresh_token' => $refresh_token,
|
||||
'expires_in' => $expires_in,
|
||||
'openid' => $openid,
|
||||
'unionid' => $unionid,
|
||||
'userinfo' => $userinfo
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
* @param string code
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
if (!$code) {
|
||||
return [];
|
||||
}
|
||||
$queryarr = array(
|
||||
"grant_type" => "authorization_code",
|
||||
"appid" => $this->config['app_id'],
|
||||
"secret" => $this->config['app_key'],
|
||||
"code" => $code,
|
||||
);
|
||||
|
||||
$response = $this->http->get(self::GET_ACCESS_TOKEN_URL.'?'.http_build_query($queryarr))->getBody()->getContents();
|
||||
$ret = (array)json_decode($response, true);
|
||||
return $ret ? $ret : [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user