chore: 添加静态资源文件和版本配置文件

添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材
添加系统版本配置文件(.version)和常量定义文件(.constant)
更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件
添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
2026-03-06 20:14:23 +08:00
commit c9a98f342c
4485 changed files with 490986 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
/**
* 错误码统一存放类
* Class ApiErrorCode
* @package crmeb\services
*/
class ApiErrorCode
{
const SUCCESS = [200, 'SUCCESS'];
const ERROR = [400, 'ERROR'];
const ERR_LOGIN_INVALID = [410000, 'Landing overdue'];
const ERR_AUTH = [400011, 'You do not have permission to access for the time being'];
const ERR_RULE = [400012, 'Interface is not authorized, you cannot access'];
const ERR_ADMINID_VOID = [400013, 'Failed to get administrator ID'];
//保存token失败
const ERR_SAVE_TOKEN = [400, 'Failed to save token'];
//登陆状态不正确
const ERR_LOGIN_STATUS = [410002, 'The login status is incorrect. Please login again.'];
//请登陆
const ERR_LOGIN = [410000, 'Please login'];
//公众号访问错误请求码
const ERROR_WECHAT_MESSAGE = [
45007 => 'graphic message limit exceeded',
45008 => 'voice playback time exceeds the limit',
45006 => 'image link field exceeds limit',
45005 => 'link field exceeds limit',
45004 => 'description field exceeds limit',
45003 => 'header field exceeds limit',
45002 => 'message content exceeds limit',
45001 => 'multimedia file size exceeds limit',
44004 => 'the text message content is empty',
44003 => 'text message content is empty',
44001 => 'the multimedia file is empty',
44002 => 'multimedia file is empty The packet of 44002 post is empty',
43019 => 'the recipient needs to be removed from the blacklist',
43005 => 'need a friend relationship',
43004 => 'needs attention of receiver',
43005 => 'need to be friends',
43003 => 'requires HTTPS request',
43002 => 'post request required',
43001 => 'get request required',
42007 => 'user changes wechat password, accesstoken and refreshtoken are invalid and need to be re authorized',
42003 => 'oauth_ Code timeout',
42002 => 'refresh_ Token timeout',
42001 => 'access_ Token timeout, please check access_ For the validity of token, please refer to basic support - access_ In token, for access_ Detailed description of token mechanism',
41009 => 'missing openid',
41008 => 'missing OAuth code',
41007 => 'missing submenu data',
41006 => 'lack of media_ ID parameter',
41005 => 'missing multimedia file data',
41004 => 'missing secret parameter',
41003 => 'missing refresh_ Token parameter',
41002 => 'missing appid parameter',
41001 => 'missing access_ Token parameter',
40163 => 'oauth_ Code used',
40155 => 'do not add any other official account\'s home page links.',
40137 => 'image format not supported',
40132 => 'illegal micro signal',
40125 => 'invalid appsecret',
40121 => 'illegal media_ ID type',
40120 => 'sub button type error',
40119 => 'button type error',
40118 => 'media_ Illegal ID size',
40117 => 'illegal group name',
40060 => 'when deleting a single text, the specified article_ Illegal idx',
40051 => 'illegal group name',
40048 => 'invalid URL',
40050 => 'illegal group ID',
40040 => 'invalid URL',
40039 => 'illegal URL length',
40038 => 'illegal request format',
40035 => 'illegal parameter',
40033 => "illegal request character, can't contain character in the format of 'uxxxx'",
40032 => 'illegal openid list length',
40031 => 'Illegal openid list',
40030 => 'Illegal refresh_ token',
40029 => 'invalid OAuth_ code',
40028 => 'Illegal custom menu user',
40027 => 'Illegal submenu button URL length',
40026 => 'Illegal submenu button key length',
40025 => 'Illegal submenu button name length',
40024 => 'Illegal submenu button type',
40023 => 'Illegal number of submenu buttons',
40022 => 'Illegal submenu series',
40021 => 'Illegal menu version number',
40020 => 'Illegal button URL length',
40019 => 'Illegal key length of button',
40018 => 'Illegal button name length',
40017 => 'Illegal button type',
40016 => 'Number of illegal buttons',
40015 => 'Illegal menu type',
40014 => 'Illegal access_ Token, please compare access carefully_ The validity of token (if expired), or whether to call the interface for the appropriate official account.',
40013 => 'Illegal appid, please check the correctness of appid, avoid abnormal characters and pay attention to case',
40012 => 'Illegal thumbnail file size',
40011 => 'Illegal video file size',
40010 => 'Illegal voice file size',
40009 => 'Illegal image file size',
40008 => 'Illegal message type',
40007 => 'Illegal media file ID',
40006 => 'Illegal file size',
40005 => 'Illegal file type',
40004 => 'Illegal media file type',
40002 => 'Illegal voucher type',
40003 => 'Illegal OpenID, developers confirm whether OpenID has been concerned about the official account number, or whether it is OpenID of other official account.',
40001 => 'Get access_ Appsecret error in token, or access_ Token is not valid. Developers are asked to compare the correctness of AppSecret with the official account, or to see if the interface is being invoked for the appropriate public number.'
];
}

291
crmeb/utils/Arr.php Normal file
View File

