代码功能更新
This commit is contained in:
Executable
+215
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use laytp\library\UploadDomain;
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Config;
|
||||
|
||||
/**
|
||||
* 系统配置服务器实现者
|
||||
* Class Auth
|
||||
* @package app\service
|
||||
*/
|
||||
class Conf
|
||||
{
|
||||
use Error;
|
||||
|
||||
// 是否使用redis,如果不想使用redis,修改此处为false即可
|
||||
protected $useRedis = true;
|
||||
|
||||
// 数据库连接句柄
|
||||
protected $db = null;
|
||||
|
||||
//判断是否配置了redis
|
||||
protected function hasRedis(){
|
||||
$redisConf = Config::get('cache');
|
||||
if(isset($redisConf['stores']['redis']['type']) && $this->useRedis){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过一个完整的key,获取配置信息
|
||||
* @param $wholeKey
|
||||
* @param $defaultValue
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public function get($wholeKey, $defaultValue='')
|
||||
{
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
if($redis){
|
||||
$value = $redis->hget($wholeKey, 'value');
|
||||
$formType = $redis->hget($wholeKey, 'form_type');
|
||||
if($formType == 'array') return json_decode($value, JSON_UNESCAPED_UNICODE);
|
||||
return $value ? $value : $defaultValue;
|
||||
}
|
||||
}
|
||||
list($group, $key) = $this->getGroupKey($wholeKey);
|
||||
$conf = \app\model\Conf::where(['group'=>$group, 'key'=>$key])->findOrEmpty()->toArray();
|
||||
if($conf){
|
||||
$value = $conf['value'];
|
||||
$formType = $conf['form_type'];
|
||||
if($formType == 'array') return json_decode($value, JSON_UNESCAPED_UNICODE);
|
||||
if($formType == 'upload'){
|
||||
$fileInfo = UploadDomain::multiJoin($value);
|
||||
$return[$key] = $value;
|
||||
if($fileInfo){
|
||||
$return[$key.'_path'] = $fileInfo['path'];
|
||||
$return[$key.'_filename'] = $fileInfo['filename'];
|
||||
}else{
|
||||
$return[$key.'_path'] = '';
|
||||
$return[$key.'_filename'] = '';
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
return $value ? $value : $defaultValue;
|
||||
}else{
|
||||
return $defaultValue ? $defaultValue : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过一个完整的key,设置配置信息
|
||||
* @param $wholeKey
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function set($wholeKey, $value)
|
||||
{
|
||||
if(is_array($value)){
|
||||
$value = json_encode($value, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
list($group, $key) = $this->getGroupKey($wholeKey);
|
||||
$id = \app\model\Conf::where(['group'=>$group, 'key'=>$key])->value('id');
|
||||
if($id){
|
||||
\app\model\Conf::where('id', '=', $id)->save(['group' => $group, 'key' => $key]);
|
||||
}else{
|
||||
\app\model\Conf::insert(['group' => $group, 'key' => $key, 'value' => $value]);
|
||||
}
|
||||
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$redis->set($wholeKey, $value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function del($group, $key)
|
||||
{
|
||||
\app\model\Conf::where(['group' => $group, 'key' => $key])->delete();
|
||||
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$redis->del($group . $key);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过数组,设置配置信息
|
||||
* @param $array
|
||||
* @return bool
|
||||
*/
|
||||
public function groupSet($array)
|
||||
{
|
||||
foreach($array as $item){
|
||||
$item['value'] = is_array($item['value']) ? json_encode($item['value'], JSON_UNESCAPED_UNICODE) : $item['value'];
|
||||
$id = \app\model\Conf::where(['group'=>$item['group'], 'key'=>$item['key']])->value('id');
|
||||
if($id){
|
||||
\app\model\Conf::where('id', '=', $id)->save($item);
|
||||
}else{
|
||||
\app\model\Conf::create($item);
|
||||
}
|
||||
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$hashKey = $item['group'] . '.' . $item['key'];
|
||||
$redis->hset($hashKey, 'group', $item['group']);
|
||||
$redis->hset($hashKey, 'key', $item['key']);
|
||||
$redis->hset($hashKey, 'value', $item['value']);
|
||||
$redis->hset($hashKey, 'form_type', $item['form_type']);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过配置分组名称,获取整个分组的信息
|
||||
* @param $group
|
||||
* @param $onlyMysql boolean 是否仅从数据库取配置
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function groupGet($group, $onlyMysql=false)
|
||||
{
|
||||
$return = [];
|
||||
$items = [];
|
||||
|
||||
if(!$onlyMysql){
|
||||
if($this->hasRedis()){
|
||||
$redis = Cache::store('redis')->handler();
|
||||
$keys = $redis->keys($group.'*');
|
||||
foreach($keys as $key){
|
||||
$items[$key] = $redis->hGetAll($key);
|
||||
}
|
||||
if(!$items){
|
||||
$items = \app\model\Conf::where(['group'=>$group])->select()->toArray();
|
||||
}
|
||||
}else{
|
||||
$items = \app\model\Conf::where(['group'=>$group])->select()->toArray();
|
||||
}
|
||||
}else{
|
||||
$items = \app\model\Conf::where(['group'=>$group])->select()->toArray();
|
||||
}
|
||||
|
||||
foreach ($items as $k => $v) {
|
||||
if ($v['form_type'] === 'array') {
|
||||
$array = json_decode($v['value'], true);
|
||||
if(!$array){
|
||||
$return[$v['key']] = [""=>""];
|
||||
}else{
|
||||
$return[$v['key']] =$array;
|
||||
}
|
||||
} elseif($v['form_type'] === 'upload') {
|
||||
$fileInfo = UploadDomain::multiJoin($v['value']);
|
||||
if($fileInfo){
|
||||
$return[$v['key']] = $fileInfo['id'];
|
||||
$return[$v['key'].'_path'] = $fileInfo['path'];
|
||||
$return[$v['key'].'_filename'] = $fileInfo['filename'];
|
||||
}else{
|
||||
$return[$v['key']] = '';
|
||||
$return[$v['key'].'_path'] = '';
|
||||
$return[$v['key'].'_filename'] = '';
|
||||
}
|
||||
} else {
|
||||
$return[$v['key']] = $v['value'];
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过完整的key,获取到分组名称和key值
|
||||
* @param $wholeKey
|
||||
* @return array|boolean
|
||||
*/
|
||||
protected function getGroupKey($wholeKey)
|
||||
{
|
||||
$arr = explode('.', $wholeKey);
|
||||
if(!$arr || count($arr) == 1){
|
||||
$this->setError('请输入一个完整的key,一个完整的key必须包含至少一个.号');
|
||||
return false;
|
||||
}
|
||||
$key = $arr[count($arr) - 1];
|
||||
$group = substr($wholeKey, 0 , strrpos($wholeKey, '.'));
|
||||
return [$group, $key];
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 系统配置服务门面
|
||||
* @package app\service
|
||||
* @method static mixed get($wholeKey, $defaultValue='') 通过完整的key获取配置信息
|
||||
* @method static mixed set($wholeKey, $value) 通过完整的key设置一个配置信息
|
||||
* @method static mixed del($group, $key) 删除某个分组下某个key的配置
|
||||
* @method static mixed groupGet($group, $onlyMysql=false) 通过分组名称,获取整个分组的配置信息
|
||||
* @method static mixed groupSet($array) 通过hash数组,设置整个分组的配置信息
|
||||
*/
|
||||
class ConfServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Conf::class;
|
||||
}
|
||||
}
|
||||
Executable
+586
@@ -0,0 +1,586 @@
|
||||
<?php
|
||||
|
||||
namespace app\service;
|
||||
|
||||
class Telegram
|
||||
{
|
||||
private $ret;
|
||||
private $token;
|
||||
private static $inlineResults = array();
|
||||
|
||||
public function __construct($token = NULL)
|
||||
{
|
||||
$this->token = $token;
|
||||
// parent::__construct();
|
||||
}
|
||||
/**
|
||||
* http_build_query兼容多维数组,返回结果数组仍支持http_build_query函数处理
|
||||
* @author Zjmainstay https://bugs.php.net/bug.php?id=67477
|
||||
* @param $data array curl传递参数的数组(原装)
|
||||
* @return array 可curl传递的格式化数组
|
||||
*/
|
||||
function http_build_query_develop($data)
|
||||
{
|
||||
if (!is_array($data)) {
|
||||
return $data;
|
||||
}
|
||||
foreach ($data as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
foreach ($val as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$data = array_merge($data, http_build_query_develop(array("{$key}[{$k}]" => $v)));
|
||||
} else {
|
||||
$data["{$key}[{$k}]"] = $v;
|
||||
}
|
||||
}
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
private function fetch($url, $postdata = null)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
if (!is_null($postdata)) {
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->http_build_query_develop($postdata));
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$re = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
return $re;
|
||||
}
|
||||
public function callMethod($method, $param = array(), $detection = true)
|
||||
{
|
||||
/** 访问网页 */
|
||||
$url = 'https://api.telegram.org/bot' . $this->token . '/' . $method;
|
||||
$ret = json_decode($this->fetch($url, $param), true);
|
||||
|
||||
/** 分析结果 */
|
||||
if ($ret['ok'] == false && $detection == true) {
|
||||
if ($ret['error_code'] != 400 && $ret['error_code'] != 403) {
|
||||
$errorModel = new ErrorModel;
|
||||
$errorModel->sendError(MASTER, '尝试调用 ' . $method . " 时出现问题,参数表如下:\n" . print_r($param, true) . "\n\n返回结果:\n" . print_r($ret, true));
|
||||
}
|
||||
}
|
||||
|
||||
/** 返回 */
|
||||
return $ret;
|
||||
}
|
||||
public function getWebhook()
|
||||
{
|
||||
$this->ret = $this->callMethod('getWebhookInfo', [], false);
|
||||
return $this->ret;
|
||||
}
|
||||
public function setWebhook($newurl)
|
||||
{
|
||||
$this->ret = $this->callMethod('setWebhook', [
|
||||
'url' => $newurl
|
||||
], false);
|
||||
return $this->ret;
|
||||
}
|
||||
public function sendMessage($chat_id, $text, $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $disable_web_page_preview = false, $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
foreach (str_split($text, 4096) as $text_i => $text_d) {
|
||||
$tmp = $this->callMethod('sendMessage', [
|
||||
'chat_id' => $chat_id,
|
||||
|
||||
'text' => $text_d,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_markup' => $reply_markup,
|
||||
'disable_web_page_preview' => $disable_web_page_preview,
|
||||
'disable_notification' => $disable_notification
|
||||
]);
|
||||
if ($text_i == 0) $this->ret = $tmp;
|
||||
}
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessage($chat_id, $message_id, $text, $reply_markup = array(), $parse_mode = 'HTML')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageText', [
|
||||
'chat_id' => $chat_id,
|
||||
'message_id' => $message_id,
|
||||
'text' => $text,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_markup' => $reply_markup
|
||||
]);
|
||||
return isset($this->ret['result']['message_id'])?$this->ret['result']['message_id']:0;
|
||||
}
|
||||
public function deleteMessage($chat_id, $message_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('deleteMessage', get_defined_vars());
|
||||
return $this->ret;
|
||||
}
|
||||
public function kickMember($chat_id, $user_id, $until_date = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('kickChatMember', [
|
||||
'chat_id' => $chat_id,
|
||||
'user_id' => $user_id,
|
||||
'until_date' => $until_date
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
|
||||
//键盘按钮 KeyboardButton $chat_id sender_chat_id
|
||||
public function KeyboardButton($chat_id, $text, $Keyboard = array(), $message_id = null, $message_thread_id = null)
|
||||
{
|
||||
return $this->sendthreadMessage($chat_id, $text, $message_id, $message_thread_id, $Keyboard);
|
||||
}
|
||||
|
||||
|
||||
public function sendthreadMessage($chat_id, $text, $reply_to_message_id = NULL, $message_thread_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $disable_web_page_preview = false, $disable_notification = false)
|
||||
{
|
||||
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
foreach (str_split($text, 4096) as $text_i => $text_d) {
|
||||
$tmp = $this->callMethod('sendMessage', [
|
||||
'chat_id' => $chat_id,
|
||||
'text' => $text_d,
|
||||
'message_thread_id' => $message_thread_id,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_markup' => $reply_markup,
|
||||
'disable_web_page_preview' => $disable_web_page_preview,
|
||||
'disable_notification' => $disable_notification
|
||||
]);
|
||||
if ($text_i == 0) $this->ret = $tmp;
|
||||
}
|
||||
|
||||
if ($this->ret['ok'] == false) {
|
||||
|
||||
if ($this->ret['description'] == "Bad Request: BUTTON_URL_INVALID") {
|
||||
//按钮设置错误导致异常
|
||||
$txt = $text . "\r\n" . "\r\n" . "由于按钮信息设置错误,异常,您可以点击按钮参考设置规则";
|
||||
$button = json_encode(array(
|
||||
'inline_keyboard' => array(
|
||||
array(array(
|
||||
'text' => '参考按钮设置',
|
||||
'callback_data' => 'xinshouxiuefrb '
|
||||
))
|
||||
|
||||
|
||||
)
|
||||
));
|
||||
$this->sendMessage($chat_id, $txt, null, $button, 'Markdown', true);
|
||||
}
|
||||
//按钮设置问题导致报错
|
||||
if (strpos($this->ret['description'], "keyboard button")) {
|
||||
//按钮设置错误导致异常
|
||||
$txt = $text . "\r\n" . "\r\n" . "由于按钮信息设置错误,异常,您可以点击按钮参考设置规则";
|
||||
$button = json_encode(array(
|
||||
'inline_keyboard' => array(
|
||||
array(array(
|
||||
'text' => '参考按钮设置',
|
||||
'callback_data' => 'xinshouxiuefrb '
|
||||
))
|
||||
|
||||
|
||||
)
|
||||
));
|
||||
$this->sendMessage($chat_id, $txt, null, $button, 'Markdown', true);
|
||||
} elseif (strpos($this->ret['description'], "Bad Request: have no rights to send a message")) {
|
||||
|
||||
$cuwucishu = Cache::get("cuwusishuo" . $chat_id);
|
||||
if ($cuwucishu > 100) {
|
||||
// $this->db->update('group', ['switch' => 0, 'botid' => $this->botid], ['group' => $chat_id]);
|
||||
|
||||
|
||||
Db::name("group")->where(['group' => $chat_id, 'botid' => $this->botid])->update(['switch' => 0]);
|
||||
|
||||
|
||||
$this->getgroupinfo($chat_id, $this->tokenbase, 1);
|
||||
} else {
|
||||
Cache::set("cuwusishuo" . $chat_id, $cuwucishu + 1, 36000);
|
||||
}
|
||||
} else {
|
||||
$txt = "本次请求出错了,错误日志如下" . "\r\n" . "检查下设置的地址是否正确或者是存在多余的空格" . "\r\n" . $this->ret['description'] . "\r\n" . "\r\n" . "实在解决不了 反馈 @kaihebug";
|
||||
if ($text == "查看群规") {
|
||||
$this->sendMessage($chat_id, $txt);
|
||||
}
|
||||
|
||||
// file_put_contents("tgsendmassttttt.txt", json_encode($this->ret).$text.$reply_markup.$chat_id.$parse_mode."\r\n", FILE_APPEND);
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (isset($this->ret['parameters']['retry_after'])) {
|
||||
$retry_after = $this->ret['parameters']['retry_after'];
|
||||
Cache::set("retry_after" . $chat_id, 1, $retry_after);
|
||||
}
|
||||
}
|
||||
//下面还可以添加规则
|
||||
if (isset($this->ret['result']['message_id'])) {
|
||||
return $this->ret['result']['message_id'];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
//return $this->ret['result']['message_id'];
|
||||
}
|
||||
//强制回复 forcereply
|
||||
public function forcereply($chat_id, $text, $message_id = null, $message_thread_id = null)
|
||||
{
|
||||
$buttonsc = json_encode(
|
||||
array(
|
||||
'force_reply' => true,
|
||||
'input_field_placeholder' => $text,
|
||||
'selective' => true,
|
||||
)
|
||||
);
|
||||
return $this->sendthreadMessage($chat_id, $text, $message_id, $message_thread_id, $buttonsc);
|
||||
}
|
||||
|
||||
public function sendPhoto($chat_id, $photo, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML')
|
||||
{
|
||||
if (is_array($photo)) {
|
||||
return $this->sendMediaGroup($chat_id, array_map(function ($p) use ($caption, $parse_mode) {
|
||||
return [
|
||||
'type' => 'photo',
|
||||
'media' => $p,
|
||||
'caption' => $caption,
|
||||
'parse_mode' => $parse_mode
|
||||
];
|
||||
}, $photo), $reply_to_message_id);
|
||||
}
|
||||
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendPhoto', [
|
||||
'chat_id' => $chat_id,
|
||||
'photo' => $photo,
|
||||
'caption' => $caption,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'reply_markup' => $reply_markup
|
||||
]);
|
||||
return isset($this->ret['result']['message_id'])?$this->ret['result']['message_id']:0;;
|
||||
}
|
||||
public function sendDocumentphoto($chat_id, $document, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML')
|
||||
{
|
||||
|
||||
$url = 'https://api.telegram.org/bot' . $this->token . '/sendPhoto';
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
|
||||
$finfo = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $document);
|
||||
$cFile = new \CURLFile($document, $finfo);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->http_build_query_develop([
|
||||
'chat_id' => $chat_id,
|
||||
'photo' => $cFile,
|
||||
'caption' => $caption,
|
||||
'parse_mode' => $parse_mode,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'reply_markup' => $reply_markup
|
||||
]));
|
||||
$result = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->ret = json_decode($result, 1);
|
||||
$message_id=isset($this->ret['result']['message_id'])?$this->ret['result']['message_id']:"";
|
||||
if(!empty($message_id)){
|
||||
unlink($document);
|
||||
}
|
||||
//var_dump($this->ret);
|
||||
return $message_id;
|
||||
}
|
||||
public function sendMediaGroup($chat_id, $media, $reply_to_message_id = NULL)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendMediaGroup', [
|
||||
'chat_id' => $chat_id,
|
||||
'media' => json_encode($media),
|
||||
'reply_to_message_id' => $reply_to_message_id
|
||||
]);
|
||||
return array_map(function ($m) {
|
||||
return $m['message_id'];
|
||||
}, $this->ret['result']);
|
||||
}
|
||||
public function sendAudio($chat_id, $audio, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $duration = '', $performer = NULL, $title = NULL, $thumb = '', $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendAudio', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendDocument($chat_id, $document, $caption = '', $reply_to_message_id = NULL, $reply_markup = array(), $parse_mode = 'HTML', $thumb = '', $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendDocument', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendVideo($chat_id, $video, $duration = '', $width = '', $height = '', $thumb = '', $caption = NULL, $parse_mode = 'HTML', $supports_streaming = '', $disable_notification = false, $reply_to_message_id = '', $reply_markup = '')
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendVideo', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendAnimation($chat_id, $animation, $duration = NULL, $width = NULL, $height = NULL, $thumb = NULL, $caption = '', $parse_mode = 'HTML', $disable_notification = NULL, $reply_to_message_id = NULL, $reply_markup = array())
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendAnimation', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function getBusinessConnection($business_connection_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getBusinessConnection', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function sendVoice($chat_id, $voice, $caption = NULL, $parse_mode = 'HTML', $duration = '', $disable_notification = false, $reply_to_message_id = '', $reply_markup = '')
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendVoice', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function getUserProfilePhotos($user_id, $offset = '', $limit = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('getUserProfilePhotos', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function unbanChatMember($chat_id, $user_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('unbanChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function restrictChatMember($chat_id, $user_id, $permissions, $until_date = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('restrictChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function promoteChatMember($chat_id, $user_id, $can_change_info = NULL, $can_post_messages = NULL, $can_edit_messages = NULL, $can_delete_messages = NULL, $can_invite_users = NULL, $can_restrict_members = NULL, $can_pin_messages = NULL, $can_promote_members = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('promoteChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatPermissions($chat_id, $permissions)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatPermissions', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function exportChatInviteLink($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('exportChatInviteLink', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatPhoto($chat_id, $photo)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatPhoto', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function deleteChatPhoto($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('deleteChatPhoto', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatTitle($chat_id, $title)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatTitle', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function setChatDescription($chat_id, $description = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('setChatDescription', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function pinChatMessage($chat_id, $message_id, $disable_notification = false)
|
||||
{
|
||||
$this->ret = $this->callMethod('pinChatMessage', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function unpinChatMessage($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('unpinChatMessage', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function leaveChat($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('leaveChat', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getChat($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChat', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getChatMembersCount($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChatMembersCount', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getChatMember($chat_id, $user_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChatMember', get_defined_vars());
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function editMessageText($chat_id = '', $message_id = '', $inline_message_id = NULL, $text, $parse_mode = 'HTML', $disable_web_page_preview = '', $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageText', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessageCaption($chat_id = '', $message_id = '', $inline_message_id = NULL, $caption = NULL, $parse_mode = 'HTML', $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageCaption', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessageMedia($chat_id = '', $message_id = '', $inline_message_id = NULL, $media, $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageMedia', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function editMessageReplyMarkup($chat_id = '', $message_id = '', $inline_message_id = NULL, $reply_markup = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('editMessageReplyMarkup', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendSticker($chat_id, $sticker, $reply_to_message_id = NULL, $reply_markup = array(), $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendSticker', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function sendGame($chat_id, $game_name, $reply_to_message_id = NULL, $reply_markup = array())
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('sendGame', [
|
||||
'chat_id' => $chat_id,
|
||||
'game_short_name' => $game_name,
|
||||
'reply_to_message_id' => $reply_to_message_id,
|
||||
'reply_markup' => $reply_markup
|
||||
]);
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function setGameScore($user_id, $score, $force = false, $disable_edit_message = false, $chat_id = NULL, $message_id = NULL, $inline_id = NULL)
|
||||
{
|
||||
$this->ret = $this->callMethod('setGameScore', [
|
||||
'user_id' => $user_id,
|
||||
'score' => $score,
|
||||
'force' => $force,
|
||||
'disable_edit_message' => $disable_edit_message,
|
||||
'chat_id' => $chat_id,
|
||||
'message_id' => $message_id,
|
||||
'inline_message_id' => $inline_id
|
||||
]);
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function forwardMessage($chat_id, $from_chat_id, $message_id, $disable_notification = false)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('forwardMessage', get_defined_vars());
|
||||
return $this->ret['result']['message_id'];
|
||||
}
|
||||
public function answerCallback($callback_id, $text = '', $show_alert = false, $url = '', $cache_time = 0)
|
||||
{
|
||||
if (isset($GLOBALS['statistics']['send_total']))
|
||||
$GLOBALS['statistics']['send_total']++;
|
||||
$this->ret = $this->callMethod('answerCallbackQuery', [
|
||||
'callback_query_id' => $callback_id,
|
||||
'text' => $text,
|
||||
'show_alert' => $show_alert,
|
||||
'url' => $url,
|
||||
'cache_time' => $cache_time
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
public function sendInlineQuery($results)
|
||||
{
|
||||
self::$inlineResults = array_merge(self::$inlineResults, $results);
|
||||
}
|
||||
public function sendInline($inline_id, $cache_time = 600, $offset = '', $switch_pm_parameter = '')
|
||||
{
|
||||
$this->ret = $this->callMethod('answerInlineQuery', [
|
||||
'inline_query_id' => $inline_id,
|
||||
'results' => json_encode(self::$inlineResults),
|
||||
'cache_time' => $cache_time,
|
||||
'next_offset' => $offset,
|
||||
'switch_pm_parameter' => $switch_pm_parameter
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
public function sendChatAction($chat_id, $action)
|
||||
{
|
||||
$this->ret = $this->callMethod('sendChatAction', [
|
||||
'chat_id' => $chat_id,
|
||||
'action' => $action
|
||||
]);
|
||||
return $this->ret;
|
||||
}
|
||||
public function getFile($file_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getFile', [
|
||||
'file_id' => $file_id,
|
||||
]);
|
||||
if ($this->ret['ok']) {
|
||||
$fileUrl = 'https://api.telegram.org/file/bot' . $this->token . '/' . $this->ret['result']['file_path'];
|
||||
$this->ret['result']['down_url'] = $fileUrl;
|
||||
}
|
||||
return $this->ret;
|
||||
}
|
||||
public function getInlineId()
|
||||
{
|
||||
return hash('sha256', uniqid(mt_rand(), true));
|
||||
}
|
||||
public function getChatAdmin($chat_id)
|
||||
{
|
||||
$this->ret = $this->callMethod('getChatAdministrators', [
|
||||
'chat_id' => $chat_id
|
||||
]);
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function getMe()
|
||||
{
|
||||
$this->ret = $this->callMethod('getMe', []);
|
||||
return $this->ret;
|
||||
}
|
||||
public function getStickerSet($name)
|
||||
{
|
||||
$this->ret = $this->callMethod('getStickerSet', [
|
||||
'name' => $name
|
||||
]);
|
||||
return $this->ret['result'];
|
||||
}
|
||||
public function isAdmin($chat_id, $user_id)
|
||||
{
|
||||
$ret = false;
|
||||
$adminList = $this->getChatAdmin($chat_id);
|
||||
foreach ($adminList as $adminList_d) {
|
||||
if ($adminList_d['user']['id'] == $user_id) {
|
||||
$ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
public function atById($userid, $username)
|
||||
{
|
||||
return '<a href="tg://user?id=' . $userid . '">@' . $username . '</a>';
|
||||
}
|
||||
public function getMaster()
|
||||
{
|
||||
return MASTER;
|
||||
}
|
||||
public function getBotName()
|
||||
{
|
||||
return BOTNAME;
|
||||
}
|
||||
public function getReturn()
|
||||
{
|
||||
return $this->ret;
|
||||
}
|
||||
public function error()
|
||||
{
|
||||
$this->callMethod('sendMessage');
|
||||
}
|
||||
}
|
||||
Executable
+157
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use app\model\admin\Role;
|
||||
use app\model\admin\role\Menu;
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* 后台权限服务实现者
|
||||
* Class Auth
|
||||
* @package app\service\admin
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
use Error;
|
||||
protected $_noNeedLogin = [];//无需登录的方法名数组
|
||||
protected $_noNeedAuth = [];//无需鉴权的方法名数组
|
||||
|
||||
/**
|
||||
* 设置无需登录的方法名数组
|
||||
* @param array $noNeedLogin
|
||||
*/
|
||||
public function setNoNeedLogin($noNeedLogin = [])
|
||||
{
|
||||
$this->_noNeedLogin = $noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需登录的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedLogin()
|
||||
{
|
||||
return $this->_noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要登录
|
||||
* @param bool $noNeedLogin
|
||||
* @return bool true:需要登录,false:不需要登录
|
||||
*/
|
||||
public function needLogin($noNeedLogin = false)
|
||||
{
|
||||
$noNeedLogin === false && $noNeedLogin = $this->getNoNeedLogin();
|
||||
$noNeedLogin = is_array($noNeedLogin) ? $noNeedLogin : explode(',', $noNeedLogin);
|
||||
//为空表示所有方法都需要登录,返回true
|
||||
if (!$noNeedLogin) {
|
||||
return true;
|
||||
}
|
||||
$noNeedLogin = array_map('strtolower', $noNeedLogin);
|
||||
$request = Request::instance();
|
||||
//判断当前请求的操作名是否存在于不需要登录的方法名数组中,如果存在,表明不需要登录,返回false
|
||||
if (in_array(strtolower($request->action()), $noNeedLogin) || in_array('*', $noNeedLogin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要登录
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置无需鉴权的方法名数组
|
||||
* @param array $noNeedAuth
|
||||
*/
|
||||
public function setNoNeedAuth($noNeedAuth = [])
|
||||
{
|
||||
$this->_noNeedAuth = $noNeedAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需鉴权的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedAuth()
|
||||
{
|
||||
return $this->_noNeedAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要鉴权
|
||||
* @param bool $noNeedAuth
|
||||
* @return bool true:需要登录,false:不需要登录
|
||||
*/
|
||||
public function needAuth($noNeedAuth = false)
|
||||
{
|
||||
$noNeedAuth === false && $noNeedAuth = $this->getNoNeedAuth();
|
||||
$noNeedAuth = is_array($noNeedAuth) ? $noNeedAuth : explode(',', $noNeedAuth);
|
||||
//为空表示所有方法都需要鉴权,返回true
|
||||
if (!$noNeedAuth) {
|
||||
return true;
|
||||
}
|
||||
$noNeedAuth = array_map('strtolower', $noNeedAuth);
|
||||
|
||||
//判断当前请求的操作名是否存在于不需要鉴权的方法名数组中,如果存在,表明不需要鉴权,返回false
|
||||
if (in_array(strtolower(Request::action()), $noNeedAuth) || in_array('*', $noNeedAuth)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要鉴权
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某用户拥有的权限列表
|
||||
* @param $userId int 用户ID,当为空时,为获取当前登录用户权限列表
|
||||
* @return array
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function getAuthList($userId = 0)
|
||||
{
|
||||
$where[] = ['is_show', '=', 1];
|
||||
$user = $userId ? \app\model\admin\User::findOrEmpty($userId) : UserServiceFacade::getUser();
|
||||
//当前后台管理员如果是超级管理员,则拥有所有的权限列表
|
||||
if ($user->is_super_manager === 1) {
|
||||
$result = \app\model\admin\Menu::where($where)->select()->toArray();
|
||||
} else {
|
||||
//如果不是超级管理员,先查询拥有哪些角色,通过角色查询出权限节点列表
|
||||
$adminUserId = $user->id;
|
||||
$roleIds = \app\model\admin\role\User::where('admin_user_id', '=', $adminUserId)->column('admin_role_id');
|
||||
$menuIds = \app\model\admin\menu\Role::where('admin_role_id', 'in', $roleIds)->column('admin_menu_id');
|
||||
$where[] = ['id', 'in', $menuIds];
|
||||
$result = \app\model\admin\Menu::where($where)->select()->toArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某用户是否有某节点的权限
|
||||
* @param integer $userId 登录用户ID
|
||||
* @param string $node 节点字符串
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function hasAuth($userId, $node)
|
||||
{
|
||||
if (!$userId || !$node) return false;
|
||||
$authList = $this->getAuthList($userId);
|
||||
$authArr = [];
|
||||
foreach ($authList as $k => $v) {
|
||||
$authArr[] = trim($v['rule'], '/');
|
||||
}
|
||||
|
||||
$authArr = array_filter(array_unique($authArr));
|
||||
sort($authArr);
|
||||
if (in_array($node, $authArr)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 后台权限服务门面
|
||||
* @package app\service\admin
|
||||
* @method static mixed setNoNeedLogin($noNeedLogin) 设置不需要登录的方法名数组
|
||||
* @method static mixed setNoNeedAuth($noNeedAuth) 设置不需要鉴权的方法名数组
|
||||
* @method static mixed needLogin() 当前节点是否需要登录
|
||||
* @method static mixed needAuth() 当前节点是否需要鉴权
|
||||
* @method static mixed getAuthList($userId) 获取某后台管理员拥有的权限列表
|
||||
* @method static mixed hasAuth($userId, $node) 某用户是否拥有某个节点的权限
|
||||
*/
|
||||
class AuthServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Auth::class;
|
||||
}
|
||||
}
|
||||
Executable
+403
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use app\model\admin\Menu;
|
||||
use laytp\library\DirFile;
|
||||
use laytp\library\Http;
|
||||
use laytp\traits\Error;
|
||||
use app\model\Migrations;
|
||||
use think\facade\Config;
|
||||
use think\facade\Filesystem;
|
||||
|
||||
/**
|
||||
* 插件市场服务实现者
|
||||
* Class Auth
|
||||
* @package app\service\admin
|
||||
*/
|
||||
class Plugins
|
||||
{
|
||||
use Error;
|
||||
|
||||
protected $ids=[];
|
||||
|
||||
// 离线安装
|
||||
public function offLineInstall()
|
||||
{
|
||||
if (!class_exists('ZipArchive')) {
|
||||
$this->setError('PHP扩展ZipArchive没有正确安装');
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = request()->file('laytpUploadFile'); // 获取上传的文件
|
||||
if (!$file) {
|
||||
$this->setError('上传失败,请选择需要上传的文件');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileExt = strtolower($file->getOriginalExtension());
|
||||
if($fileExt != 'zip'){
|
||||
$this->setError('仅允许上传zip文件');
|
||||
return false;
|
||||
}
|
||||
|
||||
$fileName = $file->getOriginalName();
|
||||
$pathinfo = pathinfo($fileName);
|
||||
$plugin = $pathinfo['filename'];
|
||||
try{
|
||||
// 将文件上传到指定目录
|
||||
Filesystem::disk('local')->putFileAs('plugins', $file, $fileName );
|
||||
$this->insideInstall($plugin);
|
||||
}catch (\Exception $e){
|
||||
$this->setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 安装
|
||||
public function install($plugin, $laytpGwToken)
|
||||
{
|
||||
if (!class_exists('ZipArchive')) {
|
||||
$this->setError('PHP扩展ZipArchive没有正确安装');
|
||||
return false;
|
||||
}
|
||||
|
||||
$download = $this->download($plugin, $laytpGwToken);
|
||||
|
||||
if(!$download){
|
||||
return false;
|
||||
}
|
||||
|
||||
$install = $this->insideInstall($plugin);
|
||||
if(!$install){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 卸载
|
||||
public function unInstall($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
// 删除数据库文件
|
||||
$migrationsFile = DirFile::recurDir($pluginDir . 'database' . DS . 'migrations');
|
||||
if($migrationsFile){
|
||||
foreach($migrationsFile as $file){
|
||||
$baseNameArr = explode('_', $file['baseName']);
|
||||
$baseNameArr = explode('.', $baseNameArr[1]);
|
||||
$migration = Migrations::where('migration_name', '=', ucfirst($baseNameArr[0]))->find();
|
||||
if($migration) $migration->delete();
|
||||
@unlink(root_path() . 'database' . DS . 'migrations' . DS . $file['baseName']);
|
||||
}
|
||||
}
|
||||
// 删除菜单
|
||||
$info = $this->getPluginInfo($plugin);
|
||||
$menuIds = $info['menu_ids'];
|
||||
if($menuIds){
|
||||
Menu::destroy(function($query) use ($menuIds){
|
||||
$query->where('id', 'in', explode(',', $menuIds));
|
||||
});
|
||||
}
|
||||
// 删除public目录下的文件
|
||||
$this->removePublicFile($plugin);
|
||||
// 删除插件目录
|
||||
DirFile::rmDirs($pluginDir);
|
||||
// 修改系统插件配置文件config/plugin.php
|
||||
$this->unInstallPluginConf($plugin, $info);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取上传zip文件所在目录
|
||||
public function getPluginRuntimeDir()
|
||||
{
|
||||
$dir = runtime_path() . 'storage' . DS . 'plugins';
|
||||
DirFile::createDir($dir);
|
||||
return $dir;
|
||||
}
|
||||
|
||||
// 下载zip文件到本地
|
||||
public function download($plugin, $laytpGwToken)
|
||||
{
|
||||
$ltVersion = request()->param('ltVersion');
|
||||
$pluginVersion = request()->param('pluginVersion');
|
||||
$res = Http::post(Config::get('plugin.apiUrl') . "/plugins/install", [
|
||||
'plugin'=>$plugin,
|
||||
'ltVersion'=>$ltVersion,
|
||||
'pluginVersion'=>$pluginVersion,
|
||||
], array(
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
"token: ".$laytpGwToken
|
||||
),
|
||||
));
|
||||
$resArr = json_decode($res, true);
|
||||
if($resArr['code'] > 0 ){
|
||||
$this->setError(['msg'=>$resArr['msg'],'code'=>$resArr['code']]);
|
||||
return false;
|
||||
}
|
||||
$url = $resArr['data']['url'];
|
||||
$zipSteam = Http::get($url, [], [
|
||||
CURLOPT_CONNECTTIMEOUT => 30,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'X-REQUESTED-WITH: XMLHttpRequest'
|
||||
]
|
||||
]);
|
||||
|
||||
$file = $this->getPluginRuntimeDir() . DS . $plugin . '.zip';
|
||||
if(file_exists($file)){
|
||||
@unlink($file);
|
||||
}
|
||||
if ($write = fopen($file, 'w')) {
|
||||
fwrite($write, $zipSteam);
|
||||
fclose($write);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 内部安装过程
|
||||
public function insideInstall($plugin)
|
||||
{
|
||||
try{
|
||||
// 解压zip文件
|
||||
$this->unzip($plugin);
|
||||
|
||||
// 复制database文件并执行php think migrate:run命令
|
||||
$this->migrate($plugin);
|
||||
|
||||
// 复制静态文件
|
||||
if(!function_exists('exec')){
|
||||
$this->setError('php函数exec不允许执行');
|
||||
return false;
|
||||
}
|
||||
$this->copyPublicFile($plugin);
|
||||
|
||||
// 生成菜单,同时将新增的菜单id写入info.ini配置文件中,便于卸载时同时删除菜单
|
||||
$this->createMenu($plugin);
|
||||
|
||||
// 修改系统插件配置文件config/plugin.php
|
||||
$this->installPluginConf($plugin);
|
||||
return true;
|
||||
}catch (\Exception $e){
|
||||
$this->setError(['msg'=>$e->getMessage(). $e->getLine() . $e->getFile(),'code'=>3]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解压插件zip文件
|
||||
* @param $plugin
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function unzip($plugin)
|
||||
{
|
||||
$file = $this->getPluginRuntimeDir() . DS . $plugin . '.zip';
|
||||
$zip = new \ZipArchive;
|
||||
if ($zip->open($file) !== TRUE) {
|
||||
@unlink($file);
|
||||
throw new \Exception('不能打开zip文件');
|
||||
}
|
||||
if(strtolower(trim($zip->getNameIndex(0),'/')) == strtolower($plugin)){
|
||||
$dir = root_path() . 'plugin' . DS;
|
||||
}else{
|
||||
$dir = root_path() . 'plugin' . DS . $plugin . DS;
|
||||
}
|
||||
if (!$zip->extractTo($dir)) {
|
||||
$zip->close();
|
||||
@unlink($file);
|
||||
throw new \Exception('不能提取zip文件');
|
||||
}
|
||||
$zip->close();
|
||||
@unlink($file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 插件代码文件解压后,执行php run:migrate命令,安装数据库文件
|
||||
public function migrate($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
if(is_dir($pluginDir . 'database' . DS . 'migrations')){
|
||||
DirFile::copyDirs($pluginDir . 'database' . DS . 'migrations', root_path() . 'database' . DS . 'migrations');
|
||||
// 删除数据库migrations表,已经安装过的版本
|
||||
$list = scandir($pluginDir . 'database' . DS . 'migrations');
|
||||
$migrationNameArr = [];
|
||||
foreach ($list as $value) {
|
||||
$pathinfo = pathinfo($value);
|
||||
if ($pathinfo['extension'] == 'php') {
|
||||
$tempArr = explode('_', $pathinfo['filename']);
|
||||
$migrationNameArr[] = ucfirst($tempArr[1]);
|
||||
}
|
||||
}
|
||||
Migrations::where('migration_name', 'in', $migrationNameArr)->delete();
|
||||
sleep(1);
|
||||
exec('php ' . app()->getRootPath() . '\think migrate:run');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 获取插件路径
|
||||
public function getPluginPath($plugin)
|
||||
{
|
||||
return app()->getRootPath() . DS . 'plugin' . DS . $plugin;
|
||||
}
|
||||
|
||||
// 获取插件信息
|
||||
public function getPluginInfo($plugin)
|
||||
{
|
||||
$pluginPath = $this->getPluginPath($plugin);
|
||||
$infoFile = $pluginPath . DS . 'info.ini';
|
||||
$info = [];
|
||||
if (is_file($infoFile)) {
|
||||
$info = parse_ini_file($infoFile, true, INI_SCANNER_TYPED) ?: [];
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置插件配置信息
|
||||
* @param $plugin
|
||||
* @param $array
|
||||
* @return bool
|
||||
*/
|
||||
public function setPluginInfo($plugin, $array)
|
||||
{
|
||||
$pluginPath = $this->getPluginPath($plugin);
|
||||
$file = $pluginPath . DS . 'info.ini';
|
||||
if (!isset($array['name'])) {
|
||||
$this->setError("插件配置写入失败");
|
||||
return false;
|
||||
}
|
||||
$res = array();
|
||||
foreach ($array as $key => $val) {
|
||||
if (is_array($val)) {
|
||||
$res[] = "[$key]";
|
||||
foreach ($val as $sKey => $sVal)
|
||||
$res[] = "$sKey = " . (is_numeric($sVal) ? $sVal : $sVal);
|
||||
} else
|
||||
$res[] = "$key = " . (is_numeric($val) ? $val : $val);
|
||||
}
|
||||
if ($handle = fopen($file, 'w')) {
|
||||
fwrite($handle, implode("\n", $res) . "\n");
|
||||
fclose($handle);
|
||||
} else {
|
||||
$this->setError("文件没有写入权限");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 生成插件菜单
|
||||
public function createMenu($plugin)
|
||||
{
|
||||
$menuFile = root_path() . 'plugin' . DS . $plugin . DS . 'menu.php';
|
||||
if(!is_file($menuFile)){
|
||||
return true;
|
||||
}
|
||||
$menus = include_once $menuFile;
|
||||
$info = $this->getPluginInfo($plugin);
|
||||
if(isset($info['parent_menu']) && $info['parent_menu'] === 'first'){
|
||||
$firstMenuId = Menu::where(['pid' => 0, 'is_show' => 1])->order(['sort'=>'desc', 'id'=>'asc'])->value('id');
|
||||
$ids = $this->createMenuIds($menus, $firstMenuId);
|
||||
}else{
|
||||
$ids = $this->createMenuIds($menus, 0);
|
||||
}
|
||||
$info['menu_ids'] = implode(',', $ids);
|
||||
if(!$this->setPluginInfo($plugin, $info)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function createMenuIds($menus, $pid=0)
|
||||
{
|
||||
foreach($menus as $menu){
|
||||
$id = Menu::insertGetId([
|
||||
'name' => $menu['name'],
|
||||
'des' => isset($menu['des']) ? $menu['des'] : '',
|
||||
'href' => isset($menu['href']) ? $menu['href'] : '',
|
||||
'rule' => isset($menu['rule']) ? $menu['rule'] : '',
|
||||
'is_menu' => $menu['is_menu'],
|
||||
'pid' => $pid,
|
||||
'icon' => isset($menu['icon']) ? $menu['icon'] : ''
|
||||
]);
|
||||
$this->ids[] = $id;
|
||||
|
||||
if(isset($menu['children'])){
|
||||
self::createMenuIds($menu['children'],$id);
|
||||
}
|
||||
}
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
// 复制静态文件,包括html css js
|
||||
public function copyPublicFile($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
if(is_dir($pluginDir . 'public')){
|
||||
DirFile::copyDirs($pluginDir . 'public', root_path() . 'public');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 删除静态文件,包括html css js
|
||||
public function removePublicFile($plugin)
|
||||
{
|
||||
$pluginDir = $this->getPluginPath($plugin) . DS;
|
||||
$pluginHtmlDir = $pluginDir . 'public' . DS . 'admin' . DS . 'plugin' . DS . $plugin;
|
||||
$publicHtmlDir = root_path() . 'public' . DS . 'admin' . DS . 'plugin' . DS . $plugin;
|
||||
if(is_dir($pluginHtmlDir) && $publicHtmlDir){
|
||||
DirFile::rmDirs($publicHtmlDir);
|
||||
}
|
||||
$pluginStaticDir = $pluginDir . 'public' . DS . 'static' . DS . 'plugin' . DS . $plugin;
|
||||
$publicStaticDir = root_path() . 'public' . DS . 'static' . DS . 'plugin' . DS . $plugin;
|
||||
if(is_dir($pluginStaticDir) && $publicStaticDir){
|
||||
DirFile::rmDirs($publicStaticDir);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 重新生成config/plugin.php文件
|
||||
public function installPluginConf($plugin)
|
||||
{
|
||||
$pluginConf = Config::get('plugin');
|
||||
$pluginConf['installed'][] = $plugin;
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
$info = $this->getPluginInfo($plugin);
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
$pluginConf['installedEditor'][] = $plugin;
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
}
|
||||
|
||||
$fileName = root_path() . DS . 'config' . DS . 'plugin.php';
|
||||
file_put_contents($fileName,"<?php\nreturn " . var_export($pluginConf,true) . ';');
|
||||
return true;
|
||||
}
|
||||
|
||||
// 重新生成config/plugin.php文件
|
||||
public function unInstallPluginConf($plugin, $info)
|
||||
{
|
||||
$pluginConf = Config::get('plugin');
|
||||
foreach($pluginConf['installed'] as $k=>$installed){
|
||||
if($installed === $plugin) unset($pluginConf['installed'][$k]);
|
||||
}
|
||||
$pluginConf['installed'] = array_unique($pluginConf['installed']);
|
||||
sort($pluginConf['installed']);
|
||||
|
||||
if(isset($info['is_editor']) && $info['is_editor']){
|
||||
foreach($pluginConf['installedEditor'] as $k=>$installedEditor){
|
||||
if($installedEditor === $plugin) unset($pluginConf['installedEditor'][$k]);
|
||||
}
|
||||
$pluginConf['installedEditor'] = array_unique($pluginConf['installedEditor']);
|
||||
sort($pluginConf['installedEditor']);
|
||||
}
|
||||
|
||||
$fileName = root_path() . DS . 'config' . DS . 'plugin.php';
|
||||
file_put_contents($fileName,"<?php\nreturn " . var_export($pluginConf,true) . ';');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 插件市场服务门面
|
||||
* @package app\service\admin
|
||||
* @method static mixed getError() 获取错误信息
|
||||
* @method static mixed offLineInstall() 离线安装
|
||||
* @method static mixed unInstall($plugin) 卸载
|
||||
* @method static mixed getPluginPath($plugin) 获取插件目录
|
||||
* @method static mixed getPluginInfo($plugin) 获取插件信息
|
||||
* @method static mixed install($plugin, $laytpGwToken) 安装插件
|
||||
*/
|
||||
class PluginsServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Plugins::class;
|
||||
}
|
||||
}
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use laytp\library\Token;
|
||||
use laytp\traits\Error;
|
||||
|
||||
/**
|
||||
* 后台用户服务实现者
|
||||
* @package app\service\admin
|
||||
*/
|
||||
class User
|
||||
{
|
||||
use Error;
|
||||
protected $_user = null;//实例化的用户对象
|
||||
protected $_token = null;//用户登录凭证,token
|
||||
protected $_isLogin = null;//当前用户是否登录
|
||||
protected $userModel = null;//用户数据模型
|
||||
protected $allowFields = ['id', 'username', 'nickname', 'avatar', 'is_super_manager', 'status', 'create_time'];
|
||||
protected $tokenKeepTime = 365 * 24 * 60 * 60;//Token默认有效时长,单位秒,365天
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param $token
|
||||
* @return bool
|
||||
*/
|
||||
public function init($token)
|
||||
{
|
||||
if (!$token) {
|
||||
$this->setError('token不能为空,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = Token::get($token);
|
||||
if (!$data) {
|
||||
$this->setError('token无效,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$userId = intval($data['user_id']);
|
||||
if ($userId > 0) {
|
||||
$user = \app\model\admin\User::with(['avatar_file'])->findOrEmpty($userId);
|
||||
if (!$user) {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
//用户状态 1正常 2禁用
|
||||
if ($user['status'] != 1) {
|
||||
$this->setError('账号被禁用,请联系管理员');
|
||||
return false;
|
||||
}
|
||||
$this->_user = $user;
|
||||
$this->_isLogin = true;
|
||||
$this->_token = $token;
|
||||
return true;
|
||||
} else {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* @return bool
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
if (!$this->_isLogin) {
|
||||
$this->setError('你没有登录');
|
||||
return false;
|
||||
}
|
||||
//设置登录标识
|
||||
$this->_isLogin = false;
|
||||
//删除Token
|
||||
Token::delete($this->_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户信息
|
||||
*/
|
||||
public function getUserInfo()
|
||||
{
|
||||
$data = $this->_user->toArray();
|
||||
$allowFields = $this->getAllowFields();
|
||||
$userInfo = array_intersect_key($data, array_flip($allowFields));
|
||||
$userInfo['avatar_file'] = $data['avatar_file'];
|
||||
$userInfo = array_merge($userInfo, ['token' => $this->_token]);
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取允许输出的字段
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowFields()
|
||||
{
|
||||
return $this->allowFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取User模型
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否登录
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLogin()
|
||||
{
|
||||
if ($this->_isLogin) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Token
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->_token;
|
||||
}
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\admin;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* 后台用户服务门面
|
||||
* @package app\service\admin
|
||||
* @method static mixed init($token) 初始化
|
||||
* @method static mixed getError() 获取错误信息
|
||||
* @method static mixed logout() 退出登录
|
||||
* @method static mixed getUserInfo() 获取登录用户信息
|
||||
* @method static mixed getAllowFields() 获取允许展示的字段
|
||||
* @method static mixed getUser() 获取User模型
|
||||
* @method static mixed isLogin() 获取登录状态
|
||||
* @method static mixed getToken() 获取token
|
||||
*/
|
||||
class UserServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return User::class;
|
||||
}
|
||||
}
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
- 容器
|
||||
- 通俗一点理解容器,我们用PHP中唯一的数据结构数组来做比方。
|
||||
- 你可以直接把容器理解为一个数组
|
||||
- 数组中的key是一个字符串,作为容器中类实例的标识,方便使用这个标识来调用类的实例
|
||||
- 数组中的value就是一个一个类的实例
|
||||
- 容器就是存储具有key-value数据结构的,用于存储标识和类实例的一个大集合
|
||||
- tp6中,默认在容器中添加了很多的类实例,手册中的[系统内置绑定到容器中的类库包括]的表格中说明了标识和系统类库对应的关系
|
||||
|
||||
- 依赖注入
|
||||
- 在容器中存入了很多key-value形式的类实例,就可以实现依赖注入。
|
||||
- 比如在控制器的某个方法中,使用依赖注入的方式,参数设置一个类,其实这个类在框架进行初始化时,就已经放在容器中了
|
||||
- 如果容器中不存在,容器也可以使用composer的类自动加载机制,实时的将类注入进入容器
|
||||
|
||||
- 服务
|
||||
- 平时在编写程序的时候,我们会写很多服务,比如权限验证,用户信息,支付,手机短信,邮件等等
|
||||
- 在tp6之前,我们一般就是写一个一个的类,需要用到的时候就new一下,得到服务类的实例,然后调用服务类的方法
|
||||
- 现在tp6使用容器来管理所有的类,当服务类需要使用依赖注入的方式调用时,就需要把服务类注册到容器中
|
||||
- tp6就提供了一个配置文件,service.php,写上哪些类需要注册到容器中
|
||||
- 注册到容器中的类还可以设置一个标识,那就使用服务类的register方法,或者bind方法
|
||||
- 服务不推荐使用,因为php本身语言的问题,容器的初始化是每次请求都会执行的,意味着,每次请求都会实例化所有服务类并注册进容器。服务越多,初始化消耗越大
|
||||
|
||||
- 门面
|
||||
- 门面为容器中的动态类提供了一个静态调用接口,相比于传统的静态方法调用,带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。
|
||||
|
||||
laytp里面的服务,其实就是用了tp6的门面,一般由两个文件组成
|
||||
- 服务具体实现者 这个类无需继承任何基类,只需要实现服务的具体方法
|
||||
- 服务门面
|
||||
- 编写服务门面的原因要谈到如何调用服务
|
||||
- 第一种:使用new关键字,创建一个服务具体实现者的类实例,就可以调用服务的方法,这种方法比较通用,但是需要多一行new的代码,而且服务本身还要考虑是否需要实现单例
|
||||
- 第二种,使用依赖注入。在控制器层可以使用此方法,调用起来也很方便,但是中间件中,不能使用依赖注入
|
||||
- 第三种,编写服务门面类,可以直接使用静态方法调用服务实现者的具体实现方法。此方式代码编写方便,中间件中也可以使用,而且服务门面基类实现了单例
|
||||
- 唯一要注意的是,服务门面类需要写好注释,PHPStorm编辑器的代码跟踪才能跟踪到门面类里面来,然后就可以在门面的getFacadeClass方法中继续跟踪服务的具体实现者类
|
||||
- 服务的目录 /app/service
|
||||
- 命名规范,以ServiceFacade结尾的就是服务门面
|
||||
|
||||
- 服务提供者,文件名和类名一般以Service结尾
|
||||
- 举例:
|
||||
- tp6的验证码就是使用的服务提供者来提供全局调用的
|
||||
- vendor/topthink/think-captcha/src/CaptchaService.php
|
||||
- 提供者仅需实现服务注册方法,如果服务需要做一些其他操作,可以使用服务启动方法进行操作。
|
||||
- 在提供者中,服务启动方法,可以进行路由注册、验证器扩展标识,
|
||||
- 服务提供者的用处
|
||||
- 提供者实现了服务注册方法,就能进行依赖注入的方式调用服务
|
||||
- 提供者的启动方法,服务在调用之前,就会执行的一些程序
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* Api权限服务实现者
|
||||
* Class Auth
|
||||
* @package app\api\service
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
use Error;
|
||||
protected $_noNeedLogin = [];//无需登录的方法名数组
|
||||
|
||||
/**
|
||||
* 设置无需登录的方法名数组
|
||||
* @param array $noNeedLogin
|
||||
*/
|
||||
public function setNoNeedLogin($noNeedLogin = [])
|
||||
{
|
||||
$this->_noNeedLogin = $noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需登录的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedLogin()
|
||||
{
|
||||
return $this->_noNeedLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要登录
|
||||
* @param bool $noNeedLogin
|
||||
* @return bool true:需要登录,false:不需要登录
|
||||
*/
|
||||
public function needLogin($noNeedLogin = false)
|
||||
{
|
||||
$noNeedLogin === false && $noNeedLogin = $this->getNoNeedLogin();
|
||||
$noNeedLogin = is_array($noNeedLogin) ? $noNeedLogin : explode(',', $noNeedLogin);
|
||||
//为空表示所有方法都需要登录,返回true
|
||||
if (!$noNeedLogin) {
|
||||
return true;
|
||||
}
|
||||
$noNeedLogin = array_map('strtolower', $noNeedLogin);
|
||||
$request = Request::instance();
|
||||
//判断当前请求的操作名是否存在于不需要登录的方法名数组中,如果存在,表明不需要登录,返回false
|
||||
if (in_array(strtolower($request->action()), $noNeedLogin) || in_array('*', $noNeedLogin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要登录
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* Api权限服务门面
|
||||
* @package app\api\service
|
||||
* @method static mixed setNoNeedLogin($noNeedLogin) 设置不需要登录的方法名数组
|
||||
* @method static mixed getNoNeedLogin() 获取无需登录的方法名数组
|
||||
* @method static mixed needLogin() 获取当前节点是否需要登录
|
||||
*/
|
||||
class AuthServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Auth::class;
|
||||
}
|
||||
}
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use app\service\ConfServiceFacade;
|
||||
use laytp\traits\Error;
|
||||
use think\facade\Config;
|
||||
use think\facade\Env;
|
||||
use think\facade\Request;
|
||||
|
||||
/**
|
||||
* Api验证签名服务实现者
|
||||
* Class CheckSign
|
||||
* @package app\api\service
|
||||
*/
|
||||
class CheckSign
|
||||
{
|
||||
use Error;
|
||||
protected $_noNeedCheckSign = [];//无需验证签名的方法名数组
|
||||
|
||||
/**
|
||||
* 设置无需验证签名的方法名数组
|
||||
* @param array $noNeedCheckSign
|
||||
*/
|
||||
public function setNoNeedCheckSign($noNeedCheckSign = [])
|
||||
{
|
||||
$this->_noNeedCheckSign = $noNeedCheckSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取无需验证签名的方法名数组
|
||||
* @return array
|
||||
*/
|
||||
public function getNoNeedCheckSign()
|
||||
{
|
||||
return $this->_noNeedCheckSign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前节点是否需要验证签名
|
||||
* @param bool $noNeedCheckSign
|
||||
* @return bool true:需要验证签名,false:不需要验证签名
|
||||
*/
|
||||
public function needCheckSign($noNeedCheckSign = false)
|
||||
{
|
||||
$noNeedCheckSign === false && $noNeedCheckSign = $this->getNoNeedCheckSign();
|
||||
$noNeedCheckSign = is_array($noNeedCheckSign) ? $noNeedCheckSign : explode(',', $noNeedCheckSign);
|
||||
//为空表示所有方法都需要验证签名,返回true
|
||||
if (!$noNeedCheckSign) {
|
||||
return true;
|
||||
}
|
||||
$noNeedCheckSign = array_map('strtolower', $noNeedCheckSign);
|
||||
$request = Request::instance();
|
||||
//判断当前请求的操作名是否存在于不需要验证签名的方法名数组中,如果存在,表明不需要验证签名,返回false
|
||||
if (in_array(strtolower($request->action()), $noNeedCheckSign) || in_array('*', $noNeedCheckSign)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//默认为需要验证签名
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
$request = Request::instance();
|
||||
$requestTime = $request->header('request-time');
|
||||
$sign = $request->header('sign');
|
||||
$signKey = ConfServiceFacade::get('system.basic.signKey');
|
||||
$backendSign = strtoupper(md5(md5($requestTime).md5($signKey)));
|
||||
if($sign != $backendSign){
|
||||
$this->setError($backendSign);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* Api验证签名服务门面
|
||||
* @package app\api\service
|
||||
* @method static mixed setNoNeedCheckSign($noNeedCheckSign) 设置不需要验证签名的方法名数组
|
||||
* @method static mixed getNoNeedCheckSign() 获取无需验证签名的方法名数组
|
||||
* @method static mixed needCheckSign() 获取当前节点是否需要验证签名
|
||||
* @method static mixed check() 验证签名
|
||||
* @method static mixed getError() 获取错误信息
|
||||
*/
|
||||
class CheckSignServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return CheckSign::class;
|
||||
}
|
||||
}
|
||||
Executable
+178
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use laytp\library\Str;
|
||||
use laytp\library\Token;
|
||||
use laytp\traits\Error;
|
||||
use laytp\library\Random;
|
||||
|
||||
/**
|
||||
* Api用户服务实现者
|
||||
* @package app\api\service
|
||||
*/
|
||||
class Member
|
||||
{
|
||||
use Error;
|
||||
protected $_user = null;//实例化的用户对象
|
||||
protected $_token = null;//用户登录凭证,token
|
||||
protected $_isLogin = null;//当前用户是否登录
|
||||
protected $userModel = null;//用户数据模型
|
||||
protected $allowFields = ['id', 'email', 'nickname', 'avatar'];
|
||||
protected $tokenKeepTime = 10 * 365 * 24 * 60 * 60;//Token默认有效时长,单位秒,365天
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param $token
|
||||
* @return bool
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function init($token)
|
||||
{
|
||||
if (!$token) {
|
||||
$this->setError('token不能为空,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$data = Token::get($token);
|
||||
if (!$data) {
|
||||
$this->setError('token无效,请重新登录');
|
||||
return false;
|
||||
}
|
||||
|
||||
$userId = intval($data['user_id']);
|
||||
if ($userId > 0) {
|
||||
$user = \app\model\Member::find($userId);
|
||||
if (!$user) {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
//用户状态 1正常 2锁定
|
||||
if ($user['status'] != 1) {
|
||||
$this->setError('账号被锁定,请联系管理员');
|
||||
return false;
|
||||
}
|
||||
$this->_user = $user;
|
||||
$this->_isLogin = true;
|
||||
$this->_token = $token;
|
||||
return true;
|
||||
} else {
|
||||
$this->setError('账号不存在,请重新登录');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱+密码注册登录
|
||||
* @param $params
|
||||
* @return bool
|
||||
*/
|
||||
public function emailRegLogin($params)
|
||||
{
|
||||
try {
|
||||
$user = \app\model\Member::where('email', '=', $params['email'])->find();
|
||||
if (!$user) {
|
||||
$data = [
|
||||
'email' => $params['email'],
|
||||
'password' => Str::createPassword($params['password']),
|
||||
'status' => 1,
|
||||
'login_time' => date('Y-m-d H:i:s'),
|
||||
'login_ip' => request()->ip(),
|
||||
];
|
||||
|
||||
$user = \app\model\Member::create($data);
|
||||
$this->_user = \app\model\Member::find($user->id);
|
||||
} else {
|
||||
$this->_user = $user;
|
||||
}
|
||||
|
||||
//设置Token
|
||||
$this->_token = Random::uuid();
|
||||
Token::set($this->_token, $user->id, $this->tokenKeepTime);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->setError('操作异常');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
if (!$this->_isLogin) {
|
||||
$this->setError('你没有登录');
|
||||
return false;
|
||||
}
|
||||
//设置登录标识
|
||||
$this->_isLogin = false;
|
||||
//删除Token
|
||||
Token::delete($this->_token);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容调用user模型的属性
|
||||
*
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->_user ? $this->_user->$name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录用户信息
|
||||
*/
|
||||
public function getUserInfo()
|
||||
{
|
||||
$data = $this->_user->toArray();
|
||||
$allowFields = $this->getAllowFields();
|
||||
$userInfo = array_intersect_key($data, array_flip($allowFields));
|
||||
$userInfo = array_merge($userInfo, ['token' => $this->_token]);
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取允许输出的字段
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowFields()
|
||||
{
|
||||
return $this->allowFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取User模型
|
||||
* @return Member
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否登录
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLogin()
|
||||
{
|
||||
if ($this->_isLogin) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前Token
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->_token;
|
||||
}
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\api;
|
||||
|
||||
use think\Facade;
|
||||
|
||||
/**
|
||||
* Api用户服务门面
|
||||
* @package plugin\core\service
|
||||
* @method static mixed init($token) 初始化
|
||||
* @method static mixed getError() 获取错误信息
|
||||
* @method static mixed emailRegLogin($param) 邮箱密码注册登录
|
||||
* @method static mixed logout() 退出登录
|
||||
* @method static mixed getUserInfo() 获取登录用户信息
|
||||
* @method static mixed getUser() 获取User模型
|
||||
* @method static mixed isLogin() 获取登录状态
|
||||
* @method static mixed getToken() 获取token
|
||||
* @method static mixed getAllowFields() 允许输出的字段
|
||||
*/
|
||||
class MemberServiceFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeClass()
|
||||
{
|
||||
return Member::class;
|
||||
}
|
||||
}
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
这里面写插件提供的服务
|
||||
一个服务,一般由三个文件组成
|
||||
- 服务具体实现者 这个类无需继承任何基类,只需要实现服务的具体方法
|
||||
- 服务提供者,也可以理解为服务注册者,将服务实现者类注册进ThinkPHP容器中,方便进行调用
|
||||
- 服务门面,为了在某些地方,不方便直接使用服务提供者的地方,能静态的访问服务实现者的方法,比如中间件中需要使用服务,那么就可能需要使用到服务门面
|
||||
|
||||
其中,以Service.php结尾的文件为服务提供者,服务提供者的类名全称会加入/config/service.php文件中,完成服务的注册
|
||||
|
||||
不移动到/app/common下了,负载均衡就全量复制到多个服务器
|
||||
Executable
+2759
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user