Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\Service;
|
||||
|
||||
/**
|
||||
* 应用服务类
|
||||
*/
|
||||
class AppService extends Service
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
// 服务注册
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
// 服务启动
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 控制器基础类
|
||||
*/
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
* Request实例
|
||||
* @var \think\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* 应用实例
|
||||
* @var \think\App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 是否批量验证
|
||||
* @var bool
|
||||
*/
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 控制器中间件
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
* @param App $app 应用对象
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->request = $this->app->request;
|
||||
|
||||
// 控制器初始化
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// 初始化
|
||||
protected function initialize()
|
||||
{}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string|array $validate 验证器名或者验证规则数组
|
||||
* @param array $message 提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @return array|string|true
|
||||
* @throws ValidateException
|
||||
*/
|
||||
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
|
||||
{
|
||||
if (is_array($validate)) {
|
||||
$v = new Validate();
|
||||
$v->rule($validate);
|
||||
} else {
|
||||
if (strpos($validate, '.')) {
|
||||
// 支持场景
|
||||
[$validate, $scene] = explode('.', $validate);
|
||||
}
|
||||
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
|
||||
$v = new $class();
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
|
||||
$v->message($message);
|
||||
|
||||
// 是否批量验证
|
||||
if ($batch || $this->batchValidate) {
|
||||
$v->batch(true);
|
||||
}
|
||||
|
||||
return $v->failException(true)->check($data);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace app;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\Handle;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\ValidateException;
|
||||
use think\Response;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 应用异常处理类
|
||||
*/
|
||||
class ExceptionHandle extends Handle
|
||||
{
|
||||
/**
|
||||
* 不需要记录信息(日志)的异常类列表
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreReport = [
|
||||
HttpException::class,
|
||||
HttpResponseException::class,
|
||||
ModelNotFoundException::class,
|
||||
DataNotFoundException::class,
|
||||
ValidateException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录异常信息(包括日志或者其它方式记录)
|
||||
*
|
||||
* @access public
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception): void
|
||||
{
|
||||
// 使用内置的方式记录异常日志
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
// 添加自定义异常处理机制
|
||||
|
||||
// 其他错误交给系统处理
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\facade\View;
|
||||
|
||||
abstract class Plugin
|
||||
{
|
||||
protected $plugin;
|
||||
protected $clientip;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function initialize($plugin){
|
||||
$this->plugin = $plugin;
|
||||
$this->clientip = real_ip();
|
||||
}
|
||||
|
||||
protected function view($tpl = null){
|
||||
if($tpl == null) $tpl = strtolower(request()->param("method", "index"));
|
||||
$template = plugin_path_get($this->plugin['class']) . '/'.$tpl.'.html';
|
||||
View::assign("plugin", $this->plugin);
|
||||
return view($template);
|
||||
}
|
||||
|
||||
public function alert($code, $msg = '', $url = null, $wait = 3)
|
||||
{
|
||||
if ($url) {
|
||||
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url);
|
||||
}
|
||||
if(empty($msg)) $msg = '未知错误';
|
||||
|
||||
View::assign([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'url' => $url,
|
||||
'wait' => $wait,
|
||||
]);
|
||||
return View::fetch(app()->getRootPath().'view/dispatch_jump.html');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace app;
|
||||
|
||||
// 应用请求对象类
|
||||
class Request extends \think\Request
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\input\Option;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
|
||||
class Cron extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('cron')
|
||||
->setDescription('定时数据清理任务');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
// 指令输出
|
||||
Db::name('querycache')->where('uptime','<',date('Y-m-d H:i:s', strtotime('-30 days')))->delete();
|
||||
$output->writeln('定时数据清理任务执行完毕');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\input\Argument;
|
||||
use think\console\Output;
|
||||
use ZipArchive;
|
||||
|
||||
class PluginPackage extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// 指令配置
|
||||
$this->setName('plugin:package')
|
||||
->addArgument('space', Argument::REQUIRED, '插件域,例如:utility')
|
||||
->setDescription('打包指定域的所有插件');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$space = $input->getArgument('space');
|
||||
// 指令输出
|
||||
$rootPath = app()->getRootPath() . '/plugin/';
|
||||
if (!is_dir($rootPath . $space)) {
|
||||
$output->writeln("该域不存在:[$space]");
|
||||
return;
|
||||
}
|
||||
$plugins = glob($rootPath . $space . '/*');
|
||||
$output->writeln("正在打包:[$space]下的文件");
|
||||
foreach ($plugins as $plugin) {
|
||||
$zip = new ZipArchive();
|
||||
$filename = $rootPath . 'output/' . $space . DIRECTORY_SEPARATOR . basename($plugin) . '.zip';
|
||||
if (!is_dir(dirname($filename))) {
|
||||
mkdir(dirname($filename), 0777, true);
|
||||
}
|
||||
if ($zip->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
|
||||
|
||||
$tree_relative = tree_relative($plugin);
|
||||
$files = multi2one($tree_relative, '', '/');
|
||||
foreach ($files as $file) {
|
||||
if ($file !== '.' && $file !== '..') {
|
||||
$zip->addFile($plugin . '/' . $file, $space . '/' . basename($plugin) . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
$zip->close();
|
||||
$output->writeln("打包成功:[$filename]");
|
||||
}
|
||||
|
||||
$output->writeln("该域所有文件都已打包完成:[$space]");
|
||||
}
|
||||
}
|
||||
+476
@@ -0,0 +1,476 @@
|
||||
<?php
|
||||
// 应用公共文件
|
||||
use think\facade\Db;
|
||||
ini_set("display_errors", 1);
|
||||
|
||||
function template_path_get(): string
|
||||
{
|
||||
return app()->getRootPath() . config("view.view_dir_name") . '/index/' . config_get('template') . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
function plugin_alias_get()
|
||||
{
|
||||
return trim(request()->param("alias"), '\\/');
|
||||
}
|
||||
|
||||
function plugin_method_get()
|
||||
{
|
||||
return request()->param("method", "index");
|
||||
}
|
||||
|
||||
function plugin_current_class_get($namespace)
|
||||
{
|
||||
return str_replace('plugin\\', '', $namespace);
|
||||
}
|
||||
|
||||
function plugin_path_get($class = '')
|
||||
{
|
||||
$class = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $class);
|
||||
return realpath(app()->getRootPath() . "/plugin/$class");
|
||||
}
|
||||
|
||||
function plugin_info_get($alias = '')
|
||||
{
|
||||
$plugin = Db::name('plugin')->where('alias',$alias)->where('enable',1)->find();
|
||||
if(!$plugin) return null;
|
||||
if(!plugin_userlevel($plugin['level'])) return null;
|
||||
$plugin['is_star'] = 0;
|
||||
if(request()->islogin){
|
||||
$stars = explode(',', request()->user['stars']);
|
||||
if(in_array($plugin['id'], $stars)){
|
||||
$plugin['is_star'] = 1;
|
||||
}
|
||||
}
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
|
||||
function msg($status = "ok", $message = "success", $data = [])
|
||||
{
|
||||
return json([
|
||||
"status" => $status,
|
||||
"message" => $message,
|
||||
"data" => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
function reset_opcache()
|
||||
{
|
||||
if (function_exists('opcache_reset')) opcache_reset();
|
||||
}
|
||||
|
||||
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
|
||||
$ckey_length = 4;
|
||||
$key = md5($key);
|
||||
$keya = md5(substr($key, 0, 16));
|
||||
$keyb = md5(substr($key, 16, 16));
|
||||
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
|
||||
$cryptkey = $keya.md5($keya.$keyc);
|
||||
$key_length = strlen($cryptkey);
|
||||
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
|
||||
$string_length = strlen($string);
|
||||
$result = '';
|
||||
$box = range(0, 255);
|
||||
$rndkey = array();
|
||||
for($i = 0; $i <= 255; $i++) {
|
||||
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
|
||||
}
|
||||
for($j = $i = 0; $i < 256; $i++) {
|
||||
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
|
||||
$tmp = $box[$i];
|
||||
$box[$i] = $box[$j];
|
||||
$box[$j] = $tmp;
|
||||
}
|
||||
for($a = $j = $i = 0; $i < $string_length; $i++) {
|
||||
$a = ($a + 1) % 256;
|
||||
$j = ($j + $box[$a]) % 256;
|
||||
$tmp = $box[$a];
|
||||
$box[$a] = $box[$j];
|
||||
$box[$j] = $tmp;
|
||||
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
|
||||
}
|
||||
if($operation == 'DECODE') {
|
||||
if(((int)substr($result, 0, 10) == 0 || (int)substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
|
||||
return substr($result, 26);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
return $keyc.str_replace('=', '', base64_encode($result));
|
||||
}
|
||||
}
|
||||
|
||||
function get_curl($url, $post=0, $referer=0, $cookie=0, $header=0, $ua=0, $nobody=0, $addheader=0)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
if($addheader){
|
||||
$httpheader = array_merge($httpheader, $addheader);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
if ($post) {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
}
|
||||
if ($header) {
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
}
|
||||
if ($cookie) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
||||
}
|
||||
if($referer){
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||
}
|
||||
if ($ua) {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
|
||||
}
|
||||
else {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
|
||||
}
|
||||
if ($nobody) {
|
||||
curl_setopt($ch, CURLOPT_NOBODY, 1);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$ret = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function jsonp_decode($jsonp, $assoc = false)
|
||||
{
|
||||
$jsonp = trim($jsonp);
|
||||
if(isset($jsonp[0]) && $jsonp[0] !== '[' && $jsonp[0] !== '{') {
|
||||
$begin = strpos($jsonp, '(');
|
||||
if(false !== $begin)
|
||||
{
|
||||
$end = strrpos($jsonp, ')');
|
||||
if(false !== $end)
|
||||
{
|
||||
$jsonp = substr($jsonp, $begin + 1, $end - $begin - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return json_decode($jsonp, $assoc);
|
||||
}
|
||||
|
||||
function dgmdate($timestamp, $d_format = 'Y-m-d H:i') {
|
||||
$timestamp=strtotime($timestamp);
|
||||
$timestamp += 8 * 3600;
|
||||
$todaytimestamp = time() - (time() + 8 * 3600) % 86400 + 8 * 3600;
|
||||
$s = gmdate($d_format, $timestamp);
|
||||
$time = time() + 8 * 3600 - $timestamp;
|
||||
if($timestamp >= $todaytimestamp) {
|
||||
if($time > 3600) {
|
||||
return '<span title="'.$s.'">'.intval($time / 3600).' 小时前</span>';
|
||||
} elseif($time > 1800) {
|
||||
return '<span title="'.$s.'">半小时前</span>';
|
||||
} elseif($time > 60) {
|
||||
return '<span title="'.$s.'">'.intval($time / 60).' 分钟前</span>';
|
||||
} elseif($time > 0) {
|
||||
return '<span title="'.$s.'">'.$time.' 秒前</span>';
|
||||
} elseif($time == 0 || $time < 0) {
|
||||
return '<span title="'.$s.'">刚刚</span>';
|
||||
} else {
|
||||
return $s;
|
||||
}
|
||||
} elseif(($days = intval(($todaytimestamp - $timestamp) / 86400)) >= 0 && $days < 7) {
|
||||
if($days == 0) {
|
||||
return '<span title="'.$s.'">昨天 '.gmdate('H:i', $timestamp).'</span>';
|
||||
} elseif($days == 1) {
|
||||
return '<span title="'.$s.'">前天 '.gmdate('H:i', $timestamp).'</span>';
|
||||
} else {
|
||||
return '<span title="'.$s.'">'.($days + 1).' 天前</span>';
|
||||
}
|
||||
} else {
|
||||
return $s;
|
||||
}
|
||||
}
|
||||
|
||||
function unzip($filepath, $filename)
|
||||
{
|
||||
if (!file_exists($filepath)) {
|
||||
return false;
|
||||
}
|
||||
$zip = new ZipArchive;
|
||||
|
||||
if ($zip->open($filepath) === true) {
|
||||
$zip->extractTo($filename);
|
||||
$zip->close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//多维转一维数组
|
||||
function multi2one($data, $dir = '', $step = '')
|
||||
{
|
||||
$list = [];
|
||||
foreach ($data as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
$list = array_merge($list, multi2one($v, $dir . $step . $k, $step));
|
||||
} else {
|
||||
$list[] = ltrim($dir . $step . $v, '\\/');
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
function tree_relative($dir)
|
||||
{
|
||||
if (!is_dir($dir)) {
|
||||
return [basename($dir)];
|
||||
}
|
||||
$arr = [];
|
||||
$scandir = scandir($dir);
|
||||
foreach ($scandir as $v) {
|
||||
if ($v != '.' && $v != '..') {
|
||||
if (is_dir("$dir/$v")) {
|
||||
$arr[$v] = tree_relative("$dir/$v");
|
||||
} else {
|
||||
$arr[] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
function copy_dir($src, $target)
|
||||
{
|
||||
if (!is_dir($target)) {
|
||||
mkdir($target, 0777, true);
|
||||
}
|
||||
foreach (glob($src . '/*') as $filename) {
|
||||
$targetFilename = $target . '/' . basename($filename);
|
||||
if (is_dir($filename)) {
|
||||
// 如果是目录,递归合并子目录下的文件。
|
||||
copy_dir($filename, $targetFilename);
|
||||
} elseif (is_file($filename)) {
|
||||
copy($filename, $targetFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function del_tree($dir)
|
||||
{
|
||||
if (!file_exists($dir)) {
|
||||
return true;
|
||||
}
|
||||
$files = array_diff(scandir($dir), array('.', '..'));
|
||||
|
||||
foreach ($files as $file) {
|
||||
(is_dir("$dir/$file")) ? del_tree("$dir/$file") : unlink("$dir/$file");
|
||||
}
|
||||
|
||||
return rmdir($dir);
|
||||
}
|
||||
|
||||
function config_get($key, $default = null)
|
||||
{
|
||||
$value = config('sys.'.$key);
|
||||
return $value ?: $default;
|
||||
}
|
||||
|
||||
function config_set($key, $value)
|
||||
{
|
||||
$res = Db::name('config')->replace()->insert(['key'=>$key, 'value'=>$value]);
|
||||
return $res!==false;
|
||||
}
|
||||
|
||||
function get_version()
|
||||
{
|
||||
return VERSION;
|
||||
}
|
||||
|
||||
function format_date($timestamp = null)
|
||||
{
|
||||
if ($timestamp === null) {
|
||||
$timestamp = time();
|
||||
}
|
||||
return date('Y-m-d H:i:s', $timestamp);
|
||||
}
|
||||
|
||||
//当前命名空间的包名
|
||||
function base_space_name($space)
|
||||
{
|
||||
$str_replace = str_replace('\\', '/', $space);
|
||||
return basename($str_replace);
|
||||
}
|
||||
|
||||
if (!function_exists('str_starts_with')) {
|
||||
function str_starts_with($str, $start)
|
||||
{
|
||||
return (@substr_compare($str, $start, 0, strlen($start)) == 0);
|
||||
}
|
||||
}
|
||||
if (!function_exists('str_ends_with')) {
|
||||
function str_ends_with(string $haystack, string $needle): bool
|
||||
{
|
||||
$needle_len = strlen($needle);
|
||||
return ($needle_len === 0 || 0 === substr_compare($haystack, $needle, -$needle_len));
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('is_valid_url')) {
|
||||
|
||||
function is_valid_url($url = null)
|
||||
{
|
||||
if (empty($url)) return false;
|
||||
if (!is_string($url)) return false;
|
||||
$filter_var = boolval(filter_var($url, FILTER_VALIDATE_URL));
|
||||
if ($filter_var) return $filter_var;
|
||||
$parse_url = parse_url($url);
|
||||
$path = array_pop($parse_url);
|
||||
|
||||
$url = str_ireplace($path, '/' . urlencode($path), $url);
|
||||
return boolval(filter_var($url, FILTER_VALIDATE_URL));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function real_ip($type=0){
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
if($type<=0 && isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
|
||||
foreach ($matches[0] AS $xip) {
|
||||
if (filter_var($xip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $xip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif ($type<=0 && isset($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif ($type<=1 && isset($_SERVER['HTTP_CF_CONNECTING_IP']) && filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
|
||||
} elseif ($type<=1 && isset($_SERVER['HTTP_ALI_CDN_REAL_IP']) && filter_var($_SERVER['HTTP_ALI_CDN_REAL_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_ALI_CDN_REAL_IP'];
|
||||
} elseif ($type<=1 && isset($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_X_REAL_IP'];
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
|
||||
function get_ip_city($ip){
|
||||
$new = new \app\lib\IpLocation();
|
||||
$arr = $new->getlocation($ip);
|
||||
if($arr){
|
||||
return $arr['province'].$arr['city'];
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_plugin_url($alias){
|
||||
if(substr($alias,0,1) == '/' || substr($alias,0,7) == 'http://' || substr($alias,0,8) == 'https://'){
|
||||
$url = $alias;
|
||||
}else{
|
||||
$url = '/'.$alias;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
//极验3.0服务端验证
|
||||
function verify_captcha(){
|
||||
if(session('gtserver') === null)return '验证加载失败';
|
||||
$GtSdk = new \app\lib\GeetestLib(config_get('captcha_id'), config_get('captcha_key'));
|
||||
$data = array(
|
||||
'user_id' => request()->islogin?request()->user['id']:'public',
|
||||
'client_type' => "web",
|
||||
'ip_address' => real_ip()
|
||||
);
|
||||
if (session('gtserver') == 1) { //服务器正常
|
||||
if ($GtSdk->success_validate(input('post.geetest_challenge'), input('post.geetest_validate'), input('post.geetest_seccode'), $data)) {
|
||||
return true;
|
||||
}
|
||||
}else{ //服务器宕机,走failback模式
|
||||
if ($GtSdk->fail_validate(input('post.geetest_challenge'), input('post.geetest_validate'), input('post.geetest_seccode'))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return '验证失败,请重新验证';
|
||||
}
|
||||
|
||||
//极验4.0服务端验证(无感)
|
||||
function verify_captcha4(){
|
||||
if(!input('?post.captcha_id') || !input('?post.lot_number') || !input('?post.pass_token') || !input('?post.gen_time') || !input('?post.captcha_output')) return false;
|
||||
$real_ip = real_ip();
|
||||
$url = 'http://gt4.geetest.com/demov4/demo/login';
|
||||
$param = ['captcha_id'=>input('post.captcha_id'), 'lot_number'=>input('post.lot_number'), 'pass_token'=>input('post.pass_token'), 'gen_time'=>input('post.gen_time'), 'captcha_output'=>input('post.captcha_output')];
|
||||
$referer = 'http://gt4.geetest.com/demov4/invisible-bind-zh.html';
|
||||
$httpheader[] = "X-Real-IP: ".$real_ip;
|
||||
$httpheader[] = "X-Forwarded-For: ".$real_ip;
|
||||
$data = get_curl($url.'?'.http_build_query($param),0,$referer,0,0,0,0,$httpheader);
|
||||
$arr = json_decode($data, true);
|
||||
if(isset($arr['result']) && $arr['result'] == 'success'){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//极验4.0服务端验证(滑动)
|
||||
function verify_captcha4_slide(){
|
||||
return verify_captcha4();
|
||||
if(!input('?post.captcha_id') || !input('?post.lot_number') || !input('?post.pass_token') || !input('?post.gen_time') || !input('?post.captcha_output')) return false;
|
||||
$url = 'http://gcaptcha4.geetest.com/validate?captcha_id='.input('post.captcha_id');
|
||||
$param = ['lot_number'=>input('post.lot_number'), 'pass_token'=>input('post.pass_token'), 'gen_time'=>input('post.gen_time'), 'captcha_output'=>input('post.captcha_output')];
|
||||
$param['sign_token'] = hash_hmac('sha256', $param['lot_number'], config_get('captcha_key'));
|
||||
$data = get_curl($url, http_build_query($param));
|
||||
$arr = json_decode($data, true);
|
||||
if(isset($arr['status']) && $arr['status']=='success'){
|
||||
if(isset($arr['result']) && $arr['result'] == 'success'){
|
||||
return true;
|
||||
}else{
|
||||
return '验证失败,'.$arr['reason'];
|
||||
}
|
||||
}else{
|
||||
return '验证失败,'.($arr['msg']?$arr['msg']:'请重新验证');
|
||||
}
|
||||
}
|
||||
|
||||
function checkdomain($domain){
|
||||
if(empty($domain))return false;
|
||||
if (!preg_match('/^[a-zA-Z0-9:\_\.\-]{2,512}$/i', $domain) || strpos($domain, '.') === false || substr($domain, -1) == '.' || substr($domain, 0 ,1) == '.' || strpos($domain, '*') !== false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取中间文本
|
||||
* @param string $str
|
||||
* @param string $leftStr
|
||||
* @param string $rightStr
|
||||
*/
|
||||
function getSubstr($str, $leftStr, $rightStr)
|
||||
{
|
||||
$left = strpos($str, $leftStr);
|
||||
$start = $left+strlen($leftStr);
|
||||
$right = strpos($str, $rightStr, $start);
|
||||
if($left < 0) return '';
|
||||
if($right>0){
|
||||
return substr($str, $start, $right-$start);
|
||||
}else{
|
||||
return substr($str, $start);
|
||||
}
|
||||
}
|
||||
|
||||
function plugin_userlevel($level){
|
||||
if($level > 0){
|
||||
if(!request()->islogin) return false;
|
||||
if(request()->user['level']<$level) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkRefererHost(){
|
||||
if(!request()->header('referer'))return false;
|
||||
$url_arr = parse_url(request()->header('referer'));
|
||||
$http_host = request()->header('host');
|
||||
if(strpos($http_host,':'))$http_host = substr($http_host, 0, strpos($http_host, ':'));
|
||||
return $url_arr['host'] === $http_host;
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\Request;
|
||||
use think\facade\Session;
|
||||
use think\facade\View;
|
||||
use app\lib\Oauth;
|
||||
use think\helper\Str;
|
||||
|
||||
class Auth extends Base
|
||||
{
|
||||
|
||||
public function login()
|
||||
{
|
||||
if(request()->islogin) {
|
||||
return $this->alert('success', '已登录', '/');
|
||||
}
|
||||
View::assign(['is_qq'=>config_get('oauth_openqq'), 'is_wx'=>config_get('oauth_openxw')]);
|
||||
return view();
|
||||
}
|
||||
|
||||
private function oauth_config(){
|
||||
return [
|
||||
'apiurl' => config_get('oauth_appurl'),
|
||||
'appid' => config_get('oauth_appid'),
|
||||
'appkey' => config_get('oauth_appkey'),
|
||||
'callback' => (string)url('/oauth/callback', [], '', true),
|
||||
];
|
||||
}
|
||||
|
||||
public function oauth()
|
||||
{
|
||||
$type = input('post.type');
|
||||
if(!$type){
|
||||
return msg('error', '登录方式不能为空');
|
||||
}
|
||||
$state = md5(uniqid(rand(), TRUE));
|
||||
session('oauth_state', $state);
|
||||
$oauth = new Oauth($this->oauth_config());
|
||||
$res = $oauth->login($type, $state);
|
||||
if(isset($res['code']) && $res['code']==0){
|
||||
return msg('ok', 'success', $res['url']);
|
||||
}else{
|
||||
return msg('error', $res ? $res['msg'] : '登录地址获取失败');
|
||||
}
|
||||
}
|
||||
|
||||
public function callback()
|
||||
{
|
||||
$code = input('get.code');
|
||||
$state = input('get.state');
|
||||
if (empty($code)) {
|
||||
return $this->alert('error', 'code不能为空', '/login');
|
||||
}
|
||||
|
||||
if(!$state || $state != session('oauth_state')){
|
||||
return $this->alert('error', 'state校验失败,请重新登录', '/login');
|
||||
}
|
||||
|
||||
$oauth = new Oauth($this->oauth_config());
|
||||
$res = $oauth->callback($code);
|
||||
if(isset($res['code']) && $res['code']==0){
|
||||
$type = $res['type'];
|
||||
$openid = $res['social_uid'];
|
||||
if(empty($res['nickname'])) $res['nickname'] = $type.Str::random(5);
|
||||
$user = Db::name('user')->where('type', $type)->where('openid', $openid)->find();
|
||||
if($user){
|
||||
if($user['enable']==0){
|
||||
session('user_block', '1');
|
||||
return $this->alert('error', '当前用户已被禁止登录', '/');
|
||||
}
|
||||
$uid = $user['id'];
|
||||
$password = $user['password'];
|
||||
Db::name('user')->where('id', $uid)->update([
|
||||
'avatar_url' => $res['faceimg'],
|
||||
'loginip' => $this->clientip,
|
||||
'update_time' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
if(session('user_block') == '1'){
|
||||
Db::name('user')->where('id', $uid)->update(['enable' => 0]);
|
||||
return $this->alert('error', '当前用户已被禁止登录', '/');
|
||||
}
|
||||
}else{
|
||||
$password = Str::random(16);
|
||||
$uid = Db::name('user')->insertGetId([
|
||||
'type' => $type,
|
||||
'openid' => $openid,
|
||||
'username' => $res['nickname'],
|
||||
'password' => $password,
|
||||
'avatar_url' => $res['faceimg'],
|
||||
'regip' => $this->clientip,
|
||||
'create_time' => date('Y-m-d H:i:s'),
|
||||
'update_time' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
if(session('user_block') == '1'){
|
||||
Db::name('user')->where('id', $uid)->update(['enable' => 0]);
|
||||
return $this->alert('error', '当前用户已被禁止登录', '/');
|
||||
}
|
||||
}
|
||||
|
||||
$session = md5($uid.$password);
|
||||
$expiretime = time()+30744000;
|
||||
$token = authcode("{$uid}\t{$session}\t{$expiretime}", 'ENCODE', config_get('syskey'));
|
||||
cookie('user_token', $token, ['expire' => $expiretime, 'httponly' => true]);
|
||||
session('oauth_state', null);
|
||||
|
||||
return redirect("/");
|
||||
}else{
|
||||
return $this->alert('error', $res ? $res['msg'] : '登录数据获取失败');
|
||||
}
|
||||
}
|
||||
|
||||
public function logout()
|
||||
{
|
||||
//session(null);
|
||||
cookie('user_token', null);
|
||||
return redirect(request()->header('referer') ?? '/');
|
||||
}
|
||||
|
||||
public function verifycode()
|
||||
{
|
||||
return captcha();
|
||||
}
|
||||
|
||||
public function adminlogin(){
|
||||
$username = input('post.username',null,'trim');
|
||||
$password = input('post.password',null,'trim');
|
||||
$captcha = input('post.captcha',null,'trim');
|
||||
|
||||
if(empty($username) || empty($password)){
|
||||
return msg('error', '用户名或密码不能为空');
|
||||
}
|
||||
if(!captcha_check($captcha)){
|
||||
return msg('error', '验证码错误');
|
||||
}
|
||||
if($username == config_get('admin_username') && password_verify($password, config_get('admin_password'))){
|
||||
$session = md5($username.config_get('admin_password'));
|
||||
$expiretime = time()+2562000;
|
||||
$token = authcode("{$username}\t{$session}\t{$expiretime}", 'ENCODE', config_get('syskey'));
|
||||
cookie('admin_token', $token, ['expire' => $expiretime, 'httponly' => true]);
|
||||
config_set('admin_lastlogin', date('Y-m-d H:i:s'));
|
||||
return msg();
|
||||
}else{
|
||||
return msg('error', '用户名或密码错误');
|
||||
}
|
||||
}
|
||||
|
||||
public function adminlogout()
|
||||
{
|
||||
cookie('admin_token', null);
|
||||
return redirect('/admin/login.html');
|
||||
}
|
||||
|
||||
public function qqlogin_api(){
|
||||
$do = input('get.do');
|
||||
$type = input('get.type');
|
||||
$info = $this->getQqloginInfo($type);
|
||||
if(!$info){
|
||||
return json(['saveOK'=>1, 'msg'=>'该登录类型不存在']);
|
||||
}
|
||||
|
||||
$login = new \app\lib\QQLogin();
|
||||
if($do == 'getqrpic'){
|
||||
$array = $login->getqrpic($info[0]);
|
||||
}
|
||||
elseif($do == 'qrlogin'){
|
||||
$array = $login->qrlogin($info[0], $info[1], input('get.qrsig'));
|
||||
if($array['saveOK'] == 0){
|
||||
$cookie = ['uin' => $array['uin'], 'cookie' => $array['cookie'], 'nickname' => $array['nickname']];
|
||||
session('qq_cookie_'.$type, $cookie);
|
||||
}
|
||||
}
|
||||
|
||||
return json($array);
|
||||
}
|
||||
|
||||
public function qqlogin(){
|
||||
if(!checkRefererHost()){
|
||||
return redirect('/');
|
||||
}
|
||||
|
||||
$redirect = input('get.redirect');
|
||||
$type = input('get.type');
|
||||
if(!$redirect || !$type){
|
||||
return $this->alert('error', '缺少参数', '/');
|
||||
}
|
||||
$info = $this->getQqloginInfo($type);
|
||||
if(!$info){
|
||||
return $this->alert('error', '该登录类型不存在', '/');
|
||||
}
|
||||
if (substr($redirect,0,1)!='/') {
|
||||
return $this->alert('error', '回调地址错误', '/');
|
||||
}
|
||||
|
||||
View::assign('logintype', base64_encode($type));
|
||||
View::assign('loginname', base64_encode($info[2]));
|
||||
View::assign('redirect', base64_encode($redirect));
|
||||
return view();
|
||||
}
|
||||
|
||||
private function getQqloginInfo($type){
|
||||
switch($type){
|
||||
case 'qzone':
|
||||
return ['5','https://qzs.qq.com/qzone/v5/loginsucc.html?para=izone', 'QQ空间'];
|
||||
break;
|
||||
case 'qun':
|
||||
return ['73','https://qun.qq.com/', 'QQ群管理'];
|
||||
break;
|
||||
case 'qqid':
|
||||
return ['1','https://id.qq.com/index.html' ,'我的QQ中心'];
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\View;
|
||||
|
||||
class Base extends BaseController
|
||||
{
|
||||
protected $clientip;
|
||||
|
||||
protected function initialize()
|
||||
{
|
||||
$this->clientip = real_ip(config_get('ip_type')??0);
|
||||
parent::initialize();
|
||||
|
||||
}
|
||||
|
||||
protected function alert($code, $msg = '', $url = null, $wait = 3)
|
||||
{
|
||||
if ($url) {
|
||||
$url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url);
|
||||
}
|
||||
if(empty($msg)) $msg = '未知错误';
|
||||
|
||||
View::assign([
|
||||
'code' => $code,
|
||||
'msg' => $msg,
|
||||
'url' => $url,
|
||||
'wait' => $wait,
|
||||
]);
|
||||
return View::fetch(app()->getRootPath().'view/dispatch_jump.html');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use think\facade\Validate;
|
||||
|
||||
class Index extends Base
|
||||
{
|
||||
const CACHE_TIME = 0;
|
||||
|
||||
public function index()
|
||||
{
|
||||
$category = Db::name('category')->cache('categorys', self::CACHE_TIME)->field('id,title,icon')->where('enable', 1)->order('weight','desc')->select();
|
||||
$link = Db::name('link')->cache('links', self::CACHE_TIME)->field('id,name,url')->where('enable', 1)->order('weight','desc')->select();
|
||||
|
||||
$tool = Db::name('plugin')->cache('plugins', self::CACHE_TIME)->field('id,title,alias,keyword,request_count,category_id,level')->where('enable', 1)->order('weight','desc')->select();
|
||||
$list = [];
|
||||
foreach($category as $item){
|
||||
$list2 = [];
|
||||
foreach($tool as $row){
|
||||
if(!plugin_userlevel($row['level'])) continue;
|
||||
if($row['category_id'] == $item['id']){
|
||||
$row['url'] = get_plugin_url($row['alias']);
|
||||
$row['out'] = substr($row['alias'],0,1) == '/' || substr($row['alias'],0,7) == 'http://' || substr($row['alias'],0,8) == 'https://';
|
||||
$list2[] = $row;
|
||||
}
|
||||
}
|
||||
$list[] = ['id'=>$item['id'], 'title'=>$item['title'], 'icon'=>$item['icon'], 'items'=>$list2];
|
||||
}
|
||||
|
||||
View::assign('category', $category);
|
||||
View::assign('tool', $list);
|
||||
View::assign('link', $link);
|
||||
return view();
|
||||
}
|
||||
|
||||
public function stars()
|
||||
{
|
||||
if(request()->isAjax()){
|
||||
if(!request()->islogin){
|
||||
return msg('error', '登录后才能收藏工具');
|
||||
}
|
||||
$uid = request()->user['id'];
|
||||
$do = input('post.do');
|
||||
if($do == 'clear'){
|
||||
Db::name('user')->where('id', $uid)->update(['stars'=>'']);
|
||||
return msg();
|
||||
}
|
||||
$id = input('post.id/d');
|
||||
if(empty($do) || empty($id)) return msg('error', 'param error');
|
||||
$plugin = Db::name('plugin')->where('id', $id)->where('enable',1)->find();
|
||||
if(!$plugin) return msg('error', '工具不存在');
|
||||
$stars = explode(',',request()->user['stars']);
|
||||
if ($do == 'add' && !in_array($id, $stars)) {
|
||||
array_push($stars, $id);
|
||||
} elseif ($do == 'del') {
|
||||
if (($key = array_search($id, $stars)) !== false) {
|
||||
unset($stars[$key]);
|
||||
}
|
||||
}
|
||||
$stars = implode(',', array_unique(array_values($stars)));
|
||||
Db::name('user')->where('id', $uid)->update(['stars'=>$stars]);
|
||||
return msg('ok', $do == 'add' ? '添加收藏成功!' : '取消收藏成功!');
|
||||
}
|
||||
|
||||
if(!request()->islogin){
|
||||
return $this->alert('info', '请先登录', '/login');
|
||||
}
|
||||
|
||||
$category = Db::name('category')->cache('categorys', self::CACHE_TIME)->field('id,title,icon')->where('enable', 1)->order('weight','desc')->select();
|
||||
$list = [];
|
||||
|
||||
$stars = request()->user['stars'];
|
||||
if(strlen($stars)>0){
|
||||
$stars = explode(',',$stars);
|
||||
$tool = Db::name('plugin')->cache('plugins', self::CACHE_TIME)->field('id,title,alias,keyword,request_count,category_id')->where('enable', 1)->order('weight','desc')->select();
|
||||
$list = [];
|
||||
foreach($category as $item){
|
||||
foreach($tool as $row){
|
||||
if(!plugin_userlevel($row['level'])) continue;
|
||||
if($row['category_id'] == $item['id'] && in_array($row['id'],$stars)){
|
||||
$row['url'] = get_plugin_url($row['alias']);
|
||||
$row['out'] = substr($row['alias'],0,1) == '/' || substr($row['alias'],0,7) == 'http://' || substr($row['alias'],0,8) == 'https://';
|
||||
$list[] = $row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
View::assign('category', $category);
|
||||
View::assign('tool', $list);
|
||||
return view();
|
||||
}
|
||||
|
||||
public function history()
|
||||
{
|
||||
if(request()->isAjax()){
|
||||
$do = input('post.do');
|
||||
if($do == 'clear'){
|
||||
cookie('tools', null);
|
||||
return msg();
|
||||
}
|
||||
}
|
||||
|
||||
$category = Db::name('category')->cache('categorys', self::CACHE_TIME)->field('id,title,icon')->where('enable', 1)->order('weight','desc')->select();
|
||||
$list = [];
|
||||
|
||||
$history = cookie('tools');
|
||||
if(strlen($history)>0){
|
||||
$history = array_reverse(array_unique(explode(',',$history)));
|
||||
$tool = Db::name('plugin')->cache('plugins', self::CACHE_TIME)->field('id,title,alias,keyword,request_count,category_id')->where('enable', 1)->order('weight','desc')->select();
|
||||
$newtool = [];
|
||||
foreach($tool as $row){
|
||||
$newtool[$row['id']] = $row;
|
||||
}
|
||||
$list = [];
|
||||
foreach($history as $id){
|
||||
$row = $newtool[$id];
|
||||
if(!$row) continue;
|
||||
if(!plugin_userlevel($row['level'])) continue;
|
||||
$row['url'] = get_plugin_url($row['alias']);
|
||||
$row['out'] = substr($row['alias'],0,1) == '/' || substr($row['alias'],0,7) == 'http://' || substr($row['alias'],0,8) == 'https://';
|
||||
$list[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
View::assign('category', $category);
|
||||
View::assign('tool', $list);
|
||||
return view();
|
||||
}
|
||||
|
||||
public function comment(){
|
||||
if(request()->isAjax()){
|
||||
$do = input('param.do');
|
||||
if($do == 'add'){
|
||||
if(!request()->islogin){
|
||||
return msg('error', '登录后才能提交留言');
|
||||
}
|
||||
$email = input('post.email', null, 'trim,strip_tags,htmlspecialchars');
|
||||
$content = input('post.content', null, 'trim,strip_tags,htmlspecialchars');
|
||||
|
||||
$data = [
|
||||
'uid' => request()->user['id'],
|
||||
'email' => $email,
|
||||
'content' => $content,
|
||||
'enable' => 0,
|
||||
'create_time' => date("Y-m-d H:i:s"),
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
];
|
||||
$validate = Validate::rule([
|
||||
'email|电子邮箱' => 'require|email',
|
||||
'content|留言内容' => 'require',
|
||||
]);
|
||||
if (!$validate->check($data)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$captcha_result = verify_captcha4_slide();
|
||||
if($captcha_result !== true){
|
||||
return msg('error', $captcha_result);
|
||||
}
|
||||
|
||||
$last = Db::name('comment')->where('uid', request()->user['id'])->order('id','desc')->find();
|
||||
if($last && time() - strtotime($last['create_time']) < 600){
|
||||
return msg('error', '你发表留言的速度太快了,过段时间再来吧');
|
||||
}
|
||||
|
||||
Db::name('comment')->insert($data);
|
||||
return msg();
|
||||
}else{
|
||||
$page = input('get.page/d');
|
||||
$limit = 5;
|
||||
$uid = request()->islogin ? request()->user['id'] : 0;
|
||||
$select = Db::name('comment')->alias('A')->leftJoin('user B', 'A.uid=B.id')->field('A.id,A.uid,content,reply,A.enable,A.create_time,A.update_time,B.username,B.avatar_url')->where('A.enable', 1)->whereOr('A.uid', $uid);
|
||||
$total = $select->count();
|
||||
$comment = $select->order('id','desc')->page($page, $limit)->select();
|
||||
$items = [];
|
||||
foreach($comment as $item){
|
||||
if(!$item['avatar_url']) $item['avatar_url'] = '/static/images/user.png';
|
||||
$item['time'] = dgmdate($item['create_time']);
|
||||
$items[] = $item;
|
||||
}
|
||||
return msg('ok', 'success', ['total'=>$total, 'page'=>$page, 'pagenum'=>ceil($total/$limit), 'items'=>$items]);
|
||||
}
|
||||
}
|
||||
return view();
|
||||
}
|
||||
|
||||
public function captcha(){
|
||||
$GtSdk = new \app\lib\GeetestLib(config_get('captcha_id'), config_get('captcha_key'));
|
||||
$data = array(
|
||||
'user_id' => request()->islogin?request()->user['id']:'public',
|
||||
'client_type' => "web",
|
||||
'ip_address' => $this->clientip
|
||||
);
|
||||
$result = $GtSdk->pre_process($data);
|
||||
session('gtserver', $result['success']);
|
||||
return json($result);
|
||||
}
|
||||
|
||||
public function statistics(){
|
||||
$id = input('post.id/d');
|
||||
if(!$id) return msg('error', 'param error');
|
||||
$plugin = Db::name('plugin')->where('id', $id)->where('enable', 1)->find();
|
||||
if(!$plugin) return msg('error', '工具不存在');
|
||||
Db::name('plugin')->where('id', $id)->inc('request_count')->update();
|
||||
|
||||
$history = cookie('tools');
|
||||
if(!$history) $history = [];
|
||||
else $history = array_unique(explode(',',$history));
|
||||
if(in_array($id, $history)){
|
||||
$key = array_search($id,$history);
|
||||
unset($history[$key]);
|
||||
}
|
||||
$history[] = $id;
|
||||
if(count($history) > 20){
|
||||
$history = array_splice($history, 0, 20);
|
||||
}
|
||||
cookie('tools', implode(',', $history));
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
|
||||
use app\lib\EnvOperation;
|
||||
use app\lib\ExecSQL;
|
||||
use PDO;
|
||||
use think\Exception;
|
||||
use think\facade\Cache;
|
||||
use think\facade\Request;
|
||||
use think\facade\Validate;
|
||||
use think\facade\View;
|
||||
use think\helper\Str;
|
||||
|
||||
|
||||
class Install extends Base
|
||||
{
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
Cache::clear();
|
||||
reset_opcache();
|
||||
}
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
// 检测是否已安装
|
||||
if (file_exists(app()->getRootPath() . 'install.lock')) {
|
||||
exit('你已安装成功,需要重新安装请删除 install.lock 文件');
|
||||
}
|
||||
Cache::clear();
|
||||
reset_opcache();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
// 检查安装环境
|
||||
$requirements = [
|
||||
'PHP >= 7.4' => PHP_VERSION >= 7.4,
|
||||
'PDO_MySQL' => extension_loaded("pdo_mysql"),
|
||||
'CURL' => extension_loaded("curl"),
|
||||
'ZipArchive' => class_exists("ZipArchive"),
|
||||
'runtime写入权限' => is_writable(app()->getRuntimePath()),
|
||||
];
|
||||
reset_opcache();
|
||||
$step = Request::param('step');
|
||||
View::assign([
|
||||
'step' => $step,
|
||||
'requirements' => $requirements,
|
||||
]);
|
||||
return view('../view/install/index.html');
|
||||
}
|
||||
|
||||
public function database()
|
||||
{
|
||||
$params = Request::param();
|
||||
$rules = [
|
||||
'hostname' => 'require',
|
||||
'hostport' => 'require|integer',
|
||||
'username' => 'require',
|
||||
'password' => 'require',
|
||||
'database' => 'require',
|
||||
];
|
||||
$validate = Validate::rule($rules);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$dsn = 'mysql:host=' . $params['hostname'] . ';dbname=' . $params['database'] . ';port=' . $params['hostport'] . ';charset=utf8';
|
||||
try {
|
||||
new PDO($dsn, $params['username'], $params['password']);
|
||||
} catch (\Exception $e) {
|
||||
return msg('error', $e->getMessage());
|
||||
}
|
||||
try {
|
||||
$envFile = file_get_contents(app()->getRootPath() . '.env.example');
|
||||
$envOperation = new EnvOperation($envFile);
|
||||
foreach (array_keys($rules) as $value) {
|
||||
$envOperation->set(mb_strtoupper($value), $params[$value]);
|
||||
}
|
||||
$envOperation->save();
|
||||
} catch (\Exception $e) {
|
||||
return msg('error', $e->getMessage());
|
||||
}
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function init_data()
|
||||
{
|
||||
try {
|
||||
|
||||
$filename = app()->getRootPath() . 'install.sql';
|
||||
if (!is_file($filename)) {
|
||||
throw new Exception('数据库 install.sql 文件不存在');
|
||||
}
|
||||
$install_sql = file($filename);
|
||||
//写入数据库
|
||||
$execSQL = new ExecSQL();
|
||||
$install_sql = $execSQL->purify($install_sql);
|
||||
foreach ($install_sql as $sql) {
|
||||
$execSQL->exec($sql);
|
||||
if (!empty($execSQL->getErrors())) {
|
||||
throw new Exception($execSQL->getErrors()[0]);
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return msg('error', $e->getMessage());
|
||||
}
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function admin()
|
||||
{
|
||||
$params = Request::param();
|
||||
$rules = [
|
||||
'username|用户名' => 'require',
|
||||
'password|密码' => 'require',
|
||||
];
|
||||
$validate = Validate::rule($rules);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
config_set("admin_username", $params['username']);
|
||||
config_set("admin_password", password_hash($params['password'], PASSWORD_DEFAULT));
|
||||
config_set("syskey", Str::random(16));
|
||||
file_put_contents(app()->getRootPath() . 'install.lock', format_date());
|
||||
return msg();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\controller\Base;
|
||||
use think\facade\Request;
|
||||
use think\facade\Validate;
|
||||
use think\facade\Db;
|
||||
|
||||
class Category extends Base
|
||||
{
|
||||
|
||||
public function list()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'page' => 'integer',
|
||||
'limit' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$page = isset($params['page']) ? intval($params['page']) : 1;
|
||||
$limit = isset($params['limit']) ? intval($params['limit']) : 50;
|
||||
|
||||
$select = Db::name('category');
|
||||
if(!empty($params['title'])){
|
||||
$select->where('title', 'like', '%' . $params['title'] . '%');
|
||||
}
|
||||
$total = $select->count();
|
||||
$items = $select->order('weight','desc')->page($page, $limit)->select();
|
||||
|
||||
return msg("ok", "success", ['total'=>$total, 'items'=>$items]);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$item = Db::name('category')->where('id', $params['id'])->findOrEmpty();
|
||||
|
||||
return msg('ok', 'success', $item);
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'title|分类标题' => 'require|unique:category',
|
||||
'icon|小图标' => 'require',
|
||||
'weight|权重' => 'require|integer',
|
||||
'enable' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('category')->cache('categorys')->insert([
|
||||
'title' => trim($params['title']),
|
||||
'icon' => trim($params['icon']),
|
||||
'weight' => $params['weight'],
|
||||
'enable' => $params['enable'],
|
||||
'create_time' => date("Y-m-d H:i:s"),
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'icon|小图标' => 'require',
|
||||
'title|分类标题' => 'require|unique:category',
|
||||
'weight|权重' => 'require|integer',
|
||||
'enable' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('category')->cache('categorys')->where('id', $params['id'])->update([
|
||||
'title' => trim($params['title']),
|
||||
'icon' => trim($params['icon']),
|
||||
'weight' => $params['weight'],
|
||||
'enable' => $params['enable'],
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function enable()
|
||||
{
|
||||
$id = input('post.id/d');
|
||||
$enable = input('post.enable/d');
|
||||
|
||||
Db::name('category')->cache('categorys')->where('id', $id)->update([
|
||||
'enable' => $enable,
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('category')->cache('categorys')->where('id', $params['id'])->delete();
|
||||
|
||||
return msg();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\controller\Base;
|
||||
use think\facade\Request;
|
||||
use think\facade\Validate;
|
||||
use think\facade\Db;
|
||||
|
||||
class Comment extends Base
|
||||
{
|
||||
|
||||
public function list()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'page' => 'integer',
|
||||
'limit' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$page = intval($params['page']);
|
||||
$limit = intval($params['limit']);
|
||||
|
||||
$select = Db::name('comment');
|
||||
if(!empty($params['uid'])){
|
||||
$select->where('uid', $params['uid']);
|
||||
}
|
||||
if(!empty($params['content'])){
|
||||
$select->where('content', 'like', '%' . $params['content'] . '%');
|
||||
}
|
||||
$total = $select->count();
|
||||
$items = $select->order('id','desc')->page($page, $limit)->select();
|
||||
|
||||
return msg("ok", "success", ['total'=>$total, 'items'=>$items]);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$item = Db::name('comment')->where('id', $params['id'])->findOrEmpty();
|
||||
|
||||
return msg('ok', 'success', $item);
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'content|留言内容' => 'require',
|
||||
'enable' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('comment')->where('id', $params['id'])->update([
|
||||
'content' => $params['content'],
|
||||
'reply' => $params['reply'],
|
||||
'enable' => $params['enable'],
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function enable()
|
||||
{
|
||||
$id = input('post.id/d');
|
||||
$enable = input('post.enable/d');
|
||||
|
||||
Db::name('comment')->where('id', $id)->update([
|
||||
'enable' => $enable,
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('comment')->where('id', $params['id'])->delete();
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
|
||||
public function uploadlog()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'page' => 'integer',
|
||||
'limit' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$page = intval($params['page']);
|
||||
$limit = intval($params['limit']);
|
||||
|
||||
$select = Db::name('uploadlog');
|
||||
if(!empty($params['uid'])){
|
||||
$select->where('uid', $params['uid']);
|
||||
}
|
||||
if(!empty($params['ip'])){
|
||||
$select->where('ip', $params['ip']);
|
||||
}
|
||||
if(!empty($params['fileurl'])){
|
||||
$select->where('fileurl', $params['fileurl']);
|
||||
}
|
||||
$total = $select->count();
|
||||
$items = $select->order('id','desc')->page($page, $limit)->select();
|
||||
|
||||
return msg("ok", "success", ['total'=>$total, 'items'=>$items]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\controller\Base;
|
||||
use think\facade\Request;
|
||||
use think\facade\Validate;
|
||||
use think\facade\Db;
|
||||
|
||||
class Link extends Base
|
||||
{
|
||||
|
||||
public function list()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'page' => 'integer',
|
||||
'limit' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$page = intval($params['page']);
|
||||
$limit = intval($params['limit']);
|
||||
|
||||
$select = Db::name('link');
|
||||
if(!empty($params['keyword'])){
|
||||
$select->where('name|url', 'like', '%' . $params['keyword'] . '%');
|
||||
}
|
||||
$total = $select->count();
|
||||
$items = $select->order('weight','desc')->page($page, $limit)->select();
|
||||
|
||||
return msg("ok", "success", ['total'=>$total, 'items'=>$items]);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$item = Db::name('link')->where('id', $params['id'])->findOrEmpty();
|
||||
|
||||
return msg('ok', 'success', $item);
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'name|名称' => 'require|chsAlphaNum|unique:link',
|
||||
'url|地址' => 'require',
|
||||
'weight|权重' => 'require|integer',
|
||||
'enable' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('link')->cache('links')->insert([
|
||||
'name' => trim($params['name']),
|
||||
'url' => trim($params['url']),
|
||||
'weight' => $params['weight'],
|
||||
'enable' => $params['enable'],
|
||||
'create_time' => date("Y-m-d H:i:s"),
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'name|名称' => 'require|chsAlphaNum|unique:link',
|
||||
'url|地址' => 'require',
|
||||
'weight|权重' => 'require|integer',
|
||||
'enable' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('link')->cache('links')->where('id', $params['id'])->update([
|
||||
'name' => trim($params['name']),
|
||||
'url' => trim($params['url']),
|
||||
'weight' => $params['weight'],
|
||||
'enable' => $params['enable'],
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function enable()
|
||||
{
|
||||
$id = input('post.id/d');
|
||||
$enable = input('post.enable/d');
|
||||
|
||||
Db::name('link')->cache('links')->where('id', $id)->update([
|
||||
'enable' => $enable,
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('link')->cache('links')->where('id', $params['id'])->delete();
|
||||
|
||||
return msg();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
|
||||
use app\BaseController;
|
||||
|
||||
class Menu extends BaseController
|
||||
{
|
||||
public function get(){
|
||||
|
||||
$homeInfo = [
|
||||
'title' => '主页',
|
||||
'href' => 'page/dashboard.html',
|
||||
];
|
||||
$logoInfo = [
|
||||
'title' => '工具网后台',
|
||||
'image' => 'images/logo.png',
|
||||
'href' => './',
|
||||
];
|
||||
$menuInfo = [
|
||||
[
|
||||
"title" => "常规管理",
|
||||
"icon" => "fa fa-address-book",
|
||||
"href" => "",
|
||||
"target" => "_self",
|
||||
"child" => [
|
||||
[
|
||||
"title" => "主页",
|
||||
"icon" => "fa fa-home",
|
||||
"target" => "_self",
|
||||
"href" => "page/dashboard.html",
|
||||
],
|
||||
[
|
||||
"title" => "分类管理",
|
||||
"href" => "page/category.html",
|
||||
"icon" => "fa fa-bookmark-o",
|
||||
"target" => "_self",
|
||||
],
|
||||
[
|
||||
"title" => "插件管理",
|
||||
"href" => "",
|
||||
"icon" => "fa fa-puzzle-piece",
|
||||
"target" => "_self",
|
||||
"child" => [
|
||||
[
|
||||
"title" => "插件列表",
|
||||
"href" => "page/plugin.html",
|
||||
"icon" => "fa fa-list",
|
||||
"target" => "_self"
|
||||
],
|
||||
[
|
||||
"title" => "安装新插件",
|
||||
"href" => "page/plugin/install.html",
|
||||
"icon" => "fa fa-cloud-upload",
|
||||
"target" => "_self"
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
"title" => "用户管理",
|
||||
"href" => "page/user.html",
|
||||
"icon" => "fa fa-user",
|
||||
"target" => "_self",
|
||||
],
|
||||
[
|
||||
"title" => "留言管理",
|
||||
"href" => "page/comment.html",
|
||||
"icon" => "fa fa-comments",
|
||||
"target" => "_self",
|
||||
],
|
||||
[
|
||||
"title" => "上传记录",
|
||||
"href" => "page/uploadlog.html",
|
||||
"icon" => "fa fa-cloud-upload",
|
||||
"target" => "_self",
|
||||
],
|
||||
[
|
||||
"title" => "友链管理",
|
||||
"href" => "page/link.html",
|
||||
"icon" => "fa fa-link",
|
||||
"target" => "_self",
|
||||
],
|
||||
[
|
||||
"title" => "系统配置",
|
||||
"href" => "",
|
||||
"icon" => "fa fa-cogs",
|
||||
"target" => "_self",
|
||||
"child" => [
|
||||
[
|
||||
"title" => "基本信息配置",
|
||||
"href" => "page/system.html",
|
||||
"icon" => "fa fa-cog",
|
||||
"target" => "_self"
|
||||
],
|
||||
[
|
||||
"title" => "管理员配置",
|
||||
"href" => "page/account.html",
|
||||
"icon" => "fa fa-user",
|
||||
"target" => "_self"
|
||||
],
|
||||
]
|
||||
],
|
||||
/*[
|
||||
"title" => "在线升级",
|
||||
"href" => "page/update.html",
|
||||
"icon" => "fa fa-cloud-upload",
|
||||
"target" => "_self",
|
||||
],*/
|
||||
],
|
||||
]
|
||||
];
|
||||
$systemInit = [
|
||||
'homeInfo' => $homeInfo,
|
||||
'logoInfo' => $logoInfo,
|
||||
'menuInfo' => $menuInfo,
|
||||
];
|
||||
return json($systemInit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\Db;
|
||||
use think\facade\Request;
|
||||
use think\facade\Session;
|
||||
use think\facade\Validate;
|
||||
|
||||
class Plugin extends BaseController
|
||||
{
|
||||
public function list()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'page' => 'integer',
|
||||
'limit' => 'integer',
|
||||
'category_id' => 'integer',
|
||||
'class' => 'is_legal_plugin_class',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$page = isset($params['page']) ? intval($params['page']) : 1;
|
||||
$limit = isset($params['limit']) ? intval($params['limit']) : 50;
|
||||
$orderby = ['id' => 'desc'];
|
||||
|
||||
$select = Db::name('plugin');
|
||||
if(!empty($params['title'])){
|
||||
$select->where('title', 'like', '%' . $params['title'] . '%');
|
||||
}
|
||||
if(!empty($params['alias'])){
|
||||
$select->where('alias', $params['alias']);
|
||||
}
|
||||
if(!empty($params['class'])){
|
||||
$select->where('class', $params['class']);
|
||||
}
|
||||
if(!empty($params['enable'])){
|
||||
$select->where('enable', '1');
|
||||
}
|
||||
if(!empty($params['category_id'])){
|
||||
$select->where('category_id', $params['category_id']);
|
||||
$orderby = ['weight' => 'desc', 'id' => 'desc'];
|
||||
}
|
||||
$total = $select->count();
|
||||
$items = $select->order($orderby)->page($page, $limit)->select();
|
||||
|
||||
return msg("ok", "success", ['total'=>$total, 'items'=>$items]);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$item = Db::name('plugin')->where('id', $params['id'])->findOrEmpty();
|
||||
|
||||
return msg('ok', 'success', $item);
|
||||
}
|
||||
|
||||
public function add()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'title|插件标题' => 'require|unique:plugin',
|
||||
'alias|路由别名' => 'require|unique:plugin',
|
||||
'class|插件类名' => 'require|unique:plugin|is_legal_plugin_class',
|
||||
'category_id|分类' => 'require|integer',
|
||||
'level|用户等级限制' => 'integer',
|
||||
'enable' => 'integer',
|
||||
'weight|权重' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('plugin')->cache('plugins')->insert([
|
||||
'title' => trim($params['title']),
|
||||
'alias' => trim($params['alias']),
|
||||
'class' => trim($params['class']),
|
||||
'keyword' => trim($params['keyword']),
|
||||
'weight' => $params['weight'],
|
||||
'enable' => $params['enable'],
|
||||
'category_id' => $params['category_id'],
|
||||
'level' => $params['level'],
|
||||
'login' => $params['login'],
|
||||
'desc' => $params['desc'],
|
||||
'create_time' => date("Y-m-d H:i:s"),
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'title|插件标题' => 'require|unique:plugin',
|
||||
'alias|路由别名' => 'unique:plugin',
|
||||
'class|插件类名' => 'unique:plugin|is_legal_plugin_class',
|
||||
'category_id|分类' => 'integer',
|
||||
'level|用户等级限制' => 'integer',
|
||||
'enable' => 'integer',
|
||||
'weight|权重' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
if(isset($params['level']) && isset($params['enable'])){
|
||||
Db::name('plugin')->cache('plugins')->where('id', $params['id'])->update([
|
||||
'title' => trim($params['title']),
|
||||
'alias' => trim($params['alias']),
|
||||
'class' => trim($params['class']),
|
||||
'keyword' => trim($params['keyword']),
|
||||
'weight' => $params['weight'],
|
||||
'enable' => $params['enable'],
|
||||
'category_id' => $params['category_id'],
|
||||
'level' => $params['level'],
|
||||
'login' => $params['login'],
|
||||
'desc' => $params['desc'],
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
}else{
|
||||
Db::name('plugin')->cache('plugins')->where('id', $params['id'])->update([
|
||||
'title' => trim($params['title']),
|
||||
'alias' => trim($params['alias']),
|
||||
'class' => trim($params['class']),
|
||||
'category_id' => $params['category_id'],
|
||||
'desc' => $params['desc'],
|
||||
'update_time' => date("Y-m-d H:i:s")
|
||||
]);
|
||||
}
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function enable(){
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'category_id|分类' => 'integer',
|
||||
'enable' => 'integer'
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('plugin')->cache('plugins')->where('id', $params['id'])->update($params);
|
||||
return msg();
|
||||
}
|
||||
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$plugin = Db::name('plugin')->where('id', $params['id'])->find();
|
||||
if(!$plugin) return msg('ok', 'success');
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
$classPath = plugin_path_get() . '/'.$plugin['class'].'/Install.php';
|
||||
if (file_exists($classPath)) {
|
||||
require $classPath;
|
||||
$class = 'plugin\\'.$plugin['class'].'\\Install';
|
||||
if (class_exists($class)) {
|
||||
$uninstall = new $class();
|
||||
$uninstall->UnInstall();
|
||||
}
|
||||
}
|
||||
Db::name('plugin')->cache('plugins')->where('id', $params['id'])->delete();
|
||||
if (!empty($plugin['class'])) {
|
||||
del_tree(plugin_path_get($plugin['class']));
|
||||
}
|
||||
// 提交事务
|
||||
Db::commit();
|
||||
} catch (\Exception $e) {
|
||||
// 回滚事务
|
||||
Db::rollback();
|
||||
return msg('error', $e->getMessage(), $e);
|
||||
}
|
||||
return msg('ok', 'success');
|
||||
}
|
||||
|
||||
public function upload()
|
||||
{
|
||||
$params = Request::file();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'file' => 'require|file',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
$uploadedFile = Request::file('file');
|
||||
$plugin = new \app\lib\Plugin();
|
||||
$zipFilepath = $plugin->getZipFilepath();
|
||||
$uploadedFile->move(dirname($zipFilepath), basename($zipFilepath));
|
||||
return $plugin->install();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\Db;
|
||||
use think\facade\Request;
|
||||
use think\facade\Validate;
|
||||
use think\facade\Cache;
|
||||
|
||||
class System extends BaseController
|
||||
{
|
||||
public function analysis(){
|
||||
$data['count1'] = Db::name('plugin')->count();
|
||||
$data['count2'] = Db::name('comment')->count();
|
||||
$data['count3'] = Db::name('user')->count();
|
||||
$data['count4'] = Db::name('user')->whereDay('create_time', date("Y-m-d"))->count();
|
||||
return msg('ok', 'success', $data);
|
||||
}
|
||||
|
||||
public function info()
|
||||
{
|
||||
|
||||
$tmp = 'version()';
|
||||
$mysqlVersion = Db::query("select version()")[0][$tmp];
|
||||
$data = [
|
||||
'framework_version' => app()::VERSION,
|
||||
'php_version' => PHP_VERSION,
|
||||
'mysql_version' => $mysqlVersion,
|
||||
'software' => $_SERVER['SERVER_SOFTWARE'],
|
||||
'os' => php_uname(),
|
||||
'date' => date("Y-m-d H:i:s"),
|
||||
'checkupdate' => '//auth.cccyun.cc/app/tool.php?version='.config('app.version').'&ver='.config('app.ver')
|
||||
];
|
||||
return msg('ok', 'success', $data);
|
||||
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
$all = Db::name('config')->select();
|
||||
return msg('ok', 'success', $all);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$key = Request::param('key');
|
||||
$value = config_get($key);
|
||||
return msg('ok', 'success', $value);
|
||||
}
|
||||
|
||||
public function set()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
foreach ($params as $v) {
|
||||
if (empty($v['key'])) {
|
||||
continue;
|
||||
}
|
||||
config_set($v['key'], $v['value']);
|
||||
}
|
||||
cache('configs', NULL);
|
||||
$all = Db::name('config')->select();
|
||||
return msg('ok', 'success', $all);
|
||||
}
|
||||
|
||||
public function setpwd()
|
||||
{
|
||||
$params = Request::param();
|
||||
if(isset($params['username']))$params['username']=trim($params['username']);
|
||||
if(isset($params['oldpwd']))$params['oldpwd']=trim($params['oldpwd']);
|
||||
if(isset($params['newpwd']))$params['newpwd']=trim($params['newpwd']);
|
||||
if(isset($params['newpwd2']))$params['newpwd2']=trim($params['newpwd2']);
|
||||
|
||||
$validate = Validate::rule([
|
||||
'username|用户名' => 'require|chsAlphaNum',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
config_set('admin_username', $params['username']);
|
||||
|
||||
if(!empty($params['oldpwd']) && !empty($params['newpwd']) && !empty($params['newpwd2'])){
|
||||
$oldpwd = config_get('admin_password');
|
||||
if($oldpwd && !password_verify($params['oldpwd'], $oldpwd)){
|
||||
return msg('error', '旧密码不正确');
|
||||
}
|
||||
if($params['newpwd'] != $params['newpwd2']){
|
||||
return msg('error', '两次新密码输入不一致');
|
||||
}
|
||||
config_set('admin_password', password_hash($params['newpwd'], PASSWORD_DEFAULT));
|
||||
}
|
||||
cache('configs', NULL);
|
||||
cookie('admin_token', null);
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function templates()
|
||||
{
|
||||
$glob = glob(app()->getRootPath() . config("view.view_dir_name") . '/index/*');
|
||||
$arr = [];
|
||||
foreach ($glob as $v) {
|
||||
if (is_dir($v)) {
|
||||
array_push($arr, basename($v));
|
||||
}
|
||||
}
|
||||
return msg('ok', 'success', $arr);
|
||||
|
||||
}
|
||||
|
||||
public function clear(){
|
||||
Cache::clear();
|
||||
reset_opcache();
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function iptype(){
|
||||
$result = [
|
||||
['name'=>'0_X_FORWARDED_FOR', 'ip'=>real_ip(0), 'city'=>get_ip_city(real_ip(0))],
|
||||
['name'=>'1_X_REAL_IP', 'ip'=>real_ip(1), 'city'=>get_ip_city(real_ip(1))],
|
||||
['name'=>'2_REMOTE_ADDR', 'ip'=>real_ip(2), 'city'=>get_ip_city(real_ip(2))]
|
||||
];
|
||||
return msg('ok', 'success', $result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
|
||||
use app\controller\Base;
|
||||
use app\lib\ExecSQL;
|
||||
use think\facade\Request;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
private $RELEASE_API = '';
|
||||
|
||||
public function initialize()
|
||||
{
|
||||
reset_opcache();
|
||||
$this->RELEASE_API = base64_decode('aHR0cHM6Ly90b29sLWNsb3VkLmFvYW9zdGFyLmNvbS9vcGVuL3JlbGVhc2U=');
|
||||
}
|
||||
|
||||
private function get_last_release()
|
||||
{
|
||||
|
||||
$res = get_curl($this->RELEASE_API, 0, Request::domain());
|
||||
$json = json_decode($res);
|
||||
|
||||
if (empty($json) || empty($json->data)) {
|
||||
if (!empty($json->message)) {
|
||||
throw new \Exception($json->message);
|
||||
}
|
||||
throw new \Exception('"连接云中心失败,请检查网络连通性是否正常"');
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
try {
|
||||
$release = $this->get_last_release();
|
||||
$release->data->current_version = get_version();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return msg('error', $e->getMessage());
|
||||
|
||||
}
|
||||
return msg('ok', 'success', $release->data);
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
try {
|
||||
$release = $this->get_last_release();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return msg('error', $e->getMessage());
|
||||
|
||||
}
|
||||
$get = get_curl($release->data->download_url);
|
||||
if (empty($get) || str_starts_with($get, 'CURL Error:')) {
|
||||
return msg('error', '下载更新包失败,请检查网络连通性是否正常');
|
||||
}
|
||||
$tmpFilename = app()->getRuntimePath() . '/tmp/' . uniqid() . '.zip';
|
||||
if (!file_exists(dirname($tmpFilename))) {
|
||||
mkdir(dirname($tmpFilename), 0777, true);
|
||||
}
|
||||
if (!file_put_contents($tmpFilename, $get)) {
|
||||
return msg('error', '保存文件失败,请检查是否有写入权限');
|
||||
}
|
||||
$rootPath = app()->getRootPath();
|
||||
if (!unzip($tmpFilename, $rootPath)) {
|
||||
return msg('error', '解压压缩包失败');
|
||||
}
|
||||
return msg('ok', '资源包解压成功', $release->data);
|
||||
}
|
||||
|
||||
public function updateDatabase()
|
||||
{
|
||||
$glob = glob(app()->getRuntimePath() . '/update/sql/*.sql');
|
||||
if (empty($glob)) {
|
||||
return msg('ok', '未发现数据库更新文件');
|
||||
}
|
||||
foreach ($glob as $value) {
|
||||
$result[$value] = [];
|
||||
$basename = basename($value);
|
||||
$lines = file($value);
|
||||
$execSQL = new ExecSQL();
|
||||
$lines = $execSQL->purify($lines);
|
||||
$number = $execSQL->exec($lines);
|
||||
$result[$value] = array_merge($result[$value], $execSQL->getErrors());
|
||||
|
||||
if ($number > 0) {
|
||||
$result[$value][] = "影响的记录数 $number";
|
||||
}
|
||||
$result[$value][] = '创建数据库升级记录成功';
|
||||
end:
|
||||
unlink($value);
|
||||
$result[$value] = "[$basename]:" . implode("\n", $result[$value]);
|
||||
}
|
||||
return msg('ok', "数据库执行结果:\n" . implode("\n", $result));
|
||||
}
|
||||
|
||||
public function updateScript()
|
||||
{
|
||||
$glob = glob(app()->getRuntimePath() . '/update/script/*.php');
|
||||
if (empty($glob)) {
|
||||
return msg('ok', '未发现更新脚本');
|
||||
}
|
||||
foreach ($glob as $value) {
|
||||
$result[$value] = [];
|
||||
$basename = basename($value);
|
||||
try {
|
||||
require $value;
|
||||
$class = 'UpdateScript';
|
||||
if (!class_exists($class)) {
|
||||
throw new \Exception("更新脚本不存在[$class]类");
|
||||
}
|
||||
$instance = new $class();
|
||||
$boot = 'main';
|
||||
if (!method_exists($instance, $boot)) {
|
||||
throw new \Exception("更新脚本不存在[$boot]方法");
|
||||
}
|
||||
$instance->main();
|
||||
$result[$value] = array_merge($result[$value], $instance->getResult());
|
||||
} catch (\Exception $e) {
|
||||
$result[$value][] = $e->getMessage();
|
||||
}
|
||||
$result[$value][] = '创建更新脚本升级记录成功';
|
||||
end:
|
||||
unlink($value);
|
||||
$result[$value] = "[$basename]:" . implode("\n", $result[$value]);
|
||||
}
|
||||
return msg('ok', "更新脚本执行结果:\n" . implode("\n", $result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller\admin;
|
||||
|
||||
use app\controller\Base;
|
||||
use think\facade\Request;
|
||||
use think\facade\Validate;
|
||||
use think\facade\Db;
|
||||
|
||||
class User extends Base
|
||||
{
|
||||
|
||||
public function list()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'page' => 'integer',
|
||||
'limit' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$page = intval($params['page']);
|
||||
$limit = intval($params['limit']);
|
||||
|
||||
$select = Db::name('user');
|
||||
if(!empty($params['id'])){
|
||||
$select->where('id|openid', $params['id']);
|
||||
}
|
||||
if(!empty($params['username'])){
|
||||
$select->where('username', 'like', '%' . $params['username'] . '%');
|
||||
}
|
||||
$total = $select->count();
|
||||
$items = $select->order('id','desc')->page($page, $limit)->select();
|
||||
|
||||
return msg("ok", "success", ['total'=>$total, 'items'=>$items]);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
$item = Db::name('user')->where('id', $params['id'])->findOrEmpty();
|
||||
|
||||
return msg('ok', 'success', $item);
|
||||
}
|
||||
|
||||
public function enable(){
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'enable' => 'integer'
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('user')->where('id', $params['id'])->update($params);
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function edit()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require',
|
||||
'level' => 'integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('user')->where('id', $params['id'])->update([
|
||||
'level' => $params['level']
|
||||
]);
|
||||
|
||||
return msg();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
$params = Request::param();
|
||||
|
||||
$validate = Validate::rule([
|
||||
'id' => 'require|integer',
|
||||
]);
|
||||
if (!$validate->check($params)) {
|
||||
return msg('error', $validate->getError());
|
||||
}
|
||||
|
||||
Db::name('user')->where('id', $params['id'])->delete();
|
||||
|
||||
return msg('ok', 'success');
|
||||
}
|
||||
|
||||
public function slogin(){
|
||||
$id = input('get.id/d');
|
||||
$item = Db::name('user')->where('id', $id)->find();
|
||||
if(!$item){
|
||||
return $this->alert('error', '用户不存在');
|
||||
}
|
||||
|
||||
$session = md5($id.$item['password']);
|
||||
$expiretime = time()+30744000;
|
||||
$token = authcode("{$id}\t{$session}\t{$expiretime}", 'ENCODE', config_get('syskey'));
|
||||
cookie('user_token', $token, ['expire' => $expiretime, 'httponly' => true]);
|
||||
|
||||
return redirect("/");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// 事件定义文件
|
||||
return [
|
||||
'bind' => [
|
||||
],
|
||||
|
||||
'listen' => [
|
||||
'AppInit' => [],
|
||||
'HttpRun' => [],
|
||||
'HttpEnd' => [],
|
||||
'LogLevel' => [],
|
||||
'LogWrite' => [],
|
||||
],
|
||||
|
||||
'subscribe' => [
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,477 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib;
|
||||
|
||||
use Exception;
|
||||
|
||||
class BilibiliHelper
|
||||
{
|
||||
private $cookie;
|
||||
private $token;
|
||||
private $mixinKey;
|
||||
|
||||
public static $qualitys = ['127'=>'8K 超高清', '126'=>'杜比视界', '125'=>'HDR 真彩', '120'=>'4K 超清', '116'=>'1080P 高帧率', '112'=>'1080P 高码率', '80'=>'1080P 高清', '74'=>'720P 高帧率', '64'=>'720P 高清', '48'=>'720P 高清', '32'=>'480P 清晰', '16'=>'360P 流畅', '6'=>'240P 极速'];
|
||||
public static $qualitys_audio = ['30216'=>'64K', '30232'=>'132K', '30280'=>'192K'];
|
||||
|
||||
|
||||
public function __construct($cookie = null, $token = null)
|
||||
{
|
||||
$this->cookie = $cookie; //For WEB
|
||||
$this->token = $token; //For APP/TV
|
||||
}
|
||||
|
||||
//获取登录信息
|
||||
public function login_info()
|
||||
{
|
||||
$url = 'https://api.bilibili.com/x/web-interface/nav';
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取登录状态失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
return true;
|
||||
}elseif($arr['code'] == -101){
|
||||
throw new Exception('COOKIE已失效');
|
||||
}else{
|
||||
throw new Exception('获取登录状态失败 '.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//获取用户上传视频信息
|
||||
public function ugc_video_info($querystring){
|
||||
$url = 'https://api.bilibili.com/x/web-interface/view?'.$querystring;
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频信息失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
return $arr['data'];
|
||||
}else{
|
||||
throw new Exception('获取视频信息失败:'.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//获取正版视频信息
|
||||
public function pgc_video_info($ep_id){
|
||||
$url = 'https://api.bilibili.com/pgc/view/web/season?ep_id='.$ep_id;
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频信息失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['result']['episodes'])) throw new Exception('获取视频信息失败,返回内容错误');
|
||||
$data = null;
|
||||
foreach($arr['result']['episodes'] as $row){
|
||||
if($ep_id == $row['id']){
|
||||
$data = $row;
|
||||
}
|
||||
}
|
||||
if(empty($data))throw new Exception('获取视频信息失败,未找到对应视频信息');
|
||||
return $data;
|
||||
}else{
|
||||
throw new Exception('获取视频信息失败:'.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//获取正版视频信息
|
||||
public function pgc_video_info_by_ssid($season_id){
|
||||
$url = 'https://api.bilibili.com/pgc/view/web/season?season_id='.$season_id;
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频信息失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['result']['episodes'])) throw new Exception('获取视频信息失败,返回内容错误');
|
||||
$data = $arr['result']['episodes'][0];
|
||||
if(empty($data))throw new Exception('获取视频信息失败,未找到对应视频信息');
|
||||
return $data;
|
||||
}else{
|
||||
throw new Exception('获取视频信息失败:'.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//获取课堂视频信息
|
||||
public function pugv_video_info($ep_id){
|
||||
$url = 'https://api.bilibili.com/pugv/view/web/season?ep_id='.$ep_id;
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频信息失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['data']['episodes'])) throw new Exception('获取视频信息失败,返回内容错误');
|
||||
$data = null;
|
||||
foreach($arr['data']['episodes'] as $row){
|
||||
if($ep_id == $row['id']){
|
||||
$data = $row;
|
||||
}
|
||||
}
|
||||
if(empty($data))throw new Exception('获取视频信息失败,未找到对应视频信息');
|
||||
return $data;
|
||||
}else{
|
||||
throw new Exception('获取视频信息失败:'.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//获取视频弹幕
|
||||
public function get_video_comment($cid){
|
||||
$danmu_xml = $this->curl('https://comment.bilibili.com/'.$cid.'.xml');
|
||||
if(!$danmu_xml){
|
||||
return msg('error','获取弹幕内容失败');
|
||||
}
|
||||
$dom = new \DOMDocument();
|
||||
$dom->loadXML($danmu_xml);
|
||||
$result = $this->getArray($dom->documentElement);
|
||||
return isset($result['d']) ? $result['d'] : [];
|
||||
}
|
||||
|
||||
//用户上传视频解析(支持外链)
|
||||
public function get_video_url($aid, $cid){
|
||||
$param = [
|
||||
'avid' => $aid,
|
||||
'cid' => $cid,
|
||||
'qn' => '120',
|
||||
'otype' => 'json',
|
||||
'fourk' => '1',
|
||||
'fnver' => '0',
|
||||
'fnval' => '128',
|
||||
'player' => '3',
|
||||
'platform' => 'html5',
|
||||
'high_quality' => '1',
|
||||
];
|
||||
$url = 'https://api.bilibili.com/x/player/playurl?'.http_build_query($param);
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频下载链接失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['data']['durl'])) throw new Exception('获取视频下载链接失败,返回内容错误');
|
||||
$url = $arr['data']['durl'][0]['url'];
|
||||
$size = $arr['data']['durl'][0]['size'];
|
||||
$quality = $arr['data']['support_formats'][0]['new_description'];
|
||||
return ['url'=>$url, 'size'=>$size, 'quality'=>$quality, 'format'=>$arr['data']['format'], 'codec'=>$this->get_codec($arr['data']['video_codecid'])];
|
||||
}else{
|
||||
throw new Exception('获取视频下载链接失败 '.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//用户上传视频解析
|
||||
public function ugc_video_parse($aid, $cid){
|
||||
$param = [
|
||||
'avid' => $aid,
|
||||
'cid' => $cid,
|
||||
'qn' => '0',
|
||||
'type' => '',
|
||||
'otype' => 'json',
|
||||
'fourk' => '1',
|
||||
'fnver' => '0',
|
||||
'fnval' => '4048',
|
||||
];
|
||||
$url = 'https://api.bilibili.com/x/player/playurl?'.http_build_query($param);
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频下载链接失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['data']['dash'])) throw new Exception('获取视频下载链接失败,返回内容错误');
|
||||
return $this->video_data_handle($arr['data']);
|
||||
}else{
|
||||
throw new Exception('获取视频下载链接失败 '.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//用户上传视频解析(TV接口)
|
||||
public function ugc_video_parse_tv($aid, $cid){
|
||||
$param = [
|
||||
'avid' => $aid,
|
||||
'cid' => $cid,
|
||||
'qn' => '0',
|
||||
'type' => '',
|
||||
'otype' => 'json',
|
||||
'fnver' => '0',
|
||||
'fnval' => '4048',
|
||||
'device' => 'android',
|
||||
'platform' => 'android',
|
||||
'mobi_app' => 'android_tv_yst',
|
||||
'npcybs' => '0',
|
||||
'force_host' => '2',
|
||||
'build' => '102801',
|
||||
];
|
||||
if($this->token){
|
||||
$param['access_key'] = $this->token;
|
||||
}
|
||||
$url = 'https://api.snm0516.aisee.tv/x/tv/ugc/playurl?'.http_build_query($param);
|
||||
$ret = $this->curl($url);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频下载链接失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['dash'])) throw new Exception('获取视频下载链接失败,返回内容错误');
|
||||
return $this->video_data_handle($arr);
|
||||
}else{
|
||||
throw new Exception('获取视频下载链接失败 '.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//正版视频解析
|
||||
public function pgc_video_parse($aid, $cid, $epid, $is_cheese=false){
|
||||
$param = [
|
||||
'avid' => $aid,
|
||||
'cid' => $cid,
|
||||
'qn' => '0',
|
||||
'type' => '',
|
||||
'otype' => 'json',
|
||||
'fourk' => '1',
|
||||
'fnver' => '0',
|
||||
'fnval' => '4048',
|
||||
'module' => 'bangumi',
|
||||
'ep_id' => $epid,
|
||||
'session' => ''
|
||||
];
|
||||
$url = 'https://api.bilibili.com/pgc/player/web/playurl?'.http_build_query($param);
|
||||
if($is_cheese){
|
||||
$url = str_replace('/pgc/','/pugv/',$url);
|
||||
}
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频下载链接失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['result']['dash'])) throw new Exception('获取视频下载链接失败,返回内容错误');
|
||||
return $this->video_data_handle($arr['result']);
|
||||
}elseif($arr['code'] == -10403 && !$is_cheese){
|
||||
$url = 'https://www.bilibili.com/bangumi/play/ep'.$epid;
|
||||
$ret = $this->curl($url, null, $this->cookie.';CURRENT_FNVAL=4048;');
|
||||
preg_match('!window\.__playinfo__=([\s\S]*?)<\/script>!',$ret,$match);
|
||||
if(isset($match[1])){
|
||||
$arr = json_decode($match[1], true);
|
||||
}else{
|
||||
throw new Exception('获取视频下载链接失败 '.$arr['message']);
|
||||
}
|
||||
}else{
|
||||
throw new Exception('获取视频下载链接失败 '.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//正版视频解析(TV接口)
|
||||
public function pgc_video_parse_tv($aid, $cid, $epid, $is_cheese=false){
|
||||
$param = [
|
||||
'appkey' => '4409e2ce8ffd12b8',
|
||||
'aid' => $aid,
|
||||
'cid' => $cid,
|
||||
'qn' => '0',
|
||||
'module' => 'bangumi',
|
||||
'ep_id' => $epid,
|
||||
'expire' => '0',
|
||||
'fnval' => '80',
|
||||
'fnver' => '0',
|
||||
'fourk' => '1',
|
||||
'mid' => '0',
|
||||
'otype' => 'json',
|
||||
'device' => 'android',
|
||||
'platform' => 'android',
|
||||
'mobi_app' => 'android_tv_yst',
|
||||
'npcybs' => '0',
|
||||
'build' => '102801',
|
||||
'ts' => time()
|
||||
];
|
||||
if($this->token){
|
||||
$param['access_key'] = $this->token;
|
||||
}
|
||||
$param['sign'] = $this->tv_get_sign($param);
|
||||
$url = 'https://api.snm0516.aisee.tv/pgc/player/api/playurltv?'.http_build_query($param);
|
||||
if($is_cheese){
|
||||
$url = str_replace('/pgc/','/pugv/',$url);
|
||||
}
|
||||
$ret = $this->curl($url);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取视频下载链接失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['dash'])) throw new Exception('获取视频下载链接失败,返回内容错误');
|
||||
return $this->video_data_handle($arr);
|
||||
}else{
|
||||
throw new Exception('获取视频下载链接失败 '.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function video_data_handle($data){
|
||||
$video = [];
|
||||
$audio = [];
|
||||
$timelength = round($data['timelength']/1000);
|
||||
if($data['dash']['video']){
|
||||
foreach($data['dash']['video'] as $row){
|
||||
if(preg_match('!://(.*:\\d+)/!',$row['base_url'],$match)){ //替换PCDN
|
||||
$row['base_url'] = str_replace($match[1], 'upos-sz-mirrorcoso1.bilivideo.com', $row['base_url']);
|
||||
}
|
||||
$size = round($timelength * $row['bandwidth'] / 8);
|
||||
$video[] = ['url'=>$row['base_url'], 'quality'=>self::$qualitys[$row['id']], 'bandwidth'=>round($row['bandwidth']/1000), 'size' => $size, 'codec'=>$this->get_codec($row['codecid']), 'ratio'=>$row['width'].'×'.$row['height'], 'fps'=>$row['frame_rate']];
|
||||
}
|
||||
}
|
||||
if($data['dash']['audio']){
|
||||
foreach($data['dash']['audio'] as $row){
|
||||
$size = round($timelength * $row['bandwidth'] / 8);
|
||||
$audio[] = ['url'=>$row['base_url'], 'quality'=>self::$qualitys_audio[$row['id']], 'bandwidth'=>round($row['bandwidth']/1000), 'size' => $size, 'codec'=>str_replace(['mp4a.40.2','ec-3'], ['M4A', 'AC3'], $row['codecs'])];
|
||||
}
|
||||
}
|
||||
return ['video'=>$video, 'audio'=>$audio];
|
||||
}
|
||||
|
||||
//获取音乐信息
|
||||
public function get_audio_info($sid){
|
||||
$url = 'https://www.bilibili.com/audio/music-service-c/web/song/info?sid='.$sid;
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取音乐信息失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
return $arr['data'];
|
||||
}else{
|
||||
throw new Exception('获取音乐信息失败:'.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
//音乐解析
|
||||
public function get_audio_url($sid){
|
||||
$url = 'https://www.bilibili.com/audio/music-service-c/web/url?sid='.$sid.'&privilege=2&quality=2';
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('获取音乐下载链接失败');
|
||||
}elseif(isset($arr['code']) && $arr['code'] == 0){
|
||||
if(!isset($arr['data']['cdns'])) throw new Exception('获取音乐下载链接失败,返回内容错误');
|
||||
$url = $arr['data']['cdns'][0];
|
||||
$size = $arr['data']['size'];
|
||||
return ['url'=>$url, 'size'=>$size, 'quality'=>'MP3(192K)'];
|
||||
}else{
|
||||
throw new Exception('获取音乐下载链接失败:'.$arr['message']);
|
||||
}
|
||||
}
|
||||
|
||||
private function curl($url,$data=null,$cookie=null,$referer=null){
|
||||
$ch=curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,$url);
|
||||
$httpheader[] = "Accept: application/json";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||
$httpheader[] = "Connection: keep-alive";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
if($data){
|
||||
if(is_array($data)) $data=http_build_query($data);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
|
||||
curl_setopt($ch, CURLOPT_POST,1);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer?$referer:'https://www.bilibili.com/');
|
||||
if($cookie){
|
||||
curl_setopt($ch,CURLOPT_COOKIE, $cookie);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.44');
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||
$ret=curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function get_codec($codecid){
|
||||
switch($codecid){
|
||||
case 13:
|
||||
return 'AV1';break;
|
||||
case 12:
|
||||
return 'HEVC';break;
|
||||
case 7:
|
||||
return 'AVC';break;
|
||||
default:
|
||||
return 'UNKNOWN';break;
|
||||
}
|
||||
}
|
||||
|
||||
private function tv_get_sign($param){
|
||||
$key = '59b43e04ad6965f34319062b478f83dd';
|
||||
ksort($param);
|
||||
$signstr = http_build_query($param);
|
||||
return md5($signstr.$key);
|
||||
}
|
||||
|
||||
private function getArray($node) {
|
||||
$array = false;
|
||||
|
||||
if ($node->hasAttributes()) {
|
||||
foreach ($node->attributes as $attr) {
|
||||
$array[$attr->nodeName] = $attr->nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($node->hasChildNodes()) {
|
||||
if ($node->childNodes->length == 1) {
|
||||
$array[$node->firstChild->nodeName] = $this->getArray($node->firstChild);
|
||||
} else {
|
||||
foreach ($node->childNodes as $childNode) {
|
||||
if ($childNode->nodeType != XML_TEXT_NODE) {
|
||||
$array[$childNode->nodeName][] = $this->getArray($childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return $node->nodeValue;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
private function encWbi($params){
|
||||
$mixin_key = $this->getMixinKey();
|
||||
$curr_time = time();
|
||||
$chr_filter = "/[!'()*]/";
|
||||
|
||||
$query = [];
|
||||
$params['wts'] = $curr_time;
|
||||
|
||||
ksort($params);
|
||||
|
||||
foreach ($params as $key => $value) {
|
||||
$value = preg_replace($chr_filter, '', $value);
|
||||
$query[] = urlencode($key) . '=' . urlencode($value);
|
||||
}
|
||||
|
||||
$query = implode('&', $query);
|
||||
$wbi_sign = md5($query . $mixin_key);
|
||||
|
||||
return $query . '&w_rid=' . $wbi_sign;
|
||||
}
|
||||
|
||||
private function getMixinKey(){
|
||||
if(!empty($this->mixinKey)) return $this->mixinKey;
|
||||
|
||||
$url = 'https://api.bilibili.com/x/web-interface/nav';
|
||||
$ret = $this->curl($url, null, $this->cookie);
|
||||
$arr = json_decode($ret, true);
|
||||
if(!$arr){
|
||||
throw new Exception('请求失败');
|
||||
}
|
||||
if(!isset($arr['data']['wbi_img'])){
|
||||
throw new Exception('获取WbiKeys失败');
|
||||
}
|
||||
|
||||
$img_url = $arr['data']['wbi_img']['img_url'];
|
||||
$sub_url = $arr['data']['wbi_img']['sub_url'];
|
||||
$img_key = substr(basename($img_url), 0, strpos(basename($img_url), '.'));
|
||||
$sub_key = substr(basename($sub_url), 0, strpos(basename($sub_url), '.'));
|
||||
$key = $img_key . $sub_key;
|
||||
|
||||
$mixinKeyEncTab = [
|
||||
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
|
||||
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
|
||||
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
|
||||
36, 20, 34, 44, 52
|
||||
];
|
||||
|
||||
$t = '';
|
||||
foreach ($mixinKeyEncTab as $n) $t .= $key[$n];
|
||||
$this->mixinKey = substr($t, 0, 32);
|
||||
return $this->mixinKey;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib;
|
||||
|
||||
class EnvOperation
|
||||
{
|
||||
|
||||
private $env;
|
||||
private $exampleEnv;
|
||||
public function __construct($exampleEnv)
|
||||
{
|
||||
$this->exampleEnv = $exampleEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEnv()
|
||||
{
|
||||
return $this->env;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $env
|
||||
*/
|
||||
public function setEnv($env): void
|
||||
{
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
public function purify($env = [])
|
||||
{
|
||||
preg_match_all('#{{(.+?)}}#', $this->env, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $v) {
|
||||
$list = explode(':', $v[1]);
|
||||
$value = isset($env[$list[0]]) ? $env[$list[0]] : '';
|
||||
$defaultValue = isset($list[1]) ? $list[1] : '';
|
||||
$type = isset($list[2]) ? $list[2] : '';
|
||||
if ($type === 'bool') {
|
||||
$value = var_export(boolval($value), 1);
|
||||
}
|
||||
if (empty($value)) {
|
||||
$value = $defaultValue;
|
||||
}
|
||||
$this->env = preg_replace('#' . $v[0] . '#', $value, $this->env);
|
||||
}
|
||||
}
|
||||
|
||||
public function set($key, $newValue)
|
||||
{
|
||||
if (is_null($this->env)) {
|
||||
$this->env = preg_replace('#{{' . $key . '}}#', $newValue, $this->exampleEnv);
|
||||
} else {
|
||||
$this->env = preg_replace('#{{' . $key . '}}#', $newValue, $this->env);
|
||||
}
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
return file_put_contents(app()->getRootPath() . '.env', $this->env);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace app\lib;
|
||||
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
class ExecSQL
|
||||
{
|
||||
private $errors = [];
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sql array|string SQL语句 传入字符串类型需以\n分割
|
||||
* @return int 返回影响行数
|
||||
*/
|
||||
public function exec($sql)
|
||||
{
|
||||
$sql = $this->purify($sql);
|
||||
$number = 0;
|
||||
foreach ($sql as $key => $line) {
|
||||
try {
|
||||
$number += Db::execute($line);
|
||||
} catch (\Exception $e) {
|
||||
$this->errors[] = '第' . $key . '行:' . iconv('utf-8','utf-8//IGNORE',$e->getMessage());
|
||||
}
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
public function purify($sql)
|
||||
{
|
||||
$tmp = '';
|
||||
$purify = [];
|
||||
if (!is_array($sql)) {
|
||||
$sql = explode("\n", $sql);
|
||||
}
|
||||
foreach ($sql as $key => &$line) {
|
||||
|
||||
$line = trim($line);
|
||||
if (substr($line, 0, 2) == '--' || $line == '' || substr($line, 0, 2) == '/*') {
|
||||
unset($sql[$key]);
|
||||
continue;
|
||||
}
|
||||
$tmp .= $line;
|
||||
if (substr($line, -1, 1) == ';') {
|
||||
unset($sql[$key]);
|
||||
$purify[] = $tmp;
|
||||
$tmp = '';
|
||||
}
|
||||
unset($sql[$key]);
|
||||
}
|
||||
return $purify;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
/**
|
||||
* 极验3.0 lib
|
||||
*/
|
||||
class GeetestLib
|
||||
{
|
||||
const SDK_VERSION = 'php_3.0.0';
|
||||
const JSON_FORMAT = "1";
|
||||
|
||||
private $geetest_id;
|
||||
private $geetest_key;
|
||||
|
||||
public function __construct($geetest_id, $geetest_key) {
|
||||
$this->geetest_id = $geetest_id;
|
||||
$this->geetest_key = $geetest_key;
|
||||
}
|
||||
|
||||
//验证初始化
|
||||
public function pre_process($params) {
|
||||
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
|
||||
return $this->pre_process_api($params);
|
||||
}else{
|
||||
return $this->pre_process_demo($params);
|
||||
}
|
||||
}
|
||||
|
||||
private function pre_process_api($params) {
|
||||
$public_params = [
|
||||
'digestmod' => 'md5',
|
||||
'gt' => $this->geetest_id,
|
||||
'sdk' => self::SDK_VERSION,
|
||||
'json_format' => self::JSON_FORMAT
|
||||
];
|
||||
$params = array_merge($params, $public_params);
|
||||
$url = 'http://api.geetest.com/register.php?' . http_build_query($params);
|
||||
$res = get_curl($url);
|
||||
$arr = json_decode($res, true);
|
||||
if($arr && isset($arr['challenge'])){
|
||||
return $this->success_process($arr['challenge']);
|
||||
}else{
|
||||
return $this->failback_process();
|
||||
}
|
||||
}
|
||||
|
||||
private function success_process($challenge) {
|
||||
$challenge = md5($challenge . $this->geetest_key);
|
||||
$result = array(
|
||||
'success' => 1,
|
||||
'gt' => $this->geetest_id,
|
||||
'challenge' => $challenge,
|
||||
'new_captcha'=>true
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function failback_process() {
|
||||
$challenge = md5(uniqid(mt_rand(), true) . microtime());
|
||||
$result = array(
|
||||
'success' => 0,
|
||||
'gt' => $this->geetest_id,
|
||||
'challenge' => $challenge,
|
||||
'new_captcha'=>true
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function pre_process_demo($params) {
|
||||
$url = 'https://www.geetest.com/demo/gt/register-fullpage?t=' . time() . "123";
|
||||
$referer = 'https://www.geetest.com/demo/slide-popup.html';
|
||||
$data = get_curl($url, 0, $referer);
|
||||
$arr = json_decode($data, true);
|
||||
if($arr && isset($arr['challenge'])){
|
||||
return $arr;
|
||||
}else{
|
||||
return $this->failback_process();
|
||||
}
|
||||
}
|
||||
|
||||
//正常流程下(即验证初始化成功),二次验证
|
||||
public function success_validate($challenge, $validate, $seccode, $params) {
|
||||
if(!empty($this->geetest_id) && !empty($this->geetest_key)){
|
||||
return $this->success_validate_api($challenge, $validate, $seccode, $params);
|
||||
}else{
|
||||
return $this->success_validate_demo($challenge, $validate, $seccode);
|
||||
}
|
||||
}
|
||||
|
||||
private function success_validate_api($challenge, $validate, $seccode, $params) {
|
||||
if (!$this->check_validate($challenge, $validate)) {
|
||||
return false;
|
||||
}
|
||||
$public_params = [
|
||||
'seccode' => $seccode,
|
||||
'challenge' => $challenge,
|
||||
'captchaid' => $this->geetest_id,
|
||||
'sdk' => self::SDK_VERSION,
|
||||
'json_format' => self::JSON_FORMAT
|
||||
];
|
||||
$params = array_merge($params, $public_params);
|
||||
$url = 'http://api.geetest.com/validate.php';
|
||||
$res = get_curl($url, http_build_query($params));
|
||||
$arr = json_decode($res, true);
|
||||
if($arr && isset($arr['seccode'])){
|
||||
if($arr['seccode'] == md5($seccode)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function check_validate($challenge, $validate) {
|
||||
if (strlen($validate) != 32) {
|
||||
return false;
|
||||
}
|
||||
if (md5($this->geetest_key . 'geetest' . $challenge) != $validate) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function success_validate_demo($challenge, $validate, $seccode) {
|
||||
$params = [
|
||||
'geetest_challenge' => $challenge,
|
||||
'geetest_validate' => $validate,
|
||||
'geetest_seccode' => $seccode
|
||||
];
|
||||
$url = 'https://www.geetest.com/demo/gt/validate-fullpage';
|
||||
$referer = 'https://www.geetest.com/demo/slide-popup.html';
|
||||
$data = get_curl($url, http_build_query($params), $referer);
|
||||
$arr = json_decode($data, true);
|
||||
if($arr && $arr['status'] == 'success'){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//异常流程下(即验证初始化失败,宕机模式),二次验证
|
||||
public function fail_validate($challenge, $validate, $seccode) {
|
||||
if(md5($challenge) == $validate){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
use Exception;
|
||||
/**
|
||||
* class Ip2Region
|
||||
* 为兼容老版本调度而创建
|
||||
* @author Anyon<[email protected]>
|
||||
* @datetime 2022/07/18
|
||||
*/
|
||||
class Ip2Region
|
||||
{
|
||||
/**
|
||||
* 查询实例对象
|
||||
* @var XdbSearcher
|
||||
*/
|
||||
private $searcher;
|
||||
|
||||
/**
|
||||
* 初始化构造方法
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->searcher = XdbSearcher::newWithFileOnly(dirname(__FILE__) . '/ip2region.xdb');
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容原 memorySearch 查询
|
||||
* @param string $ip
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function search($ip)
|
||||
{
|
||||
return $this->searcher->search($ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* destruct method
|
||||
* resource destroy
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->searcher->close();
|
||||
unset($this->searcher);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
|
||||
/** php QQWry获取ip接口 支持省 城市 完整版
|
||||
* IP 地理位置查询类 修改自 CoolCode.CN
|
||||
* 由于使用UTF8编码 如果使用纯真IP地址库的话 需要对返回结果进行编码转换
|
||||
* @author liu21st <[email protected]>
|
||||
*/
|
||||
class IpLocation {
|
||||
/**
|
||||
* QQWry.Dat文件指针
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $fp;
|
||||
|
||||
/**
|
||||
* 第一条IP记录的偏移地址
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $firstip;
|
||||
|
||||
/**
|
||||
* 最后一条IP记录的偏移地址
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $lastip;
|
||||
|
||||
/**
|
||||
* IP记录的总条数(不包含版本信息记录)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $totalip;
|
||||
|
||||
/**
|
||||
* 构造函数,打开 QQWry.Dat 文件并初始化类中的信息
|
||||
*
|
||||
* @param string $filename
|
||||
* @return IpLocation
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->fp = 0;
|
||||
$filename = dirname(__FILE__)."/QQWry.dat";
|
||||
if (($this->fp = fopen($filename, 'rb')) !== false) {
|
||||
$this->firstip = $this->getlong();
|
||||
$this->lastip = $this->getlong();
|
||||
$this->totalip = ($this->lastip - $this->firstip) / 7;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回读取的长整型数
|
||||
*
|
||||
* @access private
|
||||
* @return int
|
||||
*/
|
||||
private function getlong() {
|
||||
//将读取的little-endian编码的4个字节转化为长整型数
|
||||
$result = unpack('Vlong', fread($this->fp, 4));
|
||||
return $result['long'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回读取的3个字节的长整型数
|
||||
*
|
||||
* @access private
|
||||
* @return int
|
||||
*/
|
||||
private function getlong3() {
|
||||
//将读取的little-endian编码的3个字节转化为长整型数
|
||||
$result = unpack('Vlong', fread($this->fp, 3).chr(0));
|
||||
return $result['long'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回压缩后可进行比较的IP地址
|
||||
*
|
||||
* @access private
|
||||
* @param string $ip
|
||||
* @return string
|
||||
*/
|
||||
private function packip($ip) {
|
||||
// 将IP地址转化为长整型数,如果在PHP5中,IP地址错误,则返回False,
|
||||
// 这时intval将Flase转化为整数-1,之后压缩成big-endian编码的字符串
|
||||
return pack('N', intval(ip2long($ip)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回读取的字符串
|
||||
*
|
||||
* @access private
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
private function getstring($data = "") {
|
||||
$char = fread($this->fp, 1);
|
||||
while (ord($char) > 0) { // 字符串按照C格式保存,以\0结束
|
||||
$data .= $char; // 将读取的字符连接到给定字符串之后
|
||||
$char = fread($this->fp, 1);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回地区信息
|
||||
*
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function getarea() {
|
||||
$byte = fread($this->fp, 1); // 标志字节
|
||||
switch (ord($byte)) {
|
||||
case 0: // 没有区域信息
|
||||
$area = "";
|
||||
break;
|
||||
case 1:
|
||||
case 2: // 标志字节为1或2,表示区域信息被重定向
|
||||
fseek($this->fp, $this->getlong3());
|
||||
$area = $this->getstring();
|
||||
break;
|
||||
default: // 否则,表示区域信息没有被重定向
|
||||
$area = $this->getstring($byte);
|
||||
break;
|
||||
}
|
||||
return $area;
|
||||
}
|
||||
private $provinces = array("黑龙江省","辽宁省","吉林省","河北省","河南省","湖北省","湖南省","山东省","山西省","陕西省",
|
||||
"安徽省","浙江省","江苏省","福建省","广东省","海南省","四川省","云南省","贵州省","青海省","甘肃省",
|
||||
"江西省","台湾省","内蒙古","宁夏","新疆","西藏","广西","北京市","上海市","天津市","重庆市","香港","澳门");
|
||||
/**
|
||||
* 根据所给 IP 地址或域名返回所在地区信息
|
||||
*
|
||||
* @access public
|
||||
* @param string $ip
|
||||
* @return array
|
||||
*/
|
||||
public function getlocation($ip='') {
|
||||
if (!$this->fp) return null; // 如果数据文件没有被正确打开,则直接返回空
|
||||
if(empty($ip)) return null;
|
||||
$location['ip'] = gethostbyname($ip); // 将输入的域名转化为IP地址
|
||||
$ip = $this->packip($location['ip']); // 将输入的IP地址转化为可比较的IP地址
|
||||
// 不合法的IP地址会被转化为255.255.255.255
|
||||
// 对分搜索
|
||||
$l = 0; // 搜索的下边界
|
||||
$u = $this->totalip; // 搜索的上边界
|
||||
$findip = $this->lastip; // 如果没有找到就返回最后一条IP记录(QQWry.Dat的版本信息)
|
||||
while ($l <= $u) { // 当上边界小于下边界时,查找失败
|
||||
$i = floor(($l + $u) / 2); // 计算近似中间记录
|
||||
fseek($this->fp, $this->firstip + $i * 7);
|
||||
$beginip = strrev(fread($this->fp, 4)); // 获取中间记录的开始IP地址
|
||||
// strrev函数在这里的作用是将little-endian的压缩IP地址转化为big-endian的格式
|
||||
// 以便用于比较,后面相同。
|
||||
if ($ip < $beginip) { // 用户的IP小于中间记录的开始IP地址时
|
||||
$u = $i - 1; // 将搜索的上边界修改为中间记录减一
|
||||
}
|
||||
else {
|
||||
fseek($this->fp, $this->getlong3());
|
||||
$endip = strrev(fread($this->fp, 4)); // 获取中间记录的结束IP地址
|
||||
if ($ip > $endip) { // 用户的IP大于中间记录的结束IP地址时
|
||||
$l = $i + 1; // 将搜索的下边界修改为中间记录加一
|
||||
}
|
||||
else { // 用户的IP在中间记录的IP范围内时
|
||||
$findip = $this->firstip + $i * 7;
|
||||
break; // 则表示找到结果,退出循环
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取查找到的IP地理位置信息
|
||||
fseek($this->fp, $findip);
|
||||
$location['beginip'] = long2ip($this->getlong()); // 用户IP所在范围的开始地址
|
||||
$offset = $this->getlong3();
|
||||
fseek($this->fp, $offset);
|
||||
$location['endip'] = long2ip($this->getlong()); // 用户IP所在范围的结束地址
|
||||
$byte = fread($this->fp, 1); // 标志字节
|
||||
switch (ord($byte)) {
|
||||
case 1: // 标志字节为1,表示国家和区域信息都被同时重定向
|
||||
$countryOffset = $this->getlong3(); // 重定向地址
|
||||
fseek($this->fp, $countryOffset);
|
||||
$byte = fread($this->fp, 1); // 标志字节
|
||||
switch (ord($byte)) {
|
||||
case 2: // 标志字节为2,表示国家信息又被重定向
|
||||
fseek($this->fp, $this->getlong3());
|
||||
$location['country'] = $this->getstring();
|
||||
fseek($this->fp, $countryOffset + 4);
|
||||
$location['area'] = $this->getarea();
|
||||
break;
|
||||
default: // 否则,表示国家信息没有被重定向
|
||||
$location['country'] = $this->getstring($byte);
|
||||
$location['area'] = $this->getarea();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2: // 标志字节为2,表示国家信息被重定向
|
||||
fseek($this->fp, $this->getlong3());
|
||||
$location['country'] = $this->getstring();
|
||||
fseek($this->fp, $offset + 8);
|
||||
$location['area'] = $this->getarea();
|
||||
break;
|
||||
default: // 否则,表示国家信息没有被重定向
|
||||
$location['country'] = $this->getstring($byte);
|
||||
$location['area'] = $this->getarea();
|
||||
break;
|
||||
}
|
||||
if (trim($location['country']) == 'CZ88.NET') { // CZ88.NET表示没有有效信息
|
||||
$location['country'] = '未知';
|
||||
}
|
||||
if (trim($location['area']) == 'CZ88.NET') {
|
||||
$location['area'] = '';
|
||||
}
|
||||
$location['country'] = @iconv('gbk','utf-8',$location['country']); //转换格式,防止乱码
|
||||
$location['area'] = @iconv('gbk','utf-8',$location['area']); //转换格式,防止乱码
|
||||
foreach($this->provinces as $v) {
|
||||
if(strpos($location['country'],$v) === 0) {
|
||||
$location['province'] = $v;
|
||||
$location['city'] = str_replace($v,'',$location['country']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(empty($location['province'])) $location['province'] = $location['country'];
|
||||
if(empty($location['city'])) $location['city'] = $location['country'];
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* 析构函数,用于在页面执行结束后自动关闭打开的文件。
|
||||
*
|
||||
*/
|
||||
public function __destruct() {
|
||||
if ($this->fp) {
|
||||
fclose($this->fp);
|
||||
}
|
||||
$this->fp = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
/*
|
||||
* 快捷登录接口
|
||||
*/
|
||||
|
||||
class Oauth{
|
||||
private $apiurl;
|
||||
private $appid;
|
||||
private $appkey;
|
||||
private $callback;
|
||||
|
||||
function __construct($config){
|
||||
$this->apiurl = $config['apiurl'].'connect.php';
|
||||
$this->appid = $config['appid'];
|
||||
$this->appkey = $config['appkey'];
|
||||
$this->callback = $config['callback'];
|
||||
}
|
||||
|
||||
//获取登录跳转url
|
||||
public function login($type, $state){
|
||||
|
||||
//-------构造请求参数列表
|
||||
$keysArr = array(
|
||||
"act" => "login",
|
||||
"appid" => $this->appid,
|
||||
"appkey" => $this->appkey,
|
||||
"type" => $type,
|
||||
"redirect_uri" => $this->callback,
|
||||
"state" => $state
|
||||
);
|
||||
$login_url = $this->apiurl.'?'.http_build_query($keysArr);
|
||||
$response = get_curl($login_url);
|
||||
$arr = json_decode($response,true);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
//登录成功返回网站
|
||||
public function callback($code){
|
||||
//-------请求参数列表
|
||||
$keysArr = array(
|
||||
"act" => "callback",
|
||||
"appid" => $this->appid,
|
||||
"appkey" => $this->appkey,
|
||||
"code" => $code
|
||||
);
|
||||
|
||||
//------构造请求access_token的url
|
||||
$token_url = $this->apiurl.'?'.http_build_query($keysArr);
|
||||
$response = get_curl($token_url);
|
||||
|
||||
$arr = json_decode($response,true);
|
||||
return $arr;
|
||||
}
|
||||
|
||||
//查询用户信息
|
||||
public function query($type, $social_uid){
|
||||
//-------请求参数列表
|
||||
$keysArr = array(
|
||||
"act" => "query",
|
||||
"appid" => $this->appid,
|
||||
"appkey" => $this->appkey,
|
||||
"type" => $type,
|
||||
"social_uid" => $social_uid
|
||||
);
|
||||
|
||||
//------构造请求access_token的url
|
||||
$token_url = $this->apiurl.'?'.http_build_query($keysArr);
|
||||
$response = get_curl($token_url);
|
||||
|
||||
$arr = json_decode($response,true);
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace app\lib;
|
||||
|
||||
use think\Exception;
|
||||
use think\facade\Db;
|
||||
|
||||
/**
|
||||
* 实例化后需要保存zip文件到 $zipFilepath
|
||||
* Class Plugin
|
||||
* @package app\lib
|
||||
*/
|
||||
class Plugin
|
||||
{
|
||||
private $tmpPath = '';
|
||||
private $uniqid = '';
|
||||
private $zipFilename = '';
|
||||
private $zipFilepath = '';
|
||||
private $tmpDirPath = '';
|
||||
private $pluginPath = '';
|
||||
private $pluginAuthor = '';
|
||||
private $pluginName = '';
|
||||
private $pluginClass = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->tmpPath = app()->getRuntimePath() . '/tmp/';
|
||||
$this->uniqid = uniqid();
|
||||
$this->zipFilename = $this->uniqid . '.zip';
|
||||
$this->zipFilepath = $this->tmpPath . $this->zipFilename;
|
||||
|
||||
$this->tmpDirPath = $this->tmpPath . $this->uniqid . '/';;
|
||||
|
||||
if (!file_exists($this->tmpPath)) {
|
||||
mkdir($this->tmpPath, 0777, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function unzip()
|
||||
{
|
||||
if (!file_exists($this->zipFilepath)) {
|
||||
throw new Exception('压缩包不存在请重试');
|
||||
}
|
||||
if (!unzip($this->zipFilepath, $this->tmpDirPath)) {
|
||||
throw new Exception('解压失败');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function checkPlugin()
|
||||
{
|
||||
$tree_relative = tree_relative($this->tmpDirPath);
|
||||
$arr1 = array_keys($tree_relative);
|
||||
$pluginAuthor = reset($arr1);
|
||||
if (empty($pluginAuthor)) {
|
||||
throw new Exception('插件目录格式有误,安装失败');
|
||||
}
|
||||
$arr2 = array_keys($tree_relative[$pluginAuthor]);
|
||||
$pluginName = reset($arr2);
|
||||
|
||||
if (empty($pluginAuthor) || empty($pluginName)) {
|
||||
throw new Exception('插件目录格式有误,安装失败');
|
||||
}
|
||||
|
||||
if (!file_exists("$this->tmpDirPath/$pluginAuthor/$pluginName/Install.php")) {
|
||||
throw new Exception('插件缺失Install.php,安装失败');
|
||||
}
|
||||
return [
|
||||
$pluginAuthor,
|
||||
$pluginName,
|
||||
];
|
||||
}
|
||||
|
||||
private function clearOld()
|
||||
{
|
||||
|
||||
if (!file_exists(dirname($this->pluginPath))) {
|
||||
mkdir(dirname($this->pluginPath), 0777, true);
|
||||
}
|
||||
del_tree($this->pluginPath);
|
||||
}
|
||||
|
||||
public function install()
|
||||
{
|
||||
try {
|
||||
|
||||
$this->unzip();
|
||||
|
||||
$checkPlugin = $this->checkPlugin();
|
||||
|
||||
$this->pluginAuthor = $checkPlugin[0];
|
||||
$this->pluginName = $checkPlugin[1];
|
||||
|
||||
$this->pluginPath = plugin_path_get() . "/$this->pluginAuthor/$this->pluginName";
|
||||
//清空旧插件
|
||||
$this->clearOld();
|
||||
//移动文件
|
||||
rename("$this->tmpDirPath/$this->pluginAuthor/$this->pluginName", $this->pluginPath);
|
||||
// 执行Install.php
|
||||
require "$this->pluginPath/Install.php";
|
||||
|
||||
$this->pluginClass = "$this->pluginAuthor\\$this->pluginName";
|
||||
$class = "plugin\\$this->pluginClass\\Install";
|
||||
if (!class_exists($class)) {
|
||||
throw new Exception("插件缺失类$this->pluginClass,安装失败");
|
||||
}
|
||||
$install = new $class();
|
||||
$model = Db::name('plugin')->where('class', $this->pluginClass)->find();
|
||||
if (!$model) {
|
||||
$model['title'] = '插件' . $this->uniqid;
|
||||
$model['alias'] = $this->uniqid;
|
||||
$model['class'] = $this->pluginClass;
|
||||
$model['desc'] = '';
|
||||
$model['category_id'] = 0;
|
||||
$model['request_count'] = 0;
|
||||
}
|
||||
$pluginconfig = $install->Install();
|
||||
if(isset($pluginconfig['title'])) $model['title'] = $pluginconfig['title'];
|
||||
if(isset($pluginconfig['alias'])) $model['alias'] = $pluginconfig['alias'];
|
||||
if(isset($pluginconfig['class'])) $model['class'] = $pluginconfig['class'];
|
||||
if(isset($pluginconfig['desc'])) $model['desc'] = $pluginconfig['desc'];
|
||||
|
||||
//判断alias是否重复
|
||||
$model2 = Db::name('plugin')->where('alias', $model['alias'])->find();
|
||||
if ($model2 && $model2['id'] !== $model['id']) {
|
||||
$model['alias'] .= "_$this->uniqid";
|
||||
}
|
||||
$model['id'] = Db::name('plugin')->cache('plugins')->insertGetId($model);
|
||||
} catch (\Exception $e) {
|
||||
@del_tree($this->pluginPath);
|
||||
return msg('error', $e->getMessage());
|
||||
} finally {
|
||||
@del_tree($this->tmpDirPath);
|
||||
@unlink($this->zipFilepath);
|
||||
}
|
||||
return msg('ok', '安装成功', $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getZipFilepath(): string
|
||||
{
|
||||
return $this->zipFilepath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
/**
|
||||
* QQ群相关操作类
|
||||
*/
|
||||
|
||||
use Exception;
|
||||
|
||||
class QQGroup{
|
||||
private $uin;
|
||||
private $cookie;
|
||||
private $gtk;
|
||||
private $ua = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36';
|
||||
|
||||
public function __construct($uin, $cookie){
|
||||
$this->uin=$uin;
|
||||
preg_match('/skey=(.{10});/',$cookie,$skey);
|
||||
$this->gtk=$this->getGTK($skey[1]);
|
||||
$this->cookie=$cookie;
|
||||
}
|
||||
|
||||
private function getGTK($skey){
|
||||
$len = strlen($skey);
|
||||
$hash = 5381;
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$hash += ($hash << 5 & 2147483647) + ord($skey[$i]) & 2147483647;
|
||||
$hash &= 2147483647;
|
||||
}
|
||||
return $hash & 2147483647;
|
||||
}
|
||||
|
||||
//QQ群列表
|
||||
public function grouplist($onlyadmin = false){
|
||||
$url = 'https://qun.qq.com/cgi-bin/qun_mgr/get_group_list';
|
||||
$post = 'bkn='.$this->gtk;
|
||||
$data = get_curl($url,$post,'https://qun.qq.com/member.html',$this->cookie,0,$this->ua);
|
||||
$arr = json_decode($data,true);
|
||||
//print_r($arr);exit;
|
||||
if(!$arr){
|
||||
throw new Exception('QQ群列表获取失败!');
|
||||
} elseif(isset($arr['ec']) && $arr['ec']==0) {
|
||||
$group = [];
|
||||
if(isset($arr['create'])){
|
||||
foreach($arr['create'] as $row){
|
||||
$group[] = $row;
|
||||
}
|
||||
}
|
||||
if(isset($arr['manage'])){
|
||||
foreach($arr['manage'] as $row){
|
||||
$group[] = $row;
|
||||
}
|
||||
}
|
||||
if(!$onlyadmin && isset($arr['join'])){
|
||||
foreach($arr['join'] as $row){
|
||||
$group[] = $row;
|
||||
}
|
||||
}
|
||||
return $group;
|
||||
} elseif($arr['ec']==1 || $arr['ec']==4) {
|
||||
session('qq_cookie_qun', null);
|
||||
throw new Exception('当前QQ登录状态已失效,请重新登录!');
|
||||
} else {
|
||||
throw new Exception('QQ群列表获取失败!'.$arr['em']);
|
||||
}
|
||||
}
|
||||
|
||||
//QQ群成员列表
|
||||
public function groupmemberlist($groupid, $start, $end){
|
||||
$url='https://qun.qq.com/cgi-bin/qun_mgr/search_group_members';
|
||||
$post='gc='.$groupid.'&st='.$start.'&end='.$end.'&sort=0&bkn='.$this->gtk;
|
||||
$data = get_curl($url,$post,'https://qun.qq.com/member.html',$this->cookie,0,$this->ua);
|
||||
$arr = json_decode($data,true);
|
||||
if (!$arr) {
|
||||
throw new Exception('QQ群成员获取失败!');
|
||||
}elseif ($arr["ec"] == 1) {
|
||||
throw new Exception('SKEY已失效!');
|
||||
}elseif ($arr["ec"]!=0){
|
||||
throw new Exception('QQ群成员获取失败!'.$arr['em']);
|
||||
}
|
||||
$data = array();
|
||||
$data['code'] = 0;
|
||||
$data['count'] = $arr['count'];
|
||||
$data['mems'] = $arr['mems'];
|
||||
if($end<$arr['count'])$data['start'] = $end+1;
|
||||
else $data['start'] = 0;
|
||||
return $data;
|
||||
}
|
||||
|
||||
//群公告列表
|
||||
public function announcelist($groupid, $start){
|
||||
$url='https://web.qun.qq.com/cgi-bin/announce/list_announce';
|
||||
$post='bkn='.$this->gtk.'&qid='.$groupid.'&ft=23&s='.$start.'&n=10&ni=1&i=1';
|
||||
$data = get_curl($url,$post,'https://web.qun.qq.com/announce/index.html',$this->cookie,0,$this->ua);
|
||||
$arr = json_decode($data,true);
|
||||
if (!$arr) {
|
||||
throw new Exception('公告列表获取失败!');
|
||||
}elseif ($arr["ec"] == 1) {
|
||||
session('qq_cookie_qun', null);
|
||||
throw new Exception('当前QQ登录状态已失效,请重新登录!');
|
||||
}elseif ($arr["ec"]!=0){
|
||||
throw new Exception('公告列表获取失败!'.$arr['em']);
|
||||
}
|
||||
if(!isset($arr['feeds']) || !$arr['feeds'])return [];
|
||||
$uinlist = [];
|
||||
foreach($arr['ui'] as $uin => $row){
|
||||
$uinlist[$uin] = $row['n'];
|
||||
}
|
||||
$list = [];
|
||||
foreach($arr['feeds'] as $row){
|
||||
$msg = $row['msg']['text'];
|
||||
if(mb_strlen($msg, 'utf-8')>30)$msg=mb_substr($msg, 0, 30, 'utf-8').'...';
|
||||
if($row['pinned']==1)$msg = '<font color="red">[顶]</font>'.$msg;
|
||||
$list[] = ['fid'=>$row['fid'], 'uin'=>$row['u'], 'nick'=>$uinlist[$row['u']]?$uinlist[$row['u']]:$row['u'], 'time'=>date("Y-m-d H:i:s", $row['pubt']), 'msg'=>$msg];
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
//删除群公告
|
||||
public function delannounce($groupid, $fid){
|
||||
$url='https://web.qun.qq.com/cgi-bin/announce/del_feed';
|
||||
$post='fid='.$fid.'&ft=23&bkn='.$this->gtk.'&qid='.$groupid.'&op=0';
|
||||
$data = get_curl($url,$post,'https://web.qun.qq.com/announce/index.html',$this->cookie,0,$this->ua);
|
||||
$arr = json_decode($data,true);
|
||||
if(isset($arr["ec"]) && ($arr["ec"]==0 || $arr["ec"]==14)){
|
||||
return true;
|
||||
}elseif ($arr["ec"] == 1) {
|
||||
throw new Exception('SKEY已失效!');
|
||||
}else{
|
||||
throw new Exception('公告删除失败!'.$arr['em']);
|
||||
}
|
||||
}
|
||||
|
||||
//解散群
|
||||
public function dismissgroup($groupuin){
|
||||
$resultarr = array(11=>'需要验证码', 13=>'号码异常,暂时不允许解散', 15=>'为了企业信息安全,请登录企业帐户中心进行解散操作。', 16=>'公益群暂不支持解散。', 17=>'该群被转让不足28天,暂时还不能解散。', 25=>'付费2000人群不可解散。', 51=>'您的群已绑定了教育机构,如需进行此操作,请先与机构解绑。');
|
||||
|
||||
$url = 'https://id.qq.com/qun/dismiss_group';
|
||||
$referrer = 'https://id.qq.com/proxy.html';
|
||||
$post = 'vc=undefined&gc='.$groupuin.'&uin='.$this->uin.'&s=1&bkn='.$this->gtk;
|
||||
$data = get_curl($url,$post,$referrer,$this->cookie,0,$this->ua);
|
||||
$arr = json_decode($data,true);
|
||||
if(isset($arr["ec"]) && $arr["ec"]==0){
|
||||
return true;
|
||||
}elseif ($arr["ec"] == 1) {
|
||||
session('qq_cookie_qqid', null);
|
||||
throw new Exception('当前QQ登录状态已失效,请重新登录!');
|
||||
}elseif(isset($arr['ec']) && array_key_exists($arr['ec'],$resultarr)){
|
||||
throw new Exception($resultarr[$arr['ec']]);
|
||||
}else{
|
||||
throw new Exception('解散群失败,可能非群主或群不存在。返回信息:'.$data);
|
||||
}
|
||||
}
|
||||
|
||||
//获取加群链接
|
||||
public function getjoinlink($groupuin){
|
||||
$url = 'https://admin.qun.qq.com/cgi-bin/qun_admin/get_join_link';
|
||||
$referrer = 'https://admin.qun.qq.com/create/share/index.html?ptlang=2052&groupUin='.$groupuin;
|
||||
$post = 'gc='.$groupuin.'&type=1&bkn='.$this->gtk;
|
||||
$data = get_curl($url,$post,$referrer,$this->cookie);
|
||||
$arr = json_decode($data,true);
|
||||
if (isset($arr["ec"]) && $arr['ec']==0) {
|
||||
return $arr['url'];
|
||||
}elseif($arr['ec']==1){
|
||||
session('qq_cookie_qun', null);
|
||||
throw new Exception('加群链接获取失败,原因:SKEY已失效');
|
||||
}else{
|
||||
throw new Exception('加群链接获取失败 '.$arr['em']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
|
||||
use Zxing\QrReader;
|
||||
|
||||
class QQLogin{
|
||||
private $ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36';
|
||||
|
||||
public function getqrpic($daid){
|
||||
if(empty($daid))return array('saveOK'=>-1,'msg'=>'daid不能为空');
|
||||
if($daid == '5'){
|
||||
$url='https://ssl.ptlogin2.qq.com/ptqrshow?appid=549000912&e=2&l=M&s=4&d=72&v=4&t=0.5409099'.time().'&daid=5&pt_3rd_aid=0&u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone';
|
||||
$referer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone';
|
||||
}else{
|
||||
$url='https://ssl.ptlogin2.qq.com/ptqrshow?appid=716027609&e=2&l=M&s=4&d=72&v=4&t=0.5409099'.time().'&daid='.$daid.'&pt_3rd_aid=100384226';
|
||||
$referer='https://xui.ptlogin2.qq.com/cgi-bin/xlogin?daid='.$daid.'&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&target=self&s_url=https:%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html?para%3Dizone&pt_no_auth=0&appid=716027609&pt_3rd_aid=100384226';
|
||||
}
|
||||
$arr=$this->get_curl_split($url,$referer);
|
||||
preg_match('/qrsig=(.*?);/',$arr['header'],$match);
|
||||
if($qrsig=$match[1]){
|
||||
$qrcode = new QrReader($arr['body'], QrReader::SOURCE_TYPE_BLOB);
|
||||
$code_url = $qrcode->text();
|
||||
return array('saveOK'=>0,'qrsig'=>$qrsig,'data'=>base64_encode($arr['body']),'url'=>$code_url);
|
||||
}else{
|
||||
return array('saveOK'=>1,'msg'=>'二维码获取失败');
|
||||
}
|
||||
}
|
||||
public function qrlogin($daid,$s_url,$qrsig){
|
||||
if(empty($daid)||empty($s_url))return array('saveOK'=>-1,'msg'=>'daid和s_url不能为空');
|
||||
if(empty($qrsig))return array('saveOK'=>-1,'msg'=>'qrsig不能为空');
|
||||
if($daid == '5'){
|
||||
$url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-'.time().'000&js_ver=23042119&js_type=1&login_sig=&pt_uistyle=40&aid=549000912&daid=5&';
|
||||
}else{
|
||||
$url='https://ssl.ptlogin2.qq.com/ptqrlogin?u1='.urlencode($s_url).'&ptqrtoken='.$this->getqrtoken($qrsig).'&ptredirect=0&h=1&t=1&g=1&from_ui=1&ptlang=2052&action=0-0-'.time().'0000&js_ver=10194&js_type=1&login_sig=&pt_uistyle=40&aid=716027609&daid='.$daid.'&pt_3rd_aid=100384226&';
|
||||
}
|
||||
$ret = $this->get_curl($url,0,'https://xui.ptlogin2.qq.com/','qrsig='.$qrsig.'; ',1);
|
||||
if(preg_match("/ptuiCB\('(.*?)'\)/", $ret, $arr)){
|
||||
$r=explode("','",str_replace("', '","','",$arr[1]));
|
||||
if($r[0]==0){
|
||||
preg_match('/uin=(\d+)&/',$ret,$uin);
|
||||
$uin=$uin[1];
|
||||
preg_match('/skey=@(.{9});/',$ret,$skey);
|
||||
preg_match('/superkey=(.*?);/',$ret,$superkey);
|
||||
$data=$this->get_curl($r[2],0,0,0,1);
|
||||
if($data) {
|
||||
preg_match_all('/Set-Cookie: (.*?);/i',$data,$matchs);
|
||||
$cookie='';
|
||||
foreach ($matchs[1] as $val) {
|
||||
if(substr($val,-1)=='=')continue;
|
||||
$cookie.=$val.'; ';
|
||||
}
|
||||
$cookie = substr($cookie,0,-2);
|
||||
}
|
||||
if($cookie){
|
||||
return array('saveOK'=>0,'uin'=>$uin,'cookie'=>$cookie,'nickname'=>$r[5]);
|
||||
}else{
|
||||
return array('saveOK'=>6,'msg'=>'登录成功,获取相关信息失败!'.$r[2]);
|
||||
}
|
||||
}elseif($r[0]==65){
|
||||
return array('saveOK'=>1,'msg'=>'二维码已失效。');
|
||||
}elseif($r[0]==66){
|
||||
return array('saveOK'=>2,'msg'=>'二维码未失效。');
|
||||
}elseif($r[0]==67){
|
||||
return array('saveOK'=>3,'msg'=>'正在验证二维码。');
|
||||
}else{
|
||||
return array('saveOK'=>6,'msg'=>$r[4]);
|
||||
}
|
||||
}else{
|
||||
return array('saveOK'=>6,'msg'=>$ret);
|
||||
}
|
||||
}
|
||||
private function getqrtoken($qrsig){
|
||||
$len = strlen($qrsig);
|
||||
$hash = 0;
|
||||
for($i = 0; $i < $len; $i++){
|
||||
$hash += (($hash << 5) & 2147483647) + ord($qrsig[$i]) & 2147483647;
|
||||
$hash &= 2147483647;
|
||||
}
|
||||
return $hash & 2147483647;
|
||||
}
|
||||
private function get_curl($url,$post=0,$referer=0,$cookie=0,$header=0,$ua=0,$nobaody=0,$noproxy=0){
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,$url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$httpheader[] = "Accept: application/json";
|
||||
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: keep-alive";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
if($post){
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
}
|
||||
if($header){
|
||||
curl_setopt($ch, CURLOPT_HEADER, TRUE);
|
||||
}
|
||||
if($cookie){
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
||||
}
|
||||
if($referer){
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||
}
|
||||
if($ua){
|
||||
curl_setopt($ch, CURLOPT_USERAGENT,$ua);
|
||||
}else{
|
||||
curl_setopt($ch, CURLOPT_USERAGENT,$this->ua);
|
||||
}
|
||||
if($nobaody){
|
||||
curl_setopt($ch, CURLOPT_NOBODY,1);
|
||||
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
|
||||
$ret = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $ret;
|
||||
}
|
||||
private function get_curl_split($url,$referer=0){
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,$url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: keep-alive";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
curl_setopt($ch, CURLOPT_HEADER, TRUE);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT,$this->ua);
|
||||
if($referer){
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
|
||||
$ret = curl_exec($ch);
|
||||
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($ret, 0, $headerSize);
|
||||
$body = substr($ret, $headerSize);
|
||||
$ret=array();
|
||||
$ret['header']=$header;
|
||||
$ret['body']=$body;
|
||||
curl_close($ch);
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
/**
|
||||
* QQ空间工具类
|
||||
*/
|
||||
|
||||
use Exception;
|
||||
|
||||
class QQTool{
|
||||
private $uin;
|
||||
private $cookie;
|
||||
private $gtk;
|
||||
private $skey;
|
||||
|
||||
public function __construct($uin,$cookie,$is_skey = false){
|
||||
$this->uin=$uin;
|
||||
$this->cookie=$cookie;
|
||||
if($is_skey){
|
||||
$this->skey=getSubstr($cookie, 'skey=', ';');
|
||||
$this->gtk=$this->getGTK($this->skey);
|
||||
}else{
|
||||
$pskey=getSubstr($cookie, 'p_skey=', ';');
|
||||
$this->gtk=$this->getGTK($pskey);
|
||||
}
|
||||
}
|
||||
|
||||
private function getGTK($skey){
|
||||
$len = strlen($skey);
|
||||
$hash = 5381;
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$hash += ($hash << 5 & 2147483647) + ord($skey[$i]) & 2147483647;
|
||||
$hash &= 2147483647;
|
||||
}
|
||||
return $hash & 2147483647;
|
||||
}
|
||||
|
||||
private function getGTK2($skey){
|
||||
$salt = 5381;
|
||||
$md5key = 'tencentQQVIP123443safde&!%^%1282';
|
||||
$hash = array();
|
||||
$hash[] = ($salt << 5);
|
||||
for($i = 0; $i < strlen($skey); $i ++)
|
||||
{
|
||||
$ASCIICode = mb_convert_encoding($skey[$i], 'UTF-32BE', 'UTF-8');
|
||||
$ASCIICode = hexdec(bin2hex($ASCIICode));
|
||||
$hash[] = (($salt << 5) + $ASCIICode);
|
||||
$salt = $ASCIICode;
|
||||
}
|
||||
$md5str = md5(implode($hash) . $md5key);
|
||||
return $md5str;
|
||||
}
|
||||
|
||||
//好友与分组列表
|
||||
public function friendlist(){
|
||||
$url = 'https://mobile.qzone.qq.com/friend/mfriend_list?g_tk='.$this->gtk.'&res_uin='.$this->uin.'&res_type=normal&format=json&count_per_page=10&page_index=0&page_type=0&mayknowuin=&qqmailstat=';
|
||||
$json = get_curl($url,0,1,$this->cookie);
|
||||
$json = mb_convert_encoding($json, "UTF-8", "UTF-8");
|
||||
$arr = json_decode($json, true);
|
||||
if(!$arr){
|
||||
throw new Exception('好友列表获取失败!');
|
||||
}elseif(isset($arr['code']) && $arr['code']==0){
|
||||
return $arr["data"];
|
||||
}elseif ($arr["code"] == -3000) {
|
||||
session('qq_cookie_qzone', null);
|
||||
throw new Exception('当前QQ登录状态已失效,请重新登录!');
|
||||
}elseif (isset($arr["message"])) {
|
||||
throw new Exception('好友列表获取失败!'.$arr["message"]);
|
||||
}else{
|
||||
throw new Exception('好友列表获取失败!');
|
||||
}
|
||||
}
|
||||
|
||||
//说说列表
|
||||
public function shuoshuolist($count){
|
||||
$url='https://mobile.qzone.qq.com/list?g_tk='.$this->gtk.'&res_attach=&format=json&list_type=shuoshuo&action=0&res_uin='.$this->uin.'&count='.$count;
|
||||
$data = get_curl($url,0,1,$this->cookie);
|
||||
$arr=json_decode($data,true);
|
||||
if (isset($arr['code']) && $arr['code']==0) {
|
||||
if(isset($arr['data']['vFeeds']))
|
||||
return $arr['data']['vFeeds'];
|
||||
else
|
||||
return $arr['data']['feeds']['vFeeds'];
|
||||
}elseif ($arr["code"] == -3000) {
|
||||
session('qq_cookie_qzone', null);
|
||||
throw new Exception('当前QQ登录状态已失效,请重新登录!');
|
||||
}elseif (isset($arr["message"])) {
|
||||
throw new Exception('说说列表获取失败!'.$arr["message"]);
|
||||
}else{
|
||||
throw new Exception('说说列表获取失败!');
|
||||
}
|
||||
}
|
||||
|
||||
//说说最多点赞数
|
||||
public function shuoshuozancount($count){
|
||||
$zan = 0;
|
||||
$list = $this->shuoshuolist($count);
|
||||
foreach($list as $row){
|
||||
if($row['like']['num']>$zan) $zan=$row['like']['num'];
|
||||
}
|
||||
return $zan;
|
||||
}
|
||||
|
||||
//秒赞检测
|
||||
public function mzjc(){
|
||||
$arr = $this->friendlist();
|
||||
$friend=$arr["list"];
|
||||
$gpnames=$arr["gpnames"];
|
||||
|
||||
foreach($gpnames as $gprow){
|
||||
$gpid=$gprow['gpid'];
|
||||
$gpname[$gpid]=$gprow['gpname'];
|
||||
}
|
||||
|
||||
$arr = $this->shuoshuolist('5');
|
||||
$qqrow=array();
|
||||
$qquins=array();
|
||||
foreach ($arr as $row ) {
|
||||
$url='https://users.qzone.qq.com/cgi-bin/likes/get_like_list_app?uin='.$this->uin.'&unikey='.urlencode($row['comm']['curlikekey']).'&begin_uin=0&query_count=200&if_first_page=1&g_tk='.$this->gtk;
|
||||
$data2 = get_curl($url,0,'https://user.qzone.qq.com/',$this->cookie);
|
||||
if(!$data2){
|
||||
throw new Exception('说说点赞列表获取失败!可更新SKEY后重试');
|
||||
}
|
||||
preg_match('/_Callback\((.*?)\)\;/is',$data2,$json);
|
||||
$arr2=json_decode($json[1],true);
|
||||
$data2=$arr2['data']['like_uin_info'];
|
||||
foreach ($data2 as $row2 ) {
|
||||
$fuin=$row2['fuin'];
|
||||
if(isset($qqrow[$fuin])){$qqrow[$fuin]++;}
|
||||
else {$qqrow[$fuin]=1;$qquins[]=$fuin;}
|
||||
}
|
||||
}
|
||||
|
||||
$mzcount=count($qqrow);
|
||||
foreach ($friend as $row3 ) {
|
||||
$fuin=$row3['uin'];
|
||||
if(isset($qqrow[$fuin]))$list['mz']=$qqrow[$fuin];
|
||||
else $list['mz']=0;
|
||||
$list['uin']=$row3['uin'];
|
||||
$list['name']=$row3['nick'];
|
||||
if($row3['remark'])$list['remark']=$row3['remark'];
|
||||
else $list['remark']=$row3['nick'];
|
||||
$list['groupid']=$row3['groupid'];
|
||||
$result['friend'][]=$list;
|
||||
unset($list);
|
||||
}
|
||||
rsort($result['friend']);
|
||||
$friend=$result['friend'];
|
||||
$fcount=count($friend);
|
||||
$array=array();
|
||||
foreach($friend as $nrow){
|
||||
if($nrow['mz']) $array[$nrow['groupid']]['mzcount']=$array[$nrow['groupid']]['mzcount']+1;
|
||||
$array[$nrow['groupid']][]=$nrow;
|
||||
}
|
||||
$friend=$array;
|
||||
|
||||
return [$fcount, $mzcount, $friend, $gpnames];
|
||||
}
|
||||
|
||||
//查询当前是否VIP
|
||||
public function getisvip(){
|
||||
$data=get_curl('https://cgi.vip.qq.com/unipay/init?format=json&aid=vipminipay.pingtai.vipsite.nav_new&platform=pc&version=-1&isbreak=0&g_tk='.$this->getGTK2($this->skey),0,'https://vip.qq.com/',$this->cookie);
|
||||
$arr=json_decode($data,true);
|
||||
if($arr['ret']==-7) {
|
||||
throw new Exception('SKEY已失效!');
|
||||
}
|
||||
$isqqvip=$arr['recParam']['is_vip'];
|
||||
return $isqqvip;
|
||||
}
|
||||
|
||||
//修改QQ昵称
|
||||
public function setnickname($nickname){
|
||||
$url="https://h5.qzone.qq.com/proxy/domain/w.qzone.qq.com/cgi-bin/user/cgi_apply_updateuserinfo_new?g_tk=".$this->gtk;
|
||||
$data="qzreferrer=http%3A%2F%2Fctc.qzs.qq.com%2Fqzone%2Fv6%2Fsetting%2Fprofile%2Fprofile.html%3Ftab%3Dbase&nickname=".urlencode($nickname)."&emoji=&sex=1&birthday=2015-01-01&province=0&city=PAR&country=FRA&marriage=6&bloodtype=5&hp=0&hc=PAR&hco=FRA&career=&company=&cp=0&cc=0&cb=&cco=0&lover=&islunar=0&mb=1&uin=".$this->uin."&pageindex=1&nofeeds=1&fupdate=1&format=json";
|
||||
$return=get_curl($url,$data,$url,$this->cookie);
|
||||
$arr=json_decode($return,true);
|
||||
if(!$arr){
|
||||
throw new Exception('更换昵称失败');
|
||||
}elseif(isset($arr['code']) && $arr['code']==0){
|
||||
return true;
|
||||
}elseif($arr["code"] == -3000) {
|
||||
session('qq_cookie_qzone', null);
|
||||
throw new Exception('当前QQ登录状态已失效,请重新登录!');
|
||||
}elseif(isset($arr['message'])){
|
||||
throw new Exception($arr['message']);
|
||||
}else{
|
||||
throw new Exception('更换昵称失败');
|
||||
}
|
||||
}
|
||||
|
||||
public function set_online_status($model, $desc, $imei){
|
||||
$pt4_token = getSubstr($this->cookie, 'pt4_token=', ';');
|
||||
$ua = 'Mozilla/5.0 (Linux; Android 12; IN2010 Build/RKQ1.211119.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/97.0.4692.98 Mobile Safari/537.36 V1_AND_SQ_8.8.68_2538_YYB_D A_8086800 QQ/8.8.88 NetType/4G';
|
||||
$data = json_encode(['13031'=>['req'=>['sModel'=>$model, 'iAppType'=>3, 'sIMei'=>$imei, 'sVer'=>'8.8.88', 'sManu'=>'', 'lUin'=>intval($this->uin), 'bShowInfo'=>true, 'sDesc'=>$desc, 'sModelShow'=> $model]]]);
|
||||
$url = 'https://proxy.vac.qq.com/cgi-bin/srfentry.fcgi?ts='.time().'000&g_tk='.$this->gtk.'&data='.rawurlencode($data).'&pt4_token='.urlencode($pt4_token);
|
||||
$data = get_curl($url, 0, 'https://proxy.vac.qq.com/', $this->cookie, 0, $ua);
|
||||
$arr = json_decode($data, true);
|
||||
if(!$arr){
|
||||
throw new Exception('修改在线状态失败');
|
||||
}elseif(isset($arr['ecode']) && $arr['ecode']==0){
|
||||
if(isset($arr['13031']['ret']) && $arr['13031']['ret']==0){
|
||||
return true;
|
||||
}else{
|
||||
throw new Exception('修改在线状态失败,'.$arr['13031']['msg']);
|
||||
}
|
||||
}else{
|
||||
throw new Exception('修改在线状态失败,'.$data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,370 @@
|
||||
<?php
|
||||
namespace app\lib;
|
||||
use Exception;
|
||||
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||
// Use of this source code is governed by a Apache2.0-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// @Author Lion <[email protected]>
|
||||
// @Date 2022/06/21
|
||||
|
||||
class XdbSearcher
|
||||
{
|
||||
const HeaderInfoLength = 256;
|
||||
const VectorIndexRows = 256;
|
||||
const VectorIndexCols = 256;
|
||||
const VectorIndexSize = 8;
|
||||
const SegmentIndexSize = 14;
|
||||
|
||||
// xdb file handle
|
||||
private $handle = null;
|
||||
|
||||
// header info
|
||||
private $header = null;
|
||||
private $ioCount = 0;
|
||||
|
||||
// vector index in binary string.
|
||||
// string decode will be faster than the map based Array.
|
||||
private $vectorIndex = null;
|
||||
|
||||
// xdb content buffer
|
||||
private $contentBuff = null;
|
||||
|
||||
// ---
|
||||
// static function to create searcher
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function newWithFileOnly($dbFile)
|
||||
{
|
||||
return new XdbSearcher($dbFile, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function newWithVectorIndex($dbFile, $vIndex)
|
||||
{
|
||||
return new XdbSearcher($dbFile, $vIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function newWithBuffer($cBuff)
|
||||
{
|
||||
return new XdbSearcher(null, null, $cBuff);
|
||||
}
|
||||
|
||||
// --- End of static creator
|
||||
|
||||
/**
|
||||
* initialize the xdb searcher
|
||||
* @throws Exception
|
||||
*/
|
||||
function __construct($dbFile = null, $vectorIndex = null, $cBuff = null)
|
||||
{
|
||||
// check the content buffer first
|
||||
if ($cBuff != null) {
|
||||
$this->vectorIndex = null;
|
||||
$this->contentBuff = $cBuff;
|
||||
} else {
|
||||
// 加载默认数据文件 by Anyon
|
||||
if (is_null($dbFile)) {
|
||||
$dbFile = __DIR__ . DIRECTORY_SEPARATOR . 'ip2region.xdb';
|
||||
}
|
||||
// open the xdb binary file
|
||||
$this->handle = fopen($dbFile, "r");
|
||||
if ($this->handle === false) {
|
||||
throw new Exception("failed to open xdb file '%s'", $dbFile);
|
||||
}
|
||||
|
||||
$this->vectorIndex = $vectorIndex;
|
||||
}
|
||||
}
|
||||
|
||||
function close()
|
||||
{
|
||||
if ($this->handle != null) {
|
||||
fclose($this->handle);
|
||||
}
|
||||
}
|
||||
|
||||
function getIOCount()
|
||||
{
|
||||
return $this->ioCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* find the region info for the specified ip address
|
||||
* @throws Exception
|
||||
*/
|
||||
function search($ip)
|
||||
{
|
||||
// check and convert the sting ip to a 4-bytes long
|
||||
if (is_string($ip)) {
|
||||
$t = self::ip2long($ip);
|
||||
if ($t === null) {
|
||||
throw new Exception("invalid ip address `$ip`");
|
||||
}
|
||||
$ip = $t;
|
||||
}
|
||||
|
||||
// reset the global counter
|
||||
$this->ioCount = 0;
|
||||
|
||||
// locate the segment index block based on the vector index
|
||||
$il0 = ($ip >> 24) & 0xFF;
|
||||
$il1 = ($ip >> 16) & 0xFF;
|
||||
$idx = $il0 * self::VectorIndexCols * self::VectorIndexSize + $il1 * self::VectorIndexSize;
|
||||
if ($this->vectorIndex != null) {
|
||||
$sPtr = self::getLong($this->vectorIndex, $idx);
|
||||
$ePtr = self::getLong($this->vectorIndex, $idx + 4);
|
||||
} elseif ($this->contentBuff != null) {
|
||||
$sPtr = self::getLong($this->contentBuff, self::HeaderInfoLength + $idx);
|
||||
$ePtr = self::getLong($this->contentBuff, self::HeaderInfoLength + $idx + 4);
|
||||
} else {
|
||||
// read the vector index block
|
||||
$buff = $this->read(self::HeaderInfoLength + $idx, 8);
|
||||
if ($buff === null) {
|
||||
throw new Exception("failed to read vector index at ${idx}");
|
||||
}
|
||||
|
||||
$sPtr = self::getLong($buff, 0);
|
||||
$ePtr = self::getLong($buff, 4);
|
||||
}
|
||||
|
||||
// printf("sPtr: %d, ePtr: %d\n", $sPtr, $ePtr);
|
||||
|
||||
// binary search the segment index to get the region info
|
||||
$dataLen = 0;
|
||||
$dataPtr = null;
|
||||
$l = 0;
|
||||
$h = ($ePtr - $sPtr) / self::SegmentIndexSize;
|
||||
while ($l <= $h) {
|
||||
$m = ($l + $h) >> 1;
|
||||
$p = $sPtr + $m * self::SegmentIndexSize;
|
||||
|
||||
// read the segment index
|
||||
$buff = $this->read($p, self::SegmentIndexSize);
|
||||
if ($buff == null) {
|
||||
throw new Exception("failed to read segment index at ${p}");
|
||||
}
|
||||
|
||||
$sip = self::getLong($buff, 0);
|
||||
if ($ip < $sip) {
|
||||
$h = $m - 1;
|
||||
} else {
|
||||
$eip = self::getLong($buff, 4);
|
||||
if ($ip > $eip) {
|
||||
$l = $m + 1;
|
||||
} else {
|
||||
$dataLen = self::getShort($buff, 8);
|
||||
$dataPtr = self::getLong($buff, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// match nothing interception.
|
||||
// @TODO: could this even be a case ?
|
||||
// printf("dataLen: %d, dataPtr: %d\n", $dataLen, $dataPtr);
|
||||
if ($dataPtr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// load and return the region data
|
||||
$buff = $this->read($dataPtr, $dataLen);
|
||||
if ($buff == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// read specified bytes from the specified index
|
||||
private function read($offset, $len)
|
||||
{
|
||||
// check the in-memory buffer first
|
||||
if ($this->contentBuff != null) {
|
||||
return substr($this->contentBuff, $offset, $len);
|
||||
}
|
||||
|
||||
// read from the file
|
||||
$r = fseek($this->handle, $offset);
|
||||
if ($r == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->ioCount++;
|
||||
$buff = fread($this->handle, $len);
|
||||
if ($buff === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strlen($buff) != $len) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// --- static util functions ----
|
||||
|
||||
// convert a string ip to long
|
||||
public static function ip2long($ip)
|
||||
{
|
||||
$ip = ip2long($ip);
|
||||
if ($ip === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 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 4bytes long from a byte buffer
|
||||
public static function getLong($b, $idx)
|
||||
{
|
||||
$val = (ord($b[$idx])) | (ord($b[$idx + 1]) << 8)
|
||||
| (ord($b[$idx + 2]) << 16) | (ord($b[$idx + 3]) << 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;
|
||||
}
|
||||
|
||||
// read a 2bytes short from a byte buffer
|
||||
public static function getShort($b, $idx)
|
||||
{
|
||||
return ((ord($b[$idx])) | (ord($b[$idx + 1]) << 8));
|
||||
}
|
||||
|
||||
// load header info from a specified file handle
|
||||
public static function loadHeader($handle)
|
||||
{
|
||||
if (fseek($handle, 0) == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$buff = fread($handle, self::HeaderInfoLength);
|
||||
if ($buff === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// read bytes length checking
|
||||
if (strlen($buff) != self::HeaderInfoLength) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// return the decoded header info
|
||||
return [
|
||||
'version' => self::getShort($buff, 0),
|
||||
'indexPolicy' => self::getShort($buff, 2),
|
||||
'createdAt' => self::getLong($buff, 4),
|
||||
'startIndexPtr' => self::getLong($buff, 8),
|
||||
'endIndexPtr' => self::getLong($buff, 12)
|
||||
];
|
||||
}
|
||||
|
||||
// load header info from the specified xdb file path
|
||||
public static function loadHeaderFromFile($dbFile)
|
||||
{
|
||||
$handle = fopen($dbFile, 'r');
|
||||
if ($handle === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$header = self::loadHeader($handle);
|
||||
fclose($handle);
|
||||
return $header;
|
||||
}
|
||||
|
||||
// load vector index from a file handle
|
||||
public static function loadVectorIndex($handle)
|
||||
{
|
||||
if (fseek($handle, self::HeaderInfoLength) == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rLen = self::VectorIndexRows * self::VectorIndexCols * self::SegmentIndexSize;
|
||||
$buff = fread($handle, $rLen);
|
||||
if ($buff === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strlen($buff) != $rLen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// load vector index from a specified xdb file path
|
||||
public static function loadVectorIndexFromFile($dbFile)
|
||||
{
|
||||
$handle = fopen($dbFile, 'r');
|
||||
if ($handle === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$vIndex = self::loadVectorIndex($handle);
|
||||
fclose($handle);
|
||||
return $vIndex;
|
||||
}
|
||||
|
||||
// load the xdb content from a file handle
|
||||
public static function loadContent($handle)
|
||||
{
|
||||
if (fseek($handle, 0, SEEK_END) == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$size = ftell($handle);
|
||||
if ($size === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// seek to the head for reading
|
||||
if (fseek($handle, 0) == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$buff = fread($handle, $size);
|
||||
if ($buff === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// read length checking
|
||||
if (strlen($buff) != $size) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// load the xdb content from a file path
|
||||
public static function loadContentFromFile($dbFile)
|
||||
{
|
||||
$str = file_get_contents($dbFile, false);
|
||||
if ($str === false) {
|
||||
return null;
|
||||
} else {
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
public static function now()
|
||||
{
|
||||
return (microtime(true) * 1000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// 全局中间件定义文件
|
||||
return [
|
||||
// 全局请求缓存
|
||||
// \think\middleware\CheckRequestCache::class,
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
\think\middleware\SessionInit::class
|
||||
];
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
|
||||
class AuthAdmin
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$islogin = false;
|
||||
$cookie = cookie('admin_token');
|
||||
if($cookie){
|
||||
$token=authcode($cookie, 'DECODE', config_get('syskey'));
|
||||
if($token){
|
||||
list($user, $sid, $expiretime) = explode("\t", $token);
|
||||
$session=md5(config_get('admin_username').config_get('admin_password'));
|
||||
if($session==$sid && $expiretime>time()) {
|
||||
$islogin = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$islogin) {
|
||||
if ($request->isAjax() || !$request->isGet()) {
|
||||
return msg('error', '请登录')->code(401);
|
||||
}
|
||||
return redirect((string)url('/admin/login.html'));
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
class AuthUser
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$islogin = false;
|
||||
$cookie = cookie('user_token');
|
||||
$user = null;
|
||||
if($cookie){
|
||||
$token=authcode($cookie, 'DECODE', config_get('syskey'));
|
||||
if($token){
|
||||
list($uid, $sid, $expiretime) = explode("\t", $token);
|
||||
$user = Db::name('user')->where('id', $uid)->find();
|
||||
if($user && $user['enable']==1){
|
||||
$session=md5($user['id'].$user['password']);
|
||||
if($session==$sid && $expiretime>time()) {
|
||||
if(!$user['avatar_url']) $user['avatar_url'] = '/static/images/user.png';
|
||||
$islogin = true;
|
||||
}
|
||||
}elseif($user && $user['enable']==0 && !session('user_block')){
|
||||
session('user_block', '1');
|
||||
}
|
||||
}
|
||||
}
|
||||
$request->islogin = $islogin;
|
||||
$request->user = $user;
|
||||
/*if (!$islogin) {
|
||||
if ($request->isAjax() || !$request->isGet()) {
|
||||
return msg('error','请登录');
|
||||
}
|
||||
return redirect((string)url('/login'));
|
||||
}*/
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\Config;
|
||||
|
||||
class LoadConfig
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if (!file_exists(app()->getRootPath().'.env')){
|
||||
return redirect((string)url('/install'));
|
||||
}
|
||||
|
||||
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
||||
Config::set($res, 'sys');
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\View;
|
||||
|
||||
class RefererCheck
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if(!checkRefererHost()){
|
||||
return response('Access Denied', 403);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\View;
|
||||
|
||||
class ViewOutput
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
View::assign('islogin', $request->islogin);
|
||||
View::assign('user', $request->user);
|
||||
View::assign('cdn_cdnjs', config_get('cdn_cdnjs', '//cdn.staticfile.org/'));
|
||||
View::assign('cdn_npm', config_get('cdn_npm', 'https://unpkg.com/'));
|
||||
View::config(['view_path' => template_path_get()]);
|
||||
return $next($request)->header([
|
||||
'Cache-Control' => 'no-store, no-cache, must-revalidate',
|
||||
'Pragma' => 'no-cache',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
use app\ExceptionHandle;
|
||||
use app\Request;
|
||||
|
||||
// 容器Provider定义文件
|
||||
return [
|
||||
'think\Request' => Request::class,
|
||||
'think\exception\Handle' => ExceptionHandle::class,
|
||||
];
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use app\AppService;
|
||||
|
||||
// 系统服务定义文件
|
||||
// 服务在完成全局初始化之后执行
|
||||
return [
|
||||
AppService::class,
|
||||
\app\service\ValidateService::class
|
||||
];
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\service;
|
||||
|
||||
use think\facade\Validate;
|
||||
|
||||
class ValidateService extends \think\Service
|
||||
{
|
||||
/**
|
||||
* 注册服务
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行服务
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
Validate::maker(function ($validate) {
|
||||
$validate->extend('is_json', function ($value) {
|
||||
if (!is_string($value)) {
|
||||
$value = json_encode($value);
|
||||
}
|
||||
json_decode($value);
|
||||
return json_last_error() == JSON_ERROR_NONE;
|
||||
});
|
||||
$validate->extend('is_legal_plugin_class', function ($value) {
|
||||
if (!is_string($value)){
|
||||
return false;
|
||||
}
|
||||
$arr = explode('\\', $value);
|
||||
return count($arr) === 2;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user