@@ -0,0 +1,291 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
/**
* 操作数组帮助类
* Class Arr
* @package crmeb\utils
*/
class Arr
{
/**
* 对数组增加默认值
* @param array $keys
* @return array
*/
public static function getDefaultValue(array $keys, array $configList = [])
{
$value = [];
foreach ($keys as $val) {
if (is_array($val)) {
$k = $val[0] ?? '';
$v = $val[1] ?? '';
} else {
$k = $val;
$v = '';
}
$value[$k] = $configList[$k] ?? $v;
}
return $value;
}
/**
* 获取ivew菜单列表
* @param array $data
* @return array
*/
public static function getMenuIviewList(array $data)
{
return Arr::toIviewUi(Arr::getTree($data));
}
/**
* 转化iviewUi需要的key值
* @param $data
* @return array
*/
public static function toIviewUi($data)
{
$newData = [];
foreach ($data as $k => $v) {
$temp = [];
$temp['path'] = $v['menu_path'];
$temp['title'] = $v['menu_name'];
$temp['icon'] = $v['icon'];
$temp['header'] = $v['header'];
$temp['is_header'] = $v['is_header'];
if ($v['is_show_path']) {
$temp['auth'] = ['hidden'];
}
if (!empty($v['children'])) {
$temp['children'] = self::toIviewUi($v['children']);
}
$newData[] = $temp;
}
return $newData;
}
/**
* 获取树型菜单
* @param $data
* @param int $pid
* @param int $level
* @return array
*/
public static function getTree($data, $pid = 0, $level = 1)
{
$childs = self::getChild($data, $pid, $level);
$dataSort = array_column($childs, 'sort');
array_multisort($dataSort, SORT_DESC, $childs);
foreach ($childs as $key => $navItem) {
$resChild = self::getTree($data, $navItem['id']);
if (null != $resChild) {
$childs[$key]['children'] = $resChild;
}
}
return $childs;
}
/**
* 获取子菜单
* @param $arr
* @param $id
* @param $lev
* @return array
*/
private static function getChild(&$arr, $id, $lev)
{
$child = [];
foreach ($arr as $k => $value) {
if ($value['pid'] == $id) {
$value['level'] = $lev;
$child[] = $value;
}
}
return $child;
}
/**
* 格式化数据
* @param array $array
* @param $value
* @param int $default
* @return mixed
*/
public static function setValeTime(array $array, $value, $default = 0)
{
foreach ($array as $item) {
if (!isset($value[$item]))
$value[$item] = $default;
else if (is_string($value[$item]))
$value[$item] = (float)$value[$item];
}
return $value;
}
/**
* 获取二维数组中某个值的集合重新组成数组,并判断数组中的每一项是否为真
* @param array $data
* @param string $filed
* @return array
*/
public static function getArrayFilterValeu(array $data, string $filed)
{
return array_filter(array_unique(array_column($data, $filed)), function ($item) {
if ($item) {
return $item;
}
});
}
/**
* 获取二维数组中最大的值
* @param $arr
* @param $field
* @return int|string
*/
public static function getArrayMax($arr, $field)
{
$temp = [];
foreach ($arr as $k => $v) {
$temp[] = $v[$field];
}
if (!count($temp)) return 0;
$maxNumber = max($temp);
foreach ($arr as $k => $v) {
if ($maxNumber == $v[$field]) return $k;
}
return 0;
}
/**
* 获取二维数组中最小的值
* @param $arr
* @param $field
* @return int|string
*/
public static function getArrayMin($arr, $field)
{
$temp = [];
foreach ($arr as $k => $v) {
$temp[] = $v[$field];
}
if (!count($temp)) return 0;
$minNumber = min($temp);
foreach ($arr as $k => $v) {
if ($minNumber == $v[$field]) return $k;
}
return 0;
}
/**
* 数组转字符串去重复
* @param array $data
* @return false|string[]
*/
public static function unique(array $data)
{
return array_unique(explode(',', implode(',', $data)));
}
/**
* 获取数组中去重复过后的指定key值
* @param array $list
* @param string $key
* @return array
*/
public static function getUniqueKey(array $list, string $key)
{
return array_unique(array_column($list, $key));
}
/**
* 获取数组钟随机值
* @param array $data
* @return bool|mixed
*/
public static function getArrayRandKey(array $data)
{
if (!$data) {
return false;
}
mt_srand();
$mun = rand(0, count($data));
if (!isset($data[$mun])) {
return self::getArrayRandKey($data);
}
return $data[$mun];
}
/**
* 格式化数据
* @param array $list
* @return array
*/
public static function formatShipping(array $list)
{
$freeDate = [];
foreach ($list as $item) {
$freeDate[$item['uniqid']][] = $item;
}
$data = [];
foreach ($freeDate as $item) {
$cityIds = [];
$cityId = [];
$p = [];
foreach ($item as $value) {
$cityId[] = $value['city_id'];
$cityIds[] = is_array($value['value']) ? $value['value'] : json_decode($value['value'], true);
unset($value['city_id'], $value['value']);
$p = $value;
}
$p['city_id'] = $cityId;
$p['city_ids'] = $cityIds;
$data[] = $p;
}
return $data;
}
/**
* 过滤字段
* @param $value
* @param array $filter
* @return mixed
*/
public static function StrFilterValue($value, array $filter = [])
{
$filter = $filter ?: ['strip_tags', 'addslashes', 'trim', 'htmlspecialchars'];
foreach ($filter as $closure) {
if (function_exists($closure)) {
$value = $closure($value);
}
}
return $value;
}
/**
* 过滤字段
* @param array $data
* @return array
*/
public static function filterValue(array $data)
{
foreach ($data as &$item) {
if (is_array($item)) {
$item = self::filterValue($item);
} else {
$item = self::StrFilterValue($item);
}
}
return $data;
}
}

