first commit
This commit is contained in:
57
app/common/exception/ExceptionHandle.php
Normal file
57
app/common/exception/ExceptionHandle.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\exception;
|
||||
|
||||
use app\common\model\system\SystemLog;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
use support\exception\BusinessException;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Http\Response;
|
||||
use Throwable;
|
||||
|
||||
class ExceptionHandle extends \Webman\Exception\ExceptionHandler
|
||||
{
|
||||
public $dontReport = [
|
||||
BusinessException::class,
|
||||
];
|
||||
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
|
||||
try {
|
||||
|
||||
if (saenv('system_exception') && !empty($exception->getMessage())) {
|
||||
|
||||
$data = [
|
||||
'module' => request()->app,
|
||||
'controller' => request()->controller,
|
||||
'action' => request()->action,
|
||||
'params' => serialize(request()->all()),
|
||||
'method' => request()->method(),
|
||||
'url' => request()->url(),
|
||||
'ip' => request()->getRemoteIp(),
|
||||
'name' => session('AdminLogin.name'),
|
||||
];
|
||||
|
||||
if (empty($data['name'])) {
|
||||
$data['name'] = 'system';
|
||||
}
|
||||
|
||||
$data['type'] = 1;
|
||||
$data['code'] = $exception->getCode();
|
||||
$data['file'] = $exception->getFile();
|
||||
$data['line'] = $exception->getLine();
|
||||
$data['error'] = $exception->getMessage();
|
||||
SystemLog::write($data);
|
||||
}
|
||||
|
||||
} catch (InvalidArgumentException $e) {
|
||||
}
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
public function render(Request $request, Throwable $exception): Response
|
||||
{
|
||||
return getenv('APP_DEBUG') ? parent::render($request, $exception) : view(config('app.exception_tpl'), ['trace' => $exception]);
|
||||
}
|
||||
}
|
||||
295
app/common/library/Auth.php
Normal file
295
app/common/library/Auth.php
Normal file
@@ -0,0 +1,295 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
use system\Random;
|
||||
use support\Response;
|
||||
use think\facade\Cache;
|
||||
use app\common\model\system\User as UserModel;
|
||||
use Webman\Event\Event;
|
||||
|
||||
|
||||
class Auth
|
||||
{
|
||||
/**
|
||||
* token令牌
|
||||
* @var string
|
||||
*/
|
||||
public $token = null;
|
||||
|
||||
/**
|
||||
* 用户数据
|
||||
* @var object|array
|
||||
*/
|
||||
public $userInfo = null;
|
||||
|
||||
/**
|
||||
* 保活时间
|
||||
* @var string
|
||||
*/
|
||||
protected $keepTime = 604800;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @var string
|
||||
*/
|
||||
protected $_error = '';
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
$this->keepTime = config('session.cookie_lifetime');
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return object
|
||||
*/
|
||||
public static function instance(array $options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* @param array $post
|
||||
* @return false|mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
* @throws \think\db\exception\DbException
|
||||
*/
|
||||
public function register(array $post)
|
||||
{
|
||||
if (!saenv('user_status')) {
|
||||
$this->setError('暂未开放注册!');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁止批量注册
|
||||
*/
|
||||
$where[] = ['create_ip', '=', ip2long(request()->getRemoteIp())];
|
||||
$where[] = ['create_time', '>', linux_extime(1)];
|
||||
$totalMax = UserModel::where($where)->count();
|
||||
|
||||
if ($totalMax >= saenv('user_register_second')) {
|
||||
$this->setError('当日注册量已达到上限');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 过滤用户信息
|
||||
if (isset($post['nickname']) && UserModel::getByNickname($post['nickname'])) {
|
||||
$this->setError('当前用户名已被占用!');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($post['email']) && UserModel::getByEmail($post['email'])) {
|
||||
$this->setError('当前邮箱已被占用!');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($post['mobile']) && UserModel::getByMobile($post['mobile'])) {
|
||||
$this->setError('当前手机号已被占用!');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* 是否存在邀请注册
|
||||
*/
|
||||
$post['invite_id'] = $this->getToken('inviter');
|
||||
if (isset($post['pwd']) && $post['pwd']) {
|
||||
$post['salt'] = Random::alpha();
|
||||
$post['pwd'] = encryptPwd($post['pwd'], $post['salt']);
|
||||
}
|
||||
|
||||
$this->userInfo = UserModel::create($post);
|
||||
|
||||
return $this->responseToken($this->userInfo);
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$this->setError($th->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户检测登录
|
||||
* @param string $nickname
|
||||
* @param string $pwd
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function login(string $nickname = '', string $pwd = '')
|
||||
{
|
||||
// 支持邮箱或手机登录
|
||||
if (filter_var($nickname, FILTER_VALIDATE_EMAIL)) {
|
||||
$where[] = ['email', '=', htmlspecialchars(trim($nickname))];
|
||||
} else {
|
||||
$where[] = ['mobile', '=', htmlspecialchars(trim($nickname))];
|
||||
}
|
||||
$this->userInfo = UserModel::where($where)->find();
|
||||
|
||||
if (!empty($this->userInfo)) {
|
||||
|
||||
$uPwd = encryptPwd($pwd, $this->userInfo['salt']);
|
||||
if ($this->userInfo['pwd'] !== $uPwd) {
|
||||
$this->setError('用户名或密码错误');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->userInfo['status']) {
|
||||
$this->setError('用户异常或未审核,请联系管理员');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 更新登录数据
|
||||
$userUpdate = [
|
||||
'id' => $this->userInfo['id'],
|
||||
'login_time' => time(),
|
||||
'login_ip' => request()->getRemoteIp(),
|
||||
'login_count' => $this->userInfo['login_count'] + 1,
|
||||
];
|
||||
|
||||
if (UserModel::update($userUpdate)) {
|
||||
return $this->responseToken($this->userInfo);
|
||||
}
|
||||
}
|
||||
|
||||
$this->setError('您登录的用户不存在');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否登录
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function isLogin(): bool
|
||||
{
|
||||
$token = $this->getToken();
|
||||
if (!$token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$uid = $this->checkToken($token);
|
||||
|
||||
if (!empty($uid)) {
|
||||
$this->token = $token;
|
||||
$this->userInfo = UserModel::find($uid);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @return void
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
Cache::delete($this->token);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 返回前端令牌
|
||||
* @param mixed $userInfo
|
||||
* @param bool $token
|
||||
* @return mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function responseToken($userInfo, bool $token = false)
|
||||
{
|
||||
$this->token = $token ? $this->getToken() : $this->buildToken($userInfo['id']);
|
||||
$response = response();
|
||||
$response->cookie('uid', $userInfo['id'],$this->keepTime, '/');
|
||||
$response->cookie('token', $this->token,$this->keepTime, '/');
|
||||
$response->cookie('nickname', $userInfo['nickname'],$this->keepTime, '/');
|
||||
Cache::set($this->token, $userInfo['id'], $this->keepTime);
|
||||
Event::emit("system.userLoginSuccess", $userInfo);
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成token
|
||||
* @access protected
|
||||
* @param $id
|
||||
* @return string
|
||||
*/
|
||||
protected function buildToken($id): string
|
||||
{
|
||||
return md5(Random::alpha(16) . $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* @return array|string|null
|
||||
*/
|
||||
public function getToken($token = 'token')
|
||||
{
|
||||
return request()->header($token, input($token, request()->cookie($token)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验token
|
||||
* @access protected
|
||||
* @param $token
|
||||
* @return mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function checkToken($token)
|
||||
{
|
||||
$userId = Cache::get($token);
|
||||
return $userId ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后产生的错误
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): string
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置错误
|
||||
* @param string $error 信息信息
|
||||
*/
|
||||
protected function setError(string $error)
|
||||
{
|
||||
$this->_error = $error;
|
||||
}
|
||||
}
|
||||
57
app/common/library/DataBase.php
Normal file
57
app/common/library/DataBase.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 数据库操作类
|
||||
*/
|
||||
class DataBase {
|
||||
|
||||
/**
|
||||
* 导入目录下Install.sql文件
|
||||
* @param string $sqlPath
|
||||
* @return void
|
||||
*/
|
||||
public static function importSql(string $sqlPath)
|
||||
{
|
||||
if (is_file($sqlPath)) {
|
||||
$sql = file_get_contents($sqlPath);
|
||||
$sqlRecords = str_ireplace("\r", "\n", $sql);
|
||||
$sqlRecords = explode(";\n", $sqlRecords);
|
||||
$sqlRecords = str_replace("__PREFIX__", getenv('DATABASE_PREFIX'), $sqlRecords);
|
||||
foreach ($sqlRecords as $line) {
|
||||
if (empty($line)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Db::getPdo()->exec($line);
|
||||
} catch (\Throwable $th) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库文件表名
|
||||
* @param string $sqlFile
|
||||
* @return array
|
||||
*/
|
||||
public static function getSqlTables(string $sqlFile): array
|
||||
{
|
||||
$regex = "/^CREATE\s+TABLE\s+(IF\s+NOT\s+EXISTS\s+)?`?([a-zA-Z_]+)`?/mi";
|
||||
$tables = [];
|
||||
if (is_file($sqlFile)) {
|
||||
preg_match_all($regex, file_get_contents($sqlFile), $matches);
|
||||
if (isset($matches[2])) {
|
||||
foreach ($matches[2] as $match) {
|
||||
$tables[] = str_replace('__PREFIX__', getenv('DATABASE_PREFIX'), $match);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
}
|
||||
338
app/common/library/Email.php
Normal file
338
app/common/library/Email.php
Normal file
@@ -0,0 +1,338 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
use app\common\model\system\UserValidate;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use system\Random;
|
||||
|
||||
/**
|
||||
* 邮件发送类
|
||||
*
|
||||
*/
|
||||
class Email
|
||||
{
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* @PHPMailer 对象实例
|
||||
*/
|
||||
protected $mail = [];
|
||||
|
||||
/**
|
||||
* 验证码对象
|
||||
* @var UserValidate
|
||||
*/
|
||||
private $userVModel;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
* @var string
|
||||
*/
|
||||
protected $_error = '';
|
||||
|
||||
//默认配置
|
||||
protected $config = [
|
||||
'smtp_debug' => false, // 是否调试
|
||||
'smtp_host' => 'smtp.163.com', // 服务器地址
|
||||
'smtp_port' => 587, // 服务器端口
|
||||
'smtp_user' => 'yourname@163.com', // 邮件用户名
|
||||
'smtp_pass' => '****', // 邮件密码
|
||||
'smtp_name' => '管理员', // 发送邮件显示
|
||||
];
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// 此配置项为数组
|
||||
if ($email = saenv('email')) {
|
||||
$this->config = array_merge($this->config, $email);
|
||||
}
|
||||
|
||||
// 创建PHPMailer对象实例
|
||||
$this->mail = new PHPMailer();
|
||||
$this->mail->CharSet = 'UTF-8';
|
||||
$this->mail->IsSMTP();
|
||||
|
||||
/**
|
||||
* 是否开启调试模式
|
||||
*/
|
||||
$this->mail->SMTPDebug = $this->config['smtp_debug'];
|
||||
$this->mail->SMTPAuth = true;
|
||||
$this->mail->SMTPSecure = 'ssl';
|
||||
$this->mail->SMTPOptions = array(
|
||||
'ssl' => array(
|
||||
'verify_peer' => false,
|
||||
'verify_peer_name' => false,
|
||||
'allow_self_signed' => true
|
||||
)
|
||||
);
|
||||
|
||||
$this->mail->Host = $this->config['smtp_host'];
|
||||
$this->mail->Port = $this->config['smtp_port'];
|
||||
$this->mail->Username = $this->config['smtp_user'];
|
||||
$this->mail->Password = trim($this->config['smtp_pass']);
|
||||
$this->mail->SetFrom($this->config['smtp_user'], $this->config['smtp_name']);
|
||||
$this->userVModel = new UserValidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return EMAIL
|
||||
*/
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置邮件主题
|
||||
* @param string $subject 邮件主题
|
||||
* @return $this
|
||||
*/
|
||||
public function Subject(string $subject): Email
|
||||
{
|
||||
$this->mail->Subject = $subject;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置发件人
|
||||
* @param string $email 发件人邮箱
|
||||
* @param string $name 发件人名称
|
||||
* @return $this
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
*/
|
||||
public function from(string $email, string $name = ''): Email
|
||||
{
|
||||
$this->mail->setFrom($email, $name);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置邮件内容
|
||||
* @param $MsgHtml
|
||||
* @param boolean $isHtml 是否HTML格式
|
||||
* @return $this
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
*/
|
||||
public function MsgHTML($MsgHtml, bool $isHtml = true): Email
|
||||
{
|
||||
if ($isHtml) {
|
||||
$this->mail->msgHTML($MsgHtml);
|
||||
} else {
|
||||
$this->mail->Body = $MsgHtml;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置收件人
|
||||
* @param mixed $email 收件人,多个收件人以,进行分隔
|
||||
* @param string $name 收件人名称
|
||||
* @return $this
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
*/
|
||||
public function to($email, string $name = ''): Email
|
||||
{
|
||||
$emailArr = $this->buildAddress($email);
|
||||
foreach ($emailArr as $address => $name) {
|
||||
$this->mail->addAddress($address, $name);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加附件
|
||||
* @param string $path 附件路径
|
||||
* @param string $name 附件名称
|
||||
* @return Email
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
*/
|
||||
public function attachment(string $path, string $name = ''): Email
|
||||
{
|
||||
if (is_file($path)) {
|
||||
$this->mail->addAttachment($path, $name);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建Email地址
|
||||
* @param mixed $emails Email数据
|
||||
* @return array
|
||||
*/
|
||||
protected function buildAddress($emails): array
|
||||
{
|
||||
$emails = is_array($emails) ? $emails : explode(',', str_replace(";", ",", $emails));
|
||||
$result = [];
|
||||
foreach ($emails as $key => $value) {
|
||||
$email = is_numeric($key) ? $value : $key;
|
||||
$result[$email] = is_numeric($key) ? "" : $value;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一条
|
||||
* @param string $email
|
||||
* @return UserValidate|array|mixed|\think\Model|null
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getLast(string $email)
|
||||
{
|
||||
$sms = UserValidate::where('email', $email)->order('id', 'desc')->find();
|
||||
return $sms ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
* @param string $email 收件人邮箱
|
||||
* @param string $event
|
||||
* @return Email
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
*/
|
||||
public function captcha(string $email = '', string $event = "default"): Email
|
||||
{
|
||||
$code = Random::number();
|
||||
$array = [
|
||||
'code' => $code,
|
||||
'event' => $event,
|
||||
'email' => $email,
|
||||
'status' => 1,
|
||||
];
|
||||
|
||||
$this->userVModel->create($array);
|
||||
$content = read_file(base_path() . '/extend/conf/tpl/captcha.tpl');
|
||||
$content = str_replace(['{code}', '{site_name}', '{time}'], [$code, saenv('site_name'), date('Y-m-d H:i:s')], $content);
|
||||
$this->to($email)->Subject("验证码")->MsgHTML($content);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查验证码
|
||||
* @param string $email
|
||||
* @param string $code
|
||||
* @param string $event
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function check(string $email, string $code = '', string $event = "default"): bool
|
||||
{
|
||||
$result = $this->userVModel->where([
|
||||
['event', '=', $event],
|
||||
['email', '=', $email],
|
||||
['status', '=', 1],
|
||||
])->order("id", "desc")->find();
|
||||
|
||||
if (!empty($result) && $result->code == $code) {
|
||||
|
||||
// 设置已使用
|
||||
$result->status = 0;
|
||||
$result->save();
|
||||
|
||||
// 是否过期
|
||||
$expires = time() - strtotime($result['create_time']);
|
||||
if ($expires <= 60) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->setError("当前验证码已过期!");
|
||||
|
||||
} else {
|
||||
$this->setError("无效验证码");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后产生的错误
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): string
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置错误
|
||||
* @param string $error 信息信息
|
||||
*/
|
||||
protected function setError(string $error)
|
||||
{
|
||||
$this->_error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
* @return boolean
|
||||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
$result = false;
|
||||
|
||||
try {
|
||||
$result = $this->mail->send();
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
$this->setError($e->getMessage());
|
||||
}
|
||||
|
||||
$this->setError($result ? '' : $this->mail->ErrorInfo);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试发送
|
||||
* @return boolean
|
||||
* @throws \PHPMailer\PHPMailer\Exception
|
||||
*/
|
||||
public function testEmail($config)
|
||||
{
|
||||
|
||||
if (empty($config) || !is_array($config)) {
|
||||
return '缺少必要的信息';
|
||||
}
|
||||
|
||||
$this->config = array_merge($this->config, $config);
|
||||
$this->mail->Host = $this->config['smtp_host'];
|
||||
$this->mail->Port = $this->config['smtp_port'];
|
||||
$this->mail->Username = $this->config['smtp_user'];
|
||||
$this->mail->Password = trim($this->config['smtp_pass']);
|
||||
$this->mail->SetFrom($this->config['smtp_user'], $this->config['smtp_name']);
|
||||
return $this->to($config['smtp_test'])->Subject("测试邮件")->MsgHTML("如果您看到这封邮件,说明测试成功了!")->send();
|
||||
}
|
||||
|
||||
}
|
||||
155
app/common/library/Ftp.php
Normal file
155
app/common/library/Ftp.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
use system\Random;
|
||||
|
||||
/**
|
||||
* FTP上传类
|
||||
*
|
||||
*/
|
||||
class Ftp
|
||||
{
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
//默认配置
|
||||
protected $config = [
|
||||
'upload_ftp_host' => '127.0.0.1', // 服务器地址
|
||||
'upload_ftp_port' => 21, // 服务器端口
|
||||
'upload_ftp_user' => 'username', // FTP用户名
|
||||
'upload_ftp_pass' => 'password', // FTP密码
|
||||
'upload_path' => 'upload', // 上传路径
|
||||
];
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if ($upload = saenv('upload', true)) {
|
||||
$this->config = array_merge($this->config, $upload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return Ftp
|
||||
*/
|
||||
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* FTP上传函数
|
||||
* @access public
|
||||
* @param string $source 源文件
|
||||
* @param string $filepath 文件路径
|
||||
* @param string $filename 文件名称
|
||||
* @return bool true|false
|
||||
*/
|
||||
public function ftpUpload(string $source, string $filepath, string $filename): bool
|
||||
{
|
||||
|
||||
if (!empty($source) && !empty($filepath)) {
|
||||
|
||||
// 链接FTP
|
||||
$connect = @ftp_connect($this->config['upload_ftp_host'], $this->config['upload_ftp_port']) or die('Could not connect');
|
||||
|
||||
if (!ftp_login($connect, $this->config['upload_ftp_user'], $this->config['upload_ftp_pass'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 开启被动模式
|
||||
ftp_pasv($connect, TRUE);
|
||||
$source = fopen($source, "r");
|
||||
|
||||
// 循环创建文件夹
|
||||
$filepath = str_replace("\\", '/', $filepath);
|
||||
$dirs = explode('/', $filepath);
|
||||
foreach ($dirs as $val) {
|
||||
if (@ftp_chdir($connect, $val) == false) {
|
||||
if (!ftp_mkdir($connect, $val)) {
|
||||
//创建失败
|
||||
return false;
|
||||
}
|
||||
// 切换目录
|
||||
@ftp_chdir($connect, $val);
|
||||
}
|
||||
}
|
||||
|
||||
if (!@ftp_fput($connect, $filename, $source, FTP_BINARY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ftp_close($connect);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FTP测试函数
|
||||
* @access public
|
||||
* @param array $config 配置信息
|
||||
* @return bool true|false
|
||||
*/
|
||||
public function ftpTest(array $config): bool
|
||||
{
|
||||
|
||||
$connect = @ftp_connect($config['host'], (int)$config['port']) or die('Could not connect');
|
||||
if (@ftp_login($connect, $config['user'], $config['pass'])) {
|
||||
|
||||
try {
|
||||
// 开启被动模式
|
||||
ftp_pasv($connect, TRUE);
|
||||
$folder = Random::alpha(16);
|
||||
if (ftp_mkdir($connect, $folder)) {
|
||||
|
||||
// 读取测试文件
|
||||
$location = __DIR__;
|
||||
$source = fopen($location, "r"); // 上传测试文件
|
||||
$filename = $folder . "/target.txt";
|
||||
ftp_fput($connect, $filename, $source, FTP_BINARY);
|
||||
|
||||
// 删除测试文件
|
||||
ftp_delete($connect, $filename);
|
||||
ftp_rmdir($connect, $folder);
|
||||
ftp_close($connect);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
return $th->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
108
app/common/library/Images.php
Normal file
108
app/common/library/Images.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
use think\Image;
|
||||
|
||||
/**
|
||||
* @mixin \think\Images
|
||||
*/
|
||||
class Images
|
||||
{
|
||||
/**
|
||||
* 水印函数
|
||||
* @access public
|
||||
* @param string $filename 文件路径
|
||||
* @param array $config 配置数组
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function waterMark(string $filename, array $config)
|
||||
{
|
||||
|
||||
try {
|
||||
|
||||
// 获取文件信息
|
||||
$Image = Image::open($filename);
|
||||
$ImageInfo = getimagesize($filename);
|
||||
|
||||
// 判断水印类型
|
||||
if ($config['upload_water_type']) { // 文字水印
|
||||
$size = $config['upload_water_size'] ? $config['upload_water_size'] : 15;
|
||||
$color = $config['upload_water_color'] ?: '#000000';
|
||||
$ttf = public_path() . '/static/font/default.ttf';
|
||||
if (!preg_match('/^#[0-9a-fA-F]{6}$/', $color)) {
|
||||
$color = '#000000';
|
||||
}
|
||||
|
||||
// 设置透明度
|
||||
$transparency = intval((100 - $config['upload_water_pct']) * (127 / 100));
|
||||
$color .= dechex($transparency);
|
||||
$resWater = $Image->text($config['upload_water_font'], $ttf, $size, $color, $config['upload_water_pos'])->save($filename);
|
||||
|
||||
} else {
|
||||
|
||||
if (!file_exists($config['upload_water_img'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ImageWaterInfo = getimagesize($config['upload_water_img']);
|
||||
|
||||
// 对比图片大小
|
||||
if ($ImageWaterInfo[0] >= $ImageInfo[0] ||
|
||||
$ImageWaterInfo[1] >= $ImageInfo[1]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查图片
|
||||
$resWater = $Image->water($config['upload_water_img'], $config['upload_water_pos'], $config['upload_water_pct'])->save($filename);
|
||||
}
|
||||
|
||||
return $resWater ?? false;
|
||||
} catch (\Throwable $th) {
|
||||
throw new \Exception($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 微缩图函数
|
||||
* @access public
|
||||
* @param $filepath
|
||||
* @param $filename
|
||||
* @param $config
|
||||
* @param bool $avatar
|
||||
* @param bool $newfile
|
||||
* @return Image|void
|
||||
*/
|
||||
public function thumb($filepath, $filename, $config, bool $avatar = false, bool $newfile = true)
|
||||
{
|
||||
|
||||
$resource = $filepath . '/' . $filename;
|
||||
|
||||
try {
|
||||
// 判断图片大小,原图尺寸不得小于微缩图
|
||||
// 120x140 120x141 121x140 110x140
|
||||
$ImageInfo = getimagesize($resource);
|
||||
if ($ImageInfo[0] >= $config['upload_thumb_w'] && $ImageInfo[1] >= $config['upload_thumb_h']) {
|
||||
|
||||
$Image = Image::open($resource);
|
||||
// 判断微缩图类型
|
||||
if (!empty($avatar)) { // 用户头像模式/替换原来的图片
|
||||
$resThumb = $Image->thumb(110, 110, 6)->save($resource, NULL, 90);
|
||||
} else {
|
||||
if ($newfile) {
|
||||
// 保留原来的图片 新文件名建议源文件名+_thumb.jpg 格式
|
||||
$resource = $filepath . '/thumb_' . $filename;
|
||||
}
|
||||
|
||||
$resThumb = $Image->thumb($config['upload_thumb_w'], $config['upload_thumb_h'], 6)->save($resource, NULL, 90);
|
||||
}
|
||||
|
||||
return $resThumb;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new \Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
386
app/common/library/Ip2Region.php
Normal file
386
app/common/library/Ip2Region.php
Normal file
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
/**
|
||||
* ip2region php seacher client class
|
||||
*
|
||||
* @author chenxin<chenxin619315@gmail.com>
|
||||
* @date 2015-10-29
|
||||
*/
|
||||
declare (strict_types = 1);
|
||||
namespace app\common\library;
|
||||
use Exception;
|
||||
defined('INDEX_BLOCK_LENGTH') or define('INDEX_BLOCK_LENGTH', 12);
|
||||
defined('TOTAL_HEADER_LENGTH') or define('TOTAL_HEADER_LENGTH', 8192);
|
||||
|
||||
class Ip2Region
|
||||
{
|
||||
/**
|
||||
* db file handler
|
||||
*/
|
||||
private $dbFileHandler = NULL;
|
||||
|
||||
/**
|
||||
* header block info
|
||||
*/
|
||||
private $HeaderSip = NULL;
|
||||
private $HeaderPtr = NULL;
|
||||
private $headerLen = 0;
|
||||
|
||||
/**
|
||||
* super block index info
|
||||
*/
|
||||
private $firstIndexPtr = 0;
|
||||
private $lastIndexPtr = 0;
|
||||
private $totalBlocks = 0;
|
||||
|
||||
/**
|
||||
* for memory mode only
|
||||
* the original db binary string
|
||||
*/
|
||||
private $dbBinStr = NULL;
|
||||
private $dbFile = NULL;
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* construct method
|
||||
*
|
||||
* @param ip2regionFile
|
||||
*/
|
||||
public function __construct($ip2regionFile)
|
||||
{
|
||||
$ip2File = base_path().'/extend/conf/ip/ip2region.db';
|
||||
$ip2regionFile = !empty($ip2regionFile) ? $ip2regionFile : $ip2File;
|
||||
$this->dbFile = $ip2regionFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return ip2region
|
||||
*/
|
||||
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* all the db binary string will be loaded into memory
|
||||
* then search the memory only and this will a lot faster than disk base search
|
||||
* @Note:
|
||||
* invoke it once before put it to public invoke could make it thread safe
|
||||
*
|
||||
* @param $ip
|
||||
*/
|
||||
public function memorySearch($ip)
|
||||
{
|
||||
//check and load the binary string for the first time
|
||||
if ( $this->dbBinStr == NULL ) {
|
||||
$this->dbBinStr = file_get_contents($this->dbFile);
|
||||
if ( $this->dbBinStr == false ) {
|
||||
throw new Exception("Fail to open the db file {$this->dbFile}");
|
||||
}
|
||||
|
||||
$this->firstIndexPtr = self::getLong($this->dbBinStr, 0);
|
||||
$this->lastIndexPtr = self::getLong($this->dbBinStr, 4);
|
||||
$this->totalBlocks = ($this->lastIndexPtr-$this->firstIndexPtr)/INDEX_BLOCK_LENGTH + 1;
|
||||
}
|
||||
|
||||
if ( is_string($ip) ) $ip = self::safeIp2long($ip);
|
||||
|
||||
//binary search to define the data
|
||||
$l = 0;
|
||||
$h = $this->totalBlocks;
|
||||
$dataPtr = 0;
|
||||
while ( $l <= $h ) {
|
||||
$m = (($l + $h) >> 1);
|
||||
$p = $this->firstIndexPtr + $m * INDEX_BLOCK_LENGTH;
|
||||
$sip = self::getLong($this->dbBinStr, $p);
|
||||
if ( $ip < $sip ) {
|
||||
$h = $m - 1;
|
||||
} else {
|
||||
$eip = self::getLong($this->dbBinStr, $p + 4);
|
||||
if ( $ip > $eip ) {
|
||||
$l = $m + 1;
|
||||
} else {
|
||||
$dataPtr = self::getLong($this->dbBinStr, $p + 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not matched just stop it here
|
||||
if ( $dataPtr == 0 ) return NULL;
|
||||
|
||||
//get the data
|
||||
$dataLen = (($dataPtr >> 24) & 0xFF);
|
||||
$dataPtr = ($dataPtr & 0x00FFFFFF);
|
||||
|
||||
return array(
|
||||
'city_id' => self::getLong($this->dbBinStr, $dataPtr),
|
||||
'region' => substr($this->dbBinStr, $dataPtr + 4, $dataLen - 4)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the data block through the specified ip address or long ip numeric with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return mixed Array or NULL for any error
|
||||
*/
|
||||
public function binarySearch( $ip )
|
||||
{
|
||||
//check and conver the ip address
|
||||
if ( is_string($ip) ) $ip = self::safeIp2long($ip);
|
||||
if ( $this->totalBlocks == 0 ) {
|
||||
//check and open the original db file
|
||||
if ( $this->dbFileHandler == NULL ) {
|
||||
$this->dbFileHandler = fopen($this->dbFile, 'r');
|
||||
if ( $this->dbFileHandler == false ) {
|
||||
throw new Exception("Fail to open the db file {$this->dbFile}");
|
||||
}
|
||||
}
|
||||
|
||||
fseek($this->dbFileHandler, 0);
|
||||
$superBlock = fread($this->dbFileHandler, 8);
|
||||
|
||||
$this->firstIndexPtr = self::getLong($superBlock, 0);
|
||||
$this->lastIndexPtr = self::getLong($superBlock, 4);
|
||||
$this->totalBlocks = ($this->lastIndexPtr-$this->firstIndexPtr)/INDEX_BLOCK_LENGTH + 1;
|
||||
}
|
||||
|
||||
//binary search to define the data
|
||||
$l = 0;
|
||||
$h = $this->totalBlocks;
|
||||
$dataPtr = 0;
|
||||
while ( $l <= $h ) {
|
||||
$m = (($l + $h) >> 1);
|
||||
$p = $m * INDEX_BLOCK_LENGTH;
|
||||
|
||||
fseek($this->dbFileHandler, $this->firstIndexPtr + $p);
|
||||
$buffer = fread($this->dbFileHandler, INDEX_BLOCK_LENGTH);
|
||||
$sip = self::getLong($buffer, 0);
|
||||
if ( $ip < $sip ) {
|
||||
$h = $m - 1;
|
||||
} else {
|
||||
$eip = self::getLong($buffer, 4);
|
||||
if ( $ip > $eip ) {
|
||||
$l = $m + 1;
|
||||
} else {
|
||||
$dataPtr = self::getLong($buffer, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not matched just stop it here
|
||||
if ( $dataPtr == 0 ) return NULL;
|
||||
|
||||
|
||||
//get the data
|
||||
$dataLen = (($dataPtr >> 24) & 0xFF);
|
||||
$dataPtr = ($dataPtr & 0x00FFFFFF);
|
||||
|
||||
fseek($this->dbFileHandler, $dataPtr);
|
||||
$data = fread($this->dbFileHandler, $dataLen);
|
||||
|
||||
return array(
|
||||
'city_id' => self::getLong($data, 0),
|
||||
'region' => substr($data, 4)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the data block associated with the specified ip with b-tree search algorithm
|
||||
* @Note: not thread safe
|
||||
*
|
||||
* @param ip
|
||||
* @return Mixed Array for NULL for any error
|
||||
*/
|
||||
public function btreeSearch( $ip )
|
||||
{
|
||||
if ( is_string($ip) ) $ip = self::safeIp2long($ip);
|
||||
|
||||
//check and load the header
|
||||
if ( $this->HeaderSip == NULL ) {
|
||||
//check and open the original db file
|
||||
if ( $this->dbFileHandler == NULL ) {
|
||||
$this->dbFileHandler = fopen($this->dbFile, 'r');
|
||||
if ( $this->dbFileHandler == false ) {
|
||||
throw new Exception("Fail to open the db file {$this->dbFile}");
|
||||
}
|
||||
}
|
||||
|
||||
fseek($this->dbFileHandler, 8);
|
||||
$buffer = fread($this->dbFileHandler, TOTAL_HEADER_LENGTH);
|
||||
|
||||
//fill the header
|
||||
$idx = 0;
|
||||
$this->HeaderSip = array();
|
||||
$this->HeaderPtr = array();
|
||||
for ( $i = 0; $i < TOTAL_HEADER_LENGTH; $i += 8 ) {
|
||||
$startIp = self::getLong($buffer, $i);
|
||||
$dataPtr = self::getLong($buffer, $i + 4);
|
||||
if ( $dataPtr == 0 ) break;
|
||||
|
||||
$this->HeaderSip[] = $startIp;
|
||||
$this->HeaderPtr[] = $dataPtr;
|
||||
$idx++;
|
||||
}
|
||||
|
||||
$this->headerLen = $idx;
|
||||
}
|
||||
|
||||
//1. define the index block with the binary search
|
||||
$l = 0; $h = $this->headerLen; $sptr = 0; $eptr = 0;
|
||||
while ( $l <= $h ) {
|
||||
$m = (($l + $h) >> 1);
|
||||
|
||||
//perfetc matched, just return it
|
||||
if ( $ip == $this->HeaderSip[$m] ) {
|
||||
if ( $m > 0 ) {
|
||||
$sptr = $this->HeaderPtr[$m-1];
|
||||
$eptr = $this->HeaderPtr[$m ];
|
||||
} else {
|
||||
$sptr = $this->HeaderPtr[$m ];
|
||||
$eptr = $this->HeaderPtr[$m+1];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//less then the middle value
|
||||
if ( $ip < $this->HeaderSip[$m] ) {
|
||||
if ( $m == 0 ) {
|
||||
$sptr = $this->HeaderPtr[$m ];
|
||||
$eptr = $this->HeaderPtr[$m+1];
|
||||
break;
|
||||
} else if ( $ip > $this->HeaderSip[$m-1] ) {
|
||||
$sptr = $this->HeaderPtr[$m-1];
|
||||
$eptr = $this->HeaderPtr[$m ];
|
||||
break;
|
||||
}
|
||||
$h = $m - 1;
|
||||
} else {
|
||||
if ( $m == $this->headerLen - 1 ) {
|
||||
$sptr = $this->HeaderPtr[$m-1];
|
||||
$eptr = $this->HeaderPtr[$m ];
|
||||
break;
|
||||
} else if ( $ip <= $this->HeaderSip[$m+1] ) {
|
||||
$sptr = $this->HeaderPtr[$m ];
|
||||
$eptr = $this->HeaderPtr[$m+1];
|
||||
break;
|
||||
}
|
||||
$l = $m + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//match nothing just stop it
|
||||
if ( $sptr == 0 ) return NULL;
|
||||
|
||||
//2. search the index blocks to define the data
|
||||
$blockLen = $eptr - $sptr;
|
||||
fseek($this->dbFileHandler, $sptr);
|
||||
$index = fread($this->dbFileHandler, $blockLen + INDEX_BLOCK_LENGTH);
|
||||
|
||||
$dataPtr = 0;
|
||||
$l = 0; $h = $blockLen / INDEX_BLOCK_LENGTH;
|
||||
while ( $l <= $h ) {
|
||||
$m = (($l + $h) >> 1);
|
||||
$p = (int)($m * INDEX_BLOCK_LENGTH);
|
||||
$sip = self::getLong($index, $p);
|
||||
if ( $ip < $sip ) {
|
||||
$h = $m - 1;
|
||||
} else {
|
||||
$eip = self::getLong($index, $p + 4);
|
||||
if ( $ip > $eip ) {
|
||||
$l = $m + 1;
|
||||
} else {
|
||||
$dataPtr = self::getLong($index, $p + 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not matched
|
||||
if ( $dataPtr == 0 ) return NULL;
|
||||
|
||||
//3. get the data
|
||||
$dataLen = (($dataPtr >> 24) & 0xFF);
|
||||
$dataPtr = ($dataPtr & 0x00FFFFFF);
|
||||
|
||||
fseek($this->dbFileHandler, $dataPtr);
|
||||
$data = fread($this->dbFileHandler, $dataLen);
|
||||
|
||||
return array(
|
||||
'city_id' => self::getLong($data, 0),
|
||||
'region' => substr($data, 4)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* safe self::safeIp2long function
|
||||
*
|
||||
* @param ip
|
||||
* */
|
||||
public static function safeIp2long($ip)
|
||||
{
|
||||
$ip = ip2long($ip);
|
||||
|
||||
// convert signed int to unsigned int if on 32 bit operating system
|
||||
if ($ip < 0 && PHP_INT_SIZE == 4) {
|
||||
$ip = sprintf("%u", $ip);
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* read a long from a byte buffer
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
*/
|
||||
public static function getLong( $b, $offset )
|
||||
{
|
||||
$val = (
|
||||
(ord($b[$offset++])) |
|
||||
(ord($b[$offset++]) << 8) |
|
||||
(ord($b[$offset++]) << 16) |
|
||||
(ord($b[$offset ]) << 24)
|
||||
);
|
||||
|
||||
// convert signed int to unsigned int if on 32 bit operating system
|
||||
if ($val < 0 && PHP_INT_SIZE == 4) {
|
||||
$val = sprintf("%u", $val);
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* destruct method, resource destroy
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ( $this->dbFileHandler != NULL ) {
|
||||
fclose($this->dbFileHandler);
|
||||
}
|
||||
|
||||
$this->dbBinStr = NULL;
|
||||
$this->HeaderSip = NULL;
|
||||
$this->HeaderPtr = NULL;
|
||||
}
|
||||
}
|
||||
164
app/common/library/Jwt.php
Normal file
164
app/common/library/Jwt.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
/**
|
||||
* Jwt简易验证类
|
||||
* Class Jwt
|
||||
* @package app\common\library
|
||||
* @author meystack <
|
||||
*/
|
||||
class Jwt
|
||||
{
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
// 头部信息
|
||||
private static $header = array(
|
||||
'alg' => 'HS256', //生成signature的算法
|
||||
'typ' => 'JWT' //类型
|
||||
);
|
||||
|
||||
private static $key = '123456';
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return Jwt
|
||||
*/
|
||||
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取jwt token
|
||||
* @param $payload
|
||||
* [
|
||||
* 'iss'=>'jwt_admin', // 该JWT的签发者
|
||||
* 'iat'=>time(), // 签发时间
|
||||
* 'exp'=>time()+7200, // 过期时间
|
||||
* 'nbf'=>time()+60, // 该时间之前不接收处理该Token
|
||||
* 'sub'=>'www.admin.com', // 面向的用户
|
||||
* 'jti'=>md5(uniqid('JWT').time()) // 该Token唯一标识
|
||||
* ]
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function getToken($payload)
|
||||
{
|
||||
if (is_array($payload)) {
|
||||
$base64header = self::base64UrlEncode(json_encode(self::$header, JSON_UNESCAPED_UNICODE));
|
||||
$base64payload = self::base64UrlEncode(json_encode($payload, JSON_UNESCAPED_UNICODE));
|
||||
return $base64header . '.' . $base64payload . '.' . self::signature($base64header . '.' . $base64payload, self::$key, self::$header['alg']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证token是否有效,默认验证exp,nbf,iat时间
|
||||
* @param string $Token 需要验证的token
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function verifyToken(string $Token)
|
||||
{
|
||||
$tokens = explode('.', $Token);
|
||||
if (count($tokens) != 3)
|
||||
return false;
|
||||
|
||||
list($base64header, $base64payload, $sign) = $tokens;
|
||||
|
||||
// 获取jwt算法
|
||||
$base64DecodeHeader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);
|
||||
if (empty($base64DecodeHeader['alg']))
|
||||
return false;
|
||||
|
||||
// 签名验证
|
||||
if (self::signature($base64header . '.' . $base64payload, self::$key, $base64DecodeHeader['alg']) !== $sign)
|
||||
return false;
|
||||
|
||||
$payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);
|
||||
|
||||
// 签发时间大于当前服务器时间验证失败
|
||||
if (isset($payload['iat']) && $payload['iat'] > time())
|
||||
return false;
|
||||
|
||||
// 过期时间小宇当前服务器时间验证失败
|
||||
if (isset($payload['exp']) && $payload['exp'] < time())
|
||||
return false;
|
||||
|
||||
// 该nbf时间之前不接收处理该Token
|
||||
if (isset($payload['nbf']) && $payload['nbf'] > time())
|
||||
return false;
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现
|
||||
* @param string $input 需要编码的字符串
|
||||
* @return string
|
||||
*/
|
||||
private static function base64UrlEncode(string $input): string
|
||||
{
|
||||
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
|
||||
}
|
||||
|
||||
/**
|
||||
* base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现
|
||||
* @param string $input 需要解码的字符串
|
||||
* @return bool|string
|
||||
*/
|
||||
private static function base64UrlDecode(string $input)
|
||||
{
|
||||
$remainder = strlen($input) % 4;
|
||||
if ($remainder) {
|
||||
$addLen = 4 - $remainder;
|
||||
$input .= str_repeat('=', $addLen);
|
||||
}
|
||||
return base64_decode(strtr($input, '-_', '+/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现
|
||||
* @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
|
||||
* @param string $key
|
||||
* @param string $alg 算法方式
|
||||
* @return string
|
||||
*/
|
||||
private static function signature(string $input, string $key, string $alg = 'HS256'): string
|
||||
{
|
||||
$alg_config = array(
|
||||
'HS256' => 'sha256'
|
||||
);
|
||||
return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key, true));
|
||||
}
|
||||
|
||||
}
|
||||
224
app/common/library/ParseData.php
Normal file
224
app/common/library/ParseData.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
/**
|
||||
* 全局模型数据处理类
|
||||
* 1、自动设置字段属性
|
||||
* 2、执行数据库事件回调
|
||||
*/
|
||||
class ParseData
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取标题拼音
|
||||
* @access public
|
||||
* @param string $pinyin 属性值
|
||||
* @param array $data 当前数组
|
||||
* @return string
|
||||
*/
|
||||
public static function setPinyinAttr(string $pinyin, array $data): string
|
||||
{
|
||||
if (empty($pinyin)) {
|
||||
return pinyin($data['title'], true);
|
||||
}
|
||||
|
||||
return trim($pinyin);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取标题首字母
|
||||
* @access public
|
||||
* @param string $letter 属性值
|
||||
* @param array $data 当前数组
|
||||
* @return string
|
||||
*/
|
||||
public static function setLetterAttr(string $letter, array $data): string
|
||||
{
|
||||
if (empty($letter)) {
|
||||
|
||||
$pinyin = pinyin($data['title'], true);
|
||||
return substr($pinyin, 0, 1);
|
||||
}
|
||||
return $letter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 自动获取描述
|
||||
* @access public
|
||||
* @param string $description 属性值
|
||||
* @param array $data 当前数组
|
||||
* @return string
|
||||
*/
|
||||
public static function setDescriptionAttr(string $description, array $data): string
|
||||
{
|
||||
if (empty($description) && !empty($data['content'])) {
|
||||
return msubstr($data['content'], 0, 80);
|
||||
}
|
||||
|
||||
return $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内容数据修改器
|
||||
* @access public
|
||||
* @param string $content
|
||||
* @return string
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public static function setContentAttr(string $content): string
|
||||
{
|
||||
if ($prefix = cdn_Prefix()) {
|
||||
$content = str_replace($prefix, '', $content);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内容数据
|
||||
* @access public
|
||||
* @param string $content
|
||||
* @return string
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public static function getContentAttr(string $content): string
|
||||
{
|
||||
if (!empty($content)) {
|
||||
|
||||
// 是否开启前缀
|
||||
if ($prefix = cdn_Prefix()) {
|
||||
$pattern = "/<img.*?src=\"(.*?)\"/i";
|
||||
if (preg_match_all($pattern, $content, $images)) {
|
||||
$images = array_unique($images[1]);
|
||||
foreach ($images as $value) {
|
||||
$value = urldecode($value);
|
||||
if (!strpos($value, '://')) {
|
||||
$content = str_replace($value, $prefix . $value, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动补全图片
|
||||
* @access public
|
||||
* @param string $image
|
||||
* @param $data
|
||||
* @param bool $ready
|
||||
* @return string
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public static function setImageAttr(string $image, $data, bool $ready = false): string
|
||||
{
|
||||
if (empty($image) && !empty($data['content']) && $ready) {
|
||||
$pattern = "/<img.*?src=\"(.*?)\"/i";
|
||||
$prefix = cdn_Prefix();
|
||||
if (preg_match($pattern, $data['content'], $images)) {
|
||||
return $prefix ? str_replace($prefix, '', $images[1]) : $images[1];
|
||||
}
|
||||
}
|
||||
|
||||
return self::changeImages($image, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图片链接
|
||||
* @access public
|
||||
* @param string $image
|
||||
* @return string
|
||||
*/
|
||||
public static function getImageAttr(string $image): string
|
||||
{
|
||||
if (!empty($image)) {
|
||||
$image = urldecode($image);
|
||||
}
|
||||
|
||||
if ($image && strpos($image, '://')) {
|
||||
return $image;
|
||||
}
|
||||
|
||||
return self::changeImages($image);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理图片实例
|
||||
* @access public
|
||||
* @param string $image 图片地址
|
||||
* @param bool $bool 链接OR替换
|
||||
* @return string
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
protected static function changeImages(string $image, bool $bool = true): string
|
||||
{
|
||||
$prefix = cdn_Prefix();
|
||||
if (!empty($prefix) && $image) {
|
||||
// 过滤base64
|
||||
if (!stristr($image, 'data:image')) {
|
||||
return $bool ? $prefix . $image : str_replace($prefix, '', $image);
|
||||
}
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getIPAttr($ip)
|
||||
{
|
||||
if (!empty($ip)) {
|
||||
$ip = long2ip($ip);
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public static function setIPAttr($ip)
|
||||
{
|
||||
if (!empty($ip)) {
|
||||
$ip = ip2long($ip);
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置独立模板
|
||||
* @access public
|
||||
* @param string $skin 模板名称
|
||||
* @return string
|
||||
*/
|
||||
public static function setSkinAttr(string $skin): string
|
||||
{
|
||||
if ($skin) {
|
||||
$skin = str_replace(['.html', '.htm'], '', $skin);
|
||||
}
|
||||
|
||||
return $skin;
|
||||
}
|
||||
}
|
||||
158
app/common/library/ResultCode.php
Normal file
158
app/common/library/ResultCode.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
|
||||
/**
|
||||
* RESULT代码文件
|
||||
*/
|
||||
class ResultCode
|
||||
{
|
||||
const SUCCESS = [
|
||||
'code' => 200,
|
||||
'status' => 'SUCCESS',
|
||||
'msg' => '请求成功',
|
||||
];
|
||||
|
||||
const REGISTERSUCCESS = [
|
||||
'code' => 200,
|
||||
'status' => 'REGISTERSUCCESS',
|
||||
'msg' => '注册成功',
|
||||
];
|
||||
|
||||
const LOGINSUCCESS = [
|
||||
'code' => 200,
|
||||
'status' => 'LOGINSUCCESS',
|
||||
'msg' => '登录成功',
|
||||
];
|
||||
|
||||
const LOGINOUTSUCCESS = [
|
||||
'code' => 200,
|
||||
'status' => 'LOGINOUTSUCCESS',
|
||||
'msg' => '退出成功',
|
||||
];
|
||||
|
||||
const AUTH_ERROR = [
|
||||
'code' => -100,
|
||||
'status' => 'AUTH_ERROR',
|
||||
'msg' => '没有权限',
|
||||
];
|
||||
|
||||
const INVALID = [
|
||||
'code' => -101,
|
||||
'status' => 'INVALID',
|
||||
'msg' => '操作失败',
|
||||
];
|
||||
|
||||
const PARAMERROR = [
|
||||
'code' => -102,
|
||||
'status' => 'PARAMERROR',
|
||||
'msg' => '请求参数错误',
|
||||
];
|
||||
|
||||
const TOKEN_INVALID = [
|
||||
'code' => -103,
|
||||
'status' => 'TOKEN_INVALID',
|
||||
'msg' => 'token校验失败',
|
||||
];
|
||||
|
||||
const API_DISABLE = [
|
||||
'code' => -104,
|
||||
'status' => 'API_DISABLE',
|
||||
'msg' => '当前接口已禁用',
|
||||
];
|
||||
|
||||
const METHOD_INVALID = [
|
||||
'code' => -105,
|
||||
'status' => 'METHOD_INVALID',
|
||||
'msg' => '访问方式错误',
|
||||
];
|
||||
|
||||
const DAY_INVALID = [
|
||||
'code' => -106,
|
||||
'status' => 'DAY_INVALID',
|
||||
'msg' => '接口已达每日上限',
|
||||
];
|
||||
|
||||
const API_SPEED_INVALID = [
|
||||
'code' => -107,
|
||||
'status' => 'API_SPEED_INVALID',
|
||||
'msg' => '调用API接口速度过快',
|
||||
];
|
||||
|
||||
const CEILING_INVALID = [
|
||||
'code' => -108,
|
||||
'status' => 'CEILING_INVALID',
|
||||
'msg' => '调用总额已消费完',
|
||||
];
|
||||
|
||||
const USPWDERROR = [
|
||||
'code' => -109,
|
||||
'status' => 'USPWDERROR',
|
||||
'msg' => '用户名或密码错误',
|
||||
];
|
||||
|
||||
const STATUSEXCEPTION = [
|
||||
'code' => -110,
|
||||
'status' => 'STATUSEXCEPTION',
|
||||
'msg' => '当前用户已被禁用',
|
||||
];
|
||||
|
||||
const ACCESS_TOKEN_TIMEOUT = [
|
||||
'code' => -300,
|
||||
'status' => 'ACCESS_TOKEN_TIMEOUT',
|
||||
'msg' => '身份令牌过期',
|
||||
];
|
||||
|
||||
const ACCESS_TOKEN_INVALID = [
|
||||
'code' => -301,
|
||||
'status' => 'ACCESS_TOKEN_INVALID',
|
||||
'msg' => '获取token失败',
|
||||
];
|
||||
|
||||
const SESSION_TIMEOUT = [
|
||||
'code' => -302,
|
||||
'status' => 'SESSION_TIMEOUT',
|
||||
'msg' => 'SESSION过期',
|
||||
];
|
||||
|
||||
const UNKNOWN = [
|
||||
'code' => -990,
|
||||
'status' => 'UNKNOWN',
|
||||
'msg' => '未知错误',
|
||||
];
|
||||
|
||||
const EXCEPTION = [
|
||||
'code' => -991,
|
||||
'status' => 'EXCEPTION',
|
||||
'msg' => '系统异常',
|
||||
];
|
||||
|
||||
const VERSION_ERROR = [
|
||||
'code' => -992,
|
||||
'status' => 'VERSION_ERROR',
|
||||
'msg' => '版本错误',
|
||||
];
|
||||
|
||||
const SYSTEM_DISABLE = [
|
||||
'code' => -993,
|
||||
'status' => 'VERSION_ERROR',
|
||||
'msg' => '禁止修改系统属性',
|
||||
];
|
||||
|
||||
const LACKPARAME = [
|
||||
'code' => -994,
|
||||
'status' => 'LACKPARAME',
|
||||
'msg' => '缺少请求参数',
|
||||
];
|
||||
|
||||
}
|
||||
165
app/common/library/Sms.php
Normal file
165
app/common/library/Sms.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
use app\common\model\system\UserValidate;
|
||||
use Webman\Event\Event;
|
||||
|
||||
/**
|
||||
* 短信息类
|
||||
*
|
||||
*/
|
||||
class Sms
|
||||
{
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
// 默认配置
|
||||
protected $config = [];
|
||||
|
||||
// 错误信息
|
||||
protected $_error = '';
|
||||
|
||||
protected $smsType = 'alisms';
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// 此配置项为数组。
|
||||
if ($this->smsType = saenv('smstype')) {
|
||||
$this->config = array_merge($this->config, saenv($this->smsType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return self
|
||||
*/
|
||||
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
// 返回实例
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送短信
|
||||
* @param string $mobile
|
||||
* @param string $event
|
||||
* @return bool
|
||||
*/
|
||||
public function send(string $mobile, string $event = 'register'): bool
|
||||
{
|
||||
if (!Event::hasListener('smsMsgSend')) {
|
||||
$this->setError('短信插件未安装');
|
||||
return false;
|
||||
}
|
||||
|
||||
$config = include(base_path() . "/extend/conf/sms/sms.php");
|
||||
if (!isset($config[$this->smsType][$event]['template'])) {
|
||||
$this->setError('短信模板错误');
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = Event::emit('smsMsgSend', [
|
||||
'mobile' => $mobile,
|
||||
'event' => $event,
|
||||
'template' => $config[$this->smsType][$event]['template']
|
||||
],true);
|
||||
|
||||
if ($response['error']) {
|
||||
$this->setError($response['msg']);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一条
|
||||
* @param string $mobile
|
||||
* @return UserValidate|array|mixed|\think\Model|null
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getLast(string $mobile)
|
||||
{
|
||||
$mobile = str_replace(['+86', '-', ' ', '.'], '', $mobile);
|
||||
$sms = UserValidate::where('mobile', $mobile)->order('id', 'desc')->find();
|
||||
return $sms ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查验证码
|
||||
*
|
||||
* @param string $mobile
|
||||
* @param string $code
|
||||
* @param string $event
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function check(string $mobile, string $code, string $event = "default"): bool
|
||||
{
|
||||
$where = [
|
||||
['event', '=', $event],
|
||||
['mobile', '=', $mobile],
|
||||
['status', '=', 1],
|
||||
];
|
||||
|
||||
$result = UserValidate::where($where)->order("id", "desc")->find();
|
||||
if (!empty($result) && $result->code === $code) {
|
||||
|
||||
$result->status = 0;
|
||||
$result->save();
|
||||
$expires = time() - strtotime($result['create_time']);
|
||||
if ($expires <= 60) {
|
||||
return true;
|
||||
}
|
||||
$this->setError("当前验证码已过期!");
|
||||
} else {
|
||||
$this->setError("无效验证码");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后产生的错误
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): string
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置错误
|
||||
* @param string $error 信息信息
|
||||
*/
|
||||
protected function setError(string $error)
|
||||
{
|
||||
$this->_error = $error;
|
||||
}
|
||||
}
|
||||
471
app/common/library/Upload.php
Normal file
471
app/common/library/Upload.php
Normal file
@@ -0,0 +1,471 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\library;
|
||||
|
||||
use system\Http;
|
||||
|
||||
use app\common\model\system\Attachment;
|
||||
use app\common\validate\system\UploadFile;
|
||||
use Webman\Event\Event;
|
||||
|
||||
/**
|
||||
* UPLOAD文件上传类
|
||||
*/
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
|
||||
class Upload
|
||||
{
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* 文件类型
|
||||
*/
|
||||
protected $fileClass;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
protected $filename;
|
||||
|
||||
/**
|
||||
* 文件保存路径
|
||||
*/
|
||||
protected $filepath;
|
||||
|
||||
/**
|
||||
* 文件全路径名称
|
||||
*/
|
||||
protected $resource;
|
||||
|
||||
/**
|
||||
* 附件信息
|
||||
*/
|
||||
protected $fileInfo = [];
|
||||
|
||||
/**
|
||||
* 图形对象实例
|
||||
*/
|
||||
protected $Images;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
protected $_error = '';
|
||||
|
||||
/**
|
||||
* 配置文件
|
||||
*/
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* 类构造函数
|
||||
* class constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->Images = new Images();
|
||||
if ($config = saenv('upload', true)) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
* @return array|false
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function upload()
|
||||
{
|
||||
$param = request()->all();
|
||||
$action = input('action');
|
||||
$file = request()->file('file');
|
||||
|
||||
if (!$file || !$file->isValid()) {
|
||||
$this->setError('上传文件读写失败!');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->fileFilter($file)) {
|
||||
$this->setError($this->_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($action == 'marge') {
|
||||
return $this->multiMarge($param);
|
||||
} else if (isset($param['chunkId']) && $param['chunkId']) {
|
||||
return $this->multiPartUpload($file, $param);
|
||||
} else {
|
||||
|
||||
try {
|
||||
$this->getFileSavePath($file);
|
||||
$file->move($this->resource);
|
||||
} catch (\Exception $e) {
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
Event::emit('uploadFileAfter', [
|
||||
'fileName' => $this->filename,
|
||||
'resource' => $this->resource
|
||||
]);
|
||||
|
||||
/**
|
||||
* 过滤gif文件
|
||||
*/
|
||||
if ($this->fileClass == "images" && !str_contains($file->getUploadExtension(), 'gif')) {
|
||||
if ($this->config['upload_water']) {
|
||||
$this->Images->waterMark($this->resource, $this->config);
|
||||
}
|
||||
if ($this->config['upload_thumb']) {
|
||||
$this->Images->thumb(public_path() . '/' . $this->filepath, $this->filename, $this->config);
|
||||
}
|
||||
}
|
||||
|
||||
$this->attachment($this->resource, $file->getUploadName(), $file->getUploadMineType());
|
||||
return $this->success('上传成功', $this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分片上传
|
||||
* @param object $file
|
||||
* @param array $params
|
||||
* @return array|false
|
||||
*/
|
||||
public function multiPartUpload(object $file, array $params = [])
|
||||
{
|
||||
$index = $params['index'];
|
||||
$chunkId = $params['chunkId'];
|
||||
$chunkName = $chunkId . '_' . $index . '.part';
|
||||
|
||||
// 校验分片名称
|
||||
if (!preg_match('/^[0-9\-]/', $chunkId)) {
|
||||
$this->setError('文件信息错误');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->getFileSavePath($file);
|
||||
$chunkSavePath = root_path('runtime/chunks');
|
||||
$this->resource = $chunkSavePath . $chunkName;
|
||||
if (!$file->move($this->resource)) {
|
||||
$this->setError('请检查服务器读写权限!');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileStream = [
|
||||
'index' => $index,
|
||||
'fileName' => sha1($chunkId),
|
||||
'fileExt' => $params['fileExt'],
|
||||
'filePath' => $this->filepath,
|
||||
'resource' => $this->resource
|
||||
];
|
||||
|
||||
Event::emit('uploadFileMultipart', $fileStream);
|
||||
return $this->success('分片上传成功', '', [
|
||||
'chunkId' => $chunkId,
|
||||
'index' => intval($index)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分片合并
|
||||
* @param array $params
|
||||
* @return array|false
|
||||
*/
|
||||
public function multiMarge(array $params = [])
|
||||
{
|
||||
$chunkId = $params['chunkId'];
|
||||
$source = $params['source'];
|
||||
$fileExt = $params['fileExt'];
|
||||
$fileSize = $params['fileSize'];
|
||||
$chunkCount = $params['chunkCount'];
|
||||
$mimeType = $params['mimeType'];
|
||||
|
||||
if (!preg_match('/^[0-9\-]/', $chunkId)) {
|
||||
$this->setError('文件名错误');
|
||||
return false;
|
||||
}
|
||||
|
||||
$filePath = root_path('runtime/chunks') . $chunkId;
|
||||
if (is_file($filePath)) {
|
||||
@unlink($filePath);
|
||||
}
|
||||
|
||||
if (!$sourceFile = @fopen($filePath, "wb")) {
|
||||
$this->setError('文件读写错误');
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Acquire an exclusive lock (writer).
|
||||
flock($sourceFile, LOCK_EX);
|
||||
for ($i = 0; $i < $chunkCount; $i++) {
|
||||
$partFile = "{$filePath}_{$i}.part";
|
||||
if (is_file($partFile)) {
|
||||
if (!$handle = @fopen($partFile, "rb")) {
|
||||
break;
|
||||
}
|
||||
while ($buff = fread($handle, filesize($partFile))) {
|
||||
fwrite($sourceFile, $buff);
|
||||
}
|
||||
@fclose($handle);
|
||||
@unlink($partFile);
|
||||
}
|
||||
}
|
||||
|
||||
flock($sourceFile, LOCK_UN);
|
||||
@fclose($sourceFile);
|
||||
if (filesize($filePath) != $fileSize) {
|
||||
throw new \Exception('文件异常,请重新上传');
|
||||
}
|
||||
|
||||
} catch (\Throwable $th) {
|
||||
$this->setError($th->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
$newFilePath = $filePath . '.' . $fileExt;
|
||||
@rename($filePath, $newFilePath);
|
||||
$file = new \Webman\Http\UploadFile($newFilePath, $source, $mimeType, 200);
|
||||
if (!$this->fileFilter($file)) {
|
||||
$this->setError($this->_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->getFileSavePath($file);
|
||||
$file->move($this->resource);
|
||||
} catch (\Exception $e) {
|
||||
Event::emit('uploadExceptionDelete', [
|
||||
'fileName' => $this->resource
|
||||
]);
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->attachment($this->resource, $file->getUploadName(), $file->getUploadMineType());
|
||||
|
||||
return $this->success('上传成功', $this->resource, [
|
||||
'chunkId' => $params['chunkId'],
|
||||
'status' => 'success',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件下载函数
|
||||
* @param string|null $url
|
||||
* @return array|false
|
||||
*/
|
||||
public function download(string $url = null)
|
||||
{
|
||||
if (empty($url)) {
|
||||
$this->setError('下载地址不能为空!');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileUrl = htmlspecialchars_decode(urldecode($url));
|
||||
$fileUrl = parse_url($fileUrl);
|
||||
$urlPath = str_replace('/', '', explode('.', $fileUrl['path']));
|
||||
$fileExt = end($urlPath);
|
||||
if (!in_array($fileExt, ['jpg', 'png', 'gif', 'jpeg'])) {
|
||||
$fileExt = 'jpg';
|
||||
}
|
||||
|
||||
$content = Http::get($url);
|
||||
$this->filename = uniqid() . '.' . $fileExt;
|
||||
$this->filepath = '/' . $this->config['upload_path'] . '/images/' . date($this->config['upload_style']);
|
||||
$this->resource = public_path() . $this->filepath . '/' . $this->filename;
|
||||
|
||||
if (!write_file($this->resource, $content)) {
|
||||
$this->setError('写入文件失败!');
|
||||
return false;
|
||||
}
|
||||
|
||||
Event::emit('uploadFileAfter', [
|
||||
'fileName' => $this->filename,
|
||||
'resource' => $this->resource
|
||||
]);
|
||||
|
||||
$this->attachment($this->resource, current($urlPath) . '.' . $fileExt, mime_content_type($this->resource));
|
||||
|
||||
return $this->success('文件上传成功!', $this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除本地文件
|
||||
* @return void
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function uploadAfterDelete()
|
||||
{
|
||||
try {
|
||||
if (saenv('upload_del')) {
|
||||
@unlink($this->resource);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件数据库保存
|
||||
* @param $file
|
||||
* @param string $source
|
||||
* @param string|null $mimeType
|
||||
* @return false|void
|
||||
*/
|
||||
public function attachment($file, string $source, string $mimeType = null)
|
||||
{
|
||||
try {
|
||||
$file = new \Webman\Http\UploadFile($file, $source, $mimeType, 200);
|
||||
$filePath = str_replace('\\', '/', $this->filepath . DS . $this->filename);
|
||||
$this->fileInfo = [
|
||||
'type' => $this->fileClass,
|
||||
'filename' => $file->getUploadName(),
|
||||
'filesize' => $file->getSize(),
|
||||
'url' => $filePath,
|
||||
'extension' => $file->getUploadExtension(),
|
||||
'mimetype' => $file->getUploadMineType(),
|
||||
'user_id' => request()->cookie('uid') ?? 0,
|
||||
'sha1' => md5_file($file->getPathname()),
|
||||
];
|
||||
Attachment::create($this->fileInfo);
|
||||
} catch (\Exception $e) {
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件扩展名
|
||||
* @param object $file
|
||||
* @return false|mixed|string
|
||||
*/
|
||||
public function getFileExt(object $file)
|
||||
{
|
||||
$fileExt = $file->getUploadExtension();
|
||||
if (empty($fileExt)) {
|
||||
$textsName = explode('.', $file->getUploadName());
|
||||
return end($textsName);
|
||||
}
|
||||
return $fileExt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证文件类型
|
||||
* @param $file
|
||||
* @return bool
|
||||
*/
|
||||
public function fileFilter($file): bool
|
||||
{
|
||||
$validate = new UploadFile();
|
||||
$rules = get_object_vars($validate)['rule'];
|
||||
$fileExt = $this->getFileExt($file);
|
||||
foreach ($rules as $key => $value) {
|
||||
$fileExtArr = explode(',', $value['fileExt']);
|
||||
if (in_array(strtolower($fileExt), $fileExtArr)) {
|
||||
if ($file->getSize() > $value['fileSize']) {
|
||||
$this->setError('文件最大支持' . format_bytes($value['fileSize']));
|
||||
return false;
|
||||
}
|
||||
$this->fileClass = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (in_array($file->getUploadMineType(), ['text/x-php', 'text/html'])) {
|
||||
$this->fileClass = null;
|
||||
}
|
||||
if (is_empty($this->fileClass)) {
|
||||
$this->_error = '禁止上传的文件类型';
|
||||
return false;
|
||||
}
|
||||
// 未找到类型或验证文件失败
|
||||
return !empty($this->fileClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $file
|
||||
* @param string|null $dir
|
||||
* @return void
|
||||
*/
|
||||
public function getFileSavePath(object $file, string $dir = null)
|
||||
{
|
||||
$this->filename = uniqid() . '.' . strtolower($file->getUploadExtension());
|
||||
$this->filepath = DS . $this->config['upload_path'] . DS . ($dir ?? $this->fileClass) . DS . date($this->config['upload_style']);
|
||||
$this->resource = public_path() . $this->filepath . DS . $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $msg
|
||||
* @param string $filePath
|
||||
* @param array $extend
|
||||
* @return array
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function success(string $msg, string $filePath, array $extend = []): array
|
||||
{
|
||||
$prefix = cdn_Prefix();
|
||||
$filePath = str_replace(public_path(), '', $filePath);
|
||||
$filePath = str_replace(['//', '\\'], '/', $filePath);
|
||||
if (!empty($prefix)) {
|
||||
$filePath = $prefix . $filePath;
|
||||
}
|
||||
return array_merge(['code' => 200, 'msg' => __($msg), 'url' => $filePath], $extend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $msg
|
||||
* @param array $extend
|
||||
* @return array
|
||||
*/
|
||||
public function error($msg, array $extend = []): array
|
||||
{
|
||||
return array_merge(['code' => 101, 'msg' => __($msg)], $extend);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后产生的错误
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): string
|
||||
{
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置错误
|
||||
* @param string $error 信息信息
|
||||
*/
|
||||
protected function setError(string $error)
|
||||
{
|
||||
$this->_error = $error;
|
||||
}
|
||||
}
|
||||
15
app/common/logic/AdminLogic.php
Normal file
15
app/common/logic/AdminLogic.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\logic;
|
||||
|
||||
/**
|
||||
* 管理员日志逻辑层
|
||||
* Class AdminLogic
|
||||
* @package app\common\logic
|
||||
* @author meystack<
|
||||
* @version 1.0
|
||||
*/
|
||||
class AdminLogic extends \think\model
|
||||
{
|
||||
// TODO..
|
||||
}
|
||||
36
app/common/middleware/AccessCross.php
Normal file
36
app/common/middleware/AccessCross.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\middleware;
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
|
||||
/**
|
||||
* 全局跨域中间件
|
||||
* @package app\common\middleware
|
||||
* @author meystack
|
||||
*/
|
||||
class AccessCross implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler) : Response
|
||||
{
|
||||
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
|
||||
$header = [
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Max-Age' => 1800,
|
||||
'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
|
||||
];
|
||||
|
||||
$origin = request()->server('HTTP_ORIGIN');
|
||||
$parseUrl = parse_url($origin);
|
||||
$domains = array_merge(config('app.cors_domain'), [request()->host(true)]);
|
||||
if (in_array("*", $domains) || in_array($origin, $domains)
|
||||
|| (isset($parseUrl['host']) && in_array($parseUrl['host'], $domains))) {
|
||||
$header['Access-Control-Allow-Origin'] = $request->header('Origin', '*');
|
||||
}
|
||||
|
||||
$response->withHeaders($header);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
34
app/common/middleware/AppInitialize.php
Normal file
34
app/common/middleware/AppInitialize.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\common\middleware;
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
/**
|
||||
* 应用全局中间件
|
||||
* Class AppInitialize
|
||||
* @package app\common\middleware
|
||||
* @author meystack <
|
||||
*/
|
||||
|
||||
class AppInitialize implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler): Response
|
||||
{
|
||||
if (in_array($request->app, config('app.deny_app_list'))) {
|
||||
return \response(request_error(), 404);
|
||||
}
|
||||
|
||||
return $handler($request);
|
||||
}
|
||||
}
|
||||
15
app/common/middleware/AppLang.php
Normal file
15
app/common/middleware/AppLang.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
namespace app\common\middleware;
|
||||
|
||||
use Webman\MiddlewareInterface;
|
||||
use Webman\Http\Response;
|
||||
use Webman\Http\Request;
|
||||
|
||||
class AppLang implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, callable $handler) : Response
|
||||
{
|
||||
locale(session('lang', 'zh_CN'));
|
||||
return $handler($request);
|
||||
}
|
||||
}
|
||||
111
app/common/model/system/Admin.php
Normal file
111
app/common/model/system/Admin.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use app\common\library\ParseData;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Admin extends \think\Model
|
||||
{
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
/**
|
||||
* 关联管理组
|
||||
*
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function group(): \think\model\relation\HasOne
|
||||
{
|
||||
return $this->hasOne(AdminGroup::class, 'id', 'group_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名/密码 进行登录判断
|
||||
* @param $user
|
||||
* @param $pwd
|
||||
* @return Admin|array|mixed|Model|null
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function checkLogin($user, $pwd)
|
||||
{
|
||||
$where[] = ['pwd', '=', encryptPwd(trim($pwd))];
|
||||
if (filter_var($user, FILTER_VALIDATE_EMAIL)) {
|
||||
$where[] = ['email', '=', htmlspecialchars(trim($user))];
|
||||
} else {
|
||||
$where[] = ['name', '=', htmlspecialchars(trim($user))];
|
||||
}
|
||||
|
||||
return Admin::where($where)->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名/验证码 进行数据查找
|
||||
* @param $user
|
||||
* @param $code
|
||||
* @return Admin|array|mixed|Model|null
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function checkForget($user, $code)
|
||||
{
|
||||
// 校验格式
|
||||
if (filter_var($user, FILTER_VALIDATE_EMAIL)) {
|
||||
$where[] = ['email', '=', $user];
|
||||
} else {
|
||||
$where[] = ['mobile', '=', $user];
|
||||
}
|
||||
|
||||
$where[] = ['valicode', '=', $code];
|
||||
return Admin::where($where)->find();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置创建IP
|
||||
*/
|
||||
public function setCreateIpAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取创建IP
|
||||
*/
|
||||
public function getCreateIpAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置登录IP
|
||||
*/
|
||||
public function setLoginIpAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录IP
|
||||
*/
|
||||
public function getLoginIpAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
}
|
||||
17
app/common/model/system/AdminAccess.php
Normal file
17
app/common/model/system/AdminAccess.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class AdminAccess extends Model
|
||||
{
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
}
|
||||
48
app/common/model/system/AdminGroup.php
Normal file
48
app/common/model/system/AdminGroup.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class AdminGroup extends Model
|
||||
{
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
/**
|
||||
* 获取无限极分类
|
||||
* @access public static
|
||||
* @param string $tips 名称格式
|
||||
* @param int $pid 栏目父ID
|
||||
* @param array $array 引用数组
|
||||
* @param int $blank 替换字符
|
||||
* @param int $level 栏目等级
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getListGroup(string $tips = '', int $pid = 0, array &$array = [], int $blank = 0, int $level = 0): array
|
||||
{
|
||||
// 获取所有分类
|
||||
$result = self::where('pid', $pid)->select()->toArray();
|
||||
foreach ($result as $key => $value) {
|
||||
if (!empty($tips)) {
|
||||
$cateName = $tips . $value['title'];
|
||||
$value['title'] = str_repeat('', $blank) . $cateName;
|
||||
}
|
||||
$value['_level'] = $level;
|
||||
$array[] = $value;
|
||||
unset($result[$key]);
|
||||
self::getListGroup($tips, $value['id'], $array, $blank + 1, $level + 1);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
195
app/common/model/system/AdminRules.php
Normal file
195
app/common/model/system/AdminRules.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class AdminRules extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
/**
|
||||
* 获取无限极分类
|
||||
* @access public static
|
||||
* @param string $tips 名称格式
|
||||
* @param int $pid 栏目父ID
|
||||
* @param array $array 引用数组
|
||||
* @param int $blank 替换字符
|
||||
* @param int $level 栏目等级
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getListRule(string $tips = '', int $pid = 0, array &$array = [], int $blank = 0, int $level = 0): array
|
||||
{
|
||||
$result = self::where('pid', $pid)->select()->toArray();
|
||||
foreach ($result as $key => $value) {
|
||||
if (!empty($tips)) {
|
||||
$catename = $tips . $value['title'];
|
||||
$value['title'] = str_repeat('', $blank) . $catename;
|
||||
}
|
||||
$value['_level'] = $level;
|
||||
$array[] = $value;
|
||||
unset($result[$key]);
|
||||
self::getListRule($tips, $value['id'], $array, $blank + 1, $level + 1);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回栏目树形结构
|
||||
*
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getListTree()
|
||||
{
|
||||
$array = self::field('*,title as name')->order('sort asc')->select()->toArray();
|
||||
foreach ($array as $key => $value) {
|
||||
$array[$key]['name'] = __($value['name']);
|
||||
$array[$key]['title'] = __($value['title']);
|
||||
}
|
||||
if (is_array($array) && !empty($array)) {
|
||||
return list_to_tree($array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归创建菜单
|
||||
* @param array $list 菜单列表
|
||||
* @param string $note
|
||||
* @param mixed $parent 父类的name或pid
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function createMenu(array $list = [], string $note = '', $parent = 0)
|
||||
{
|
||||
$fields = array_flip(['title', 'router', 'alias', 'type', 'icon', 'note', 'status']);
|
||||
foreach ($list as $key => $item) {
|
||||
$data = array_intersect_key($item, $fields);
|
||||
$data['pid'] = $parent;
|
||||
$children = isset($item['children']) && $item['children'];
|
||||
$data['type'] = $children ? 0 : $item['type'] ?? 1;
|
||||
$data['note'] = $note;
|
||||
$data['auth'] = $item['auth'] ?? 1;
|
||||
$data['isSystem'] = $item['isSystem'] ?? 0;
|
||||
$data['sort'] = $item['sort'] ?? self::count() + 1;
|
||||
$data['alias'] = substr(str_replace('/', ':', $data['router']), 1);
|
||||
$result = self::withTrashed()->where(['note' => $data['note'], 'pid' => $data['pid'], 'router' => $data['router']])->find();
|
||||
if (empty($result)) {
|
||||
$result = self::create($data);
|
||||
} else {
|
||||
$result->where('id', $result->id)->update($data);
|
||||
}
|
||||
if ($children) {
|
||||
self::createMenu($item['children'], $note, $result['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用菜单
|
||||
* @param string $name
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function enabled(string $name)
|
||||
{
|
||||
$list = self::getNoteByMenus($name);
|
||||
foreach ($list as $item) {
|
||||
$item->restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用菜单
|
||||
* @param string $name
|
||||
* @param bool $force
|
||||
* @return void
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function disabled(string $name, bool $force = false)
|
||||
{
|
||||
$list = self::getNoteByMenus($name);
|
||||
foreach ($list as $item) {
|
||||
self::destroy($item['id'], $force);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出指定名称的菜单规则
|
||||
* @param string $name
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function export(string $name): array
|
||||
{
|
||||
$list = self::field('id,pid,title,router,icon,auth,type')->where('note', $name)->select()->toArray();
|
||||
return self::parseMenuChildren(list_to_tree($list));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析菜单/子菜单
|
||||
* @param array $list
|
||||
* @return array
|
||||
*/
|
||||
protected static function parseMenuChildren(array $list): array
|
||||
{
|
||||
foreach ($list as $key => $value) {
|
||||
unset($list[$key]['id']);
|
||||
unset($list[$key]['pid']);
|
||||
if (isset($value['children'])) {
|
||||
$list[$key]['children'] = self::parseMenuChildren($value['children']);
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名称获取规则IDS
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getNoteByMenus(string $name)
|
||||
{
|
||||
return self::withTrashed()->where('note', $name)->select();
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段修改器
|
||||
*
|
||||
* @param [type] $value
|
||||
* @return void
|
||||
*/
|
||||
public function setSortAttr($value)
|
||||
{
|
||||
if (is_empty($value)) {
|
||||
return self::max('id') + 1;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
32
app/common/model/system/Attachment.php
Normal file
32
app/common/model/system/Attachment.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Attachment extends Model
|
||||
{
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
/**
|
||||
* 获取文件大小
|
||||
* @access public
|
||||
* @param $filesize
|
||||
* @return string
|
||||
*/
|
||||
public function getFilesizeAttr($filesize): string
|
||||
{
|
||||
if (!empty($filesize)) {
|
||||
return format_bytes($filesize);
|
||||
}
|
||||
return $filesize;
|
||||
}
|
||||
|
||||
}
|
||||
16
app/common/model/system/Company.php
Normal file
16
app/common/model/system/Company.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Company extends Model
|
||||
{
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
|
||||
}
|
||||
54
app/common/model/system/Config.php
Normal file
54
app/common/model/system/Config.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Config extends Model
|
||||
{
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
|
||||
/**
|
||||
* 获取系统配置
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $group
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function all(string $name = '', bool $group = false): array
|
||||
{
|
||||
$config = [];
|
||||
$where = $group ? ['group' => $name] : [];
|
||||
|
||||
$list = self::where($where)->select()->toArray();
|
||||
|
||||
foreach ($list as $option) {
|
||||
if (!is_empty($option['type']) && 'array' == trim($option['type'])) {
|
||||
$config[$option['name']] = json_decode($option['value'], true);
|
||||
} else {
|
||||
$config[$option['name']] = $option['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
47
app/common/model/system/Department.php
Normal file
47
app/common/model/system/Department.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use think\facade\Db;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Department extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
/**
|
||||
* 树形分类
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function getListTree(): array
|
||||
{
|
||||
$array = self::select()->toArray();
|
||||
if (is_array($array) && !empty($array)) {
|
||||
return list_to_tree($array);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// 字段修改器
|
||||
public function setSortAttr($value)
|
||||
{
|
||||
if (is_empty($value)) {
|
||||
return self::max('id') + 1;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
64
app/common/model/system/Dictionary.php
Normal file
64
app/common/model/system/Dictionary.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Dictionary extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
// 字段修改器
|
||||
public function setSortAttr($value)
|
||||
{
|
||||
if (is_empty($value)) {
|
||||
return self::max('id') + 1;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典信息
|
||||
* @param string $value
|
||||
* @return array
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws ModelNotFoundException
|
||||
*/
|
||||
public static function getValueList(string $value = ''): array
|
||||
{
|
||||
$list = [];
|
||||
$data = self::where([
|
||||
'pid' => 0,
|
||||
'value' => $value
|
||||
])->find();
|
||||
if (!empty($data)) {
|
||||
$list = self::where('pid', $data['id'])->select();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回最小id
|
||||
* @return int
|
||||
*/
|
||||
public static function minId(): int
|
||||
{
|
||||
return (int)self::where('pid', '0')->min('id');
|
||||
}
|
||||
}
|
||||
38
app/common/model/system/Jobs.php
Normal file
38
app/common/model/system/Jobs.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Jobs extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
|
||||
/**
|
||||
* 树形分类
|
||||
*/
|
||||
public static function getListTree()
|
||||
{
|
||||
$array = self::select()->toArray();
|
||||
if (is_array($array) && !empty($array)) {
|
||||
return list_to_tree($array);
|
||||
}
|
||||
}
|
||||
|
||||
// 字段修改器
|
||||
public function setSortAttr($value)
|
||||
{
|
||||
if (is_empty($value)) {
|
||||
return self::max('id') + 1;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
25
app/common/model/system/LoginLog.php
Normal file
25
app/common/model/system/LoginLog.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
|
||||
/**
|
||||
* login_log
|
||||
* 登录日志
|
||||
* @package app\admin\model\system
|
||||
*/
|
||||
class LoginLog extends Model
|
||||
{
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
protected $deleteTime = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
20
app/common/model/system/Project.php
Normal file
20
app/common/model/system/Project.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class Project extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
}
|
||||
|
||||
55
app/common/model/system/SystemLog.php
Normal file
55
app/common/model/system/SystemLog.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use app\common\library\ParseData;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class SystemLog extends Model
|
||||
{
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
// 写入日志
|
||||
public static function write($logs = null)
|
||||
{
|
||||
if (!empty($logs) && is_array($logs)) {
|
||||
try {
|
||||
self::create($logs);
|
||||
}
|
||||
catch (\Throwable $th) {
|
||||
if (preg_match('/\'(.*?)\'/',$th->getMessage(),$matches)) {
|
||||
$logs[$matches[1]] = '0'; // 字节太长
|
||||
self::write($logs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function setIPAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIPAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
}
|
||||
196
app/common/model/system/User.php
Normal file
196
app/common/model/system/User.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
use think\Model;
|
||||
use app\common\library\ParseData;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class User extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
// 定义第三方关联
|
||||
public function third(): \think\model\relation\HasMany
|
||||
{
|
||||
return $this->hasMany(UserThird::class,'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联用户组
|
||||
*
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function group(): \think\model\relation\HasOne
|
||||
{
|
||||
return $this->hasOne(UserGroup::class,'id','group_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册会员前
|
||||
* @param object $model
|
||||
* @return void
|
||||
*/
|
||||
public static function onBeforeInsert(object $model)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 更新会员前
|
||||
* @param object $model
|
||||
* @return void
|
||||
*/
|
||||
public static function onBeforeUpdate(object $model)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 注册会员后
|
||||
* @param object $model
|
||||
* @return void
|
||||
*/
|
||||
public static function onAfterInsert(object $model)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 更新会员数据
|
||||
* @param object $model
|
||||
* @return void
|
||||
*/
|
||||
public static function onAfterUpdate(object $model)
|
||||
{}
|
||||
|
||||
/**
|
||||
* 获取头像
|
||||
* @param string $value
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatarAttr(string $value, array $data): string
|
||||
{
|
||||
|
||||
if ($value && strpos($value,'://')) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (empty($value)) {
|
||||
$value = '/static/images/user_default.jpg';
|
||||
}
|
||||
|
||||
$prefix = cdn_Prefix();
|
||||
if (!empty($prefix) && $value) {
|
||||
if (!str_contains($value,'data:image')) {
|
||||
return $prefix.$value;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置头像
|
||||
* @param string $value
|
||||
* @param array $data
|
||||
* @return string
|
||||
*/
|
||||
public function setAvatarAttr(string $value, array $data): string
|
||||
{
|
||||
return ParseData::setImageAttr($value, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
public function getLoginTimeAttr($value)
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$value = date('Y-m-d H:i:s',$value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置创建IP
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function setCreateIpAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取创建IP
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function getCreateIpAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置登录IP
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function setLoginIpAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录IP
|
||||
*/
|
||||
public function getLoginIpAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function setIPAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIPAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 减少会员积分
|
||||
*
|
||||
* @param integer $id
|
||||
* @param integer $score
|
||||
* @return void
|
||||
*/
|
||||
public static function reduceScore(int $id = 0, int $score = 0)
|
||||
{
|
||||
try {
|
||||
if ($score) {
|
||||
self::where('id', $id)->dec('score', $score)->update();
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
54
app/common/model/system/UserGroup.php
Normal file
54
app/common/model/system/UserGroup.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\Model;
|
||||
use think\facade\Db;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class UserGroup extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
|
||||
/**
|
||||
* 关联用户组
|
||||
*
|
||||
* @return int|\think\model\relation\HasMany
|
||||
*/
|
||||
public function userTotal()
|
||||
{
|
||||
return $this->hasMany(User::class,'group_id','id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户组
|
||||
*
|
||||
* @param integer $id
|
||||
* @param boolean $mark
|
||||
* @return void|array
|
||||
* @throws DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public static function ToObtain(int $id = 0, bool $mark = true)
|
||||
{
|
||||
$groupList = system_cache('groupList');
|
||||
if (empty($groupList)) {
|
||||
$groupList = self::select()->toArray();
|
||||
system_cache('groupList',$groupList,86400);
|
||||
}
|
||||
|
||||
return $groupList;
|
||||
}
|
||||
}
|
||||
|
||||
17
app/common/model/system/UserThird.php
Normal file
17
app/common/model/system/UserThird.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class UserThird extends Model
|
||||
{
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
protected $updatetime = 'update_time';
|
||||
}
|
||||
42
app/common/model/system/UserValidate.php
Normal file
42
app/common/model/system/UserValidate.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\model\system;
|
||||
|
||||
use think\Model;
|
||||
use app\common\library\ParseData;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class UserValidate extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'create_time';
|
||||
|
||||
/**
|
||||
* 设置IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function setIPAttr($ip)
|
||||
{
|
||||
return ParseData::setIPAttr($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取IP转换
|
||||
* @access public
|
||||
* @param $ip
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIPAttr($ip)
|
||||
{
|
||||
return ParseData::getIPAttr($ip);
|
||||
}
|
||||
|
||||
}
|
||||
101
app/common/taglib/SaLibs.php
Normal file
101
app/common/taglib/SaLibs.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?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> Apache 2.0 License
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\common\taglib;
|
||||
|
||||
use system\Random;
|
||||
use think\facade\Db;
|
||||
use think\template\TagLib;
|
||||
|
||||
/**
|
||||
* 注意:定界符结尾必须靠墙立正
|
||||
*/
|
||||
class SaLibs extends TagLib
|
||||
{
|
||||
|
||||
/**
|
||||
* 定义标签列表
|
||||
*/
|
||||
protected $tags = [
|
||||
// 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次
|
||||
'variable' => ['attr' => 'name', 'close' => 0], // 自定义变量
|
||||
'company' => ['attr' => 'name,alias', 'close' => 0], // 公司信息
|
||||
'dictionary' => ['attr' => 'id,value'], // 获取字典列表
|
||||
];
|
||||
|
||||
/**
|
||||
* 自定义变量标签
|
||||
* @access public
|
||||
* @param $tags
|
||||
* @return mixed
|
||||
* @throws \Psr\SimpleCache\InvalidArgumentException
|
||||
*/
|
||||
public function tagVariable($tags)
|
||||
{
|
||||
if (!isset($tags['name']) || !$tags['name']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取变量
|
||||
$variable = saenv('variable');
|
||||
if (isset($variable[$tags['name']])) {
|
||||
return $variable[$tags['name']];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公司变量
|
||||
* @access public
|
||||
* @param $tags
|
||||
* @return mixed
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function tagCompany($tags)
|
||||
{
|
||||
$where = [];
|
||||
if (isset($tags['alias']) && $tags['alias']) {
|
||||
$where[] = ['alias', '=', $tags['alias']];
|
||||
} else { // 默认查询
|
||||
$where[] = ['id', '=', '1'];
|
||||
}
|
||||
|
||||
$data = Db::name('company')->where($where)->find();
|
||||
if (!empty($data) && isset($data[$tags['name']])) {
|
||||
return $data[$tags['name']];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典标签
|
||||
* @access public
|
||||
* @param array $tags
|
||||
* @param string $content 自定义元素
|
||||
* @return string
|
||||
*/
|
||||
public function tagDictionary(array $tags, string $content): string
|
||||
{
|
||||
$tags['id'] = $tags['id'] ?? 'vo';
|
||||
$id = $this->autoBuildVar($tags['id']);
|
||||
$value = $tags['value'] ?? '';
|
||||
$_var = Random::alpha();
|
||||
$parse = '<?php ';
|
||||
$parse .= '$_' . $_var . ' = \app\common\model\system\Dictionary::getValueList("' . $value . '");';
|
||||
$parse .= ' ?>';
|
||||
$parse .= '<?php foreach($_' . $_var . ' as $key=>' . $id . '):?>';
|
||||
$parse .= $content;
|
||||
$parse .= '<?php endforeach; ?>';
|
||||
return $parse;
|
||||
}
|
||||
}
|
||||
40
app/common/validate/system/Admin.php
Normal file
40
app/common/validate/system/Admin.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Admin extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'name' => 'require|min:2|max:12|chsAlphaNum',
|
||||
'pwd|密码' => 'require|min:6|max:64',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'name.require' => '用户名不能为空',
|
||||
'name.min' => '用户名不能少于2个字符',
|
||||
'name.max' => '用户名不能超过12个字符',
|
||||
'name.filters' => '用户名包含禁止注册字符',
|
||||
'name.chsAlphaNum' => '用户名只能是汉字、字母和数字',
|
||||
];
|
||||
|
||||
// 测试验证场景
|
||||
protected $scene = [
|
||||
'edit' => ['name']
|
||||
];
|
||||
}
|
||||
54
app/common/validate/system/AdminGroup.php
Normal file
54
app/common/validate/system/AdminGroup.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
use app\common\model\system\AdminGroup as AdminGroupModel;
|
||||
|
||||
class AdminGroup extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'pid' => 'notEqId',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'pid.notEqId' => '选择上级分类错误!',
|
||||
];
|
||||
|
||||
/**
|
||||
* 自定义验证规则
|
||||
* @param $value
|
||||
* @param $rules
|
||||
* @param $data
|
||||
* @return bool
|
||||
*/
|
||||
protected function notEqId($value, $rules ,$data): bool
|
||||
{
|
||||
if ($value == $data['id']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($data['id']) && $value > $data['id']) {
|
||||
if (AdminGroupModel::getByPid($data['id'])) {
|
||||
$this->message['pid.notEqId'] = '禁止修改存在子类的栏目';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
46
app/common/validate/system/AdminRules.php
Normal file
46
app/common/validate/system/AdminRules.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class AdminRules extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'pid' => 'notEqId',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'pid.notEqId' => '选择上级分类错误!',
|
||||
];
|
||||
|
||||
/**
|
||||
* 自定义验证规则
|
||||
* @param $value
|
||||
* @param $rule
|
||||
* @param $data
|
||||
* @return bool
|
||||
*/
|
||||
protected function notEqId($value, $rule, $data): bool
|
||||
{
|
||||
if ($value == $data['id']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
45
app/common/validate/system/Department.php
Normal file
45
app/common/validate/system/Department.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Department extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'pid' => 'notEqId',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'pid.notEqId' => '选择上级分类错误!',
|
||||
];
|
||||
|
||||
/**
|
||||
* 自定义验证规则
|
||||
* @param $value
|
||||
* @param $rule
|
||||
* @param $post
|
||||
* @return bool
|
||||
*/
|
||||
protected function notEqId($value, $rule, $post): bool
|
||||
{
|
||||
if ($value == $post['id']) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
21
app/common/validate/system/Dictionary.php
Normal file
21
app/common/validate/system/Dictionary.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use app\common\model\system\Dictionary as SystemDictionary;
|
||||
use think\Validate;
|
||||
|
||||
class Dictionary extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'name' => 'require',
|
||||
'value' => 'require',
|
||||
];
|
||||
}
|
||||
45
app/common/validate/system/Jobs.php
Normal file
45
app/common/validate/system/Jobs.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Jobs extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'pid' => 'notEqId',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'pid.notEqId' => '选择上级分类错误!',
|
||||
];
|
||||
|
||||
/**
|
||||
* 自定义验证规则
|
||||
* @param $value
|
||||
* @param $rule
|
||||
* @param $post
|
||||
* @return bool
|
||||
*/
|
||||
protected function notEqId($value, $rule, $post): bool
|
||||
{
|
||||
if ($value == $post['id']) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
31
app/common/validate/system/LoginLog.php
Normal file
31
app/common/validate/system/LoginLog.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class LoginLog extends Validate
|
||||
{
|
||||
/**
|
||||
* 验证规则
|
||||
*/
|
||||
protected $rule = [
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*/
|
||||
protected $message = [
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* 验证场景
|
||||
*/
|
||||
protected $scene = [
|
||||
'add' => [],
|
||||
'edit' => [],
|
||||
];
|
||||
|
||||
}
|
||||
38
app/common/validate/system/UploadFile.php
Normal file
38
app/common/validate/system/UploadFile.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class UploadFile extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $rule = [
|
||||
'images'=>[
|
||||
'fileSize' => 419430400,
|
||||
'fileExt' => 'jpg,jpeg,png,bmp,gif,svg',
|
||||
'fileMime' => 'image/jpeg,image/png,image/gif,image/svg+xml'],
|
||||
'video'=>[
|
||||
'fileSize' => 419430400,
|
||||
'fileExt' => 'flv,swf,mkv,avi,rm,rmvb,mpeg,mpg,ogg,ogv,mov,wmv,mp4,webm,mp3,wav,mid'],
|
||||
'document'=>[
|
||||
'fileSize' => 419430400,
|
||||
'fileExt' => 'txt,doc,xls,ppt,docx,xlsx,pptx'],
|
||||
'files'=>[
|
||||
'fileSize' => 419430400,
|
||||
'fileExt' => 'exe,dll,sys,so,dmg,iso,zip,rar,7z,sql,pem,pdf,psd']
|
||||
];
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [];
|
||||
}
|
||||
59
app/common/validate/system/User.php
Normal file
59
app/common/validate/system/User.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\validate\system;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class User extends Validate
|
||||
{
|
||||
/**
|
||||
* 定义验证规则
|
||||
* 格式:'字段名' => ['规则1','规则2'...]
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rule = [
|
||||
'test_filed' => 'max:255',
|
||||
'nickname' => 'require|min:2|max:12|filters|chsAlphaNum',
|
||||
'pwd|密码' => 'require|min:6|max:64',
|
||||
];
|
||||
|
||||
/**
|
||||
* 定义错误信息
|
||||
* 格式:'字段名.规则名' => '错误信息'
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $message = [
|
||||
'nickname.require' => '用户名不能为空',
|
||||
'nickname.min' => '用户名不能少于2个字符',
|
||||
'nickname.max' => '用户名不能超过12个字符',
|
||||
'nickname.filters' => '用户名包含禁止注册字符',
|
||||
'nickname.chsAlphaNum' => '用户名只能是汉字、字母和数字',
|
||||
'test_filed.max' => '测试场景用',
|
||||
];
|
||||
|
||||
// 测试验证场景
|
||||
protected $scene = [
|
||||
'test' => ['test_filed'],
|
||||
];
|
||||
|
||||
/**
|
||||
* 自定义验证规则
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function filters($value): bool
|
||||
{
|
||||
$notAllow = saenv('user_reg_notallow');
|
||||
$notAllow = explode(',', $notAllow);
|
||||
foreach ($notAllow as $values) {
|
||||
if ($value == $values) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user