323
crmeb/utils/Canvas.php Normal file
View File

@@ -0,0 +1,323 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
/**
* Class Canvas
* @package crmeb\utils
* @method $this setFileName(string $fileName) 设置文件名
* @method $this setPath(string $path) 设置存放路径
* @method $this setImageType(string $imageType) 设置图片类型
* @method $this setBackgroundHeight(int $backgroundHeight) 设置背景高
* @method $this setBackgroundWidth(int $backgroundWidth) 设置背景宽
* @method $this setFontSize(int $fontSize) 设置字体大小
* @method $this setFontColor($fontColor) 设置字体颜色
* @method $this setFontLeft(int $fontLeft) 设置字体距离左侧位置
* @method $this setFontTop(int $fontTop) 设置字体距离顶部位置
* @method $this setFontText(string $fontText) 设置文字
* @method $this setFontPath(string $fontPath) 设置字体文件路径
* @method $this setFontAngle(int $fontAngle) 设置字体角度
* @method $this setImageUrl(string $imageUrl) 设置图片路径
* @method $this setImageLeft(int $imageLeft) 设置图片距离左侧位置
* @method $this setImageTop(int $imageTop) 设置图片距离顶部位置
* @method $this setImageRight(int $imageRight) 设置图片距离左侧位置
* @method $this setImageStream(bool $imageStream) 设置图片是否未流文件
* @method $this setImageBottom(int $imageBottom) 设置图片距离底部位置
* @method $this setImageWidth(int $imageWidth) 设置图片宽
* @method $this setImageHeight(int $imageHeight) 设置图片高
* @method $this setImageOpacity(int $imageOpacity) 设置图片透明度
*/
class Canvas
{
const FONT = 'statics/font/Alibaba-PuHuiTi-Regular.otf';
/**
* 背景宽
* @var int
*/
protected $backgroundWidth = 600;
/**
* 背景高
* @var int
*/
protected $backgroundHeight = 1000;
/**
* 图片类型
* @var string
*/
protected $imageType = 'jpeg';
/**
* 保存地址
* @var string
*/
protected $path = 'uploads/routine/';
/**
* 文件名
* @var string
*/
protected $fileName;
/**
* 规则
* @var array
*/
protected $propsRule = ['fileName', 'path', 'imageType', 'backgroundHeight', 'backgroundWidth'];
/**
* 字体数据集
* @var array
*/
protected $fontValue = [];
/**
* 字体默认可设置vlaue
* @var array
*/
protected $defaultFontValue = [
'fontSize' => 0,
'fontColor' => '231,180,52',
'fontLeft' => 0,
'fontTop' => 0,
'fontText' => '',
'fontPath' => self::FONT,
'fontAngle' => 0,
];
protected $defaultFont;
/**
* 图片数据集
* @var array
*/
protected $imageValue = [];
/**
* 图片可设置属性
* @var array
*/
protected $defaultImageValue = [
'imageUrl' => '',
'imageLeft' => 0,
'imageTop' => 0,
'imageRight' => 0,
'imageBottom' => 0,
'imageWidth' => 0,
'imageHeight' => 0,
'imageOpacity' => 0,
'imageStream' => false,
];
/**
* 实例化本身
* @var self
*/
protected static $instance;
protected $defaultImage;
protected function __construct()
{
$this->defaultImage = $this->defaultImageValue;
$this->defaultFont = $this->defaultFontValue;
}
/**
* 实例化本类
* @return Canvas
*/
public static function instance()
{
if (is_null(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 创建一个新图象
* @param string $file
* @return array
*/
public function createFrom(string $file): array
{
$file = str_replace('https', 'http', $file);
$imagesize = getimagesize($file);
$type = image_type_to_extension($imagesize[2], true);
switch ($type) {
case '.png':
$canvas = imagecreatefrompng($file);
break;
case '.jpg':
case '.jpeg':
$canvas = imagecreatefromjpeg($file);
break;
case '.gif':
$canvas = imagecreatefromgif($file);
break;
}
return [$canvas, $imagesize];
}
/**
* 放入字体
* @return $this
*/
public function pushFontValue()
{
array_push($this->fontValue, $this->defaultFontValue);
$this->defaultFontValue = $this->defaultFont;
return $this;
}
/**
* 放入图片
* @return $this
*/
public function pushImageValue()
{
array_push($this->imageValue, $this->defaultImageValue);
$this->defaultImageValue = $this->defaultImage;
return $this;
}
/**
* 创建背景
* @param int $w
* @param int $h
* @return false|resource
*/
public function createTrueColor(int $w = 0, int $h = 0)
{
return imagecreatetruecolor($w ? $w : $this->backgroundWidth, $h ? $h : $this->backgroundHeight);
}
/**
* 开始画图
* @param bool $force 生成错误时是否抛出异常
* @return string
* @throws \Exception
*/
public function starDrawChart(bool $force = false): string
{
try {
$image = $this->createTrueColor();
foreach ($this->imageValue as $item) {
if ($item['imageUrl']) {
if ($item['imageStream']) {
$res = getimagesizefromstring($item['imageUrl']);
$mer = imagecreatefromstring($item['imageUrl']);
} else {
[$mer, $res] = $this->createFrom($item['imageUrl']);
}
if ($mer && $res) {
$scrW = $res[0] ?? 0;
$scrH = $res[1] ?? 0;
$imageWidth = $item['imageWidth'] ?: $scrW;
$imageHeight = $item['imageHeight'] ?: $scrH;
imagecopyresampled($image, $mer, $item['imageLeft'], $item['imageTop'], $item['imageRight'], $item['imageBottom'], $imageWidth, $imageHeight, $scrW, $scrH);
unset($scrW, $scrH, $imageWidth, $imageHeight, $res, $mer);
}
}
}
foreach ($this->fontValue as $val) {
if (!is_array($val['fontColor']))
$fontColor = explode(',', $val['fontColor']);
else
$fontColor = $val['fontColor'];
if (count($fontColor) < 3)
throw new \RuntimeException('fontColor Separation of thousand bits');
[$r, $g, $b] = $fontColor;
$fontColor = imagecolorallocate($image, $r, $g, $b);
$val['fontLeft'] = $val['fontLeft'] < 0 ? $this->backgroundWidth - abs($val['fontLeft']) : $val['fontLeft'];
$val['fontTop'] = $val['fontTop'] < 0 ? $this->backgroundHeight - abs($val['fontTop']) : $val['fontTop'];
imagettftext($image, $val['fontSize'], $val['fontAngle'], $val['fontLeft'], $val['fontTop'], $fontColor, $val['fontPath'], $val['fontText']);
unset($r, $g, $b, $fontColor);
}
if (is_null($this->fileName)) {
$this->fileName = md5(time());
}
$strlen = stripos($this->path, 'uploads');
$path = $this->path;
if ($strlen !== false) {
$path = substr($this->path, 8);
}
make_path($path, 4, true);
$save_file = $this->path . $this->fileName . '.' . $this->imageType;
switch ($this->imageType) {
case 'jpeg':
case 'jpg':
imagejpeg($image, public_path() . $save_file, 70);
break;
case 'png':
imagepng($image, public_path() . $save_file, 70);
break;
case 'gif':
imagegif($image, public_path() . $save_file, 70);
break;
default:
throw new \RuntimeException('Incorrect type set:' . $this->imageType);
}
imagedestroy($image);
return $save_file;
} catch (\Throwable $e) {
if ($force || $e instanceof \RuntimeException)
throw new \Exception($e->getMessage());
return '';
}
}
/**
* Magic access..
*
* @param $method
* @param $args
* @return $this
*/
public function __call($method, $args): self
{
if (0 === stripos($method, 'set') && strlen($method) > 3) {
$method = lcfirst(substr($method, 3));
}
$imageValueKes = array_keys($this->defaultImageValue);
$fontValueKes = array_keys($this->defaultFontValue);
if (in_array($method, $imageValueKes)) {
$this->defaultImageValue[$method] = array_shift($args);
}
if (in_array($method, $fontValueKes)) {
$this->defaultFontValue[$method] = array_shift($args);
}
if (in_array($method, $this->propsRule)) {
$this->{$method} = array_shift($args);
}
return $this;
}
}

317
crmeb/utils/Captcha.php Normal file
View File

@@ -0,0 +1,317 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
use crmeb\services\CacheService;
use think\facade\Config;
use think\Response;
/**
* Class Captcha
* @package crmeb\utils
*/
class Captcha
{
// 验证码图片实例
private $im = null;
// 验证码字体颜色
private $color = null;
// 验证码字符集合
protected $codeSet = '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY';
// 验证码过期时间(s)
protected $expire = 1800;
// 使用中文验证码
protected $useZh = false;
// 中文验证码字符串
protected $zhSet = '们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借';
// 使用背景图片
protected $useImgBg = false;
// 验证码字体大小(px)
protected $fontSize = 25;
// 是否画混淆曲线
protected $useCurve = false;
// 是否添加杂点
protected $useNoise = true;
// 验证码图片高度
protected $imageH = 0;
// 验证码图片宽度
protected $imageW = 0;
// 验证码位数
protected $length = 4;
// 验证码字体,不设置随机获取
protected $fontttf = '';
// 背景颜色
protected $bg = [243, 251, 254];
//算术验证码
protected $math = false;
//验证码
protected $generator;
/**
* 架构方法 设置参数
* Captcha constructor.
* @param array $config
*/
public function __construct(array $config = [])
{
$this->length = $config['length'] ?? Config::get('captcha.length', $this->length);
$this->imageW = $config['imageW'] ?? $this->imageW;
$this->imageH = $config['imageH'] ?? $this->imageH;
$this->useCurve = $config['useCurve'] ?? $this->useCurve;
$this->fontSize = $config['fontSize'] ?? $this->fontSize;
$this->useImgBg = $config['useImgBg'] ?? $this->useImgBg;
$this->useZh = $config['useZh'] ?? $this->useZh;
$this->expire = $config['expire'] ?? $this->expire;
$this->math = $config['math'] ?? $this->math;
$this->zhSet = $config['zhSet'] ?? $this->zhSet;
$this->codeSet = $config['codeSet'] ?? $this->codeSet;
}
/**
* 创建验证码
* @return array
* @throws Exception
*/
public function generate(): array
{
$bag = '';
if ($this->math) {
$this->useZh = false;
$x = random_int(10, 30);
$y = random_int(1, 9);
$bag = "{$x} + {$y} = ";
$key = $x + $y;
$key .= '';
} else {
if ($this->useZh) {
$characters = preg_split('/(?<!^)(?!$)/u', $this->zhSet);
} else {
$characters = str_split($this->codeSet);
}
mt_srand();
for ($i = 0; $i < $this->length; $i++) {
$bag .= $characters[rand(0, count($characters) - 1)];
}
$key = mb_strtolower($bag, 'UTF-8');
}
$hash = password_hash($key, PASSWORD_BCRYPT, ['cost' => 10]);
$generator = [
'value' => $bag,
'key' => $hash,
];
CacheService::set('captcha_' . $key, $generator, $this->expire);
return $generator;
}
/**
* 验证验证码是否正确
* @access public
* @param string $code 用户验证码
* @return bool 用户验证码是否正确
*/
public function check(string $code): bool
{
$code = mb_strtolower(trim($code), 'UTF-8');
$name = 'captcha_' . $code;
if (!CacheService::has($name) || !($generator = CacheService::get($name))) {
return false;
}
$key = $generator['key'] ?? '';
$res = password_verify($code, $key);
if ($res) {
CacheService::delete($name);
}
return $res;
}
/**
* 输出验证码
* @param array|null $generator
* @return $this
*/
public function create(array $generator = null): Response
{
if (!$generator) {
$generator = $this->generate();
}
// 图片宽(px)
$this->imageW || $this->imageW = $this->length * $this->fontSize * 1.5 + $this->length * $this->fontSize / 2;
// 图片高(px)
$this->imageH || $this->imageH = $this->fontSize * 2.5;
// 建立一幅 $this->imageW x $this->imageH 的图像
$this->im = imagecreate($this->imageW, $this->imageH);
// 设置背景
imagecolorallocate($this->im, $this->bg[0], $this->bg[1], $this->bg[2]);
mt_srand();
// 验证码字体随机颜色
$this->color = imagecolorallocate($this->im, mt_rand(1, 150), mt_rand(1, 150), mt_rand(1, 150));
// 验证码使用随机字体
$ttfPath = dirname(dirname(app()->getThinkPath())) . DS . 'think-captcha' . DS . 'assets/' . ($this->useZh ? 'zhttfs' : 'ttfs') . '/';
if (empty($this->fontttf)) {
$dir = dir($ttfPath);
$ttfs = [];
while (false !== ($file = $dir->read())) {
if ('.' != $file[0] && substr($file, -4) == '.ttf') {
$ttfs[] = $file;
}
}
$dir->close();
mt_srand();
$this->fontttf = $ttfs[array_rand($ttfs)];
}
$fontttf = $ttfPath . $this->fontttf;
if ($this->useImgBg) {
$this->background();
}
if ($this->useNoise) {
// 绘杂点
$this->writeNoise();
}
if ($this->useCurve) {
// 绘干扰线
$this->writeCurve();
}
// 绘验证码
$text = $this->useZh ? preg_split('/(?<!^)(?!$)/u', $generator['value']) : str_split($generator['value']); // 验证码
mt_srand();
foreach ($text as $index => $char) {
$x = $this->fontSize * ($index + 1) * mt_rand(1.2, 1.6) * ($this->math ? 1 : 1.5);
$y = $this->fontSize + mt_rand(10, 20);
$angle = $this->math ? 0 : mt_rand(-40, 40);
imagettftext($this->im, $this->fontSize, $angle, $x, $y, $this->color, $fontttf, $char);
}
ob_start();
// 输出图像
imagepng($this->im);
$content = ob_get_clean();
imagedestroy($this->im);
return response($content, 200)->contentType('image/png');
}
/**
* 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数)
*
* 高中的数学公式咋都忘了涅,写出来
* 正弦型函数解析式:y=Asin(ωx+φ)+b
* 各常数值对函数图像的影响:
* A:决定峰值(即纵向拉伸压缩的倍数)
* b:表示波形在Y轴的位置关系或纵向移动距离(上加下减)
* φ:决定波形与X轴位置关系或横向移动距离(左加右减)
* ω:决定周期(最小正周期T=2π/∣ω∣)
*
*/
protected function writeCurve(): void
{
$px = $py = 0;
mt_srand();
// 曲线前部分
$A = mt_rand(1, $this->imageH / 2); // 振幅
$b = mt_rand(-$this->imageH / 4, $this->imageH / 4); // Y轴方向偏移量
$f = mt_rand(-$this->imageH / 4, $this->imageH / 4); // X轴方向偏移量
$T = mt_rand($this->imageH, $this->imageW * 2); // 周期
$w = (2 * M_PI) / $T;
$px1 = 0; // 曲线横坐标起始位置
$px2 = mt_rand($this->imageW / 2, $this->imageW * 0.8); // 曲线横坐标结束位置
for ($px = $px1; $px <= $px2; $px = $px + 1) {
if (0 != $w) {
$py = $A * sin($w * $px + $f) + $b + $this->imageH / 2; // y = Asin(ωx+φ) + b
$i = (int)($this->fontSize / 5);
while ($i > 0) {
imagesetpixel($this->im, $px + $i, $py + $i, $this->color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多
$i--;
}
}
}
// 曲线后部分
$A = mt_rand(1, $this->imageH / 2); // 振幅
$f = mt_rand(-$this->imageH / 4, $this->imageH / 4); // X轴方向偏移量
$T = mt_rand($this->imageH, $this->imageW * 2); // 周期
$w = (2 * M_PI) / $T;
$b = $py - $A * sin($w * $px + $f) - $this->imageH / 2;
$px1 = $px2;
$px2 = $this->imageW;
for ($px = $px1; $px <= $px2; $px = $px + 1) {
if (0 != $w) {
$py = $A * sin($w * $px + $f) + $b + $this->imageH / 2; // y = Asin(ωx+φ) + b
$i = (int)($this->fontSize / 5);
while ($i > 0) {
imagesetpixel($this->im, $px + $i, $py + $i, $this->color);
$i--;
}
}
}
}
/**
* 画杂点
* 往图片上写不同颜色的字母或数字
*/
protected function writeNoise(): void
{
mt_srand();
$codeSet = '2345678abcdefhijkmnpqrstuvwxyz';
for ($i = 0; $i < 10; $i++) {
//杂点颜色
$noiseColor = imagecolorallocate($this->im, mt_rand(150, 225), mt_rand(150, 225), mt_rand(150, 225));
for ($j = 0; $j < 5; $j++) {
// 绘杂点
imagestring($this->im, 5, mt_rand(-10, $this->imageW), mt_rand(-10, $this->imageH), $codeSet[mt_rand(0, 29)], $noiseColor);
}
}
}
/**
* 绘制背景图片
* 注:如果验证码输出图片比较大,将占用比较多的系统资源
*/
protected function background(): void
{
$path = dirname(dirname(app()->getThinkPath())) . DS . 'think-captcha' . DS . '/assets/bgs/';
$dir = dir($path);
$bgs = [];
while (false !== ($file = $dir->read())) {
if ('.' != $file[0] && substr($file, -4) == '.jpg') {
$bgs[] = $path . $file;
}
}
$dir->close();
mt_srand();
$gb = $bgs[array_rand($bgs)];
[$width, $height] = @getimagesize($gb);
// Resample
$bgImage = @imagecreatefromjpeg($gb);
@imagecopyresampled($this->im, $bgImage, 0, 0, 0, 0, $this->imageW, $this->imageH, $width, $height);
@imagedestroy($bgImage);
}
}

135
crmeb/utils/Cron.php Normal file
View File

@@ -0,0 +1,135 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
use think\swoole\Manager;
use Swoole\Timer;
use think\facade\Log;
/**
* Cron定时执行
* Class Cron
* @package crmeb\utils
*/
class Cron
{
/**
* @var Manager
*/
protected $manager;
/**
* @var int
*/
protected $workerId = 0;
/**
* @var
*/
protected $timer;
/**
* @var bool
*/
protected $debug = false;
/**
* Cron constructor.
* @param Manager $manager
*/
public function __construct(Manager $manager)
{
$this->manager = $manager;
$this->debug = env('APP_DEBUG', false);
$this->workerId = $this->manager->getWorkerId();
}
/**
* @param int $workerId
* @return Cron
*/
public function setWorkerId(int $workerId)
{
$this->workerId = $workerId;
return $this;
}
/**
* 沙盒运行
* @param callable $callable
*/
protected function runInSandbox(callable $callable)
{
$callable();
}
/**
* 添加启动定时任务
* @param int $ms
* @param callable $callable
* @return mixed
*/
public function tick(int $ms, callable $callable)
{
if ($this->workerId === $this->manager->getWorkerId()) {
return Timer::tick($ms, fn() => $this->runInSandbox($callable));
} else {
return null;
}
}
/**
* 每天的某时某分运行一次
* minuteTick('12:15',fun()) 例如: 12:15 会在当天的中午12点15分钟运行一次
* @param string $time
* @param callable $callable
* @return mixed|null
*/
public function minuteTick(string $time, callable $callable)
{
return $this->tick(1000 * 60, function () use ($callable, $time) {
$nowTime = date('H:i');
if ($nowTime === $time) {
$callable();
}
});
}
/**
* 一次执行
* @param int $ms
* @param callable $callable
*/
public function after(int $ms, callable $callable)
{
Timer::after($ms, fn() => $this->runInSandbox($callable));
}
/**
* 清除定时任务
* @param int $timer
*/
public function clear(int $timer)
{
Timer::clear($timer);
}
/**
* 清除所有定时任务
*/
public function clearAll()
{
Timer::clearAll();
}
}

68
crmeb/utils/Hook.php Normal file
View File

@@ -0,0 +1,68 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
use think\helper\Str;
/**
*
* Class Hook
* @package crmeb\utils
*/
class Hook
{
/**
* 类名
* @var string
*/
protected $namespace;
/**
* 方法前缀
* @var string
*/
protected $prefix;
/**
* 构造方法
* Hook constructor.
* @param string $namespace
* @param string|null $prefix
*/
public function __construct(string $namespace, string $prefix = null)
{
$this->namespace = $namespace;
if ($prefix) {
$this->prefix = $prefix;
}
}
/**
* 执行挂载方法
* @param string $hookName
* @param mixed ...$arguments
* @return bool
*/
public function listen(string $hookName, ...$arguments)
{
if (class_exists($this->namespace)) {
$handle = app()->make($this->namespace);
$hookName = Str::studly(($this->prefix ?: '') . ucfirst($hookName));
if (method_exists($handle, $hookName)) {
try {
return call_user_func_array([$handle, $hookName], $arguments);
} catch (\Throwable $e) {
}
}
}
return false;
}
}

134
crmeb/utils/Json.php Normal file
View File

@@ -0,0 +1,134 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
use think\facade\Config;
use think\facade\Lang;
use think\Log;
use think\Response;
/**
* Json输出类
* Class Json
* @package crmeb\utils
*/
class Json
{
/**
* @var int
*/
private int $code = 200;
/**
* @param int $code
* @return $this
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/19
*/
public function code(int $code): self
{
$this->code = $code;
return $this;
}
/**
* 压缩数据
* @param $str
* @return string
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
protected function compress($str): string
{
return base64_encode(gzdeflate(json_encode($str, JSON_UNESCAPED_UNICODE), 9));
}
/**
* @param int $status
* @param string $msg
* @param array|null $data
* @return Response
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
public function make(int $status, string $msg, ?array $data = null): Response
{
$request = app()->request;
$res = compact('status', 'msg');
if (!is_null($data)) {
$jsonData = json_encode($data);
//在debug关闭的时候返回压缩数据
$compressData = null;
if (app()->request->rule() && strstr('/' . app()->request->rule()->getRule(), '/api/') !== false && strlen($jsonData) > 1024 && app()->config->get('cache.is_gzde', false)) {
$compressData = $this->compress($data);
$res['gzde'] = 1;
}
$res['data'] = $compressData ?: $data;
}
if ($res['msg'] && !is_numeric($res['msg'])) {
if (!$range = $request->get('lang')) {
$range = $request->cookie(Config::get('lang.cookie_var'));
}
$langData = array_values(Config::get('lang.accept_language', []));
if (!in_array($range, $langData)) {
$range = 'zh-cn';
}
$res['msg'] = Lang::get($res['msg'], [], $range);
}
return Response::create($res, 'json', $this->code);
}
public function success($msg = 'ok', ?array $data = null): Response
{
if (is_array($msg)) {
$data = $msg;
$msg = 'ok';
}
return $this->make(200, $msg, $data);
}
public function successful(...$args): Response
{
return $this->success(...$args);
}
public function fail($msg = 'fail', ?array $data = null): Response
{
if (is_array($msg)) {
$data = $msg;
$msg = 'ok';
}
return $this->make(400, $msg, $data);
}
public function status($status, $msg = 'ok', $result = [])
{
$status = strtoupper($status);
if (is_array($msg)) {
$result = $msg;
$msg = 'ok';
}
return $this->success($msg, compact('status', 'result'));
}
}

114
crmeb/utils/JwtAuth.php Normal file
View File

@@ -0,0 +1,114 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
use crmeb\exceptions\AdminException;
use crmeb\services\CacheService;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use think\facade\Env;
/**
* Jwt
* Class JwtAuth
* @package crmeb\utils
*/
class JwtAuth
{
/**
* token
* @var string
*/
protected $token;
/**
* @var string
*/
protected $app_key = 'crmeb_app_key';
/**
* 获取token
* @param int $id
* @param string $type
* @param array $params
* @return array
*/
public function getToken(int $id, string $type, array $params = []): array
{
$host = app()->request->host();
$time = time();
$exp_time = strtotime('+ 7day');
if (app()->request->isApp()) {
$exp_time = strtotime('+ 30day');
}
if ($type == 'out') {
$exp_time = strtotime('+ 1day');
}
$params += [
'iss' => $host,
'aud' => $host,
'iat' => $time,
'nbf' => $time,
'exp' => $exp_time,
];
$params['jti'] = compact('id', 'type');
$token = JWT::encode($params, Env::get('app.app_key', $this->app_key) ?: $this->app_key, 'HS256');
return compact('token', 'params');
}
/**
* 解析token
* @param string $jwt
* @return array
*/
public function parseToken(string $jwt): array
{
$this->token = $jwt;
[, $bodyb64,] = explode('.', $this->token);
$payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64));
return [$payload->jti->id, $payload->jti->type, $payload->auth ?? ''];
}
/**
* 验证token
*/
public function verifyToken()
{
JWT::$leeway = 60;
$key = Env::get('app.app_key', $this->app_key) ?: $this->app_key;
JWT::decode($this->token, new Key($key, 'HS256'));
$this->token = null;
}
/**
* 获取token并放入令牌桶
* @param int $id
* @param string $type
* @param array $params
* @return array
*/
public function createToken(int $id, string $type, array $params = [])
{
$tokenInfo = $this->getToken($id, $type, $params);
$exp = $tokenInfo['params']['exp'] - $tokenInfo['params']['iat'] + 60;
$res = CacheService::setTokenBucket(md5($tokenInfo['token']), ['uid' => $id, 'type' => $type, 'token' => $tokenInfo['token'], 'exp' => $exp], (int)$exp, $type);
if (!$res) {
throw new AdminException(ApiErrorCode::ERR_SAVE_TOKEN);
}
return $tokenInfo;
}
}

25
crmeb/utils/QRcode.php Normal file
View File

@@ -0,0 +1,25 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
class QRcode extends \dh2y\qrcode\QRcode
{
public function setCacheDir(string $cache_dir)
{
$this->cache_dir = root_path() . 'public/' . $cache_dir;
if (!file_exists($this->cache_dir)) {
mkdir($this->cache_dir, 0775, true);
}
return $this;
}
}

106
crmeb/utils/Start.php Normal file
View File

@@ -0,0 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace crmeb\utils;
use think\App;
/**
* Start输出类
* Class Json
* @package crmeb\utils
*/
class Start
{
public function show()
{
$this->opCacheClear();
$context = $this->logo();
$context .= $this->displayItem('php version', phpversion());
$context .= $this->displayItem('swoole version', phpversion('swoole'));
$context .= $this->displayItem('thinkphp version', App::VERSION);
$context .= $this->displayItem('crmeb version', get_crmeb_version());
//http配置
$httpConf = \config("swoole.http");
$context .= $this->displayItem('http enable', $httpConf["enable"]);
$context .= $this->displayItem('http host', $httpConf["host"]);
$context .= $this->displayItem('http port', $httpConf["port"]);
$context .= $this->displayItem('http worker_num', $httpConf["worker_num"]);
//websocket配置
$context .= $this->displayItem('websocket enable', \config("swoole.websocket.enable"));
//rpc配置
$rpcConf = \config("swoole.rpc.server");
$context .= $this->displayItem('rpc enable', $rpcConf["enable"]);
if ($rpcConf["enable"]) {
$context .= $this->displayItem('rpc host', $rpcConf["host"]);
$context .= $this->displayItem('rpc port', $rpcConf["port"]);
$context .= $this->displayItem('rpc worker_num', $rpcConf["worker_num"]);
}
//队列配置
$context .= $this->displayItem('queue enable', \config("swoole.queue.enable"));
//热更新配置
$context .= $this->displayItem('hot_update enable', (bool)\config("swoole.hot_update.enable"));
//debug配置
$context .= $this->displayItem('app_debug enable', (bool)env("APP_DEBUG"));
//打印信息
echo $context;
}
private function logo()
{
return <<<LOGO
██████ ███████ ████ ████ ████████ ██████ ███████ ███████ ███████
██░░░░██ ░██░░░░██ ░██░██ ██░██ ░██░░░░░ ░█░░░░██ ░██░░░░██ ░██░░░░██ ██░░░░░██
██ ░░ ░██ ░██ ░██░░██ ██ ░██ ░██ ░█ ░██ ░██ ░██ ░██ ░██ ██ ░░██
░██ ░███████ ░██ ░░███ ░██ ░███████ ░██████ █████ ░███████ ░███████ ░██ ░██
░██ ░██░░░██ ░██ ░░█ ░██ ░██░░░░ ░█░░░░ ██ ░░░░░ ░██░░░░ ░██░░░██ ░██ ░██
░░██ ██ ░██ ░░██ ░██ ░ ░██ ░██ ░█ ░██ ░██ ░██ ░░██ ░░██ ██
░░██████ ░██ ░░██ ░██ ░██ ░████████ ░███████ ░██ ░██ ░░██ ░░███████
░░░░░░ ░░ ░░ ░░ ░░ ░░░░░░░░ ░░░░░░░ ░░ ░░ ░░ ░░░░░░░
LOGO;
}
private function displayItem($name, $value)
{
if ($value === true) {
$value = 'true';
}
elseif ($value === false) {
$value = 'false';
}
elseif ($value === null) {
$value = 'null';
}
return "\e[32m" . str_pad($name, 30, ' ', STR_PAD_RIGHT) . "\e[34m" . $value . "\e[0m \n";
}
private function opCacheClear()
{
if (function_exists('apc_clear_cache')) {
apc_clear_cache();
}
if (function_exists('opcache_reset')) {
opcache_reset();
}
}
}

99
crmeb/utils/Tag.php Normal file
View File

@@ -0,0 +1,99 @@
<?php
/**
* +----------------------------------------------------------------------
* | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
* +----------------------------------------------------------------------
* | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
* +----------------------------------------------------------------------
* | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
* +----------------------------------------------------------------------
* | Author: CRMEB Team <admin@crmeb.com>
* +----------------------------------------------------------------------
*/
namespace crmeb\utils;
use think\cache\TagSet;
use think\Container;
/**
* Class Tag
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
* @package crmeb\utils
* @mixin TagSet
*/
class Tag
{
protected TagSet $tag;
/**
* @var string
*/
protected string $tagStr;
/**
* Tag constructor.
* @param TagSet $tag
* @param string $tagStr
*/
public function __construct(TagSet $tag, string $tagStr)
{
$this->tag = $tag;
$this->tagStr = $tagStr;
}
/**
* @param string $name
* @param $value
* @param null $expire
* @return mixed
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
public function remember(string $name, $value, $expire = null)
{
//不开启数据缓存直接返回
if (!app()->config->get('cache.is_data')) {
if ($value instanceof \Closure) {
$value = Container::getInstance()->invokeFunction($value);
}
return $value;
}
$name = $this->tagStr . $name;
return $this->tag->remember($name, $value, $expire);
}
/**
* 缓存写入
* @param string $name
* @param $value
* @param $expire
* @return bool
* User: liusl
* DateTime: 2024/11/29 下午4:11
*/
public function set(string $name, $value, $expire = null)
{
$name = $this->tagStr . $name;
return $this->tag->set($name, $value, $expire);
}
/**
* @param $name
* @param $arguments
* @author 等风来
* @email 136327134@qq.com
* @date 2022/11/10
*/
public function __call($name, $arguments)
{
return $this->tag->{$name}(...$arguments);
}
}