Compare commits

..

6 Commits

Author SHA1 Message Date
MI15\Win
0d7353e692 v2.0.37-20230830 2023-08-30 13:04:36 +08:00
MI15\Win
1fe39f83f4 v2.0.37-20230830 2023-08-30 12:49:45 +08:00
MI15\Win
5c7136ff0f v2.0.36-20230823 2023-08-23 16:33:53 +08:00
MI15\Win
86be0ca786 v2.0.35-20230816 2023-08-16 01:14:09 +08:00
MI15\Win
1ece1135ea v2.0.34-20230809 2023-08-09 14:52:37 +08:00
MI15\Win
cec87b24f2 v2.0.33-20230802 2023-08-02 15:57:19 +08:00
67 changed files with 2674 additions and 1135 deletions

View File

@@ -1,4 +1,4 @@
TwoNav 是一款开源免费的书签导航管理程序界面简洁安装简单使用方便。TwoNav可帮助你将浏览器书签集中式管理解决跨设备、跨平台、跨浏览器之间同步和访问困难问题做到一处部署随处访问。
TwoNav 是一款开源的书签(导航)管理程序,界面简洁,安装简单,使用方便,基础功能免费。TwoNav可帮助你将浏览器书签集中式管理解决跨设备、跨平台、跨浏览器之间同步和访问困难问题做到一处部署随处访问。
- **演示站**: [http://two.lm21.top](http://two.lm21.top)
- **仅供体验,定期清理数据** 账号密码`admin`
@@ -26,14 +26,18 @@ TwoNav 是一款开源免费的书签(导航)管理程序,界面简洁,
* 支持加密链接
* 支持分享链接
* 支持二级分类
* 支持用户分组
* 支持用户分组/权限管理
* 支持Chrome/Firefox/Edge书签批量导入
* 支持多种主题风格
* 支持批量更新链接图标/标题/描述等信息
* 支持链接信息自动识别
* 支持API
* 支持Docker部署
* 支持uTools插件
* 支持Chromium内核的[浏览器扩展]
* 支持简易文章管理
* 支持更换各种模板/支持混搭,20+个主题模板
* 安全性支持:更换登录入口/二级密码/OTP双重验证
![](https://foruda.gitee.com/images/1680680754989095293/fcc56e76_10359480.jpeg "主页预览")
![](https://foruda.gitee.com/images/1680680836189756220/8c227c34_10359480.jpeg "主题模板")

View File

@@ -66,7 +66,12 @@ if(!in_array($c,[$global_config["Register"],'ico','icon'])){
}
session_name('TwoNavSID');
if(defined('UID')){
define('is_login',is_login()); $is_login = is_login;
}
if(empty($c) || $c == 'index'){
$c = 'index';
require "./system/index.php";//主页
}elseif($c == $global_config["Register"]){
require "./system/Register.php";//注册

View File

@@ -165,6 +165,14 @@ if(!empty($_GET['type'])){
update_db("user_login_info", ["user" => $_POST['new_user_name']], ["user" => $USER['User']]);
update_db("user_log", ["user" => $_POST['new_user_name']], ["user" => $USER['User']]);
update_db("global_user", ["User" => $_POST['new_user_name']], ["ID" => $_POST['ID']],[1,'操作成功']);
}elseif($_GET['type'] == 'del_otp'){
$user_data = get_db('global_user','*',['ID'=>$_POST['ID']]);
$LoginConfig = unserialize($user_data['LoginConfig']);
if(empty($LoginConfig['totp_key'])){
msgA(['code'=>-1,'msg'=>'当前账号未开启OTP双重验证']);
}
$LoginConfig['totp_key'] = '';
update_db("global_user", ["LoginConfig" => $LoginConfig], ["ID" => $_POST['ID']],[1,'操作成功']);
}
msgA(['code'=>-1,'msg'=>'请求类型错误']);
@@ -267,6 +275,7 @@ function echo_Atool(){
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="set_pwd">改密码</a>
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="set_root">设站长</a>
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="set_user_name">改账号</a>
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="del_otp" title="移除OTP登录验证">删OTP</a>
</div>
</script>
<script src="../static/Layui/v2.8.10/layui.js"></script>
@@ -280,7 +289,7 @@ function echo_Atool(){
var table = layui.table;
var cols = [[
{field:'ID',title:'ID',width:60,sort:true}
,{title:'操作',toolbar:'#tablebar',width:175}
,{title:'操作',toolbar:'#tablebar',width:220}
,{field:'User',title:'账号',minWidth:120,templet:function(d){
return '<a style="color:#3c78d8" title="打开用户主页" target="_blank" href="../?u='+d.User+'">'+d.User+'</a>'
}}
@@ -359,6 +368,14 @@ function echo_Atool(){
}
});
});
}else if(obj.event == 'del_otp'){
$.post('./ATool.php?type=del_otp',{ID:data.ID},function(data,status){
if(data.code == 1) {
layer.msg(data.msg, {icon: 1});
}else{
layer.msg(data.msg, {icon: 5});
}
});
}
});
$('.set').click(function () {

161
system/Authenticator.php Normal file
View File

@@ -0,0 +1,161 @@
<?php
class PHPGangsta_GoogleAuthenticator
{
protected $_codeLength = 6;
public function createSecret($secretLength = 16)
{
$validChars = $this->_getBase32LookupTable();
if ($secretLength < 16 || $secretLength > 128) {
throw new Exception('Bad secret length');
}
$secret = '';
$rnd = false;
if (function_exists('random_bytes')) {
$rnd = random_bytes($secretLength);
} elseif (function_exists('mcrypt_create_iv')) {
$rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
} elseif (function_exists('openssl_random_pseudo_bytes')) {
$rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
if (!$cryptoStrong) {
$rnd = false;
}
}
if ($rnd !== false) {
for ($i = 0; $i < $secretLength; ++$i) {
$secret .= $validChars[ord($rnd[$i]) & 31];
}
} else {
throw new Exception('No source of secure random');
}
return $secret;
}
public function getCode($secret, $timeSlice = null)
{
if ($timeSlice === null) {
$timeSlice = floor(time() / 30);
}
$secretkey = $this->_base32Decode($secret);
$time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
$hm = hash_hmac('SHA1', $time, $secretkey, true);
$offset = ord(substr($hm, -1)) & 0x0F;
$hashpart = substr($hm, $offset, 4);
$value = unpack('N', $hashpart);
$value = $value[1];
$value = $value & 0x7FFFFFFF;
$modulo = pow(10, $this->_codeLength);
return str_pad($value % $modulo, $this->_codeLength, '0', STR_PAD_LEFT);
}
public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
{
$width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
$height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
$level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
$urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
if (isset($title)) {
$urlencoded .= urlencode('&issuer='.urlencode($title));
}
return "https://api.qrserver.com/v1/create-qr-code/?data=$urlencoded&size=${width}x${height}&ecc=$level";
}
public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
{
if ($currentTimeSlice === null) {
$currentTimeSlice = floor(time() / 30);
}
if (strlen($code) != 6) {
return false;
}
for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
$calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
if ($this->timingSafeEquals($calculatedCode, $code)) {
return true;
}
}
return false;
}
public function setCodeLength($length)
{
$this->_codeLength = $length;
return $this;
}
protected function _base32Decode($secret)
{
if (empty($secret)) {
return '';
}
$base32chars = $this->_getBase32LookupTable();
$base32charsFlipped = array_flip($base32chars);
$paddingCharCount = substr_count($secret, $base32chars[32]);
$allowedValues = array(6, 4, 3, 1, 0);
if (!in_array($paddingCharCount, $allowedValues)) {
return false;
}
for ($i = 0; $i < 4; ++$i) {
if ($paddingCharCount == $allowedValues[$i] &&
substr($secret, -($allowedValues[$i])) != str_repeat($base32chars[32], $allowedValues[$i])) {
return false;
}
}
$secret = str_replace('=', '', $secret);
$secret = str_split($secret);
$binaryString = '';
for ($i = 0; $i < count($secret); $i = $i + 8) {
$x = '';
if (!in_array($secret[$i], $base32chars)) {
return false;
}
for ($j = 0; $j < 8; ++$j) {
$x .= str_pad(base_convert(@$base32charsFlipped[@$secret[$i + $j]], 10, 2), 5, '0', STR_PAD_LEFT);
}
$eightBits = str_split($x, 8);
for ($z = 0; $z < count($eightBits); ++$z) {
$binaryString .= (($y = chr(base_convert($eightBits[$z], 2, 10))) || ord($y) == 48) ? $y : '';
}
}
return $binaryString;
}
protected function _getBase32LookupTable()
{
return array(
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '2', '3', '4', '5', '6', '7',
'=',
);
}
private function timingSafeEquals($safeString, $userString)
{
if (function_exists('hash_equals')) {
return hash_equals($safeString, $userString);
}
$safeLen = strlen($safeString);
$userLen = strlen($userString);
if ($userLen != $safeLen) {
return false;
}
$result = 0;
for ($i = 0; $i < $userLen; ++$i) {
$result |= (ord($safeString[$i]) ^ ord($userString[$i]));
}
return $result === 0;
}
}

View File

@@ -1,13 +1,5 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}
$sql =<<<EOF
CREATE TABLE IF NOT EXISTS `user_article_categorys` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`uid` varchar(32) NOT NULL COMMENT '用户id',
`name` varchar(64) NOT NULL COMMENT '名称',
`weight` int(11) NOT NULL DEFAULT '0' COMMENT '权重',
`add_time` int(10) UNSIGNED NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `user_article_list` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,

View File

@@ -280,15 +280,6 @@ CREATE TABLE IF NOT EXISTS `global_icon` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- 用户文章分类
CREATE TABLE IF NOT EXISTS `user_article_categorys` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`uid` varchar(32) NOT NULL COMMENT '用户id',
`name` varchar(64) NOT NULL COMMENT '名称',
`weight` int(11) NOT NULL DEFAULT '0' COMMENT '权重',
`add_time` int(10) UNSIGNED NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- 用户文章列表
CREATE TABLE IF NOT EXISTS `user_article_list` (

View File

@@ -4,21 +4,10 @@ if($global_config['Maintenance'] != 0){Amsg(-1,'网站正在进行维护,请稍
$global_templates = unserialize(get_db("global_config",'v', ["k" => "s_templates"]));
//如果是Get请求则载入登录模板
if($_SERVER['REQUEST_METHOD'] === 'GET'){
$t_name = $global_templates['register'];
$t_dir = "./templates/register/".$t_name; //模板目录
$t_path = "./templates/register/{$t_name}/index.php"; //模板路径
//如果不存在则使用默认模板
if(!file_exists($t_path)){
$t_name = 'default';
$t_dir ='./templates/register/default';
$t_path = './templates/register/default/index.php';
$global_templates['register'] = 'default';
update_db("global_config", ["v" => $global_templates], ["k"=>"s_templates"]);
}
$copyright = empty($global_config['copyright'])?'<a target="_blank" href="https://gitee.com/tznb/TwoNav">Copyright © TwoNav</a>':$global_config['copyright'];
$ICP = empty($global_config['ICP'])?'':'<a target="_blank" href="https://beian.miit.gov.cn">'.$global_config['ICP'].'</a>';
$reg_tips = get_db('global_config','v',['k'=>'reg_tips']);
require $t_path;
//通用数据初始化
require DIR."/system/templates.php";
$reg_tips = get_db('global_config','v',['k'=>'reg_tips']); //注册提示
require $index_path;
exit;
}

View File

@@ -1,14 +1,5 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}
$sql =<<<EOF
CREATE TABLE IF NOT EXISTS "user_article_categorys" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"uid" integer(10) NOT NULL,
"name" text NOT NULL DEFAULT "",
"weight" integer NOT NULL,
"add_time" integer(10) NOT NULL,
CONSTRAINT "id" UNIQUE ("id" ASC)
);
CREATE TABLE "user_article_list" (
"id" integer PRIMARY KEY AUTOINCREMENT,
"uid" integer(10) NOT NULL,

View File

@@ -245,15 +245,7 @@ CREATE TABLE IF NOT EXISTS "global_icon" (
"extend" text NOT NULL DEFAULT "",
CONSTRAINT "id" UNIQUE ("id" ASC)
);
-- 用户文章分类
CREATE TABLE IF NOT EXISTS "user_article_categorys" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"uid" integer(10) NOT NULL,
"name" text NOT NULL DEFAULT "",
"weight" integer NOT NULL,
"add_time" integer(10) NOT NULL,
CONSTRAINT "id" UNIQUE ("id" ASC)
);
-- 用户文章列表
CREATE TABLE "user_article_list" (
"id" integer PRIMARY KEY AUTOINCREMENT,

View File

@@ -392,7 +392,7 @@ if($_GET['type'] == 'upload'){
}
//数据库清除
if(!empty($_POST['TABLE'])){
$TABLE = ["user_categorys","user_links","user_pwd_group","user_share","user_apply"];
$TABLE = ["user_categorys","user_links","user_pwd_group","user_share","user_apply","user_article_list"];
foreach($_POST['TABLE'] as $key =>$value){
if(in_array($key,$TABLE)){
delete_db($key,['uid'=>UID]);
@@ -418,7 +418,7 @@ if($_GET['type'] == 'upload'){
//文件删除
if(!empty($_POST['FILE'])){
$FILE = ["MessageBoard","favicon"];
$FILE = ["MessageBoard","favicon","upload"];
foreach($_POST['FILE'] as $key =>$value){
$path = DIR.'/data/user/'.U.'/'.$key;
if(in_array($key,$FILE) && is_dir($path)){

View File

@@ -47,7 +47,7 @@ if(!defined('DIR')){
$info['file_db'] = $info['backup_dir'] .'/'. $info['file'].'.db3';
$info['file_info'] = $info['backup_dir'] .'/'. $info['file'].'.info';
$info['file_gz'] = $info['backup_dir'] .'/'. $info['file'].'.tar';
$info['table_arr'] = ['user_config','user_categorys','user_links','user_pwd_group','user_apply','user_share'];
$info['table_arr'] = ['user_config','user_categorys','user_links','user_pwd_group','user_apply','user_share','user_article_list'];
$info['lock'] = DIR.'/data/user/'.U.'/lock.'.UID;
if (!extension_loaded('phar')) {
msg(-1,'不支持phar扩展');
@@ -167,7 +167,7 @@ if(!defined('DIR')){
}
//遍历删除用户数据
$info['table_arr'] = ['user_config','user_categorys','user_links','user_pwd_group','user_apply','user_share'];
$info['table_arr'] = ['user_config','user_categorys','user_links','user_pwd_group','user_apply','user_share','user_article_list'];
foreach($info['table_arr'] as $table_name){
//删除数据
@@ -186,8 +186,15 @@ if(!defined('DIR')){
$where['name'] = $table_name;
$where['LIMIT'] = [($page - 1) * $limit,$limit];
$datas = $MyDB->select('backup','data',$where);
foreach($datas as $data){
foreach($datas as $key => $data){
$data = unserialize($data);
//处理null
foreach ($data as $key => $value) {
if ($value === null) {
$data[$key] = '';
}
}
if(isset($data['id'])){
unset($data['id']);
}

View File

@@ -4,14 +4,15 @@ $page = trim($_GET['page']); //获取请求参数
$Ver = !Debug?SysVer:SysVer.'.'.time(); //版本
$LoginConfig = unserialize($USER_DB['LoginConfig']); //登录配置
define('offline',$global_config['offline'] == 1); //是否离线模式
define('is_login',is_login()); //是否已登录
//未登录,载入登录提示页
if(!is_login){
require(DIR.'/templates/admin/page/LoginPrompt.php');
exit;
}//已登录,检查是否需要验证二级密码
elseif(!empty($LoginConfig['Password2']) && !Check_Password2($LoginConfig)){
require DIR.'/templates/admin/other/verify_pwd2.php';
$c = 'verify';$_GET['c'] = 'pwd2';
require DIR."/system/templates.php";
require $index_path;
exit;
}
@@ -64,7 +65,7 @@ if($page == 'config_home'){
$theme_config = empty($theme_config['config']) ? []:$theme_config['config'];
//读取用户主题配置
if(!in_array($_GET['fn'],['home','login','register','transit','guide'])){
if(!in_array($_GET['fn'],['home','login','register','transit','guide','article','verify','guestbook','apply'])){
msg(-1,"参数错误");
}
$theme_config_db = get_db('user_config','v',['t'=>'theme_'.$_GET['fn'],'k'=>$theme,'uid'=>UID]);
@@ -178,64 +179,6 @@ if( $page == 'theme_home' || $page == 'theme_login' || $page == 'theme_transit'
}
}
//菜单接口
if ($page == 'menu') {
$menu = [];
if(check_purview('site_info',1)){
array_push($menu,['title'=>'站点设置','href'=>'SiteSetting','icon'=>'fa fa-cog']);
}
if(check_purview('theme_in',1)){
array_push($menu,['title'=>'主题设置','href'=>'theme_home','icon'=>'fa fa-magic']);
}
array_push($menu,
['title'=>'分类管理','href'=>'category_list','icon'=>'fa fa-list-ul'],
['title'=>'加密管理','href'=>'pwd_group','icon'=>'fa fa-lock'],
['title'=>'链接管理','icon'=>'fa fa-folder-open-o','href'=>'','child'=>
[
['title'=>'链接列表','href'=>'link_list','icon'=>'fa fa-link'],
['title'=>'添加链接','href'=>'link_add','icon'=>'fa fa-plus-square-o'],
['title'=>'书签分享','href'=>'share','icon'=>'fa fa-external-link'],
['title'=>'导出导入','href'=>'data_control','icon'=>'fa fa-retweet'],
]
]);
//扩展功能
$extend = [];
if($global_config['apply'] == 1 && check_purview('apply',1)){
array_push($extend,['title'=>'收录管理','href'=>'expand/apply-admin','icon'=>'fa fa-pencil']);
}
if($global_config['guestbook'] == 1 && check_purview('guestbook',1)){
array_push($extend,['title'=>'留言管理','href'=>'expand/guestbook-admin','icon'=>'fa fa-commenting-o']);
}
if($global_config['article'] == 1 && check_purview('article',1)){
array_push($extend,['title'=>'文章管理','href'=>'expand/article-list','icon'=>'fa fa-file-text-o']);
}
if(!empty($extend)){
$extend = ['title'=>'扩展功能','icon'=>'fa fa-folder-open-o','href'=>'','child'=> $extend];
array_push($menu,$extend);
}
//如果是管理员则追加菜单
if($USER_DB['UserGroup'] == 'root'){
array_push($menu,
['title'=>'网站管理','icon'=>'fa fa-wrench','href'=>'','child'=>
[
['title'=>'系统设置','href'=>'root/sys_setting','icon'=>'fa fa-gears'],
['title'=>'授权管理','href'=>'root/vip','icon'=>'fa fa-diamond'],
//['title'=>'默认设置','href'=>'root/default_setting','icon'=>'fa fa-heart-o'],
['title'=>'用户管理','href'=>'root/user_control','icon'=>'fa fa-user'],
['title'=>'用户分组','href'=>'root/users_control','icon'=>'fa fa-users'],
['title'=>'注册管理','href'=>'root/reg_control','icon'=>'fa fa-user-plus'],
['title'=>'站长工具','href'=>'root/tool','icon'=>'fa fa-exclamation-triangle'],
]
]);
}
$init = array( 'homeInfo'=>['title'=>'概要','href'=>'home'],'logoInfo'=>['title'=>'TwoNav','image'=>'./templates/admin/img/logo.png','href'=>'./?u='.U],'menuInfo'=>$menu);
header('Content-Type:application/json; charset=utf-8');
exit(json_encode($init));
}
//不带参数是载入框架
if(empty($page)){
$site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));

View File

@@ -4,52 +4,48 @@ header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Access-Control-Allow-Private-Network,Content-Type, AccessToken, X-CSRF-Token, Authorization, Token,X-Token,X-Cid");
AccessControl();
//鉴权验证 Cookie验证通过,验证二级密码,Cookie验证失败时尝试验证token
if(!empty(trim($_REQUEST['token']))){ $_COOKIE = []; } //兼容浏览器插件,避免干扰
//获取请求方法
$method = htmlspecialchars(trim($_GET['method']),ENT_QUOTES);
$LoginConfig = unserialize($USER_DB['LoginConfig']);
$api_model = $LoginConfig['api_model']; //API模式
if(!is_login()){
//没登录,根据API模式来限制
$api_model = $LoginConfig['api_model']; //API模式
$token = trim($_REQUEST['token']); //尝试获取令牌
if( empty($USER_DB['Token']) && $api_model != 'compatible+open' ){
Amsg(-1,'未设置token');
//没登录,尝试验证token
if( empty($USER_DB['Token']) ){
msg(-1,'鉴权失败:未登录且未设置token');
}
//获取请求token
$token = trim($_REQUEST['token']);
if(empty($token)){
if($api_model != 'compatible+open'){
Amsg(-1,'非开放模式,token不能为空!');
}
if(in_array($method,['link_list','get_a_link','q_category_link','category_list','get_a_category','check_login','app_info'])){
define('Access_Type','open'); //数据访问类型:仅开放
require 'api_compatible.php';
exit;
}else{
Amsg(-1,'token为空时不允许访问此接口');
}
msg(-1,'鉴权失败:未登录且请求未携带token');
}else{
if($token === $USER_DB['Token']){
define('Access_Type','all');
//验证通过
}else{
Amsg(-1,'token验证失败');
msg(-1,'鉴权失败:未登录且token错误');
}
}
if($api_model === 'compatible' || $api_model ==='compatible+open'){
require 'api_compatible.php';
}
//Cookie登录验证OK,验证二级密码
}elseif(Check_Password2($LoginConfig)){
// Cookie 二级密码验证成功(未设置时也认为成功)
}else{
msg(-1,'请先验证二级密码!');
}
//是否加载扩展API
//扩展API
if($global_config['api_extend'] == 1 && is_file('./system/api_extend.php')){
require './system/api_extend.php';
}
//兼容API
$compatible_list = ['add_link','edit_link','del_link','link_list','get_a_link','q_category_link','category_list','get_a_category','add_category','edit_category','app_info','check_login','global_search'];
if(in_array($api_model,['compatible','compatible+open']) && in_array($method,$compatible_list)){
require 'api_compatible.php';
exit;
}
//站长相关方法名
$root = ['write_subscribe','write_sys_settings','write_default_settings','read_user_list','write_user_info','read_purview_list','read_users_list','write_users','read_regcode_list','write_regcode','other_upsys','read_log','other_root'];
if(in_array($method,$root)){
@@ -63,9 +59,7 @@ if(in_array($method,$root)){
if ( preg_match("/^read_|^write_|^other_/",$method) && function_exists($method) ) {
$method();
}else{
if($api_model == 'security'){
Amsg(-1,'方法未找到 >> '.$method);
}
Amsg(-1,'方法未找到 >> '.$method);
}
//读分类列表
@@ -661,7 +655,7 @@ function write_link(){
unset($data['keywords']);
}
//更新数据
update_db('user_links',$data,['uid'=>UID,'lid'=>intval($_POST['lid']) ]);
update_db('user_links',$data,['uid'=>UID,'lid'=>$lid ]);
msgA(['code'=>1,'msg'=>'修改成功','icon' => $icon]);
//删除
}elseif($_GET['type'] === 'del'){
@@ -686,10 +680,6 @@ function write_link(){
update_db('user_links',['weight'=>$key[1]],['uid'=>UID,'lid'=>$key[0]]);
}
msg(1,'保存成功');
msg(-1,'未支持');
//私有切换
}elseif($_GET['type'] === 'property_sw' ){
update_db('user_links',['property'=>intval($_POST['property']) ],['uid'=>UID,'lid'=>intval($_POST['lid']) ],[1,'保存成功']);
@@ -953,11 +943,11 @@ function write_security_setting(){
'HttpOnly'=>['int'=>true,'min'=>0,'max'=>1,'msg'=>'HttpOnly参数错误'],
'KeySecurity'=>['int'=>true,'min'=>0,'max'=>2,'msg'=>'Key安全参数错误'],
'KeyClear'=>['int'=>true,'min'=>1,'max'=>60,'msg'=>'Key清理参数错误'],
'api_model'=>['v'=>['security','compatible','compatible+open'],'msg'=>'API模式参数错误'],
'api_model'=>['v'=>['security','compatible'],'msg'=>'API模式参数错误'],
'login_page'=>['v'=>['admin','index','auto'],'msg'=>'登录成功参数错误'],
'Password2'=>['empty'=>true]
];
$LoginConfig = unserialize($USER_DB['LoginConfig']);
foreach ($datas as $key => $data){
if($data['int']){
$LoginConfig[$key] = ($_POST[$key] >= $data['min'] && $_POST[$key] <= $data['max'])?intval($_POST[$key]):msg(-1,$data['msg']);
@@ -1181,20 +1171,21 @@ function write_transit_setting(){
'admin_stay_time'=>['int'=>true,'min'=>0,'max'=>60,'msg'=>'管理员停留时间范围0-60'],
'default_keywords'=>['int'=>true,'min'=>0,'max'=>1,'msg'=>'默认关键字参数错误']
];
foreach ($datas as $key => $data){
if($data['int']){
$s[$key] = ($_POST[$key] >= $data['min'] && $_POST[$key] <= $data['max'])?intval($_POST[$key]):msg(-1,$data['msg']);
}elseif(isset($data['v'])){
$s[$key] = in_array($_POST[$key],$data['v']) ? $_POST[$key]:msg(-1,$data['msg']);
}else{
$s[$key] = $data['empty']?$_POST[$key]:(!empty($_POST[$key])?$_POST[$key]:msg(-1,$data['msg']));
}
}
$s = Post_data_filter($datas);
write_user_config('s_transition_page',$s,'config','过渡页配置');
msg(1,"保存成功!");
}
//写验证页配置
function write_verify_page(){
$datas = [
'link_tip'=>['empty'=>true],
'share_tip'=>['empty'=>true]
];
$s = Post_data_filter($datas);
write_user_config('s_verify_page',$s,'config','验证页配置');
msg(1,"保存成功!");
}
//修改密码
function write_user_password(){
@@ -1217,6 +1208,65 @@ function write_user_password(){
msg(1,'修改成功');
}
//读双重验证
function read_totp(){
global $USER_DB;
if($USER_DB['Password'] !== Get_MD5_Password($_POST['Password'],$USER_DB['RegTime'])){
msg(-1102,'密码错误,请核对后再试!');
}
$LoginConfig = unserialize($USER_DB['LoginConfig']);
if(empty($LoginConfig['totp_key'])){
require DIR . '/system/Authenticator.php';
$totp = new PHPGangsta_GoogleAuthenticator();
$key = $totp->createSecret();
msgA(['code'=>2,'msg'=>'未开启双重验证','key'=> $key ]);
}
msgA(['code'=>1,'msg'=>'已开启双重验证']);
}
//写双重验证
function write_totp(){
global $USER_DB;
if($USER_DB['Password'] !== Get_MD5_Password($_POST['Password'],$USER_DB['RegTime'])){
msg(-1102,'密码错误,请核对后再试!');
}
if($_GET['type'] === 'delete'){ //删除双重验证
$LoginConfig = unserialize($USER_DB['LoginConfig']);
if(empty($LoginConfig['totp_key'])){
msgA(['code'=>-1,'msg'=>'未开启双重验证',]);
}
$LoginConfig['totp_key'] = '';
update_db("global_user", ["LoginConfig"=>$LoginConfig],["ID"=>UID],[1,'操作成功']);
}elseif($_GET['type'] === 'set'){ //设置双重验证
//必填项验证
if(empty($_POST['key'])){
msgA(['code'=>-1,'msg'=>'Key不能为空']);
}elseif(empty($_POST['code'])){
msgA(['code'=>-1,'msg'=>'验证码不能为空']);
}
$LoginConfig = unserialize($USER_DB['LoginConfig']);
if(!empty($LoginConfig['totp_key'])){
msgA(['code'=>-1,'msg'=>'已开启双重验证,无法继续开启!']);
}
//载入totp库
require DIR . '/system/Authenticator.php';
$totp = new PHPGangsta_GoogleAuthenticator();
$checkResult = $totp->verifyCode($_POST['key'], $_POST['code'], 2);
if(!$checkResult){
msgA(['code'=>-1,'msg'=>'验证失败,请重试']);
}
//写入数据库
$LoginConfig = unserialize($USER_DB['LoginConfig']);
$LoginConfig['totp_key'] = $_POST['key'];
update_db("global_user", ["LoginConfig"=>$LoginConfig],["ID"=>UID],[1,'操作成功']);
}else{
msg(-1,'请求参数有误');
}
}
//查Token
function read_token(){
global $USER_DB;
@@ -1305,10 +1355,137 @@ function other_testing_link(){
msgA(['code' => 0 ,'StatusCode'=> $code]);
}
//读主题信息
function read_theme(){
global $global_config;
global $USER_DB;
// 检查权限
if(!check_purview('theme_in',1)){
msg(-1,'无权限');
}
$check_dirs = ['home','login','transit','register','guide','article','apply','verify','guestbook'];
$request_dir = $_GET['dir'];
if(in_array($request_dir,$check_dirs)){
if(in_array($request_dir,['register','guide']) && $USER_DB['UserGroup'] != 'root' ){
msg(-1,'管理此模板需管理员权限');
}
}else{
msg(-1,'dir参数错误');
}
$son_dirs = get_dir_list(DIR.'/templates/'.$request_dir);
foreach ($son_dirs as $son_dir) {
$path = DIR.'/templates/'.$request_dir.'/'.$son_dir; //目录完整路径
//没有信息文件则跳过
if(!is_file($path.'/info.json') ) {continue;}
//读取主题信息
$themes[$son_dir] = json_decode(@file_get_contents($path.'/info.json'),true);
//是否支持配置
$themes[$son_dir]['config'] = is_file($path.'/config.php') ? '1':'0';
//预览图优先顺序:png>jpg>info>default
if(is_file($path.'/screenshot.jpg')){
$themes[$son_dir]['screenshot'] = "./templates/$request_dir/$son_dir/screenshot.jpg";
}elseif(is_file($path.'/screenshot.png')){
$themes[$son_dir]['screenshot'] = "./templates/$request_dir/$son_dir/screenshot.png";
}elseif(empty($themes[$son_dir]['screenshot'])){
$themes[$son_dir]['screenshot'] = "./templates/admin/static/42ed3ef2c4a50f6d.png";
}
}
function filter($arr){
foreach($arr as $key => $data){
$new[$key]['name'] = $data['name'] ?? 'null';
$new[$key]['description']= $data['description'] ?? 'null';
$new[$key]['homepage']= $data['homepage'] ?? 'null';
$new[$key]['version']= $data['version'] ?? 'null';
$new[$key]['update']= $data['update'] ?? 'null';
$new[$key]['author']= $data['author'] ?? 'null';
$new[$key]['screenshot']= $data['screenshot'] ?? 'null';
$new[$key]['config'] = $data['config'] ?? '0';
$new[$key]['state'] = $data['up'] == 1 ? 'up' : (empty($data['dir']) ? 'local' : 'dw');
}
return $new;
}
//在线主题处理
if ( !$global_config['offline'] && $USER_DB['UserGroup'] === 'root'){
if(preg_match('/^v.+-(\d{8})$/i',SysVer,$matches)){
$sysver = intval( $matches[1] );//取版本中的日期
}else{
msg(-1,'获取程序版本异常');
}
//读取缓存
$page = 'theme_'.$request_dir;
$template = get_db('global_config','v',['k'=>$page.'_cache']);
if(!empty($template)){
$data = json_decode($template, true);
}
//没有缓存 或 禁止缓存 或 缓存过时
if(empty($template) || $_GET['cache'] === 'no' || time() - $data["time"] > 1800 ){
$urls = [
"lm21" => "https://update.lm21.top/TwoNav/{$request_dir}_template.json",
"gitee" => "https://gitee.com/tznb/twonav_updata/raw/master/{$request_dir}_template.json"
];
$Source = $global_config['Update_Source'] ?? '';
if (!empty($Source) && isset($urls[$Source])) {
$urls = [$Source => $urls[$Source]];
}
}else{
$cache = true;
}
//读取超时参数
$overtime = !isset($global_config['Update_Overtime']) ? 3 : ($global_config['Update_Overtime'] < 3 || $global_config['Update_Overtime'] > 60 ? 3 : $global_config['Update_Overtime']);
//远程获取
foreach($urls as $key => $url){
$Res = ccurl($url,$overtime);
$data = json_decode($Res["content"], true);
if($data["code"] == 200 ){ //如果获取成功
$data["time"] = time(); //记录当前时间
write_global_config($page.'_cache',json_encode($data),$request_dir.'_模板缓存');
break; //跳出循环.
}
}
//解析
foreach($data["data"] as $key){
$path = DIR.'/templates/'.$request_dir.'/'.$key["dir"];
if( is_dir($path) ) { //本地存在
$value = $key["dir"];
//检查是否可以更新
$update = str_replace('/','',$themes[$value]['update']); //本地主题版本
$update_new = str_replace('/','',$key["update"]); //远程主题版本
if( $sysver >= intval($key["low"]) && $sysver <= intval($key["high"]) && $update < $update_new ){
$themes[$value]['up'] = '1';
}
}else{
//判断是否适配当前系统版本
if( $sysver >= intval($key["low"]) && $sysver <= intval($key["high"]) ){
$value = $key["dir"];
$themes[$value] = json_decode(json_encode($key),true);
}
}
}
}
//取正在使用的模板
$s_templates = unserialize(get_db("user_config", "v", ["uid"=>UID,"k"=>"s_templates"]));
if($request_dir == 'home'){
$current['home_pad'] = $s_templates['home_pad'] ?? 'default';
$current['home_pc'] = $s_templates['home_pc'] ?? 'default';
}else{
$current[$request_dir] = $s_templates[$request_dir] ?? 'default';
}
$themes = filter($themes);
msgA(['code'=>1,'data'=>$themes,'current'=>$current,'referrer'=>($data['referrer'] ?? '')]);
}
//主题下载/更新/删除
function write_theme(){
global $global_config;
$fn = $_POST['fn'];if($_GET['type'] != 'config' && !in_array($fn,['home','login','transit','register','guide','article'])){msg(-1,'fn参数错误');}
$fn = $_POST['fn'];if($_GET['type'] != 'config' && !in_array($fn,['home','login','transit','register','guide','article','verify','guestbook','apply'])){msg(-1,'fn参数错误');}
if($_GET['type'] == 'download'){
is_root();
if($global_config['offline']){msg(-1,"离线模式禁止下载主题!");} //离线模式
@@ -1413,6 +1590,11 @@ function write_theme(){
//读取用户模板配置
require DIR."/system/templates.php";
if($fn == 'register' || $fn == 'guide'){
$global_templates[$fn] = $name;
update_db('global_config',['v'=>$global_templates],['k'=>'s_templates'],[1,'操作成功']);
}
//判断设置的类型
if($fn == 'home'){
if( $type == 'PC/Pad'){
@@ -1425,18 +1607,8 @@ function write_theme(){
}else{
msg(-1,'参数错误');
}
}elseif($fn == 'login'){
$s_templates['login'] = $name;
}elseif($fn == 'transit'){
$s_templates['transit'] = $name;
}elseif($fn == 'article'){
$s_templates['article'] = $name;
}elseif($fn == 'register'){
$global_templates['register'] = $name;
update_db('global_config',['v'=>$global_templates],['k'=>'s_templates'],[1,'注册模板设置成功']);
}elseif($fn == 'guide'){
$global_templates['guide'] = $name;
update_db('global_config',['v'=>$global_templates],['k'=>'s_templates'],[1,'引导页模板设置成功']);
}else{
$s_templates[$fn] = $name;
}
//更新数据
update_db('user_config',['v'=>$s_templates],['uid'=>UID,'k'=>'s_templates'],[1,'设置成功']);
@@ -1455,7 +1627,7 @@ function write_theme(){
msg(-1,"获取模板类型错误");
}
$fn = empty($GET['fn']) ? $_GET['template_type'] : $GET['fn'];
if(!in_array($fn,['home','login','register','transit','guide','article'])){
if(!in_array($fn,['home','login','transit','register','guide','article','verify','guestbook','apply'])){
msg(-1,"参数错误");
}
//0420 END
@@ -1767,6 +1939,75 @@ function read_data(){
$data = ['dates'=>$dates,'day_data'=>$day_data];
msgA(['code'=>1,'data'=>$data]);
}elseif($_GET['type'] == 'tongji_ip_list'){
$days = isset($_GET['date']) && !empty($_GET['date']) ? $_GET['date'] : 7;
$dates = [];
for ($i = 0; $i < $days; $i++) {
$date = date('Ymd', strtotime("-$i days"));
$dates[] = $date;
}
$dates = array_reverse($dates);
$day_data = [];
foreach ($dates as $date) {
$list = get_db('user_count', 'e', ['uid' => UID, 'k' => $date, 't' => 'ip_list']);
$list = unserialize($list);
$day_data[$date] = empty($list) ? [] : $list ;
}
msgA(['code'=>1,'data'=>$day_data]);
}elseif($_GET['type'] == 'menu'){
global $global_config;
$menu = [];
if(check_purview('site_info',1)){
array_push($menu,['title'=>'站点设置','href'=>'SiteSetting','icon'=>'fa fa-cog']);
}
if(check_purview('theme_in',1)){
array_push($menu,['title'=>'主题管理','href'=>'theme','icon'=>'fa fa-magic']);
}
array_push($menu,
['title'=>'分类管理','href'=>'category_list','icon'=>'fa fa-list-ul'],
['title'=>'加密管理','href'=>'pwd_group','icon'=>'fa fa-lock'],
['title'=>'链接管理','icon'=>'fa fa-folder-open-o','href'=>'','child'=>
[
['title'=>'链接列表','href'=>'link_list','icon'=>'fa fa-link'],
['title'=>'添加链接','href'=>'link_add','icon'=>'fa fa-plus-square-o'],
['title'=>'书签分享','href'=>'share','icon'=>'fa fa-external-link'],
['title'=>'导出导入','href'=>'data_control','icon'=>'fa fa-retweet'],
]
]);
//扩展功能
$extend = [];
if($global_config['apply'] == 1 && check_purview('apply',1)){
array_push($extend,['title'=>'收录管理','href'=>'expand/apply-admin','icon'=>'fa fa-pencil']);
}
if($global_config['guestbook'] == 1 && check_purview('guestbook',1)){
array_push($extend,['title'=>'留言管理','href'=>'expand/guestbook-admin','icon'=>'fa fa-commenting-o']);
}
if($global_config['article'] > 0 && check_purview('article',1)){
array_push($extend,['title'=>'文章管理','href'=>'expand/article-list','icon'=>'fa fa-file-text-o']);
}
if(!empty($extend)){
$extend = ['title'=>'扩展功能','icon'=>'fa fa-folder-open-o','href'=>'','child'=> $extend];
array_push($menu,$extend);
}
//如果是管理员则追加菜单
if($USER_DB['UserGroup'] == 'root'){
array_push($menu,
['title'=>'网站管理','icon'=>'fa fa-wrench','href'=>'','child'=>
[
['title'=>'系统设置','href'=>'root/sys_setting','icon'=>'fa fa-gears'],
['title'=>'授权管理','href'=>'root/vip','icon'=>'fa fa-diamond'],
['title'=>'用户管理','href'=>'root/user_control','icon'=>'fa fa-user'],
['title'=>'用户分组','href'=>'root/users_control','icon'=>'fa fa-users'],
['title'=>'注册管理','href'=>'root/reg_control','icon'=>'fa fa-user-plus'],
['title'=>'站长工具','href'=>'root/tool','icon'=>'fa fa-exclamation-triangle'],
]
]);
}
$init = array( 'homeInfo'=>['title'=>'概要','href'=>'home'],'logoInfo'=>['title'=>'TwoNav','image'=>'./templates/admin/img/logo.png','href'=>'./?u='.U],'menuInfo'=>$menu);
msgA($init);
}
}
@@ -1818,3 +2059,17 @@ function other_get_link_info(){
$link['description'] = $info['site_description'];
msgA(['code'=>1,'data'=>$link]);
}
//POST数据过滤
function Post_data_filter($datas){
foreach ($datas as $key => $data){
if($data['int']){
$s[$key] = ($_POST[$key] >= $data['min'] && $_POST[$key] <= $data['max'])?intval($_POST[$key]):msg(-1,$data['msg']);
}elseif(isset($data['v'])){
$s[$key] = in_array($_POST[$key],$data['v']) ? $_POST[$key]:msg(-1,$data['msg']);
}else{
$s[$key] = $data['empty']?$_POST[$key]:(!empty($_POST[$key])?$_POST[$key]:msg(-1,$data['msg']));
}
}
return $s;
}

View File

@@ -3,7 +3,7 @@
$type = htmlspecialchars(trim($_GET['type']),ENT_QUOTES);
if (function_exists($type) ) {
if($GLOBALS['global_config']['article'] != 1 || !check_purview('article',1)){
if($GLOBALS['global_config']['article'] < 1 || !check_purview('article',1)){
msg(-1,'无权限');
}
$type();
@@ -23,7 +23,7 @@ function uploadImage(){
//取后缀并判断是否支持
$suffix = strtolower(end(explode('.',$_FILES["file"]["name"])));
if(!preg_match('/^(jpg|png|gif|bmp|jpeg|svg)$/',$suffix)){
if(!preg_match('/^(jpg|png|gif|bmp|jpeg|svg|webp)$/',$suffix)){
@unlink($_FILES["file"]["tmp_name"]);
msgA(['errno'=>-1,'message'=>'文件格式不被支持']);
}
@@ -46,7 +46,26 @@ function uploadImage(){
msgA(['errno'=>0,'data'=>['url'=>"./data/user/{$u}/upload/{$ym}/$tmp_name",'alt'=>$_FILES["file"]["name"],'href'=>''],'message'=>'上传成功']);
}
}
//删除图片
function deleteImage(){
global $u;
if(empty($_POST['path'])){
msg(-1,'请求参数错误');
}
$path = $_POST['path'];
$pattern = "/^\.\/data\/user\/{$u}\/upload\/\d{6}\/AI_[A-Za-z0-9_]+\.(jpg|png|gif|bmp|jpeg|svg|webp)$/i";
if(preg_match($pattern,$path) && is_file($path)){
@unlink($path);
}else{
msg(-1,'请求参数错误');
}
//需考虑编辑文章删除封面时未点击保存的情况
if(is_file($path)){
msg(-1,'删除失败');
}else{
msg(1,'删除成功');
}
}
//上传视频
function uploadVideo(){
msgA(['errno'=>-1,'message'=>'未开放']);
@@ -107,25 +126,26 @@ function article_list(){
$limit = empty(intval($_REQUEST['limit'])) ? 50 : intval($_REQUEST['limit']);
$offset = ($page - 1) * $limit; //起始行号
$where['LIMIT'] = [$offset,$limit];
$where['ORDER']['weight'] = 'ASC';
$datas = select_db('user_article_list',['id','title','category','category_name','state','password','top','add_time','up_time','browse_count','summary'],$where);
$categorys = select_db('user_article_categorys',['id','name'],['uid'=>UID]);
foreach (select_db('user_article_categorys',['id','name'],['uid'=>UID]) as $data) {
$categorys[$data['id']] = $data['name'];
}
$datas = select_db('user_article_list',['id','title','category','state','password','top','add_time','up_time','browse_count','summary','cover'],$where);
//查询分类
$categorys = select_db('user_categorys',['cid(id)','name'],['uid'=>UID]);
$categorys = array_column($categorys,'name','id');
//为文章添加分类名称
foreach ($datas as &$data) {
$data['category_name'] = $categorys[$data['category']];
$data['category_name'] = $categorys[$data['category']] ?? 'Null';
}
msgA(['code'=>1,'count'=>$count,'data'=>$datas]);
}
//保存文章
function save_article(){
check_category($_POST['category']);$time = time();
if(empty($_POST['category']) || !has_db('user_categorys',['uid'=>UID,'cid'=>$_POST['category']])){
msg(-1,'分类不存在');
}
$time = time();
//id为空,添加文章
if(empty($_POST['id'])){
insert_db('user_article_list',[
'uid'=>UID,
@@ -139,9 +159,10 @@ function save_article(){
'browse_count'=>0,
'summary'=>$_POST['summary'],
'content'=>$_POST['content'],
'cover'=>'',
'cover'=>$_POST['cover_url'],
'extend'=>''
],[1,'保存成功']);
],[1,'保存成功']);
//存在id,更新文章数据
}else{
if(!has_db('user_article_list',['uid'=>UID,'id'=>$_POST['id']])){
msg(-1,'文章id错误');
@@ -153,7 +174,8 @@ function save_article(){
'up_time'=>$time,
'summary'=>$_POST['summary'],
'content'=>$_POST['content'],
],['uid'=>UID,'id'=>$_POST['id']],[1,'保存成功']);
'cover'=>$_POST['cover_url']
],['uid'=>UID,'id'=>$_POST['id']],[1,'保存成功']);
}
@@ -161,50 +183,40 @@ function save_article(){
//删除文章
function del_article(){
$id = json_decode($_POST['id']);
delete_db('user_article_list',['uid'=>UID,'id'=>$id],[1,'删除成功']);
if(empty($id)) msg(-1,'参数错误');
delete_db('user_article_list',['uid'=>UID,'id'=>$id],[1,'操作成功']);
}
//分类列表
function category_list(){
$where['uid'] = UID;
$where['ORDER']['weight'] = 'ASC';
$data = select_db('user_article_categorys',['id','name','weight','add_time'],$where);
msgA(['code'=>1,'count'=>count($data),'data'=>$data]);
}
//添加分类
function add_category(){
$name = trim($_POST['name']);
$time = time();
if(empty($name)){
msg(-1,'分类名称不能为空');
}
if(has_db('user_article_categorys',['uid'=>UID,'name'=>$name])){
msg(-1,'分类名称已存在');
}
insert_db('user_article_categorys',[
'uid'=>UID,
'name'=>$name,
'weight'=>0,
'add_time'=>$time
],[1,'添加成功']);
msg(-1,'添加失败');
}
//删除分类
function del_category(){
check_category($_POST['id']);
delete_db('user_article_categorys',['uid'=>UID,'id'=>$_POST['id']],[1,'删除成功']);
}
//保存分类
function save_category(){
check_category($_POST['id']);
update_db('user_article_categorys',['name'=>$_POST['name'],'weight'=>$_POST['weight']],['uid'=>UID,'id'=>$_POST['id']],[1,'更新成功']);
}
//检查分类
function check_category($id){
if(empty($id)){
msg(-1,'分类ID不能为空');
}
if(!has_db('user_article_categorys',['uid'=>UID,'id'=>$id])){
//修改分类
function up_category(){
$id = json_decode($_POST['id']);
if(empty($id)) msg(-1,'参数错误');
if(empty($_POST['category_id']) || !has_db('user_categorys',['uid'=>UID,'cid'=>$_POST['category_id']])){
msg(-1,'分类不存在');
}
update_db('user_article_list',['category'=>$_POST['category_id']],['uid'=>UID,'id'=>$id],[1,'操作成功']);
}
//修改状态
function up_state(){
$id = json_decode($_POST['id']);
if(empty($id)) msg(-1,'参数错误');
if(!in_array($_POST['state_id'],['1','2','3','4'])){
msg(-1,'状态参数错误');
}
update_db('user_article_list',['state'=>$_POST['state_id']],['uid'=>UID,'id'=>$id],[1,'操作成功']);
}
//保存设置 (与站点配置共享)
function save_article_set(){
//检查配置参数
if(!in_array($_POST['visual'],['0','1','2']) || !in_array($_POST['icon'],['0','1','2'])){
msg(-1,'参数错误');
}
//读取站点配置
$s_site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));
$s_site['article_visual'] = $_POST['visual'];
$s_site['article_icon'] = $_POST['icon'];
update_db("user_config",["v"=>$s_site],["k"=>'s_site',"uid"=>UID],[1,'保存成功']);
}

View File

@@ -1,6 +1,6 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}
if ( in_array($method,['link_list','get_a_link','q_category_link','category_list','get_a_category','check_login','add_link','app_info','del_link','global_search']) && function_exists($method) ) {
if (function_exists($method)) {
$method();
}else{
Amsg(-1,'方法未找到 >> '.$method);
@@ -42,16 +42,55 @@ function add_link(){
insert_db('user_links',$data);
msgA(['code'=>0,'id'=>$lid]);
}
//编辑链接
function edit_link(){
$lid = intval(@$_POST['id']);
$fid = intval(@$_POST['fid']);
$title = $_POST['title'];
$url = $_POST['url'];
$description = empty($_POST['description']) ? '' : $_POST['description'];
$property = empty($_POST['property']) ? 0 : 1;
//检测链接是否合法
check_link($fid,$title,$url,'');
//描述长度检测
$length_limit = unserialize(get_db("global_config","v",["k"=>"length_limit"]));
if($length_limit['l_desc'] > 0 && strlen($description) > $length_limit['l_desc'] ){
msg(-1,'描述长度不能大于'.$length_limit['l_desc'].'个字节');
}
//关键字长度检测
if($length_limit['l_key'] > 0 && strlen($keywords) > $length_limit['l_key'] ){
msg(-1,'关键字长度不能大于'.$length_limit['l_key'].'个字节');
}
//检查链接是否已存在
if(has_db('user_links',['uid'=>UID ,'lid[!]'=>$lid, "url" => $url])){msg(-1011,'链接已存在!');}
//检查链接ID是否存在
if(!has_db('user_links',['uid'=>UID ,'lid'=>$lid])){msg(-1012,'链接ID不存在!');}
$data = [
'fid' => $fid,
'title' => htmlspecialchars($title,ENT_QUOTES),
'url' => $url,
'description' => htmlspecialchars($description,ENT_QUOTES),
'up_time' => time(),
'property' => $property
];
//更新数据
update_db('user_links',$data,['uid'=>UID,'lid'=>$lid ]);
msgA(['code'=>0,'msg'=>'successful']);
}
//删除链接
function del_link(){
$lid = intval(trim($_REQUEST['id']));
if(empty($lid)){
msg(-1,'id不能为空');
msg(-1010,'链接ID不能为空');
}
$where['lid'] = $lid;
$where['uid'] = UID;
if(!has_db('user_links',$where)){
msg(-1,'链接id不存在');
msg(-1010,'链接id不存在');
}
delete_db('user_links',$where,[0,'删除成功']);
}
@@ -59,32 +98,19 @@ function del_link(){
//搜索链接
function global_search(){
$keyword = htmlspecialchars($_REQUEST['keyword']);
if( strlen($keyword) < 2 ) {
msg(-2000,'关键字的长度太短');
}elseif( strlen($keyword) > 32 ) {
msg(-2000,'关键字长度过长');
}
$where['uid'] = UID;
$where['status'] = 1;
$where['AND']['OR'] = ["title[~]" => $keyword,"url[~]" => $keyword, "url_standby[~]" => $keyword,"description[~]" => $keyword];
$where['ORDER'] = ['weight'=>'DESC'];
$field = ['lid(id)','fid','status','property','title','url','url_standby','weight','description','click','add_time','up_time'];
$data = select_db('user_links',$field,$where);
// 查询出分类名称
$categorys = select_db('user_categorys',['cid(id)','name'],['uid'=>UID,'status'=>1]);
// 遍历分类以id作为键名
foreach ($categorys as $category) {
$newCategorys[$category['id']] = $category['name'];
}
// 遍历查询的数据,然后添加父级分类名称
foreach ($data as $key => $value) {
$data[$key]['category_name'] = $newCategorys[$value['fid']];
}
msgA(['code'=>0,'msg'=>'获取成功','count'=>count($data),'data'=>$data]);
$datas = select_db('user_links',$field,$where);
links_add_category_field($datas); //添加分类信息
msgA(['code'=>0,'msg'=>'获取成功','count'=>count($datas),'data'=>$datas]);
}
//查询链接列表
function link_list(){
@@ -92,11 +118,7 @@ function link_list(){
$limit = empty(intval($_REQUEST['limit'])) ? 50 : intval($_REQUEST['limit']);
$offset = ($page - 1) * $limit; //起始行号
$where['uid'] = UID;
$where['AND']['status'] = 1;
if(Access_Type != 'all'){
$where['property'] = 0;
}
$where['status'] = 1;
$count = count_db('user_links',$where); //统计条数
//权重排序(数字小的排前面)
$where['ORDER']['weight'] = 'ASC';
@@ -105,6 +127,7 @@ function link_list(){
$where['LIMIT'] = [$offset,$limit];
//查询
$datas = select_db('user_links',['lid(id)','fid','property','title','url','url_standby','weight','description','icon','click','add_time','up_time'],$where);
links_add_category_field($datas); //添加分类信息
msgA(['code'=>0,'msg'=>'获取成功','count'=>$count,'data'=>$datas]);
}
//查询单个链接
@@ -119,11 +142,7 @@ function get_a_link(){
if(empty($link_info)){
msgA(['code'=>-1,'msg'=>'没有找到链接信息','data'=>[]]);
}else{
if(Access_Type == 'all' || $link_info['property'] == 0){
msgA(['code'=>0,'data'=>$link_info]);
}else{
msgA(['code'=>-1,'msg'=>'私有链接,无权查看','data'=>[]]);
}
msgA(['code'=>0,'data'=>$link_info]);
}
}
//查询指定分类的链接
@@ -135,9 +154,6 @@ function q_category_link(){
$where['uid'] = UID;
$where['AND']['status'] = 1;
$where['AND']['fid'] = $category_id;
if(Access_Type != 'all'){
$where['property'] = 0;
}
$count = count_db('user_links',$where); //统计条数
//权重排序(数字小的排前面)
@@ -147,17 +163,120 @@ function q_category_link(){
$where['LIMIT'] = [$offset,$limit];
//查询
$datas = select_db('user_links',['lid(id)','fid','property','title','url','url_standby','weight','description','icon','click','add_time','up_time'],$where);
links_add_category_field($datas); //添加分类信息
msgA(['code'=>0,'msg'=>'获取成功','count'=>$count,'data'=>$datas]);
}
//查询分类列表
function category_list(){
$where = ['uid'=>UID,'status'=>1,'ORDER' => ['weight'=>'ASC']];
if(Access_Type != 'all'){
$where['property'] = 0;
}
$datas = select_db('user_categorys',['cid(id)','fid','property','name','add_time','up_time','weight','description','font_icon'],$where);
msgA(['code'=>0,'msg'=>'获取成功','count'=>count($datas),'data'=>$datas ]);
}
//添加分类
function add_category(){
if(empty($_POST['name'])){
msg(-1,'分类名称不能为空');
}elseif(!preg_match('/^(fa fa-|layui-icon layui-icon-)([A-Za-z0-9]|-)+$/',$_POST['font_icon'])){
$_POST['font_icon'] = 'fa fa-star-o';
}
//分类名查重
if(get_db('user_categorys','cid',['uid'=>UID ,"name" => $_POST['name']])){
msg(-1,'分类名称已存在');
}
//父分类不能是二级分类
if(intval($_POST['fid']) !=0 && get_db('user_categorys','fid',['uid'=>UID ,"cid" => intval($_POST['fid']) ]) !=0 ){
msg(-1,'父分类不能是二级分类');
}
//长度检测
$length_limit = unserialize(get_db("global_config","v",["k"=>"length_limit"]));
if($length_limit['c_name'] > 0 && strlen($_POST['name']) > $length_limit['c_name'] ){
msg(-1,'名称长度不能大于'.$length_limit['c_name'].'个字节');
}
if($length_limit['c_desc'] > 0 && strlen($_POST['description']) > $length_limit['c_desc'] ){
msg(-1,'名称长度不能大于'.$length_limit['c_desc'].'个字节');
}
//取最大CID
$cid = get_maxid('category_id');
//插入数据库
insert_db('user_categorys',[
'uid'=>UID,
'cid'=>$cid,
'fid'=>intval($_POST['fid']??'0'),
'pid'=>0,
'status'=>1,
'property'=>intval($_POST['property']??'0'),
'name'=>htmlspecialchars($_POST['name'],ENT_QUOTES),
'add_time'=>time(),
'up_time'=>time(),
'weight'=>$cid,
'description'=>htmlspecialchars($_POST['description'],ENT_QUOTES),
'font_icon'=>$_POST['font_icon'],
'icon'=>''
],[0,'添加成功']
);
}
//编辑分类
function edit_category(){
if(empty($_POST['name'])){
msg(-1,'分类名称不能为空');
}elseif(!preg_match('/^(fa fa-|layui-icon layui-icon-)([A-Za-z0-9]|-)+$/',$_POST['font_icon'])){
$_POST['font_icon'] = 'fa fa-star-o';
}
//父分类不能是自己
if($_POST['id'] == $_POST['fid']){
msg(-1,'父分类不能是自己');
}
//查CID是否存在
if(!get_db('user_categorys','cid',['uid'=>UID ,"cid" => intval($_POST['id'])])){
msg(-1,'分类不存在');
}
//分类名查重(排除自身)
if(get_db('user_categorys','cid',['uid'=>UID,'cid[!]'=>intval($_POST['id']),"name" => $_POST['name']])){
msg(-1,'分类名称已存在');
}
//父分类不能是二级分类
if(intval($_POST['fid']) !=0 && get_db('user_categorys','fid',['uid'=>UID ,"cid" => intval($_POST['fid']) ]) !=0 ){
msg(-1,'父分类不能是二级分类');
}
//分类下存在子分类,禁止修改父分类
if( $_POST['fid']!=0 && count_db('user_categorys',['uid'=>UID,'fid'=>$_POST['id']])>0){
msg(-1,'该分类下已存在子分类!');
}
//查父分类是否存在
if( $_POST['fid'] !=0 && !get_db('user_categorys','cid',['uid'=>UID ,"cid" => intval($_POST['fid'])])){
msg(-1,'父分类不存在');
}
//长度检测
$length_limit = unserialize(get_db("global_config","v",["k"=>"length_limit"]));
if($length_limit['c_name'] > 0 && strlen($_POST['name']) > $length_limit['c_name'] ){
msg(-1,'名称长度不能大于'.$length_limit['c_name'].'个字节');
}
if($length_limit['c_desc'] > 0 && strlen($_POST['description']) > $length_limit['c_desc'] ){
msg(-1,'名称长度不能大于'.$length_limit['c_desc'].'个字节');
}
//更新数据
$data = [
'fid'=>$_POST['fid'],
'property'=>intval($_POST['property']??'0'),
'name'=>$_POST['name'],
'up_time'=>time(),
'description'=>$_POST['description']??'',
'font_icon'=>$_POST['font_icon'],
];
if(!isset($_POST['fid'])){ //为空时不修改父id,避免二级变一级
unset($data['fid']);
}
if(!isset($_POST['font_icon'])){
unset($data['font_icon']);
}
update_db('user_categorys',$data,['uid'=>UID ,"cid"=>intval($_POST['id'])],[0,'successful']);
}
//查询单个分类信息
function get_a_category(){
$cid = intval(trim($_REQUEST['id']));
@@ -170,14 +289,11 @@ function get_a_category(){
if(empty($category_info)){
msgA(['code'=>-1,'msg'=>'没有找到分类信息','data'=>[]]);
}else{
if(Access_Type == 'all' || $category_info['property'] == 0){
msgA(['code'=>0,'data'=>$category_info]);
}else{
msgA(['code'=>-1,'msg'=>'私有分类,无权查看','data'=>[]]);
}
msgA(['code'=>0,'data'=>$category_info]);
}
}
//获取TwoNav信息
function app_info(){
$data['php_version'] = floatval(PHP_VERSION);
$data['onenav_version'] = SysVer;
@@ -187,11 +303,19 @@ function app_info(){
msgA(['code'=>200,'msg'=>'success','data'=>$data]);
}
//是否已登录
//是否已登录,由于上游已经拦截未登录状态,所以这里固定返回已登录
function check_login(){
if(Access_Type == 'open'){
msgA(['code'=>-1002,'data'=>'false','err_msg'=>'Authorization failure!']);
}else{
msgA(['code'=>200,'data'=>'true','msg'=>'success']);
msgA(['code'=>200,'data'=>'true','msg'=>'success']);
}
//给链接数组添加分类字段
function links_add_category_field(&$arr){
$where['uid'] = UID;
$where['status'] = 1;
$categorys = select_db('user_categorys',['cid(id)','name'],$where);
$newCategorys = array_column($categorys,'name','id');
foreach ($arr as &$data) {
$data['category_name'] = $newCategorys[$data['fid']];
}
}
return $arr;
}

View File

@@ -352,6 +352,25 @@ function write_user_info(){
delete_db('global_user',["ID" => $uids]);
msg(1,'删除成功');
break;
//删除OTP验证
case "Del_OTP":
$uids = json_decode($_POST['ID']);
$USER_S = select_db('global_user',['LoginConfig','ID','User'],['ID'=>$uids]);
$fail = 0;
foreach($USER_S as $USER){
$LoginConfig = unserialize($USER['LoginConfig']);
if(empty($LoginConfig['totp_key'])){
$fail ++;
continue;
}
$LoginConfig['totp_key'] = '';
update_db("global_user", ["LoginConfig" => $LoginConfig], ["ID" => $USER['ID']]);
}
if($fail > 0){
msg(1,'操作完毕,有'.$fail.'个账号未开启OTP双重验证');
}
msg(1,'操作成功');
break;
//设用户组
case "set_UserGroup":
if(empty($_POST['UserGroup'])){
@@ -555,7 +574,7 @@ function write_sys_settings(){
'apply'=>['int'=>true,'min'=>0,'max'=>1,'msg'=>'收录管理参数错误'],
'guestbook'=>['int'=>true,'min'=>0,'max'=>1,'msg'=>'留言管理参数错误'],
'link_extend'=>['int'=>true,'min'=>0,'max'=>1,'msg'=>'链接扩展参数错误'],
'article'=>['int'=>true,'min'=>0,'max'=>1,'msg'=>'文章管理参数错误']
'article'=>['int'=>true,'min'=>0,'max'=>2,'msg'=>'文章管理参数错误']
];
$o_config = [];
foreach ($datas as $key => $data){

View File

@@ -4,7 +4,7 @@ $id = intval($_GET['id']);
//IP数统计
count_ip();
//如果id为空,则显示404
if(empty($id)){Not_Found();}
if(empty($id)) Not_Found();
//查询链接信息
$where['lid'] = $id;
@@ -13,18 +13,7 @@ $where['status'] = 1;
$link = get_db('user_links','*',$where);
//查找失败时显示404
if(empty($link)){Not_Found();}
//站点设置和站点图标
$site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));
$site['Title'] = $site['title'].(empty($site['subtitle'])?'':' - '.$site['subtitle']);
//免费用户请保留版权,谢谢!
$copyright = empty($global_config['copyright'])?'<a target="_blank" href="https://gitee.com/tznb/TwoNav">Copyright © TwoNav</a>':$global_config['copyright'];
$ICP = empty($global_config['ICP'])?'':'<a target="_blank" href="https://beian.miit.gov.cn">'.$global_config['ICP'].'</a>';
$favicon = ( !empty($site['site_icon_file'])) ? $site['site_icon'] : './favicon.ico';
//取登录状态
$is_login = is_login();
if(empty($link)) Not_Found();
//取父分类和祖分类信息
$info_c = ['cid','fid','property','status','pid'];
@@ -72,7 +61,9 @@ if(!$is_login){
$verify_type = 'link_pwd';
$password = get_db('user_pwd_group','password',['uid'=>UID,'pid'=>$link['pid']]);
if($_SESSION['verify']['link'][$link['lid']] != $password){
require DIR.'/templates/admin/other/verify_link_pwd.php';
$c = 'verify';
require DIR."/system/templates.php";
require $index_path;
exit();
}
}
@@ -81,7 +72,9 @@ if(!$is_login){
$verify_type = 'category_pwd';
$password = get_db('user_pwd_group','password',['uid'=>UID,'pid'=>$category_parent['pid']]);
if($_SESSION['verify']['category'][$category_parent['cid']] != $password){
require DIR.'/templates/admin/other/verify_link_pwd.php';
$c = 'verify';
require DIR."/system/templates.php";
require $index_path;
exit();
}
}
@@ -90,39 +83,22 @@ if(!$is_login){
$verify_type = 'category_pwd';
$password = get_db('user_pwd_group','password',['uid'=>UID,'pid'=>$category_ancestor['pid']]);
if($_SESSION['verify']['category'][$category_ancestor['cid']] != $password){
require DIR.'/templates/admin/other/verify_link_pwd.php';
$c = 'verify';
require DIR."/system/templates.php";
require $index_path;
exit();
}
}
}
//取模板信息
require DIR ."/system/templates.php";
$dir_path = DIR.'/templates/transit/'.$s_templates['transit'];
$theme_dir = str_replace(DIR.'/templates/transit',"./templates/transit",$dir_path);
$transit_path = $dir_path.'/index.php';
//检查是否存在,不存在则使用默认
if(!is_file($transit_path)){
$transit_path= DIR.'/templates/transit/default/index.php';
}
//统计点击数
write_user_count(date('Ym'),'click_Ym');
write_user_count(date('Ymd'),'click_Ymd');
update_db("user_links", ["click[+]"=>1],['uid'=>UID,'lid'=>$id]);
//读取用户主题配置
$theme_config_db = unserialize(get_db('user_config','v',['t'=>'theme_transit','k'=>$s_templates['transit'],'uid'=>UID]));
//读取默认主题配置
$theme_info = json_decode(@file_get_contents($dir_path.'/info.json'),true);
$theme_config = empty($theme_info['config']) ? []:$theme_info['config'];
$theme_ver = !Debug?$theme_info['version']:$theme_info['version'].'.'.time();
//合并配置数据
$theme_config = empty($theme_config_db) ? $theme_config : array_merge ($theme_config??[],$theme_config_db??[]);
//通用数据初始化
require DIR."/system/templates.php";
//如果主题信息声明支持扩展字段
if($global_config['link_extend'] == 1 && check_purview('link_extend',1) && in_array($theme_info['support']['link_extend'],["true","1"])){
@@ -154,11 +130,11 @@ if(!empty($link['url_standby'])) {
if(in_array(intval($code),[200,301,302,401]) ){
$site['link_model'] = $site['link_model'] == 'direct' ? '302' : $site['link_model'];
}else{
require $transit_path;
require $index_path;
exit;
}
}else{
require $transit_path;
require $index_path;
exit;
}
}
@@ -185,11 +161,6 @@ if ($site['link_model'] == '302'){ //302重定向(临时)
echo '<html lang="zh-ch"><head><title>正在保护您的隐私..</title><meta name="referrer" content="same-origin"><meta http-equiv="refresh" content="0;url='.$link['url'].'"></head>';
exit;
}else{ //Transition 过渡页
require $transit_path;
require $index_path;
exit;
}
//返回404
function Not_Found() {
header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;
}

View File

@@ -18,7 +18,8 @@ if ( $apply['apply'] == 0 ){
}
//get请求载入页面
if($_SERVER['REQUEST_METHOD'] === 'GET'){
require DIR.'/templates/admin/page/expand/apply-user.php';
require DIR."/system/templates.php";
require($index_path);
exit;
}
//载入提示页

View File

@@ -1,58 +1,28 @@
<?php if(!defined('DIR')){Not_Found();}AccessControl();
$id = intval($_GET['id']);
//判断全局开关和用户权限
if($global_config['article'] < 1 || !check_purview('article',1)) Not_Found();
//IP数统计
count_ip();
//如果id为空,则显示404
if(empty($id)){Not_Found();}
//查询文章
$where['uid'] = UID;
$where['state'] = 1; //1表示公开
$where['id'] = $id;
$data = get_db('user_article_list','*',$where);
//取GET参数中的id
$id = intval($_GET['id']);
//如果id为空,则显示404
if(empty($id)) Not_Found();
//通用数据初始化
require DIR."/system/templates.php";
//读取文章内容
$data = get_article_content($id);
//查找失败时显示404
if(empty($data)){Not_Found();}
//var_dump($data);
//exit;
//站点设置和站点图标
$site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));
$site['Title'] = $site['title'].(empty($site['subtitle'])?'':' - '.$site['subtitle']);
//免费用户请保留版权,谢谢!
$copyright = empty($global_config['copyright'])?'<a target="_blank" href="https://gitee.com/tznb/TwoNav">Copyright © TwoNav</a>':$global_config['copyright'];
$ICP = empty($global_config['ICP'])?'':'<a target="_blank" href="https://beian.miit.gov.cn">'.$global_config['ICP'].'</a>';
$favicon = ( !empty($site['site_icon_file'])) ? $site['site_icon'] : './favicon.ico';
//取模板信息
require DIR ."/system/templates.php";
$dir_path = DIR.'/templates/article/'.$s_templates['article'];
$theme_dir = str_replace(DIR.'/templates/article',"./templates/article",$dir_path);
$path = $dir_path.'/index.php';
//检查是否存在,不存在则使用默认
if(!is_file($path)){
$path= DIR.'/templates/article/default/index.php';
}
if(empty($data)) Not_Found();
//统计点击数
update_db("user_article_list", ["browse_count[+]"=>1],['uid'=>UID,'id'=>$id]);
//读取用户主题配置
$theme_config_db = unserialize(get_db('user_config','v',['t'=>'theme_article','k'=>$s_templates['article'],'uid'=>UID]));
//读取默认主题配置
$theme_info = json_decode(@file_get_contents($dir_path.'/info.json'),true);
$theme_config = empty($theme_info['config']) ? []:$theme_info['config'];
$theme_ver = !Debug?$theme_info['version']:$theme_info['version'].'.'.time();
//合并配置数据
$theme_config = empty($theme_config_db) ? $theme_config : array_merge ($theme_config??[],$theme_config_db??[]);
require $path;
exit;
//返回404
function Not_Found() {
header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;
}
//载入模板
require $index_path;

View File

@@ -16,23 +16,23 @@ if(!Check_Path("data/user/{$u}/MessageBoard")){
//POST提交留言
if($_SERVER['REQUEST_METHOD'] === 'POST'){
if($s['allow'] != '1'){ msg(-1015,'提交失败,当前禁止留言!'); }
if($s['allow'] != '1'){ msg(-1,'提交失败,当前禁止留言!'); }
$type = $_POST['type']; //类型
$contact = $_POST['contact']; //联系方式
$title = $_POST['title']; //标题
$content = $_POST['content']; //内容
if(empty($type)){
msg(-1015,'提交失败,类型不能为空');
msg(-1,'提交失败,类型不能为空');
}elseif(empty($contact)){
msg(-1015,'提交失败,联系方式不能为空');
msg(-1,'提交失败,联系方式不能为空');
}elseif(empty($title)){
msg(-1015,'提交失败,标题不能为空');
msg(-1,'提交失败,标题不能为空');
}elseif(empty($content)){
msg(-1015,'提交失败,内容不能为空');
msg(-1,'提交失败,内容不能为空');
}elseif(strlen($type) >= 32 || strlen($contact) >= 64 || strlen($title) >= 128 || strlen($content) >= 2048){
msg(-1015,'提交失败,长度超限');
msg(-1,'提交失败,长度超限');
}elseif(ShuLiang("data/user/{$u}/MessageBoard/") > 256){
msg(-1015,'提交失败,留言太多了请稍后再试');
msg(-1,'提交失败,留言太多了请稍后再试');
}
$json_arr = array(
@@ -48,9 +48,9 @@ if($_SERVER['REQUEST_METHOD'] === 'POST'){
$json = json_encode($json_arr);
$path = "data/user/{$u}/MessageBoard/".time().'_'.crc32($json).'.json';
if( Check_Path("data/user/{$u}/MessageBoard") && file_put_contents($path, $json)){
msg(0,'提交成功');
msg(1,'提交成功');
}else{
msg(-1015,'系统错误,提交失败'); //创建目录或写入文件失败,请检查权限
msg(-1,'系统错误,提交失败'); //创建目录或写入文件失败,请检查权限
}
}
@@ -67,5 +67,8 @@ function ShuLiang($path){
}
return $sl;
}
require DIR.'/templates/admin/page/expand/guestbook-user.php';
//通用数据初始化
require DIR."/system/templates.php";
require $index_path;
exit;

View File

@@ -1,6 +1,60 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}AccessControl();
//主页入口
define('is_login',is_login());
//是否载入引导页
if(@$global_config['default_page'] == 2){
if(empty(Get('u')) && empty($_COOKIE['Default_User'])){
$c = 'guide';
require DIR."/system/templates.php";
require $index_path;
exit;
}
}
//书签分享
$share = Get('share');
if(!empty($share)){
$share = get_db('user_share','*',['uid'=>UID,'sid'=>$share]);
if(empty($share)){
$content = '分享已被删除,请联系作者!';
require DIR.'/templates/admin/page/404.php';
exit;
}
//判断是否过期
if(time() > $share['expire_time']){
$content = '分享已过期,请联系作者!';
require DIR.'/templates/admin/page/404.php';;
exit;
}
//判断是否加密
if(!empty($share['pwd']) && !is_login()){
session_start();
if($_SESSION['verify']['share'][$share['id']] != $share['pwd']){
$c = 'verify';$_GET['c'] = 'share';
require DIR."/system/templates.php";
require $index_path;
exit;
}
}
$data = json_decode($share['data']);
//判断分享类型(1.分类 2.链接)
if($share['type'] == 1){
$where['cid'] = $data;
if($share['pv'] == 1){
unset($where['property']);
}
}else if($share['type'] == 2){
$category_parent = [['name' => $share['name'] ,"font_icon" =>"fa fa-bookmark-o" , "id" => 'share' ,"description" => "书签分享"]];
$categorys = $category_parent;
}
//浏览计次
update_db("user_share", ["views[+]"=>1],['uid'=>UID,'id'=>$share['id']]);
}
//通用数据初始化
require DIR."/system/templates.php";
//判断用户组,是否允许未登录时访问主页
if(!is_login && ($global_config['Privacy'] == 1 || !check_purview('Common_home',1))){
@@ -8,76 +62,13 @@ if(!is_login && ($global_config['Privacy'] == 1 || !check_purview('Common_home',
header("Location: ./?c=admin&u=".U);
exit;
}
//载入站点设置
$site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));
//如果没有权限则清除自定义代码
if(!check_purview('header',1)){$site['custom_header'] = '';}
if(!check_purview('footer',1)){$site['custom_footer'] = '';}
$site['Title'] = $site['title'].(empty($site['subtitle'])?'':' - '.$site['subtitle']);
//免费用户请保留版权,谢谢!
$copyright = empty($global_config['copyright'])?'<a target="_blank" href="https://gitee.com/tznb/TwoNav">Copyright © TwoNav</a>':$global_config['copyright'];
$ICP = empty($global_config['ICP'])?'':'<a target="_blank" href="https://beian.miit.gov.cn">'.$global_config['ICP'].'</a>';
$favicon = ( !empty($site['site_icon_file'])) ? $site['site_icon'] : './favicon.ico';
//例外主题,不支持热门网址/最新网址/输出上限
$site['ex_theme'] = in_array($theme,['snail-nav','heimdall']);
//读取默认模板信息
require DIR ."/system/templates.php";
//引导页
if(!empty($global_config['default_page']) && $global_config['default_page'] == 2){
if(empty(Get('u')) && empty($_COOKIE['Default_User'])){
$theme = $global_templates['guide'];
$dir_path = DIR.'/templates/guide/'.$global_templates['guide'];
$index_path = $dir_path.'/index.php';
if(!is_file($index_path)){
$dir_path= DIR.'/templates/guide/default';
$index_path = $dir_path.'/index.php';
}
$theme_dir = str_replace(DIR.'/templates/guide',"./templates/guide",$dir_path);
$theme_info = json_decode(@file_get_contents($dir_path.'/info.json'),true);
$theme_config = empty($theme_info['config']) ? []:$theme_info['config'];
$theme_config_db = get_db('user_config','v',['t'=>'theme_guide','k'=>$theme,'uid'=>UID]);
$theme_config_db = unserialize($theme_config_db);
$theme_config = empty($theme_config_db) ? $theme_config : array_merge ($theme_config,$theme_config_db);
require($index_path);
exit;
}
}
//参数指定主题优先
$theme = trim(@$_GET['theme']);
if ( !empty ($theme) && check_purview('theme_in',1)){
$dir_path = DIR.'/templates/home/'.$theme;
$index_path = $dir_path.'/index.php';
}else{
$is_Pad = preg_match('/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i',$_SERVER['HTTP_USER_AGENT']);
$theme = $is_Pad?$s_templates['home_pad']:$s_templates['home_pc'];
$dir_path = DIR.'/templates/home/'.$theme;
$index_path = $dir_path.'/index.php';
}
//检查是否存在,不存在则使用默认
if(!is_file($index_path)){
$dir_path= DIR.'/templates/home/default';
$index_path = $dir_path.'/index.php';
}
//相对路径
$theme_dir = str_replace(DIR.'/templates/home',"./templates/home",$dir_path);
//主题信息
$theme_info = json_decode(@file_get_contents($dir_path.'/info.json'),true);
//支持属性
$support_subitem = $theme_info['support']['subitem']??0; //0.不支持子分类 1.分类栏支持 2.链接栏支持 3.都支持
$support_category_svg = $theme_info['support']['category_svg']??0; //0.不支持 1.支持
//主题配置(默认)
$theme_config = empty($theme_info['config']) ? []:$theme_info['config'];
//主题配置(用户)
$theme_config_db = get_db('user_config','v',['t'=>'theme_home','k'=>$theme,'uid'=>UID]);
$theme_config_db = unserialize($theme_config_db);
//合并配置数据
$theme_config = empty($theme_config_db) ? $theme_config : array_merge ($theme_config,$theme_config_db);
//主题版本(调试时追加时间戳)
$theme_ver = !Debug?$theme_info['version']:$theme_info['version'].'.'.time();
$site['ex_theme'] = in_array($theme,['snail-nav','heimdall']); //例外主题,不支持热门网址/最新网址/输出上限
//分类查找条件
$categorys = []; //声明一个空数组
$content = ['cid(id)','name','property','font_icon','icon','description'];//需要的内容
$content = ['cid(id)','fid','name','property','font_icon','icon','description'];//需要的内容
$where['uid'] = UID;
$where['fid'] = 0;
$where['status'] = 1;
@@ -102,7 +93,7 @@ function get_category_sub($id) {
if(!empty($share)){
$where['cid'] = $data;
}
$content = ['cid(id)','name','property','font_icon','icon','description'];
$content = ['cid(id)','name','fid','property','font_icon','icon','description'];
$where['uid'] = UID;
$where['fid'] = intval($id);
$where['status'] = 1;
@@ -129,7 +120,6 @@ function get_links($fid) {
$where['ORDER']['lid'] = 'ASC';
if(!is_login){
$where['property'] = 0;
}
//书签分享>私有可见
if(isset($share['pv']) && $share['pv'] == 1){
@@ -197,6 +187,7 @@ function get_links($fid) {
//获取图标链接
$links[$key]['ico'] = $lock ? $GLOBALS['libs'].'/Other/lock.svg' : geticourl($site['link_icon'],$link);
$links[$key]['type'] = 'link';
}
//处理扩展信息
if($GLOBALS['global_config']['link_extend'] == 1 && check_purview('link_extend',1) && in_array($GLOBALS['theme_info']['support']['link_extend'],["true","1"])){
@@ -207,6 +198,30 @@ function get_links($fid) {
}
}
//生成文章链接, 条件:非隐藏,且主题未声明不显示文章
if( intval($site['article_visual'] ?? '1') > 0 && $GLOBALS['theme_info']['support']['article'] != 'notdisplay'){
$articles = get_article_list($fid);
foreach ($articles['data'] as $article) {
$url = "./index.php?c=article&id={$article['id']}&u={$u}";
if($site['article_icon'] == '1'){ //站点图标
$icon = $GLOBALS['favicon'];
}elseif($site['article_icon'] == '2' && !empty($article['cover'])){ //封面
$icon = $article['cover'];
}else{ //首字
$icon = './system/ico.php?text='.mb_strtoupper(mb_substr($article['title'], 0, 1));
}
$article_link = ['type'=>'article','id'=>0,'title'=>htmlspecialchars($article['title'],ENT_QUOTES),'url'=>$url,'real_url'=>$url,'description'=> htmlspecialchars($article['summary'],ENT_QUOTES),'ico'=>$icon,'icon'=>$icon];
//判断靠前还是靠后
if($site['article_visual'] == '1'){
array_unshift($links,$article_link);
}else{
array_push($links,$article_link);
}
}
}
if($max_link && $count > $site['max_link']){
$oc_url = "./index.php?u={$u}&oc={$fid}" . (empty($_GET['theme']) ? '':"&theme={$_GET['theme']}");
array_push($links,['id'=>0,'title'=>'查看全部','url'=>$oc_url,'real_url'=>$oc_url,'description'=>'该分类共有'.$count.'条数据','ico'=>'./favicon.ico']);
@@ -215,45 +230,7 @@ function get_links($fid) {
return $links;
}
//书签分享
$share = Get('share');
if(!empty($share)){
$share = get_db('user_share','*',['uid'=>UID,'sid'=>$share]);
if(empty($share)){
$content = '分享已被删除,请联系作者!';
require DIR.'/templates/admin/page/404.php';
exit;
}
//判断是否过期
if(time() > $share['expire_time']){
$content = '分享已过期,请联系作者!';
require DIR.'/templates/admin/page/404.php';;
exit;
}
//判断是否加密
if(!empty($share['pwd']) && !is_login){
session_start();
if($_SESSION['verify']['share'][$share['id']] != $share['pwd']){
require DIR.'/templates/admin/other/verify_share_pwd.php';
exit;
}
}
$data = json_decode($share['data']);
//判断分享类型(1.分类 2.链接)
if($share['type'] == 1){
$where['cid'] = $data;
if($share['pv'] == 1){
unset($where['property']);
}
}else if($share['type'] == 2){
$category_parent = [['name' => $share['name'] ,"font_icon" =>"fa fa-bookmark-o" , "id" => 'share' ,"description" => "书签分享"]];
$categorys = $category_parent;
}
//浏览计次
update_db("user_share", ["views[+]"=>1],['uid'=>UID,'id'=>$share['id']]);
}
//如果为空则查找分类
if($category_parent == []){

View File

@@ -161,7 +161,8 @@ $db_config = array(
'port' => $_POST['db_port'],
'database' => $_POST['db_name'],
'username' => $_POST['db_user'],
'password' => $_POST['db_password']
'password' => $_POST['db_password'],
'charset' => 'utf8mb4'
]);
//判断版本,目前基于5.6.50开发,其他版本兼容性未知,若您需要强制安装请屏蔽检测

View File

@@ -1,17 +1,9 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}
//登录入口
require "./system/templates.php";
//如果是Get请求则载入登录模板
if($_SERVER['REQUEST_METHOD'] === 'GET'){
require DIR ."/system/templates.php";
$t_path = DIR ."/templates/login/{$s_templates['login']}/index.php"; //模板路径
$copyright = empty($global_config['copyright'])?'<a target="_blank" href="https://gitee.com/tznb/TwoNav">Copyright © TwoNav</a>':$global_config['copyright'];
$ICP = empty($global_config['ICP'])?'':'<a target="_blank" href="https://beian.miit.gov.cn">'.$global_config['ICP'].'</a>';
//检查是否存在,不存在则使用默认
if(!is_file($t_path)){
$t_path = DIR.'/templates/login/default/index.php';
}
require $t_path;
require DIR."/system/templates.php";
require $index_path;
exit;
}
@@ -41,11 +33,25 @@ if(strlen($Password)!==32){
msg(-1,"浏览器UA长度异常,请更换浏览器!");
}
$LoginConfig = unserialize( $USER_DB['LoginConfig'] );
//开启双重验证时验证OTP验证码
if(!empty($LoginConfig['totp_key'])){
if(empty($_POST['otp_code'])){
msgA(['code'=>-1,'msg'=>'您已开启双重验证,请输入OTP验证码']);
}
require DIR . '/system/Authenticator.php';
$totp = new PHPGangsta_GoogleAuthenticator();
$checkResult = $totp->verifyCode($LoginConfig['totp_key'], $_POST['otp_code'], 2);
if(!$checkResult){
msgA(['code'=>-1,'msg'=>'OTP验证码错误,请重试!']);
}
}
//计算请求密码和数据库的对比
if(Get_MD5_Password($Password,$USER_DB["RegTime"]) === $USER_DB["Password"]){
update_db("user_log", ["description" => "请求登录>登录成功"], ["id"=>$log_id]);
Set_key($USER_DB);
$LoginConfig = unserialize( $USER_DB['LoginConfig'] );
if(empty($LoginConfig['login_page']) || $LoginConfig['login_page'] == 'admin'){
$url = "./?c=admin&u={$USER_DB['User']}";
}elseif($LoginConfig['login_page'] == 'index'){

View File

@@ -713,10 +713,10 @@ function send_email($config){
$mail->SMTPSecure = $config['secure'];
$mail->Port = intval($config['port']);
if(preg_match('/(.+)<(.+)>/', $config['sender'], $match)){
if(preg_match('/(.+)<(.+@.+)>$/', $config['sender'], $match)){
$mail->setFrom($match[2],$match[1]);
}else{
$mail->setFrom($config['sender']);
$mail->setFrom($config['user'],empty($config['sender'])?'TwoNav':$config['sender']);
}
$mail->addAddress($config['addressee']); //收件人

View File

@@ -3,98 +3,281 @@
//读取全局模板配置
$global_templates = unserialize(get_db("global_config",'v', ["k" => "s_templates"]));
//读取用户模板配置
$s_templates = unserialize(get_db("user_config", "v", ["uid"=>UID,"k"=>"s_templates"]));
//没找到用户模板配置
if(empty($s_templates)){
//将全局默认模板配置写到用户配置
$s_templates = $global_templates;
insert_db("user_config", ["uid" => UID,"k"=>"s_templates","v"=>$global_templates,"t"=>"config","d" => '默认模板']);
if(defined('UID')){
//读取用户模板配置
$s_templates = unserialize(get_db("user_config", "v", ["uid"=>UID,"k"=>"s_templates"]));
//没找到用户模板配置
if(empty($s_templates)){
$s_templates = $global_templates;
insert_db("user_config", ["uid" => UID,"k"=>"s_templates","v"=>$global_templates,"t"=>"config","d" => '默认模板']);
}
}
//载入辅助函数
if(empty($c) || in_array($c,['index','click'])){
//将URL转换为base64编码
function base64($url){
$urls = parse_url($url);
$scheme = empty( $urls['scheme'] ) ? 'http://' : $urls['scheme'].'://'; //获取请求协议
$host = $urls['host']; //获取主机名
$port = empty( $urls['port'] ) ? '' : ':'.$urls['port']; //获取端口
$new_url = $scheme.$host.$port;
return base64_encode($new_url);
//根据请求来读取模板名
if($c == 'index'){
$theme = trim(@$_GET['theme']); //主题预览
if (empty($theme)){
$is_Pad = preg_match('/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i',$_SERVER['HTTP_USER_AGENT']);
$theme = $is_Pad ? $s_templates['home_pad'] : $s_templates['home_pc'];
}
//是否启用收录
function is_apply(){
global $global_config;
$apply_user = unserialize( get_db("user_config", "v", ["k" => "apply","uid"=>UID]));
return ($global_config['apply'] == 1 && $apply_user['apply'] == 1);
$dir_path = DIR.'/templates/home';
}elseif($c == 'click'){ //过渡
$theme = $s_templates['transit'];
$dir_path = DIR.'/templates/transit';
}elseif($c == 'verify'){ //验证
if($_GET['c'] == 'click'){
$data['title'] = $link['title'];
$data['tip'] = '查看加密链接';
$data['input_tip'] = '请输入密码';
$data['post_url'] = "./index.php?c=verify&type=link_pwd&u={$u}&id={$_GET['id']}";
$config = unserialize(get_db("user_config", "v", ["k" => "s_verify_page","uid"=>$USER_DB['ID']]));
$data['get_tip'] = $config['link_tip'];
}elseif($_GET['c'] == 'share'){
$data['title'] = $share['name'];
$data['tip'] = '查看分享书签';
$data['input_tip'] = '请输入提取码';
$data['post_url'] = "./index.php?c=verify&type=share_pwd&u={$u}&share={$_GET['share']}";
$config = unserialize(get_db("user_config", "v", ["k" => "s_verify_page","uid"=>$USER_DB['ID']]));
$data['get_tip'] = $config['share_tip'];
}elseif($_GET['c'] == 'pwd2'){
$data['title'] = '验证二级密码';
$data['tip'] = '验证二级密码';
$data['input_tip'] = '请输入二级密码';
$data['post_url'] = "./index.php?c=verify&type=pwd2&u={$u}";
}
//是否启用留言
function is_guestbook(){
global $global_config;
$guestbook_user = unserialize( get_db("user_config", "v", ["k" => "guestbook","uid"=>UID]) );
return ($global_config['guestbook'] == 1 && $guestbook_user['allow'] == 1);
}
//获取图标URL
function geticourl($icon,$link){
if( !empty( $link['icon']) ){
if(substr($link['icon'], 0,4) == '<svg'){
return('data:image/svg+xml;base64,'.base64_encode($link['icon']));
}else{
return($link['icon']);
}
}
if ($site['link_icon'] == 'default'){
return($GLOBALS['libs'].'/Other/default.ico');
}elseif ($icon ==20){
return('./index.php?c=icon&url='.base64_encode($link['real_url']));
}elseif ($icon ==21){
return('./ico/'.base64_encode($link['real_url']));
}elseif($icon ==2){
return('//favicon.png.pub/v1/'.base64($link['real_url']));
}elseif($icon ==4){
return('//api.15777.cn/get.php?url='.$link['real_url']);
}elseif($icon ==5){
return('//favicon.cccyun.cc/'.$link['real_url']);
}elseif($icon ==6){
return('//api.iowen.cn/favicon/'.parse_url($link['real_url'])['host'].'.png');
}elseif($icon ==7){
return('https://toolb.cn/favicon/'.parse_url($link['real_url'])['host']);
}elseif($icon ==8){
return('https://apis.jxcxin.cn/api/Favicon?url='.$link['real_url']);
}elseif($icon ==0){
return('./system/ico.php?text='.mb_strtoupper(mb_substr($link['title'], 0, 1)));
$theme = $s_templates['verify'];
$dir_path = DIR.'/templates/verify';
}elseif($c == 'article'){ //文章
$theme = $s_templates['article'];
$dir_path = DIR.'/templates/article';
}elseif($c == 'guestbook'){ //留言
$theme = $s_templates['guestbook'];
$dir_path = DIR.'/templates/guestbook';
}elseif($c == 'apply'){ //收录
$theme = $s_templates['apply'];
$dir_path = DIR.'/templates/guestbook/';
}elseif($c == $global_config['Login'] || $c == $USER_DB['Login']){ //登录
$theme = $s_templates['login'];
$dir_path = DIR.'/templates/login';
}elseif($c == $global_config["Register"] ){ //注册
$theme = $global_templates['register'];
$dir_path = DIR.'/templates/register';
}elseif($c == 'guide'){ //引导页,由主页修改$c
$theme = $global_templates['guide'];
$dir_path = DIR.'/templates/guide';
}
//模板类型(用于读取配置)
$templates_type = substr($dir_path, strrpos($dir_path, "/") + 1) ;
//无权限或不存在使用默认
if( !check_purview('theme_in',1) || !is_file("{$dir_path}/{$theme}/index.php")){
$theme = 'default';
$dir_path .= '/default';
$index_path = $dir_path.'/index.php';
}else{
$dir_path .= '/'.$theme;
$index_path = $dir_path.'/index.php';
}
//相对路径
$theme_dir = str_replace(DIR,'.',$dir_path);
//主题信息
$theme_info = json_decode(@file_get_contents($dir_path.'/info.json'),true);
//主题配置(默认)
$theme_config = empty($theme_info['config']) ? []:$theme_info['config'];
if(defined('UID')){
//主题配置(用户)
$theme_config_db = get_db('user_config','v',['t'=>"theme_{$templates_type}",'k'=>$theme,'uid'=>UID]);
$theme_config_db = unserialize($theme_config_db);
}else{
//主题配置(用户)
$theme_config_db = get_db('global_config','v',['t'=>"theme_{$templates_type}",'k'=>$theme]);
$theme_config_db = unserialize($theme_config_db);
}
//合并配置数据
$theme_config = empty($theme_config_db) ? $theme_config : array_merge ($theme_config,$theme_config_db);
//主题版本
$theme_ver = Debug ? "{$theme_info['version']}.".time() : $theme_info['version'];
if(defined('UID')){
//载入站点设置
$site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));
//如果没有权限则清除自定义代码
if(!check_purview('header',1)){$site['custom_header'] = '';}
if(!check_purview('footer',1)){$site['custom_footer'] = '';}
//主页标题( 主标题 - 副标题 )
$site['Title'] = $site['title'].(empty($site['subtitle'])?'':' - '.$site['subtitle']);
//站点图标
$favicon = ( !empty($site['site_icon_file'])) ? $site['site_icon'] : './favicon.ico';
}else{
//站点图标
$favicon = './favicon.ico';
}
//版权信息
$copyright = empty($global_config['copyright'])?'<a target="_blank" href="https://gitee.com/tznb/TwoNav">Copyright © TwoNav</a>':$global_config['copyright'];
//备案信息
$ICP = empty($global_config['ICP'])?'':'<a target="_blank" href="https://beian.miit.gov.cn">'.$global_config['ICP'].'</a>';
//是否启用收录
function is_apply(){
$apply_user = unserialize( get_db("user_config", "v", ["k" => "apply","uid"=>UID]));
return ($GLOBALS['global_config']['apply'] == 1 && $apply_user['apply'] > 0);
}
//是否启用留言
function is_guestbook(){
$guestbook_user = unserialize( get_db("user_config", "v", ["k" => "guestbook","uid"=>UID]) );
return ($GLOBALS['global_config']['guestbook'] == 1 && $guestbook_user['allow'] == 1);
}
//取URL域名
function get_url_host($url, $get_scheme = false, $get_port = false){
$urls = parse_url($url);
$host = $urls['host']; //获取主机名
$port = $get_port === true ? ( empty( $urls['port'] ) ? '' : ':'.$urls['port']) : '';
$scheme = $get_port === true ? ( empty( $urls['scheme'] ) ? 'http://' : $urls['scheme'].'://') : ''; //获取请求协议
return $scheme.$host.$port;
}
//获取图标URL
function geticourl($icon,$link){
if( !empty( $link['icon']) ){
if(substr($link['icon'], 0,4) == '<svg'){
return('data:image/svg+xml;base64,'.base64_encode($link['icon']));
}else{
return('./favicon/index2.php?url='.$link['real_url']);
}//如果参数错误则使用本地服务器
}
//取分类图标(六零系主题在用)
function get_category($content){ //抽风的命名..过度几个版本后删除
return get_category_icon($content);
}
function get_category_icon($content){
if(empty($content)){
return '';
}
if(substr($content, 0,4) == '<svg'){
return 'data:image/svg+xml;base64,'.base64_encode($content);
}else{
return $content;
return($link['icon']);
}
}
//获取公开分类(返回数组cid)
function get_open_category(){
$where['uid'] = UID;
$where['fid'] = 0;
$where['status'] = 1;
if ($site['link_icon'] == 'default'){
return($GLOBALS['libs'].'/Other/default.ico');
}elseif ($icon ==20){
return('./index.php?c=icon&url='.base64_encode($link['real_url']));
}elseif ($icon ==21){
return('./ico/'.base64_encode($link['real_url']));
}elseif($icon ==2){
return('https://favicon.png.pub/v1/'.base64_encode(get_url_host($link['real_url'],true,true)));
}elseif($icon ==4){
return('https://api.15777.cn/get.php?url='.$link['real_url']);
}elseif($icon ==5){
return('https://favicon.cccyun.cc/'.$link['real_url']);
}elseif($icon ==6){
return('https://api.iowen.cn/favicon/'.parse_url($link['real_url'])['host'].'.png');
}elseif($icon ==7){
return('https://toolb.cn/favicon/'.parse_url($link['real_url'])['host']);
}elseif($icon ==8){
return('https://apis.jxcxin.cn/api/Favicon?url='.$link['real_url']);
}else{
return('./system/ico.php?text='.mb_strtoupper(mb_substr($link['title'], 0, 1)));
}
}
//取分类图标
function get_category_icon($content = ''){
return empty($content) ? '' : ( substr($content, 0,4) == '<svg' ? 'data:image/svg+xml;base64,'.base64_encode($content) : $content);
}
//获取公开分类(返回数组cid)
function get_open_category(){
$where['uid'] = UID;
$where['fid'] = 0;
$where['status'] = 1;
$where['property'] = 0;
$categorys = select_db('user_categorys','cid',$where);
$where['fid'] = $categorys;
$categorys = array_merge ($categorys,select_db('user_categorys','cid',$where));
return $categorys;
}
//获取文章列表
function get_article_list($category = 0,$limit = 0){
$where['uid'] = UID;
if(!is_login()){
$where['AND']['state'] = 1; //状态筛选
}else{
$where['AND']['OR']['state'] = [1,2]; //状态筛选
}
//分类筛选
if($category > 0){
$where['AND']['category'] = $category;
}
//统计条数
$count = count_db('user_article_list',$where);
//获取条数
if($limit > 0){
$where['LIMIT'] = [0,$limit];
}
//获取文章列表
$datas = select_db('user_article_list','*',$where);
//查询分类
$categorys = select_db('user_categorys',['cid(id)','name'],['uid'=>UID]);
$categorys = array_column($categorys,'name','id');
//为文章添加分类名称
foreach ($datas as &$data) {
$data['category_name'] = $categorys[$data['category']] ?? 'Null';
$data['title'] = htmlspecialchars($data['title'],ENT_QUOTES);
$data['summary'] = htmlspecialchars($data['summary'],ENT_QUOTES);
}
return ['data'=>$datas,'count'=>$count];
}
//根据文章id获取内容
function get_article_content($id){
$where['uid'] = UID;
if(!is_login()){
$where['state'] = 1; //状态筛选
}
$where['id'] = $id;
$data = get_db('user_article_list','*',$where);
$data['title'] = htmlspecialchars($data['title'],ENT_QUOTES);
$data['summary'] = htmlspecialchars($data['summary'],ENT_QUOTES);
$data['category_name'] = get_db('user_categorys','name',['uid'=>UID,'cid'=>$data['category']]);
return $data;
}
//获取分类列表
function get_category_list($layer = false){
//查询条件
$where = [];
$where['uid'] = UID;
$where['fid'] = 0;
$where['status'] = 1;
$where['ORDER'] = ['weight'=>'ASC'];
if(!is_login()){
$where['property'] = 0;
$categorys = select_db('user_categorys','cid',$where);
$where['fid'] = $categorys;
$categorys = array_merge ($categorys,select_db('user_categorys','cid',$where));
return $categorys;
}
//查找一级分类
$content = ['cid(id)','name','property','font_icon','icon','description'];
$category_parent = select_db('user_categorys',$content,$where);
//查找二级分类
$categorys = [];
if($layer === true){
foreach ($category_parent as $key => $category) {
$where['fid'] = $category['id'];
$category_subitem = select_db('user_categorys',$content,$where);
$category['subitem_count'] = count($category_subitem);
$category['subitem'] = $category_subitem;
array_push($categorys,$category);
}
}else{
foreach ($category_parent as $key => $category) {
$where['fid'] = $category['id'];
$category_subitem = select_db('user_categorys',$content,$where);
$category['subitem_count'] = count($category_subitem);
array_push($categorys,$category);
$categorys = array_merge ($categorys,$category_subitem);
}
}
return $categorys;
}
//返回404
function Not_Found() {
header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;
}

View File

@@ -23,8 +23,8 @@ switch ($type) {
break;
case "pwd2":
$LoginConfig = unserialize($USER_DB['LoginConfig']);
if($_POST['Password2'] === $LoginConfig['Password2']){
setcookie($USER_DB['User'].'_Password2', md5($USER_DB['Password'].$_COOKIE[U.'_key'].$_POST['Password2']), 0,'','',false,true);
if($_POST['Password'] === $LoginConfig['Password2']){
setcookie($USER_DB['User'].'_Password2', md5($USER_DB['Password'].$_COOKIE[U.'_key'].$_POST['Password']), 0,'','',false,true);
msg(1,'二级密码正确!');
}else{
msg(-1,'二级密码错误!');
@@ -32,7 +32,7 @@ switch ($type) {
break;
case "link_pwd":
//读取链接信息
$link = get_db('user_links',['pid','fid','property'],['uid'=>UID,'lid'=>$_POST['id'],'status'=>1]);
$link = get_db('user_links',['pid','fid','property'],['uid'=>UID,'lid'=>$_GET['id'],'status'=>1]);
if(empty($link)){
msg(-1,'链接不存在'); //查找链接失败
}
@@ -44,7 +44,7 @@ switch ($type) {
}
if($password == $_POST['Password']){
session_start();
$_SESSION['verify']['link'][$_POST['id']] = $password;
$_SESSION['verify']['link'][$_GET['id']] = $password;
msg(1,'验证通过');
}else{
msg(-1,'密码错误!');

View File

@@ -1 +1 @@
v2.0.32-20230727
v2.0.37-20230830

View File

@@ -82,7 +82,7 @@ layui.config({version:"<?php echo $Ver;?>"});
layui.use(['layer','miniAdmin'], function () {
var layer = layui.layer;
layui.miniAdmin.render({
iniUrl: "./index.php?c=admin&page=menu&u="+u,
iniUrl: "./index.php?c=api&method=read_data&type=menu&u="+u,
urlHashLocation: true,
bgColorDefault: false,
menuChildOpen: true,

View File

@@ -1,140 +1,307 @@
layui.use(['form','miniTab'], function () {
var form = layui.form,
layer = layui.layer,
miniTab = layui.miniTab;
miniTab.listen();
layer.photos({photos: '.img-list',anim: 5});
layui.use(function(){
var datas,local_theme,active;
var buttons = [
{'name':'主页模板','dir':'home','display':true},
{'name':'过渡模板','dir':'transit','display':true},
{'name':'登录模板','dir':'login','display':true},
{'name':'验证模板','dir':'verify','display':true},
{'name':'收录模板','dir':'apply','display':apply},
{'name':'留言模板','dir':'guestbook','display':guestbook},
{'name':'文章模板','dir':'article','display':article},
{'name':'注册模板','dir':'register','display':is_admin},
{'name':'引导页模板','dir':'guide','display':is_admin}
];
var $tab = $('#tab');
$tab.append('<button class="layui-btn layui-btn-primary layui-border-green layui-btn-sm" id="refresh" title="刷新数据"><i class="layui-icon layui-icon-refresh"></i></button>');
$tab.append('<button class="layui-btn layui-btn-primary layui-border-green layui-btn-sm" id="tips" title="提示信息"><i class="layui-icon layui-icon-tips"></i></button>');
$tab.append('<button class="layui-btn layui-btn-primary layui-border-green layui-btn-sm" style="display: none;" id="set_up" title="设置"><i class="layui-icon layui-icon-set"></i></button>');
buttons.forEach(item => {
if(item.display){
$tab.append(`<button class="layui-btn layui-btn-sm layui-btn-primary dir" dir="${item.dir}">${item.name}</button>`);
}
});
//监听按钮
$(".layui-btn-group .layui-btn").click(function () {
var dir= $(this).parent().attr("id");//取目录名key
var fn= $(this).parent().parent().attr("id");//取模板类型
var type = $(this).attr("id");//取事件类型
var data = datas[dir].info;
//console.log(data);alert('目录:'+dir+',类型:'+type+',模板类型:'+fn);
if(type === 'dw' || type === 'up' ){ //下载或更新
if (data.desc != null && data.desc.length != 0){ //存在描述时弹窗显示描述
layer.open({title:data.name,content: data.desc,btn: ['下载', '取消']
,yes: function(index, layero){
theme_download(dir,data.name,data.desc,fn);
},btn2: function(index, layero){
return true;
},cancel: function(){
return true;
}
});
}else{
theme_download(dir,data.name,data.desc,fn);
}
}else if(type === 'del' ){ //删除
layer.confirm('确认删除?',{icon: 3, title:'温馨提示'}, function(index){
theme_del(dir,fn);
var tag_btns = $('#tab .dir');
local_theme = localStorage.getItem(u + "_theme_active") || 'home';
local_theme = tag_btns.filter('[dir="' + local_theme + '"]');
active = local_theme.length > 0 ? local_theme : tag_btns.first();
$(active).addClass('layui-this'); //激活第一个
active = $(active).attr('dir'); //取激活的dir
load_data(active); //加载数据
//刷新按钮
$('#refresh').click(function() {
load_data(active,true);
});
//预览按钮
$("#preview").click(function() {
window.open(`./index.php?c=${loginAddress}&u=${u}`);
});
//提示信息
$("#tips").click(function() {
let tip,url;
let title = $("#tab .layui-this:first").text();
if(active == 'home'){
tip = '部分模板来自其它开源项目, 本程序仅做适配 <br />主题版权归原作者所有, 如有问题请联系! <br />注意: 部分模板可能不支持书签分享';
}else if(active == 'login'){
tip = '只有使用您的专属登录入口时才会生效,即:概要页面中的专属地址>登录';
url = `./index.php?c=${loginAddress}&u=${u}`;
}else if(active == 'verify'){
tip = '验证加密链接/加密分类/二级密码的页面样式';
}else if(active == 'apply'){
tip = '收录页面的样式,需在收录管理>设置>申请收录>开启';
url = `./index.php?c=apply&u=${u}`;
}else if(active == 'guestbook'){
tip = '留言板的页面样式,需在留言管理>当前设置>允许留言(点击蓝字切换)';
url = `./index.php?c=guestbook&u=${u}`;
}else if(active == 'article'){
tip = '浏览文章页面的样式,前端显示样式与后端编辑器不一致属正常现象!';
}else if(active == 'register'){
tip = '注册页面的样式';
}else if(active == 'guide'){
tip = '引导页面的样式,需将系统设置>默认页面>改为引导页面 <br />未登录时直接访问域名显示引导页 <br />登录后将显示用户主页';
}
if(url != undefined){
layer.alert(tip, {title:title,shadeClose: true,anim: 2,closeBtn: 0,
btn: ['预览', '确定'],btn1: function(){
layer.closeAll();
setTimeout(function() { window.open(url) }, 288);
}
});
}else if(type === 'config' ){ //配置
theme_config(dir,data.name,fn);
}else if(type === 'preview' ){ //预览
if(fn == 'home'){
window.open('./index.php?theme='+dir+'&u='+u);
}else{
layer.msg('不支持预览此模板', {icon: 3});return;
}else{
layer.alert(tip,{title:title,shadeClose: true,anim: 2,closeBtn: 0});
}
});
//设置(目前仅用于过渡页)
$('#set_up').click(function() {
if(active == 'transit'){
layer_open2('过渡页面设置',`/?c=admin&page=set_transit&u=${u}`);
}else if(active == 'verify'){
layer_open2('过渡页面设置',`/?c=admin&page=set_verify&u=${u}`);
}
});
//切换tab按钮
tag_btns.click(function() {
const dir = $(this).attr('dir');
if(active == dir) return;
active = dir;
tag_btns.removeClass('layui-this').filter(this).addClass('layui-this');
load_data(active);
localStorage.setItem(u + "_theme_active",active);
});
function layer_open2(title,url) {
layer.open({type: 2,title: title,shadeClose: true,area : ['100%','100%'],scrollbar: false,resize: false,content: url});
}
//加载数据
function load_data(dir,cache = false) {
const set_up = (dir == 'transit' || dir == 'verify');
$("#set_up")[ set_up ? "show" : "hide"]();
$("#tips")[ !set_up ? "show" : "hide"]();
layer.load(1, {shade: [0.5,'#fff']});//加载层
layer.msg('正在获取数据..', {icon: 16,time: 1000*300});
$.post(`./index.php?c=api&method=read_theme&dir=${dir}&u=${u}&cache=${cache ? 'no':'yes'}`, function (r, status) {
layer.closeAll();
if (r.code == 1) {
datas = r.data;
render_data(r);
} else {
layer.alert("获取数据失败,请重试!",{icon:5,title:'错误',anim: 2,closeBtn: 0,btn: ['刷新页面']},function () {location.reload();});
}
}).fail(function () {
layer.alert("获取数据异常,请重试!",{icon:5,title:'错误',anim: 2,closeBtn: 0,btn: ['刷新页面']},function () {location.reload();});
});
}
//渲染数据
function render_data(d){
$row = $('.layui-row');
$row.html('');
for (const key in d.data) {
const t = d.data[key];
let upordw = '';
if(is_admin){
if(t.state == 'dw' || t.state == 'up'){
upordw = `<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="${t.state}">${t.state == 'dw' ? '下载' : '更新' }</button>`;
}
}
}else if(type === 'set' ){ //使用
if(fn == 'home'){
set_theme(dir,data.name,fn);
}else{
set_theme2(dir,'',fn);
}
}else if(type === 'detail' ){ //详情
theme_detail(data);
let html =
`<div class="layui-col-xs layui-col-sm4 layui-col-md3" id="col_${key}">
<div class="layui-card">
<div class="layui-card-header">
<div clas="left" style="float:left; cursor:pointer;" title="${key}" id="t_${key}">${t.name}</div>
<div style="float:right;cursor:pointer;" title="${t.update}">${t.version}</div>
</div>
<div class="layui-card-body">
<div class="img-list"><img class="screenshot" layer-src="${t.screenshot}" data-original="${t.screenshot}"></div>
</div>
<div class="layui-card-header" style="height: 1px;"></div>
<div class="layui-card-header" style="height: auto;" id="${active}">
<div class="layui-btn-group" id="${key}">
${upordw}
${t.state == 'local' || t.state == 'up' ? '<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="set">使用</button>':''}
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="detail">详情</button>
${t.state == 'local' && active == 'home' ? '<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="preview">预览</button>':''}
${t.config == '1' && theme_set == true ? '<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="config">配置</button>':''}
${(t.state == 'local' || t.state == 'up' ) && is_admin == true ? '<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="del">删除</button>':''}
</div>
</div>
</div>
</div>`;
$row.append(html);
}
//监听End
})
//标记当前模板,使用中靠前显示
if(active == 'home'){
var current1 = $(`#t_${d.current.home_pc}`);
current1.css('color','#03a9f4');
current1.prepend('</i><i class="fa fa-tv" title="PC终端正在使用此主题"></i> ');
$(`#col_${d.current.home_pc}`).prependTo($row);
var current2 = $(`#t_${d.current.home_pad}`);
current2.css('color','#03a9f4');
current2.prepend('<i class="layui-icon layui-icon-cellphone" title="移动终端正在使用此主题"> ');
$(`#col_${d.current.home_pad}`).prependTo($row);
//if(current1.is(current2)){ $("#set:first").remove(); }
}else{
if(d.current[active] !== null && d.current[active] !== undefined && d.current[active].length > 0){
var current = $(`#t_${d.current[active]}`);
current.css('color','#03a9f4');
current.prepend('<i class="fa fa-magic" style="color: #03a9f4;" title="正在使用"></i> ');
$(`#col_${d.current[active]}`).prependTo($row);
//$("#set:first").remove();
}
}
$(`#col_default`).prependTo($row);
//点击图片放大
layer.photos({photos: '.img-list',anim: 5});
//懒加载预览图
$('.screenshot').lazyload({placeholder:"./templates/admin/img/loading.gif",threshold : 600});
//监听按钮
$(".layui-btn-group .layui-btn").click(function () {
var dir= $(this).parent().attr("id");//取目录名key
var fn= $(this).parent().parent().attr("id");//取模板类型
var type = $(this).attr("id");//取事件类型
var data = datas[dir];
//console.log('目录:'+dir+',类型:'+type+',模板类型:'+fn);
if(type === 'dw' || type === 'up' ){ //下载或更新
if (data.desc != null && data.desc.length != 0){ //存在描述时弹窗显示描述
layer.open({title:data.name,content: data.desc,btn: ['下载', '取消']
,yes: function(index, layero){
theme_download(dir,data.name,data.desc,fn);
},btn2: function(index, layero){
return true;
},cancel: function(){
return true;
}
});
}else{
theme_download(dir,data.name,data.desc,fn);
}
}else if(type === 'del' ){ //删除
layer.confirm('确认删除?',{icon: 3, title:'温馨提示'}, function(index){
theme_del(dir,fn);
});
}else if(type === 'config' ){ //配置
theme_config(dir,data.name,fn);
}else if(type === 'preview' ){ //预览
if(fn == 'home'){
window.open('./index.php?theme='+dir+'&u='+u);
}else{
layer.msg('不支持预览此模板', {icon: 3});return;
}
}else if(type === 'set' ){ //使用
if(fn == 'home'){
set_theme(dir,data.name,fn);
}else{
set_theme2(dir,'',fn);
}
}else if(type === 'detail' ){ //详情
theme_detail(data);
}
});
}
//下载主题
function theme_download(dir,name,desc,fn){
layer.msg('下载安装中,请稍后..', {shade:[0.5,'black'],anim: 1,icon: 16,time: 1000*300});
$.post(get_api('write_theme','download'),{dir:dir,name:name,fn:fn},function(data,status){
layer.closeAll();
if( data.code == 1 ) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {load_data(active);}, 800);
}else{
layer.alert(data.msg,{icon:5,title:"错误",anim: "slideDown",shadeClose: true,closeBtn: 0,btn: ['知道了']});
}
});
}
});
//加载预览图
$('.screenshot').lazyload({placeholder:"./templates/admin/img/loading.gif",threshold : 600});
//下载主题
function theme_download(dir,name,desc,fn){
layer.load(1, {shade:[0.1,'#fff']});//加载层
layer.msg('下载安装中,请稍后..', {offset: 'b',anim: 1,time: 60*1000});
$.post(get_api('write_theme','download'),{dir:dir,name:name,fn:fn},function(data,status){
layer.closeAll();
if( data.code == 1 ) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {location.reload();}, 500);//延迟刷新
}else{
//layer.msg(data.msg, {icon: 5});
layer.alert(data.msg,{icon:5,title:"错误",anim: "slideDown",shadeClose: true,closeBtn: 0,btn: ['知道了']});
}
});
}
//删除主题
function theme_del(dir,fn){
layer.load(1, {shade:[0.1,'#fff']});//加载层
layer.msg('正在删除,请稍后..', {offset: 'b',anim: 1,time: 60*1000});
$.post(get_api('write_theme','del'),{dir:dir,fn:fn},function(data,status){
layer.closeAll();
if( data.code == 1 ) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {location.reload();}, 500);
}else{
layer.msg(data.msg, {icon: 5});
}
});
}
//载入主题配置
function theme_config(key,name,fn){
layer.open({
type: 2,
title: name + ' - 主题配置',
shadeClose: true,
area : [( $(window).width() < 768 ? '100%' : '568px' ),'100%'],
scrollbar: false,
resize: false,
offset: 'rt',
content: './index.php?c=admin&page=config_home&u='+u+'&theme='+key+'&fn='+fn+'&source=admin',
});
}
//使用主题提示框
function set_theme(key,name,fn) {
layer.open({
title:name
,content: '请选择要应用的设备类型 ?'
,btn: ['全部', 'PC', 'Pad']
,yes: function(index, layero){
set_theme2(key,'PC/Pad',fn);
},btn2: function(index, layero){
set_theme2(key,'PC',fn);
},btn3: function(index, layero){
set_theme2(key,'Pad',fn);
},cancel: function(){
return true;
}
});
}
//使用主题
function set_theme2(name,type,fn) {
console.log(type,name);
$.post(get_api('write_theme','set'),{type:type,name:name,fn:fn},function(data,status){
if( data.code == 1 ) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {location.reload();}, 500);
}else{
layer.msg(data.msg, {icon: 5});
}
});
}
//主题详情
function theme_detail(data){
layer.open({type: 1,scrollbar: false,maxmin: false,shadeClose: true,resize: false,title: data.name + ' - 主题详情',area: ['60%', '59%'],content: '<body class="layui-fluid"><div class="layui-row" style = "margin-top:1em;"><div class="layui-col-sm9" style = "border-right:1px solid #e2e2e2;"><div style = "margin-left:1em;margin-right:1em;"><img src="'+data.screenshot+'" alt="" style = "max-width:100%;"></div></div><div class="layui-col-sm3"><div style = "margin-left:1em;margin-right:1em;"><h1>'+data.name+'</h1><p>描述:'+data.description+'</p><p>版本:'+data.version+'</p><p>更新时间:'+data.update+'</p><p>作者:'+data.author+'</p><p>主页:<a style = "color:#01AAED;" href="'+data.homepage+'" target="_blank" rel = "nofollow">访问主页</a></p></div></div></div></body>'});
}
//删除主题
function theme_del(dir,fn){
layer.load(1, {shade:[0.5,'black']});//加载
layer.msg('正在删除,请稍后..', {offset: 'b',anim: 1,time: 60*1000});
$.post(get_api('write_theme','del'),{dir:dir,fn:fn},function(data,status){
layer.closeAll();
if( data.code == 1 ) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {load_data(active);}, 800);
}else{
layer.msg(data.msg, {icon: 5});
}
});
}
//载入主题配置
function theme_config(key,name,fn){
layer.open({
type: 2,
title: name + ' - 主题配置',
shadeClose: true,
area : [( $(window).width() < 768 ? '100%' : '666px' ),'100%'],
scrollbar: false,
resize: false,
offset: 'rt',
content: './index.php?c=admin&page=config_home&u='+u+'&theme='+key+'&fn='+fn+'&source=admin',
});
}
//使用主题提示框
function set_theme(key,name,fn) {
layer.open({
title:name
,content: '请选择要应用的设备类型 ?'
,btn: ['全部', 'PC', 'Pad']
,yes: function(index, layero){
set_theme2(key,'PC/Pad',fn);
},btn2: function(index, layero){
set_theme2(key,'PC',fn);
},btn3: function(index, layero){
set_theme2(key,'Pad',fn);
},cancel: function(){
return true;
}
});
}
//使用主题
function set_theme2(name,type,fn) {
$.post(get_api('write_theme','set'),{type:type,name:name,fn:fn},function(data,status){
if( data.code == 1 ) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {load_data(active);}, 800);
}else{
layer.msg(data.msg, {icon: 5});
}
});
}
//主题详情
function theme_detail(data){
layer.open({type: 1,scrollbar: false,maxmin: false,shadeClose: true,resize: false,title: data.name + ' - 主题详情',area: ['60%', '59%'],content: '<body class="layui-fluid"><div class="layui-row" style = "margin-top :1em;"><div class="layui-col-sm9" style = "border-right:1px solid #e2e2e2;"><div style = "margin-left:1em;margin-right:1em;"><img src="'+data.screenshot+'" alt="" style = "max-width:100%;"></div></div><div class ="layui-col-sm3"><div style = "margin-left:1em;margin-right:1em;"><h1>'+data.name+'</h1><p>描述:'+data.description+'</p><p>版本:'+data.version+'</p><p>更新时间:'+data.update+'</p><p>作者:'+data.author+'</p><p >主页:<a style = "color:#01AAED;" href="'+data.homepage+'" target="_blank" rel = "nofollow">访问主页</a></p></div></div></div></body>'});
}
});

View File

@@ -1,4 +1,6 @@
<?php $title='安全设置'; require 'header.php'; ?>
<?php $title='安全设置'; require 'header.php';
$LoginConfig = unserialize($USER_DB['LoginConfig']);
$LoginConfig['totp_key'] = empty($LoginConfig['totp_key']) ? '0':'1';?>
<body>
<div class="layuimini-container">
<div class="layuimini-main">
@@ -83,10 +85,9 @@
<select name="api_model">
<option value="security" selected>安全模式</option>
<option value="compatible">兼容模式</option>
<option value="compatible+open">兼容模式+开放</option>
</select>
</div>
<div class="layui-form-mid layui-word-aux">部分主题和插件需设为兼容+开放模式 <a href="javascript:;" layuimini-content-href="Token" data-title="Token"><font color="red"> 获取API ( Token )</font></a></div>
<div class="layui-form-mid layui-word-aux">部分主题和插件需设为兼容 <a href="javascript:;" layuimini-content-href="Token" data-title="Token"><font color="red"> 获取API ( Token )</font></a></div>
</div>
<div class="layui-form-item">
@@ -110,14 +111,58 @@
</div>
<div class="layui-form-item">
<div class="layui-input-block"><button class="layui-btn layui-btn-normal" lay-submit lay-filter="save">确认保存</button></div>
<div class="layui-input-block">
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="save">确认保存</button>
<button class="layui-btn layui-bg-purple" lay-submit lay-filter="open_totp">OTP 双重验证</button>
</div>
</div>
</div>
</form>
</div>
</div>
<ul class="ul_totp" style="margin-top:18px;display:none;padding-right: 10px;">
<form class="layui-form" lay-filter="ul_totp">
<div class="layui-form-item">
<label class="layui-form-label">二维码</label>
<div id="qr"></div><div id="qrcode"></div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">秘钥</label>
<div class="layui-input-inline">
<input type="text" name="key" id="key" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">为了您的账户安全,成功保存后无法再查看秘钥,请勿泄漏秘钥</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">验证码</label>
<div class="layui-input-inline">
<input type="text" name="code" id="code" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">请输入生成的验证码</div>
</div>
<pre class="layui-code" >
这东西叫法太多了,比如双重验证/动态密码/动态口令/动态令牌/身份验证器/双因子认证/2FA/TOTP验证码等等
原理是基于时间的动态验证码,网上客户端也大把,喜欢那个安装那个
开启后登录时需输入OTP验证码,作用是提高账号安全性
</pre>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-warm" type="button" id="close" >关闭</button>
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="save_totp" id="save_totp">保存</button>
</div>
</div>
</form>
</ul>
<script src = "<?php echo $libs;?>/jquery/jquery-3.6.0.min.js"></script>
<script src = "<?php echo $libs;?>/jquery/jquery.md5.js"></script>
<script src = "<?php echo $libs; ?>/jquery/jquery.qrcode.min.js"></script>
<script src = "./templates/admin/js/public.js?v=<?php echo $Ver;?>"></script>
<?php load_static('js');?>
<script>
@@ -127,9 +172,9 @@ layui.use(['jquery','form','miniTab'], function () {
miniTab = layui.miniTab;
miniTab.listen();
//表单赋值
form.val('form', <?php echo json_encode(unserialize( $USER_DB['LoginConfig'] ));?>);
form.val('form', <?php echo json_encode($LoginConfig);?>);
//监听提交
//保存
form.on('submit(save)', function (data) {
$("*").blur(); //失去焦点,解决按回车无限提交
data.field.Password=$.md5(data.field.Password);
@@ -137,7 +182,7 @@ layui.use(['jquery','form','miniTab'], function () {
if(data.code == 1) {
var index = layer.alert("保存成功!", function () {
layer.close(index);
//miniTab.deleteCurrentByIframe();
//miniTab.deleteCurrentByIframe(); //关闭页面
});
}else{
layer.msg(data.msg, {icon: 5});
@@ -145,6 +190,69 @@ layui.use(['jquery','form','miniTab'], function () {
});
return false;
});
//双重验证
form.on('submit(open_totp)', function (data) {
$("*").blur(); //失去焦点,解决按回车无限提交
data.field.Password=$.md5(data.field.Password);
pwd_md5 = data.field.Password;
$.post(get_api('read_totp'),data.field,function(data,status){
if(data.code == 1){
layer.confirm('已开启双重验证,是否要关闭?',{icon: 3, title:'温馨提示'}, function(index){
layer.closeAll();
$.post(get_api('write_totp','delete'),{'Password':pwd_md5},function(data,status){
if(data.code == 1) {
layer.msg(data.msg, {icon: 1});
}else{
layer.msg(data.msg, {icon: 5});
}
});
});
}else if(data.code == 2) {
layer.confirm('未开启双重验证,是否要开启?',{icon: 3, title:'温馨提示'}, function(index){
layer.closeAll();
$('#key').val(data.key);
$('#code').val('');
$("#qr").html('');//防止多次操作出现多个二维码
let content = `otpauth://totp/${u}?secret=${data.key}&issuer=TwoNav`;
$('#qr').qrcode({render: "canvas",width: 200,height: 200,text: content});
var index = layer.open({type: 1,scrollbar: false,shadeClose: true,title: '双重验证',area : ['100%', '100%'],content: $('.ul_totp')});
});
return false;
}else{
layer.msg(data.msg, {icon: 5});
}
});
return false;
});
$('#key').on('input', function() {
$("#key").html('');
let key = $('#key').val();
let content = `otpauth://totp/${u}?secret=${key}&issuer=TwoNav`;
$("#qr").html('');
$('#qr').qrcode({render: "canvas",width: 200,height: 200,text: content});
});
//保存双重验证
form.on('submit(save_totp)', function (data) {
$("*").blur(); //失去焦点,解决按回车无限提交
data.field.Password = pwd_md5;
$.post(get_api('write_totp','set'),data.field,function(data,status){
if(data.code == 1) {
layer.closeAll();
layer.msg(data.msg, {icon: 1});
}else{
layer.msg(data.msg, {icon: 5});
}
});
return false;
});
//关闭页面
$(document).on('click', '#close', function() {
layer.closeAll();
});
});
</script>
</body>

View File

@@ -69,15 +69,16 @@
<label class="layui-form-label">链接图标</label>
<div class="layui-input-inline" >
<select name="link_icon">
<option value="0" selected>离线图标</option>
<option value="0" selected>离线图标(首字图标)</option>
<option value="20" >本地服务</option>
<option value="21" >本地服务(伪静态)</option>
<option value="2" >favicon.png.pub (小图标)</option>
<option value="4" >api.15777.cn</option>
<option value="5" >favicon.cccyun.cc</option>
<!--<option value="4" >api.15777.cn</option>-->
<!--<option value="5" >favicon.cccyun.cc</option>-->
<option value="6" >api.iowen.cn</option>
<!--<option value="7" >toolb.cn</option>-->
<!--<option value="8" >apis.jxcxin.cn</option>-->
<!--<option value="9" >ico.kucat.cn</option>-->
</select>
</div>
<div class="layui-form-mid layui-word-aux">所有API接口均由其他大佬提供!若有异常请尝试更换接口!</div>

View File

@@ -14,9 +14,8 @@
<div class="layui-colla-item">
<div class="layui-colla-title">API模式的差别</div>
<div class="layui-colla-content">
<p>安全模式: 仅提供TwoNav自身的API接口,访客(未登录/Token为空)无法调用!</p>
<p>兼容模式: 兼容部分OneNav的API接口,以便于其他插件调用!不允许访客调用!</p>
<p>兼容模式+开放: 在兼容模式的基础上允许访客调用API获取共有数据!</p>
<p>安全模式: 仅提供TwoNav自身的API接口,不兼容Onenav的API接口!</p>
<p>兼容模式: 兼容部分OneNav的API接口,以便于其他插件调用!不支持访客调用!</p>
<p>如果你未使用相关扩展插件,则无需修改模式并将Token删除,以提高账号的安全性!</p>
</div>
</div>
@@ -24,10 +23,12 @@
<div class="layui-colla-title">如何使用Chrome浏览器扩展 [非官方]</div>
<div class="layui-colla-content">
前言: 由于浏览器扩展插件非TwoNav所开发适配,如存在Bug或无法使用属正常现象!<br />
安装: 谷歌应用商店下载<a href="https://chrome.google.com/webstore/detail/onenav/omlkjgkogkfpjbdigianpdbjncdchdco?hl=zh-CN&authuser=0" >OneNav</a>并安装 ( 已知0.9.24可用,其他版本未知 )<br />
设置S: 1.TwoNav后台>右上角账号>安全设置>API模式>设为<兼容模式>或<兼容模式+开放> 2.在本页面获取Token<br />
安装: 谷歌应用商店下载<a href="https://chrome.google.com/webstore/detail/onenav/omlkjgkogkfpjbdigianpdbjncdchdco?hl=zh-CN&authuser=0" >OneNav</a>并安装 ( 已知0.9.24 - 1.0.1可用,其他版本未知 )<br />
设置S: 1.TwoNav后台>右上角账号>安全设置>API模式>设为<兼容模式> 2.在本页面获取Token<br />
设置C: 插件API设置>填入域名和Token并保存>完成<br />
常见问题1: 对于单用户使用,确保系统设置中默认用户是当前用户即可!多用户使用时需开启二级域名功能并将域名替换成用户的二级域名,注意结尾不需要带/
问题1: 对于单用户使用,确保系统设置中默认用户是当前用户即可!多用户使用时需开启二级域名功能并将域名替换成用户的二级域名,注意结尾不需要带/
问题2: 因为插件非官方开发维护,能用就尽量不要更新,如果插件更新可能会导致无法正常使用,需这个更新获得兼容性!
问题3: 因为国内环境限制,你可能无法访问谷歌,这种情况你可以在交流群获取插件(安装方法自行百度,部分浏览器可能需要开发者模式加载)
</div>
</div>
<div class="layui-colla-item">
@@ -35,7 +36,7 @@
<div class="layui-colla-content">
<p>前言: 由于uTools扩展插件非TwoNav所开发适配,如存在Bug或无法使用属正常现象!</p>
<p>安装: 在uTools插件应用市场>搜索OneNav>点击获取 </p>
<p>设置S: 1.TwoNav后台>右上角账号>安全设置>API模式>设为<兼容模式>或<兼容模式+开放> 2.在本页面获取SecretKey ( 即插件设置中的API KEY )</p>
<p>设置S: 1.TwoNav后台>右上角账号>安全设置>API模式>设为<兼容模式> 2.在本页面获取SecretKey ( 即插件设置中的API KEY )</p>
<p>设置C: 打开uTools中的OneNav,点击右下角小齿轮>输入网站地址/用户名/API KEY</p>
</div>
</div>

View File

@@ -175,7 +175,7 @@
</blockquote>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;"><legend>本地备份 (订阅可用)</legend></fieldset>
<blockquote class="layui-elem-quote" style="margin-top: 10px;border-left: 2px solid #FF5722; color: #FF5722;">1.备份数据库仅保存最近20份数据<br />2.该功能仅辅助备份使用无法确保100%数据安全,因此定期对整个站点打包备份仍然是必要的</blockquote>
<blockquote class="layui-elem-quote" style="margin-top: 10px;border-left: 2px solid #FF5722; color: #FF5722;">1.备份数据库仅保存最近20份数据<br />2.该功能仅辅助备份使用无法确保100%数据安全,因此定期对整个站点打包备份仍然是必要的<br />3.不支持将新版本备份回滚到旧版本中,不建议跨数据库类型回滚</blockquote>
<!-- 数据表格 -->
<table class="layui-hide" id="list" lay-filter="list"></table>
<!--本地备份备注输入-->
@@ -233,8 +233,10 @@
<input type="checkbox" name="TABLE[user_pwd_group]" title="加密" checked>
<input type="checkbox" name="TABLE[user_share]" title="分享" checked>
<input type="checkbox" name="TABLE[user_apply]" title="收录" checked>
<input type="checkbox" name="TABLE[user_article_list]" title="文章" checked>
<input type="checkbox" name="FILE[MessageBoard]" title="留言" checked>
<input type="checkbox" name="FILE[favicon]" title="图标" checked>
<input type="checkbox" name="FILE[upload]" title="上传目录(如文章图片)" checked>
</div>
</div>
<div class="layui-form-item">

View File

@@ -1,8 +1,25 @@
<?php
if($global_config['article'] != 1 || !check_purview('article',1)){
if($global_config['article'] < 1 || !check_purview('article',1)){
require(DIR.'/templates/admin/page/404.php');
exit;
}
// if($global_config['article'] == 2 ){
// if(is_file(DIR.'/static/UEditor/ueditor.all.min.js')){
// require('article-edit-2.php');
// exit;
// }else{
// $content = '未检测到UEditor资源';
// require DIR.'/templates/admin/page/404.php';
// exit;
// }
// }
if(!is_file(DIR.'/static/wangEditor/wangEditor.css') || !is_file(DIR.'/static/wangEditor/wangEditor.js')){
$content = '由于缺少静态资源,当前无法加载编辑器!<br />如果您是站长,请在系统设置页面点击确定保存,系统将自动下载相关资源!<br />如果您是用户,请联系站长处理或耐心等候!';
require DIR.'/templates/admin/page/404.php';
exit;
}
$article_id = Get('id');
$mode = empty($article_id) ? 'add' : 'edit' ;
@@ -18,13 +35,6 @@ if($mode == 'edit'){
$title = $mode == 'add' ? '添加文章' : '编辑文章';
function echo_article_category(){
$where['uid'] = UID;
foreach (select_db('user_article_categorys','*',$where) as $category) {
echo "<option value=\"{$category['id']}\">{$category['name']}</option>";
}
}
require dirname(__DIR__).'/header.php' ?>
<link href="<?php echo $libs?>/wangEditor/wangEditor.css" rel="stylesheet">
<style type="text/css">
@@ -32,6 +42,11 @@ require dirname(__DIR__).'/header.php' ?>
#toolbar-container { border-bottom: 1px solid #ccc; }
#editor-container { height: 400px; }
.w40{width:40px;}
.layui-upload-drag .layui-icon{font-size: 40px;color: #c2c2c2;}
.layui-upload-drag{padding: 10px;}
.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:11px;font-weight:700;color:#fff;line-height:1;vertical-align:middle;white-space:nowrap;text-align:center;background-color:#777;border-radius:10px}
.bg-red{background-color:#e74c3c!important}
.uploads-delete-tip{position: absolute;right: 10px;font-size: 12px;}
.layui-input-block{margin-left: 70px;}
@media screen and (max-width: 768px) {
.layui-input-block {margin-left: 12px;}
@@ -47,7 +62,7 @@ require dirname(__DIR__).'/header.php' ?>
<div class="layui-form-item ">
<label class="layui-form-label w40">标题:</label>
<div class="layui-input-block">
<input class="layui-input" name="title" placeholder='请输入文章标题' autocomplete="off" value="<?php echo $data['title'];?>">
<input class="layui-input" name="title" placeholder='请输入文章标题' autocomplete="off" value="<?php echo htmlspecialchars($data['title'],ENT_QUOTES);?>">
</div>
</div>
@@ -55,7 +70,7 @@ require dirname(__DIR__).'/header.php' ?>
<label class="layui-form-label w40">分类:</label>
<div class="layui-input-block">
<select name="category" lay-search>
<?php echo_article_category(); ?>
<?php echo_category(true); ?>
</select>
</div>
</div>
@@ -75,7 +90,7 @@ require dirname(__DIR__).'/header.php' ?>
<div class="layui-form-item">
<label class="layui-form-label w40">摘要:</label>
<div class="layui-input-block">
<textarea name="summary" rows ="2" placeholder="文章摘要,留空时自动获取" class="layui-textarea"><?php echo $data['summary'];?></textarea>
<textarea name="summary" rows ="2" placeholder="文章摘要,留空时自动获取" class="layui-textarea" style="min-height: 45px;"><?php echo htmlspecialchars($data['summary'],ENT_QUOTES);?></textarea>
</div>
</div>
@@ -84,10 +99,21 @@ require dirname(__DIR__).'/header.php' ?>
<div class="layui-input-block" id="editor—wrapper">
<div id="toolbar-container"></div>
<div id="editor-container"></div>
<textarea name="content" id="content" class="layui-textarea layui-hide"><?php echo $data['content'] ?? '<p><br></p>';?></textarea>
<textarea name="content" id="content" class="layui-textarea layui-hide"><?php echo htmlspecialchars($data['content'],ENT_QUOTES) ?? '<p><br></p>';?></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label w40">封面:</label>
<div class="layui-upload-drag">
<input type="text" name="cover_url" id="cover_url" style="display: none;" value="<?php echo $data['cover'];?>">
<small class="uploads-delete-tip bg-red badge" style="cursor:pointer;display: none;" id="del_cover_view">×</small>
<i class="up_cover layui-icon layui-icon-add-1" id="up_cover" style="padding-right: 20px; padding-left: 20px;color: #e2e2e2;"></i>
<p class="up_cover">上传封面</p>
<div id="cover_view" style="display: none;"><img src="<?php echo $data['cover'];?>" style="max-width: 196px"></div>
</div>
</div>
</form>
<div class="layui-form-item">
@@ -180,7 +206,7 @@ const editor = createEditor({
mode: 'default'
})
const toolbarConfig = {excludeKeys: ['fullScreen','group-video']}
const toolbarConfig = {excludeKeys: ['fullScreen','uploadVideo']}
const toolbar = createToolbar({
editor,
@@ -190,8 +216,9 @@ const toolbar = createToolbar({
})
layui.use(['form'], function () {
var form = layui.form;
layui.use(['form','upload'], function () {
var form = layui.form,
upload = layui.upload;
<?php if($mode == 'edit'){ ?>
form.val('form',{category:<?php echo $data['category'];?>,state:<?php echo $data['state'];?>});
@@ -211,6 +238,55 @@ layui.use(['form'], function () {
return false;
});
//如果存在封面则加载
if($("#cover_url").val() != ''){
layui.$('#cover_view img').attr('src', $("#cover_url").val());
layui.$('#cover_view').show();
layui.$('#del_cover_view').show();
layui.$('.up_cover').hide();
}
//上传
var uploadInst = upload.render({
elem: '.up_cover'
,url: get_api('write_article','uploadImage')
,accept: 'images'
,acceptMime: 'image/*'
,exts:'jpg|png|gif|bmp|jpeg|svg|webp'
,size: 5*1024
,done: function(res){
if(res.errno == 0){
$("#cover_url").val(res.data.url);
layui.$('#cover_view img').attr('src', res.data.url);
layui.$('#cover_view').show();
layui.$('#del_cover_view').show();
layui.$('.up_cover').hide();
layer.msg('上传成功', {icon: 1});
}else{
layer.msg(res.message || '上传失败', {icon: 5});
}
},error: function(){
layer.msg("上传异常,请刷新重试", {icon: 5});
}
});
//删除封面
$(document).on('click', '#del_cover_view', function() {
$.post(get_api('write_article','deleteImage'),{'path':$("#cover_url").val()},function(data,status){
if(data.code == 1) {
$("#cover_url").val('');
layui.$('#cover_view').hide();
layui.$('#del_cover_view').hide();
layui.$('.up_cover').show();
uploadInst.config.elem.next()[1].value = '';
layer.msg("删除成功",{icon:1});
}else{
layer.msg(data.msg || '未知错误',{icon: 5});
}
});
});
$('#save').click(function () {
let data = form.val('form');
if(data.title == ''){

View File

@@ -1,16 +1,13 @@
<?php
if($global_config['article'] != 1 || !check_purview('article',1)){
if($global_config['article'] < 1 || !check_purview('article',1)){
require(DIR.'/templates/admin/page/404.php');
exit;
}
//读取设置
$s_site = unserialize(get_db('user_config','v',['uid'=>UID,'k'=>'s_site']));
$set['visual'] = $s_site['article_visual'] ?? '1';
$set['icon'] = $s_site['article_icon'] ?? '1';
$title='文章列表';
function echo_article_category(){
$where['uid'] = UID;
foreach (select_db('user_article_categorys','*',$where) as $category) {
echo "<option value=\"{$category['id']}\">{$category['name']}</option>";
}
}
require dirname(__DIR__).'/header.php' ?>
<body>
<div class="layuimini-container">
@@ -22,7 +19,7 @@ require dirname(__DIR__).'/header.php' ?>
<select name="category" lay-search>
<option value="0" selected="">全部</option>
<optgroup label="用户分类">
<?php echo_article_category(); ?>
<?php echo_category(true); ?>
</optgroup>
</select>
</div>
@@ -63,48 +60,77 @@ require dirname(__DIR__).'/header.php' ?>
<!-- 表头工具栏 -->
<script type="text/html" id="toolbar">
<div class="layui-btn-group">
<button class="layui-btn layui-btn-sm layui-btn-danger layui-hide-xs" lay-event="batch_del">删除选中</button>
<button class="layui-btn layui-btn-sm layui-btn-danger" id="batch_operation"><span>批量操作</span><i class="layui-icon layui-icon-down layui-font-12"></i></button>
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="add_article">添加文章</button>
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="category">分类管理</button>
<button class="layui-btn layui-btn-sm " lay-event="set">设置</button>
</div>
</script>
<script src = "<?php echo $libs;?>/jquery/jquery-3.6.0.min.js"></script>
<script src = "./templates/admin/js/public.js?v=<?php echo $Ver;?>"></script>
<?php load_static('js');?>
<ul class="category" style="margin-top: 18px;display:none;padding-right: 10px;padding-left: 10px;">
<div class="layui-btn-container">
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-submit id="to_article_list">返回</button>
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-submit id="add_category">添加</button>
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-submit id="refresh_category">刷新</button>
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-submit id="category_tip">权重提示</button>
</div>
<table id="category_list" lay-filter="category_list"></table>
</ul>
<ul class="edit_category" style="margin-top: 18px;display:none;padding-right: 10px;padding-left: 10px;">
<form class="layui-form" lay-filter="edit_category_form">
<input type="text" name="id" autocomplete="off" class="layui-input" style="display:none;">
<!--批量修改分类-->
<ul class="batch_category" style="margin-top: 18px;display:none;padding-right: 10px;padding-left: 10px;">
<form class="layui-form" lay-filter="batch_category">
<div class="layui-form-item">
<label class="layui-form-label" style="width: 40px;">名称</label>
<div class="layui-input-block" style="margin-left: 70px">
<input type="text" name="name" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" style="width: 40px;">权重</label>
<div class="layui-input-block" style="margin-left: 70px">
<input type="number" name="weight" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item" style="padding-top: 10px;">
<label class="layui-form-label">父级分类</label>
<div class="layui-input-block">
<button class="layui-btn" lay-submit id="save_category">保存</button>
<select id="batch_category_fid">
<?php echo_category(true); ?>
</select>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-normal layui-btn-danger cancel" type="button">取消</button>
<button class="layui-btn" type="button" id="batch_category" >确定修改</button>
</div>
</div>
</form>
</ul>
<!--设置-->
<ul class="set" style="margin-top: 18px;display:none;padding-right: 10px;padding-left: 10px;">
<form class="layui-form" lay-filter="set_form">
<div class="layui-form-item">
<label class="layui-form-label">显示文章</label>
<div class="layui-input-inline">
<select name="visual">
<option value="1">显示靠前</option>
<option value="2">显示靠后</option>
<option value="0">隐藏</option>
</select>
</div>
<div class="layui-form-mid layui-word-aux">是否在主页显示文章链接</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">链接图标</label>
<div class="layui-input-inline">
<select name="icon">
<option value="0">首字图标</option>
<option value="1">站点图标</option>
<option value="2">文章封面</option>
</select>
</div>
<div class="layui-form-mid layui-word-aux">设为文章封面且无封面时显示站点图标</div>
</div>
<div class="layui-form-item" style="padding-top: 10px;">
<div class="layui-input-block">
<button class="layui-btn layui-btn-normal layui-btn-danger cancel">取消</button>
<button class="layui-btn" lay-submit id="save_set">保存</button>
</div>
</div>
<pre class="layui-code" >
小提示:
1.文章所属分类加密时不会对文章加密 (暂不支持文章加密,不想被看到可将文章设为私有)
2.文章所属分类私有且未登录时不显示文章链接 (通过文章链接访问不受限制,不想被看到可将文章设为私有)
3.上传图片支持格式:jpg|png|gif|bmp|jpeg|svg 大小限制:5M
4.编辑器中上传图片小于128KB时使用base64编码存入数据库,大于128KB时将以文件的方式上传到服务器
5.显示文章选项中的靠前/靠后是指文章链接在所属分类下的位置,隐藏则不在主页显示
</pre>
</form>
</ul>
<script>
layui.use(['form','table','dropdown','miniTab'], function () {
var $ = layui.jquery;
@@ -117,10 +143,9 @@ layui.use(['form','table','dropdown','miniTab'], function () {
var state_data = ["Null","公开", "私有", "草稿", "废弃"];
var cols=[ //表头
{type:'checkbox'} //开启复选框
//,{field: 'id', title: 'ID', width:80, sort: true}
,{ title:'操作', toolbar: '#tablebar',width:110}
,{field: 'title', title: '标题', minWidth:200,templet: function(d){
return '<a style="color:#3c78d8" target="_blank" href="/index.php?c=article&id=' +d.id + '&u=' + u + '">'+d.title+'</a>'
return '<a style="color:#3c78d8" target="_blank" href="./?c=article&id=' +d.id + '&u=' + u + '" title="' + htmlspecialchars(d.summary) + '">'+htmlspecialchars(d.title)+'</a>'
}}
,{field:'category',title:'分类',width:100,templet: function(d){
return d.category_name;
@@ -153,6 +178,7 @@ layui.use(['form','table','dropdown','miniTab'], function () {
,method: 'post'
,response: {statusCode: 1 }
,done: function (res, curr, count) {
batch_operation();//初始化批量操作菜单
//获取当前每页显示数量.并写入本都储存
var temp_limit = $(".layui-laypage-limits option:selected").val();
if(temp_limit > 0 && localStorage.getItem(u + "_limit") != temp_limit){
@@ -160,7 +186,80 @@ layui.use(['form','table','dropdown','miniTab'], function () {
}
}
});
//批量操作
function batch_operation(){
dropdown.render({
elem: '#batch_operation',
data: [{
title: ' 修改分类 ',
id: 'up_category'
},{
title: '修改状态',
child: [{
title: '设为公开',
id: "up_state",
value: 1
},{
title: '设为私有',
id: "up_state",
value: 2
},{
title: '设为草稿',
id: "up_state",
value: 3
},{
title: '设为废弃',
id: "up_state",
value: 4
}]
},{
title: '批量删除',
id: 'del_article'
}],
click: function(obj){
let checkStatus = table.checkStatus('table').data;
if( checkStatus.length == 0 ) {
layer.msg('未选中任何数据!');
return;
}
//获取被选ID并格式化
tableIds = checkStatus.map(function (value) {return value.id;});
tableIds = JSON.stringify(tableIds);
//删除文章
if(obj.id == 'del_article'){
layer.confirm('确认删除?',{icon: 3, title:'温馨提示'}, function(index){
$.post(get_api('write_article','del_article'),{id:tableIds},function(data,status){
if(data.code == 1) {
search();
layer.msg(data.msg, {icon: 1});
}else{
layer.msg(data.msg, {icon: 5});
}
});
});
}else if(obj.id == 'up_category'){
index = layer.open({type: 1,scrollbar: false,shadeClose: true,title: false ,area : ['100%', '100%'],closeBtn:0,content: $('.batch_category')});
}else if(obj.id == 'up_state'){
$.post(get_api('write_article','up_state'),{'id':tableIds,'state_id':obj.value},function(data,status){
if(data.code == 1) {
search();
layer.msg('操作成功', {icon: 1});
}else{
layer.msg(data.msg || '未知错误',{icon: 5});
}
});
}
}
});
}
//输入框回车事件和搜索按钮点击事件
$('#keyword, #search').on('keydown click', function(e) {
if ( (e.target.id === 'keyword' && e.keyCode === 13) || (e.target.id === 'search' && e.type === 'click') ) {
search();
}
});
//搜索
function search(){
let data = form.val('form');
table.reload('table', {
@@ -171,16 +270,10 @@ layui.use(['form','table','dropdown','miniTab'], function () {
,page: {curr: 1}
});
}
//关键字回车搜索
$('#keyword').keydown(function (e){if(e.keyCode === 13){search();}});
//搜索按钮点击
$('#search').on('click', function(){search();});
//监听工具栏 - 文章列表
//监听工具栏
table.on('toolbar(table)', function (obj) {
var btn = obj.event;
if (btn == 'add_article') {
if (btn == 'add_article') { //添加文章
layer.open({
title: false,
type: 2,
@@ -190,23 +283,21 @@ layui.use(['form','table','dropdown','miniTab'], function () {
shadeClose: true,
closeBtn:0,
area: ['100%', '100%'],
content: './index.php?c=admin&page=expand/article-edit&u=' + u,
content: './?c=admin&page=expand/article-edit&u=' + u,
end: function(){
search();
}
});
}else if(btn == 'category'){
category_index = layer.open({type: 1,scrollbar: false,shadeClose: true,title: false ,area : ['100%', '100%'],closeBtn:0,content: $('.category'),
success: function(layero, index, that){
category_list();
}
});
}else{
}else if(btn == 'set'){ //设置
index = layer.open({type: 1,scrollbar: false,shadeClose: true,title: false ,area : ['100%', '100%'],closeBtn:0,content: $('.set')});
}else{ //综合批量操作
//取选中数据
var checkStatus = table.checkStatus(obj.config.id);
if( checkStatus.data.length == 0 && ['LAYTABLE_COLS','LAYTABLE_EXPORT','LAYTABLE_PRINT'].indexOf(btn) == -1 ) {
layer.msg('未选中任何数据!');
return;
}
//批量删除
if(btn == 'batch_del'){
tableIds = checkStatus.data.map(function (value) {return value.id;});
tableIds = JSON.stringify(tableIds);
@@ -221,12 +312,12 @@ layui.use(['form','table','dropdown','miniTab'], function () {
});
});
}
}
});
//监听行工具 - 文章列表
//监听行工具
table.on('tool(table)', function (obj) {
let btn = obj.event;
let data = obj.data;
@@ -251,118 +342,50 @@ layui.use(['form','table','dropdown','miniTab'], function () {
shadeClose: true,
closeBtn:0,
area: ['100%', '100%'],
content: './index.php?c=admin&page=expand/article-edit&id='+data.id+'&u=' + u,
content: './?c=admin&page=expand/article-edit&id='+data.id+'&u=' + u,
end: function(){
search();
}
});
}
});
//监听行工具 - 分类列表
table.on('tool(category_list)', function (obj) {
let btn = obj.event;
let data = obj.data;
if (btn === 'del') {
layer.confirm('确认删除?',{icon: 3, title:'温馨提示'}, function(index){
$.post(get_api('write_article','del_category'),{id:data.id},function(data,status){
if(data.code == 1) {
obj.del();
layer.msg(data.msg, {icon: 1});
}else{
layer.msg(data.msg, {icon: 5});
}
});
});
}else if(btn === 'edit'){
form.val('edit_category_form', data);
edit_category_index = layer.open({type: 1,scrollbar: false,shadeClose: true,title: '编辑分类',area : ['auto', 'auto'],content: $('.edit_category')});
}
//设置相关
form.val('set_form', <?php echo json_encode($set);?>);
$('#save_set').on('click', function(){
$.post(get_api('write_article','save_article_set'),form.val('set_form'),function(data,status){
if(data.code == 1) {
layer.close(index);
layer.msg('操作成功', {icon: 1});
}else{
layer.msg(data.msg || '未知错误',{icon: 5});
}
});
return false;
});
//添加分类
$('#add_category').click(function () {
add_category_index = layer.prompt({formType: 0,value: '',title: '请输入分类名称:',shadeClose: false,"success":function(){
$("input.layui-layer-input").on('keydown',function(e){
if(e.which == 13) {add_category();}
});
}},function(){
add_category()
});
});
//返回
$('#to_article_list').click(function () {
layer.close(category_index);
location.reload();
});
//刷新
$('#refresh_category').click(function () {
category_list();
});
//分类提示
$('#category_tip').click(function () {
layer.alert("权重越小越靠前",{title:'提示',anim: 2,closeBtn: 0});
//取消按钮
$('.cancel').click(function () {
layer.close(index);
return false;
});
//编辑分类-保存
$('#save_category').click(function () {
$.post(get_api('write_article','save_category'),form.val('edit_category_form'),function(data,status){
$("input.layui-layer-input").val("");
//批量修改分类
$('#batch_category').click(function () {
fid = $('#batch_category_fid').val();
$.post(get_api('write_article','up_category'),{'id':tableIds,'category_id':fid},function(data,status){
if(data.code == 1) {
category_list();
search();
layer.close(index);
layer.msg('操作成功', {icon: 1});
layer.close(edit_category_index);
}else{
$("input.layui-layer-input").focus();
layer.msg(data.msg || '未知错误',{icon: 5});
}
});
return false;
});
function add_category(){
let name = $("input.layui-layer-input").val();
if(name == ''){ return false; }
$("*").blur();
let loading = layer.msg('正在添加文章分类,请稍后..', {icon: 16,time: 1000*300,shadeClose: false});
$.post(get_api('write_article','add_category'),{'name':name},function(data,status){
layer.close(loading); layer.close(add_category_index);
$("input.layui-layer-input").val("");
if(data.code == 1) {
category_list();
layer.msg('操作成功', {icon: 1});
}else{
$("input.layui-layer-input").focus();
layer.msg(data.msg || '未知错误',{icon: 5});
}
});
function htmlspecialchars(str) {
return $('<div/>').text(str).html();
}
function category_list(){
table.render({
elem: '#category_list'
,height: 'full-70'
,url: get_api('read_article','category_list')
,page: false
,limit:999
,limits: [999]
,even:true
,loading:true
,id:'category_list'
,cols: [[
{title:'操作', toolbar: '#tablebar', width:110}
,{field: 'name', title: '分类名称', minWidth:200,width:300}
,{field: 'weight', title: '权重', minWidth:100,width:160}
]]
,method: 'post'
,response: {statusCode: 1 }
,done: function (res, curr, count) {
//获取当前每页显示数量.并写入本都储存
var temp_limit = $(".layui-laypage-limits option:selected").val();
if(temp_limit > 0 && localStorage.getItem(u + "_limit") != temp_limit){
localStorage.setItem(u + "_limit",temp_limit);
}
}
});
}
});
</script>

View File

@@ -202,7 +202,7 @@ require 'header.php';
</div>
<?php if(check_purview('theme_in',1)){ ?>
<div class="layui-col-xs3 layuimini-qiuck-module">
<a href="javascript:;" layuimini-content-href="theme_home" data-title="主题设置" data-icon="fa fa-magic">
<a href="javascript:;" layuimini-content-href="theme" data-title="主题设置" data-icon="fa fa-magic">
<i class="fa fa-magic"></i>
<cite>主题设置</cite>
</a>
@@ -242,7 +242,7 @@ require 'header.php';
<div class="layui-card">
<div class="layui-card-header">
<div style="display: flex; justify-content: space-between;">
<div><i class="fa fa-line-chart icon"></i>报表统计</div>
<div id="tongji" style="cursor: pointer;"><i class="fa fa-line-chart icon" ></i>报表统计</div>
<div>
<button class="layui-btn layui-btn-primary echarts" style="border: none;display:none;"><span>最近7天</span><i class="layui-icon layui-icon-down layui-font-12"></i></button>
</div>
@@ -359,6 +359,26 @@ if($USER_DB['UserGroup'] == 'root'){
}
});
$('#tongji').on('click', function(){
$.post('./index.php?c=api&method=read_data&date='+home_echarts+'&type=tongji_ip_list&u='+u,function(data,status){
if(data.code == 1){
var content = '<table class="layui-table" border="1"><thead><tr><th>日期</th><th>IP列表</th></tr></thead><tbody>';
$.each(data.data, function (date, ipAddresses) {
content += '<tr><td>' + date + '</td><td>';
$.each(ipAddresses, function (index, ipAddress) {
content += ipAddress + '<br>';
});
content += '</td></tr>';
});
content += '</tbody></table>';
layer.open({
title: '访问IP列表',
content: content,
area: ['100%', '100%']
});
}
});
});
//加载报表统计
function load_echarts(){
var echartsRecords = echarts.init(document.getElementById('echarts-records'), 'walden');

View File

@@ -56,9 +56,9 @@ $title='系统设置';require(dirname(__DIR__).'/header.php');
<div class="layui-form-item">
<label class="layui-form-label">发送人</label>
<div class="layui-input-inline">
<input type="text" name="sender" lay-verify="required" lay-reqtext="发送人邮箱不能为空" placeholder='' autocomplete="off" class="layui-input">
<input type="text" name="sender" lay-verify="required" lay-reqtext="发送人名称不能为空" placeholder='' autocomplete="off" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">例如: TwoNav书签&lt;test@qq.com&gt;</div>
<div class="layui-form-mid layui-word-aux">例如: TwoNav</div>
</div>
<div class="layui-form-item">

View File

@@ -259,7 +259,7 @@ $title='系统设置';require(dirname(__DIR__).'/header.php');
<option value="1" >开启</option>
</select>
</div>
<div class="layui-form-mid layui-word-aux">简易文章管理功能 ( 请勿和专业的比,暂无前端模板支持,视情况逐渐优化 )</div>
<div class="layui-form-mid layui-word-aux">简易文章管理功能 ( 请勿和专业的比,首次开启时自动下载相关资源 )</div>
</div>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;"><legend>相关限制</legend></fieldset>

View File

@@ -35,6 +35,7 @@ $user_groups = select_db('user_group',['id','code','name'],'');
<script type="text/html" id="user_tool">
<div class="layui-btn-group">
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="Del">删除</button>
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="Del_OTP" title="移除OTP双重验证">移除OTP验证</button>
<button class="layui-btn layui-btn-sm" lay-event="register" <?php echo $global_config['RegOption'] == 0? 'style = "display:none;"':'' ?> >注册账号</button>
<button class="layui-btn layui-btn-sm" lay-event="set_UserGroup">设用户组</button>
<button class="layui-btn layui-btn-sm" lay-event="username_retain">账号保留</button>
@@ -163,6 +164,16 @@ layui.use(['table','layer','form'], function () {
}else if(event == 'set_UserGroup'){
IDs = tableIds;
index = layer.open({type: 1,scrollbar: false,shadeClose: true,title: '修改用户组',area : ['100%', '100%'],content: $('.set_UserGroup')});
}else if(event == 'Del_OTP'){
layer.alert("以下账号将被移除OTP双重验证,确定继续吗?<br />"+table_Users,{icon:3,title:'确认操作',anim: 2,closeBtn: 0,btn: ['确定','取消']},function () {
$.post(get_api('write_user_info','Del_OTP'),{ID:tableIds},function(data,status){
if(data.code == 1){
layer.msg(data.msg,{icon: 1})
} else{
layer.msg(data.msg,{icon: 5});
}
});
});
}
});
//行工具

View File

@@ -4,7 +4,7 @@
<div class="layuimini-main">
<form class="layui-form" lay-filter="form">
<div class="layui-form layuimini-form layui-form-pane">
<blockquote class="layui-elem-quote layui-text">注意: 存在备用链接时停留时间可能无效!</blockquote>
<blockquote class="layui-elem-quote layui-text">注意: 存在备用链接时停留时间可能无效,需模板支持!</blockquote>
<div class="layui-form-item">
<label class="layui-form-label">访客停留</label>
<div class="layui-input-inline">
@@ -33,7 +33,7 @@
</div>
<div class="layui-form-item">
<div class="layui-input-block"><button class="layui-btn layui-btn-normal" lay-submit lay-filter="save">保存</button></div>
<div class="layui-input-block"><button class="layui-btn layui-btn-warm" type="button" id="close" >关闭</button><button class="layui-btn layui-btn-normal" lay-submit lay-filter="save">保存</button></div>
</div>
</div>
</form>
@@ -60,6 +60,10 @@ layui.use(['jquery','form'], function () {
});
return false;
});
//关闭按钮
$(document).on('click', '#close', function() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
});
});
</script>
</body>

View File

@@ -0,0 +1,58 @@
<?php $title='验证页面 - 设置'; require 'header.php'; ?>
<body>
<div class="layuimini-container">
<div class="layuimini-main">
<form class="layui-form" lay-filter="form">
<div class="layui-form layuimini-form layui-form-pane">
<blockquote class="layui-elem-quote layui-text">注意事项: 需模板支持,提示内容以http开头则打开网页,其他内容则弹出提示<br />使用场景: 加密链接/加密分类/二级密码/书签分享等</blockquote>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">加密链接</label>
<div class="layui-input-block">
<textarea name="link_tip" class="layui-textarea" placeholder='查看加密链接或分类时提示如何获取密码,可为空'></textarea>
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">书签分享</label>
<div class="layui-input-block">
<textarea name="share_tip" class="layui-textarea" placeholder='获取书签分享提取码的提示,可为空'></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block"><button class="layui-btn layui-btn-warm" type="button" id="close" >关闭</button><button class="layui-btn layui-btn-normal" lay-submit lay-filter="save">保存</button></div>
</div>
</div>
</form>
</div>
</div>
<script src = "<?php echo $libs;?>/jquery/jquery-3.6.0.min.js"></script>
<?php load_static('js.layui');?>
<script>
layui.use(['jquery','form'], function () {
var form = layui.form,
layer = layui.layer;
//表单赋值
form.val('form', <?php echo json_encode(unserialize( get_db("user_config", "v", ["k" => "s_verify_page","uid"=>$USER_DB['ID']]) ));?>);
//监听提交
form.on('submit(save)', function (data) {
$.post('./index.php?c=api&method=write_verify_page&u='+u,data.field,function(data,status){
if(data.code == 1) {
layer.msg(data.msg, {icon: 1});
}else{
layer.msg(data.msg, {icon: 5});
}
});
return false;
});
//关闭按钮
$(document).on('click', '#close', function() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,36 @@
<?php $title='主题管理';$awesome=true; require 'header.php';?>
<style>
.tab-header .layui-btn.layui-this{border-color: #1E9FFF; color: #1E9FFF;}
.screenshot{
width: 99%;
height: 99%;
max-width: 100%;
max-height: 100%;
aspect-ratio:16/9;
}
.layui-btn-container .layui-btn {
margin-right: 5px;
}
#default #del {display: none;}
</style>
<div class="layuimini-container">
<div class="layuimini-main">
<div class="tab-header layui-btn-container" id="tab" style="margin-left: 5px;"></div>
<div class="layui-bg-gray" style="padding: 1px;" >
<div class="layui-row layui-col-space15"></div>
</div>
</div>
</div>
<script src="<?php echo $libs;?>/jquery/jquery-3.6.0.min.js"></script>
<script src="<?php echo $libs;?>/jquery/jquery.lazyload.min.js"></script>
<script src="./templates/admin/js/public.js?v=<?php echo $Ver;?>"></script>
<?php load_static('js');?>
<script src="./templates/admin/js/theme.js?v=<?php echo $Ver;?>"></script>
<script>
const is_admin = <?php echo $USER_DB['UserGroup'] === 'root' ? 'true' : 'false'; ?>;
const theme_set = <?php echo check_purview('theme_set',1) ? 'true' : 'false'; ?>;
const apply = <?php echo check_purview('apply',1) ? 'true' : 'false'; ?>;
const guestbook = <?php echo check_purview('guestbook',1) ? 'true' : 'false'; ?>;
const article = <?php echo check_purview('article',1) ? 'true' : 'false'; ?>;
const loginAddress = '<?php echo $USER_DB['Login']; ?>';
</script>

View File

@@ -2,13 +2,92 @@
<body>
<div class="layuimini-container">
<div class="layuimini-main" style=" margin-left: 20px;">
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<h4 class="layui-timeline-title">v2.0.37-20230830</h4>
<ul>
<li>[变更] 优化前端前置处理代码,让模板调用数据更加灵活</li>
<li>[新增] 支持更换验证模板/收录模板/留言模板</li>
<li>[新增] 验证模板支持设置提示内容,如获取密码的提示</li>
<li>[新增] 挽风导航V1的收录模板和留言模板</li>
<li>[新增] 4个简约风格的验证模板</li>
<li>[修复] 文章编辑器输入HTML代码时在编辑存在异常的问题</li>
<li>[修复] 文章标题/摘要存在HTML标签时被解析的问题</li>
<li>[修复] WebStack-Hugo主页模板4个已知问题</li>
<li>[修复] 特定情况下安装时使用MySQL数据库可能乱码的问题</li>
</ul>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<h4 class="layui-timeline-title">v2.0.36-20230824</h4>
<ul>
<li>[修复] 判断是否显示收录的逻辑错误(导致设为无需审核时不显示)</li>
<li>[变更] 移除2个链接图标API,因稳定性欠佳</li>
<li>[修复] WebStack-Hugo主页模板悬停提示不显示</li>
<li>[新增] 挽风导航主页模板(内置文章模板/拟态风格),注:内置文章模板在预览状态下是不生效的!</li>
<li>[新增] 挽风导航登录模板/过度模板</li>
<li>[新增] 后台概要页可以点击报表统计获取访问的IP列表</li>
<li>[修复] 文章状态非公开且已登录无法预览文章</li>
</ul>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<h4 class="layui-timeline-title">v2.0.35-20230816</h4>
<ul>
<li>[新增] Atool工具箱增加关闭OTP双重验证选项(删OTP),用于解决站长丢失OTP令牌造成无法登录</li>
<li>[新增] 用户管理支持关闭OTP双重验证选项,用于站长帮助用户关闭OTP双重验证</li>
<li>[优化] 邮件配置发送人只填发送人名称未按要求格式填写邮箱时由系统自动完成拼接</li>
<li>[优化] 文章管理特定情况造成缺少资源时提醒用户如何解决</li>
<li>[模板] 新增爱导航V1主页模板,轻量化设计简洁不卡顿/支持缓存/自适应/站内搜索,适合书签多的用户使用</li>
<li>[模板] WebStack-Hugo主页模板新增:夜间背景图/炫彩横幅</li>
<li>[模板] 修复默认过度模板兼容问题</li>
</ul>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<h4 class="layui-timeline-title">v2.0.34-20230809</h4>
<ul>
<li>[新增] 安全设置新增OTP双重验证</li>
<li>[模板] 所有登录模板:已开启双重验证时,支持输入OTP验证码,版本:2.0.4 </li>
<li>[警告] 如果您正在使用非默认登录模板,请立即更新登录模板,以免因模板不支持输入OTP验证码造成无法登录</li>
<li>[新增] 导出导入>清空数据>支持清空文章和上传目录(upload)</li>
<li>[新增] 导出导入>本地备份>支持备份和回滚文章列表</li>
</ul>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<h4 class="layui-timeline-title">v2.0.33-20230802</h4>
<ul>
<li>[新增] 文章编辑新增封面上传功能,插入网络视频功能</li>
<li>[新增] 文章列表以链接的方式展现到主页( 已登录时显示公开和私有,未登录时显示公开文章 )</li>
<li>[新增] 文章列表新增批量操作,支持批量删除,批量修改文章分类和状态</li>
<li>[修复] 文章相关功能的已知问题</li>
<li>[变更] 移除文章功能的独立分类机制,改为使用链接分类 ( 已存在的文章需手动更新分类 )</li>
<li>[变更] API接口鉴权逻辑调整,新增几个兼容API,移除API模式中的兼容+开放模式</li>
<li>[变更] 默认主页模板右键对查看全部或文章链接操作给出提示,给文章链接添加黑色角标</li>
<li>[新增] 主页模板:简约主题 ( 需将安全设置>API模式>改为兼容模式才能使用全部功能 ) 作者:涂山</li>
<li>[新增] 主页模板:花森主页( 自带文章浏览功能 ),作者:花森JioJio</li>
<li>[新增] 文章模板:挽风导航,作者:凌云</li>
<li>[优化] 默认文章模板样式</li>
</ul>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<h4 class="layui-timeline-title">v2.0.32-20230727</h4>
<ul>
<li>[新增] 扩展功能新增简易文章管理 [ 半成品,尚未完善 ]</li>
<li>[新增] 链接自定义字段类型新增up_img,该类型支持上传1M大小的图片,权限上传图标共享</li>
<li>[新增] 链接自定义字段类型新增up_img,该类型支持上传1M大小的图片,权限上传图标共享</li>
<li>[新增] 链接自定义字段新增提示内容</li>
<li>[变更] 主页模板前置处理,若模板支持链接扩展时提供扩展信息</li>
<li>[跟进] 支持onenav新版浏览器插件的兼容</li>

View File

@@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<title>申请收录</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel='stylesheet' href='<?php echo $layui['css']; ?>'>
<style>
body{background-color:rgba(0, 0, 51, 0.8);}
.title{max-width: 400px;height: auto;margin-left: auto;margin-right: auto;margin-top:5em;}
.title h1{color:#FFFFFF;text-align: center;}
.required {color: red;margin-left: 5px;float: right;}
</style>
</head>
<body>
<div class="layui-container">
<div class="layui-row">
<div class="title">
<h1>申请收录</h1>
</div>
<div class="layui-col-lg6 layui-col-md-offset3" style ="margin-top:3em;">
<form class="layui-form layui-form-pane" action="" lay-filter="apply">
<div class="layui-form-item" style="color: #fbfbfb;">
<?php echo $apply['Notice'];?>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站标题<span class="required">*</span></label>
<div class="layui-input-block">
<input type="text" name="title" required lay-verify="required" placeholder="例如 百度一下" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站链接<span class="required">*</span></label>
<div class="layui-input-block">
<input type="url" name="url" required lay-verify="required|url" placeholder="例如 https://www.baidu.com" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站分类<span class="required">*</span></label>
<div class="layui-input-block">
<select name="category_id" lay-verify="required" lay-search>
<option ></option>
<?php echo_category(false);//输出公开分类 ?>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站图标</label>
<div class="layui-input-block">
<input type="url" name="iconurl" lay-verify="url" placeholder="例如 https://www.baidu.com/favicon.ico" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站描述</label>
<div class="layui-input-block">
<input type="text" name="description" placeholder="例如 搜索引擎" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">联系邮箱</label>
<div class="layui-input-block">
<input type="text" name="email" placeholder="例如 admin@qq.com" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn" lay-submit lay-filter="submit" style = "width:100%;">提交</button>
</div>
</form>
<?php if( is_login() ) { echo
'<div class="layui-form-item"><button class="layui-btn" lay-submit lay-filter="test" style = "width:100%;">生成测试数据 (自己登录时才显示此按钮)</button></div>'
;} ?>
</div>
</div>
</div>
<script src='<?php echo $layui['js']; ?>'></script>
<script>
layui.use(['form','layer'], function(){
var form = layui.form;
var $ = layui.jquery;
form.on('submit(submit)', function(data){
$.post('',data.field,function(re,status){
if(re.code == 1) {
layer.msg(re.msg, {icon: 1});
}else{
layer.msg(re.msg, {icon: 5});
}
});
return false;
});<?php if( is_login() ) { echo '
//生成测试数据
form.on("submit(test)", function(data){
form.val("apply", {
"title": "百度一下"
,"url": "https://"+ Math.round(new Date()) +".baidu.com"
,"iconurl": "https://www.baidu.com/favicon.ico"
,"description": "搜索引擎"
,"email": "admin@qq.com"
});
return false;
});' ;} ?>
});
</script>
</body>
</html>

View File

@@ -0,0 +1,8 @@
{
"name": "默认模板",
"description": "默认",
"homepage": "https://gitee.com/tznb/TwoNav",
"version": "2.0.0",
"update": "2023/08/25",
"author": "TwoNav"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title><?php echo $theme;?> - 主题配置</title>
<link rel='stylesheet' href='<?php echo $layui['css']; ?>'>
<style>
.layui-form-item {margin-bottom: 10px;}
</style>
</style>
</head>
<body>
<div class="layui-row" style = "margin-top:18px;">
<div class="layui-container">
<div class="layui-col-lg8 layui-col-md-offset2">
<form class="layui-form" lay-filter="form">
<div class="layui-form-item">
<label class="layui-form-label">最大宽度</label>
<div class="layui-input-block">
<input type="text" name="container_width" placeholder="默认为空(全宽),输入格式80%或1280px" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item" style="padding-top: 10px;">
<div class="layui-input-block"><button class="layui-btn" lay-submit lay-filter="save">保存</button></div>
</div>
</form>
</div>
</div>
</div>
<script src="<?php echo $layui['js']; ?>"></script>
<script src="./templates/admin/js/public.js?v=<?php echo $Ver;?>"></script>
<script>
var u = _GET('u');
layui.use(['form'], function(){
var form = layui.form;var $ = layui.$;
form.val('form', <?php echo json_encode($theme_config);?>);
form.on('submit(save)', function(data){
$.post(get_api('write_theme','config') + '&t=' + _GET('theme'),data.field,function(data,status){
if(data.code == 1) {
layer.msg(data.msg, {icon: 1,time: 500,end: function() {if(_GET('source') != 'admin'){parent.location.reload();}}});
}else{
layer.msg(data.msg, {icon: 5});
}
});
return false;
});
});
</script>
</body>
</html>

View File

@@ -1,145 +1,68 @@
@charset "utf-8";
html{height: 100%;}
body{margin: 0;background: #0D1721;font-family:'pingfang SC','helvetica neue',arial,'hiragino sans gb','microsoft yahei ui','microsoft yahei',simsun,sans-serif;font-size:16px;line-height: 140%;color: #ddd;}
ul, ol, li,dt,dd{margin:0; padding:0;list-style: none;}
dl{margin-top:0; margin-bottom:0;}
p{margin:0 0 10px;}
img{border: 0; vertical-align:middle;max-width: 100%;}
img.img-responsive{width: 100%;}
input{outline: medium none;outline: none;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}
input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { color: #8A8A8A;}
input:focus{border-color:#FF9900; -webkit-box-shadow:inset 0 1px 1px rgba(255,136,0,.075),0 0 8px rgba(255,136,0,.6);}
/* container */
*{-webkit-box-sizing:border-box; -moz-box-sizing:border-box; box-sizing:border-box}
:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
.container {width: 75%;position: relative;padding-right: 15px;padding-left: 15px;margin: 0 auto;}
.row{position: relative; margin-right: -15px; margin-left: -15px;}
.container:before,.container:after,.row:before,.row:after,.clearfix:before, .clearfix:after{ display: table; content: " "; clear: both;}
/* text */
h1{ font-size:22px; line-height: 28px;}
h2{ font-size:20px; line-height: 26px;}
h3{ font-size:18px; line-height: 24px;}
h4{ font-size:16px; line-height: 22px;}
h5{ font-size:14px; line-height: 20px;}
h6{ font-size:12px; line-height: 18px;}
h1,h2,h3,h4,h5,h6{ font-weight: 400; margin-top:10px; margin-bottom:10px}
a,button{ text-decoration:none; outline:none; -webkit-tap-highlight-color:rgba(0,0,0,0)}
a,h1, h2, h3, h4, h5, h6{ color: #8A8A8A;}
a,h1{color: #ffffff;}
a{color: #b1edff;}
a:focus,a:hover,a:active{text-decoration:none;color: #FF9900;}
.col-pd{ padding: 15px 20px;}
.text-muted{ color: #999;}
.split-line{display: inline-block; margin-left: 12px; margin-right: 12px; width: 1px; height: 14px; vertical-align: -2px; background: #636060;}
.news-title{
border-bottom: 1px solid #4f4f4f !important;
padding-bottom: 12px;
}
/* header */
.newbui-header__top{position: relative;height: 100px;padding: 0 20px;}
.newbui-header__logo{float:left; margin-right: 120px;}
.newbui-header__logo{width: auto;margin-top: 20px;}
.newbui-header__logo .logo{display:block;width: auto;height:60px;}
.newbui-header__search{float: right;position:relative;width:280px;margin-top: 32px;}
.newbui-header__search .form-control{display:block;width:100%;height: 35px;padding:6px 45px 6px 10px;font-size:12px;line-height:32px;border-radius: 5px;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;background: #2D2F36;color: #8A8A8A;-webkit-text-fill-color: #8A8A8A;border: 0;}
.newbui-header__search .submit{display:block; position:absolute; top: 0; right: 0; width:35px; height:35px; border: 0; cursor: pointer; background: url(img/icon_seacrh.png) center no-repeat;}
.newbui-header__bar{position:relative;margin: 0;background: #223855;color: #191A20;box-shadow: 0 5px 10px #000;}
.newbui-header__menu > li{ position: relative; float:left;}
.newbui-header__menu > li > a{display:inline-block; padding: 15px 30px; font-size:15px; color: #fff;}
.newbui-header__menu > li > a:hover {background: #191A20;color: #FF9900;}
.newbui-header__menu > li.active > a{background: #191A20; color: #fff;}
.newbui-header__menu li .dropdown{display: none;width: 100%;position: absolute;z-index: 999;top: 100%;right: 0;text-align: center;font-size: 12px;color: #999;background: #2D2F36;box-shadow: 0 2px 8px rgba(0,0,0,.1);}
.newbui-header__menu li .dropdown li{ padding: 8px 0; border-top: 1px solid #2D2F36;}
.newbui-header__menu li .dropdown li:first-child{ padding-top: 15px; border-top: 0;}
.newbui-header__menu li .dropdown li:last-child{ padding-bottom: 15px;}
.newbui-header__menu li a{ font-size: 14px;}
.newbui-header__menu li:hover .dropdown{ display: block;}
.newbui-header__more{float: left;padding-top: 20px;width: 250px;}
.newbui-header__more li{margin-bottom: 5px;color: #ddd;}
.newbui-header__more li .text{ display: inline-block; width: 60px; color: #fff;}
/* pannel */
.newbui-pannel{position: relative;margin-top: 30px;background: #0D1721;border-radius: 5px;border: 1px solid #2D2F36;}
.newbui-pannel-left{ float: left; width: 70%;}
.newbui-pannel-side{ float: left; width: 30%;}
.newbui-pannel__head{padding: 15px 20px;line-height: 25px;border-bottom: 1px solid #2D2F36;}
.newbui-pannel__head .title{ margin: 0;}
.newbui-pannel__foot{ padding: 15px 20px;}
/* more */
.margin-0{ margin: 0 !important;}
.padding-0{ padding: 0 !important;}
.pull-left{ float: left !important;}
.pull-right{ float: right !important;}
.hide,.visible-lg, .visible-md, .visible-sm, .visible-xs, .visible-mi{ display: none !important;}
.newbui-foot{ padding: 20px; text-align: center; color: #999;}
.pc{display: block!important;}
.m{display: none!important;}
.navbar-light {
color: #fff !important;
font-size: 16px;
/*font-weight: bold;*/
text-shadow: 0px 1px 0px #000
}
@media (min-width: 1200px){
.visible-lg { display: block !important;}
.hidden-lg {display: none !important;}
h1,h2,h3,h4,h5{
color: black;
}
@media (max-width: 1199px) and (min-width: 992px){
.visible-md { display: block !important;}
.hidden-md {display: none!important;}
li {
line-height: 2.2;
}
/*图片边距*/
img {
margin: 10px;
}
/*代码段样式*/
pre {
background-color: #f2f2f2;
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
margin: 10px 0;
font-family: "Courier New", monospace;
font-size: 14px;
line-height: 1.5;
overflow-x: auto;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);
}
/*表格样式*/
.mdui-table {
border-collapse: collapse;
width: 100%;
}
.mdui-table th,
.mdui-table td {
border: 1px solid #ccc;
padding: 8px;
text-align: center;
}
.mdui-table th::after,
.mdui-table td::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: -1px;
width: 1px;
background-color: #ccc;
}
@media (max-width: 991px) and (min-width: 768px){
.visible-sm{ display: block !important;}
.hidden-sm {display: none !important;}
/*a标签样式*/
.container a {
text-decoration: none;
color: inherit;
font-family: Arial, sans-serif;
color: #007bff;
padding: 5px 10px;
border-radius: 5px;
background-color: #f2f2f2;
}
.container a:hover {
color: #ff4500;
}
@media (max-width: 1023px){
.container{ width: 100%; padding-right: 30px; padding-left: 30px;}
/*文章标题样式*/
.mdui-typo-title, .mdui-typo-title-opacity {
font-size: 1em;
}
@media (max-width:767px){
.visible-xs { display: block !important;}
.hidden-xs {display: none!important;}
.container{ padding: 0;}
.row{ margin: 0;}
.col-pd{ padding: 10px;}
/* header */
.newbui-header__top{ height: 60px; padding:0 10px;}
.newbui-header__logo{margin: 12px 0 0;padding: 0;}
.newbui-header__logo .logo{width: 148px; height:35px;}
.newbui-header__search{ float: none; width: auto; margin: 0; position: absolute; top: 15px; right: 10px; left: 168px;}
.newbui-header__search .form-control{ height: 30px; line-height: 30px; border-radius: 5px; padding:6px 40px 6px 10px; border: 0;}
.newbui-header__search .submit{ width: 30px; height: 30px;}
.newbui-header__bar{ box-shadow: none;}
.newbui-header__menu { position:relative; margin: 0; overflow: auto; white-space:nowrap; overflow-y:hidden;overflow-x:scroll; -webkit-overflow-scrolling:touch}
.newbui-header__menu > li{ float: none; display: inline-block;}
.newbui-header__menu > li > a{ padding: 10px 15px; font-size: 14px;}
.newbui-header__menu li:hover .dropdown{ display: none;}
/* pannel */
.newbui-pannel{ margin-top: 10px; border: 0; border-radius: 0; box-shadow: none;}
.newbui-pannel__head{ padding: 10px; line-height: 25px; border-bottom: 1px solid #2D2F36;}
.newbui-pannel__head .title{ font-size: 16px;}
.newbui-pannel__foot{ padding: 10px;}
.pc{
display: none!important;
}
.m{
display: block!important;
}
}
/*prism 代码上色*/
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}

File diff suppressed because one or more lines are too long

View File

@@ -1,46 +1,44 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title><?php echo $data['title'];?></title>
<meta name="keywords" content="<?php echo $data['summary']; ?>">
<meta name="description" content="<?php echo $data['summary']; ?>">
<link rel="stylesheet" href="<?php echo $theme_dir?>/index.css?v=<?php echo $theme_ver; ?>" type="text/css" media="all" />
<link rel="shortcut icon" href="<?php echo $favicon;?>">
</head>
<body>
<div class="newbui-header__bar clearfix">
<div class="container">
<div class="row">
<ul class="newbui-header__menu clearfix">
<li class="pc"><a class="navbar-light" href="./index.php?u=<?php echo $GLOBALS['u'];?>">首页</a></li>
</ul>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="newbui-pannel clearfix">
<div class="newbui-pannel-box clearfix">
<div class="newbui-pannel_bd col-pd clearfix">
<h1 class="news-title"><?php echo $data['title'];?></h1>
<div class="news-content">
<?php echo $data['content'];?>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="newbui-foot clearfix">
<p class="text-muted">
<?php echo $copyright.PHP_EOL;?>
<?php echo $ICP.PHP_EOL;?>
</p>
<?php echo $site['custom_footer'].PHP_EOL;?>
<?php echo $global_config['global_footer'].PHP_EOL;?>
</div>
</body>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="renderer" content="webkit"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=5.0">
<meta http-equiv="Cache-Control" content="no-siteapp"/>
<title><?php echo $data['title'];?> - <?php echo $site['title']; ?></title>
<meta name="keywords" content="<?php echo $data['summary']; ?>">
<meta name="description" content="<?php echo $data['summary']; ?>">
<link rel="shortcut icon" href="<?php echo $favicon;?>">
<link rel="stylesheet" href="<?php echo $libs?>/MDUI/v1.0.1/css/mdui.min.css">
<link rel="stylesheet" href="<?php echo $theme_dir?>/index.css">
</head>
<body class="mdui-drawer-body-left mdui-appbar-with-toolbar mdui-theme-primary-indigo mdui-theme-accent-pink mdui-theme-layout-auto">
<header class="appbar mdui-appbar mdui-appbar-fixed">
<div class="mdui-toolbar mdui-color-theme">
<span class="mdui-btn mdui-btn-icon mdui-ripple mdui-ripple-white" mdui-drawer="{target: '#main-drawer', swipe: true}">
<i class="mdui-icon material-icons">menu</i>
</span>
<a href="" class="mdui-typo-headline mdui-hidden-xs"><?php echo $site['logo'];?></a>
<a href="" class="mdui-typo-title"><?php echo $data['title'];?></a>
<div class="mdui-toolbar-spacer"></div>
</div>
</header>
<div class="mdui-drawer" id="main-drawer">
<div class="mdui-collapse-item-header mdui-list-item mdui-ripple" data_id="to_top">
<i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-blue">&#xe25a;</i>
<div class="mdui-list-item-content">文章开始</div>
</div>
<div class="mdui-collapse-item-header mdui-list-item mdui-ripple" data_id="to_bottom" id="to_bottom">
<i class="mdui-list-item-icon mdui-icon material-icons mdui-text-color-blue">&#xe258;</i>
<div class="mdui-list-item-content">文章结尾</div>
</div>
</div>
<div class="container p-download mdui-container" style="max-width: <?php echo $theme_config['container_width'];?> ;">
<?php echo $data['content'];?>
</div>
<script src="<?php echo $libs?>/MDUI/v1.0.1/js/mdui.min.js"></script>
<script src="<?php echo $libs?>/jquery/jquery-3.6.0.min.js"></script>
<script src="<?php echo $theme_dir?>/index.js"></script>
</body>
</html>

View File

@@ -1,9 +1,12 @@
{
"name":"默认",
"description":"待优化",
"name":"默认模板",
"description":"系统默认的文章模板,支持代码段上色,支持自适应!",
"homepage":"https://gitee.com/tznb/TwoNav",
"version":"2.0.0",
"update":"2023/07/27",
"update":"2023/07/01",
"author":"TwoNav",
"screenshot":"https://s3.bmp.ovh/imgs/2022/04/17/8cac968a8cc8135c.png"
"screenshot":"https://img.lm21.top/article_default.jpg",
"config": {
"container_width":""
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -0,0 +1,87 @@
<?php ?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title><?php echo $site['title'];?> - 极简留言板</title>
<link rel='stylesheet' href='<?php echo $layui['css']; ?>'>
<style>
.layui-form-item {
margin-bottom: 10px;
height: 38px;
}
</style>
</head>
<body>
<div>
<!-- 内容主体区域 -->
<div class="layui-row" style = "margin-top:18px;">
<div class="layui-container">
<div class="layui-col-lg10 ">
<form class="layui-form">
<fieldset class="layui-elem-field layui-field-title " style="margin-top: 30px;"><legend>极简留言板</legend></fieldset>
<div class="layui-form-item">
<label class="layui-form-label">反馈类型</label>
<div class="layui-input-inline">
<select lay-verify="required" id="type" name="type" lay-search >
<option value="投诉建议" >投诉建议</option>
<option value="问题反馈" selected="" >问题反馈</option>
<option value="商务合作" >商务合作</option>
<option value="其他" >其他</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">联系方式</label>
<div class="layui-input-inline" >
<input id = "contact" name="contact" value = "" placeholder="仅管理员可见" required lay-verify="required" class="layui-input" maxlength="64">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">标题</label>
<div class="layui-input-block" >
<input id = "title" name="title" value = "" placeholder="" required lay-verify="required" class="layui-input" maxlength="128">
</div>
</div>
<div class="layui-form-text">
<label class="layui-form-label">内容</label>
<div class="layui-input-block">
<textarea id = "content" name="content" rows = "10" class="layui-textarea" required lay-verify="required" maxlength="2048"></textarea>
</div>
</div>
<div class="layui-form-item" style="padding-top: 10px;">
<div class="layui-input-block">
<?php if($s['allow'] == '1'){ echo '<button class="layui-btn" lay-submit lay-filter="Submit">提交</button>';} ?>
</div>
</div>
</form>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend><?php echo $copyright;?></legend>
<!--非订阅用户请勿去除版权,谢谢-->
</fieldset>
</div>
<!-- 内容主题区域END -->
</div>
<script src = '<?php echo $libs?>/jquery/jquery-3.6.0.min.js'></script>
<script src = '<?php echo $layui['js']; ?>'></script>
<script>
layui.use(['form'], function(){
var form = layui.form;
form.on('submit(Submit)', function(data){
$.post('',data.field,function(data,status){
if(data.code == 1) {
layer.msg(data.msg, {icon: 1});
setTimeout(() => {location.reload();}, 1000);
}else{
layer.msg(data.msg, {icon: 5});
}
});
return false;
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,8 @@
{
"name": "默认模板",
"description": "默认",
"homepage": "https://gitee.com/tznb/TwoNav",
"version": "2.0.0",
"update": "2023/08/25",
"author": "TwoNav"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,5 +1,5 @@
{
"name": "默认",
"name": "默认模板",
"description": "模板来自于html5up.net",
"homepage": "https://gitee.com/tznb/TwoNav",
"version": "2.0.0",

View File

@@ -192,10 +192,8 @@ body{
<!--定义一个卡片-->
<div class="mdui-card link-line mdui-hoverable CBC">
<!-- 如果是私有链接,则显示角标 -->
<?php if($link['property'] == 1 ) { ?>
<div class="angle">
<span> </span>
</div>
<?php if($link['property'] == 1 || $link['type'] == 'article') { ?>
<div class="angle" <?php echo $link['type'] == 'article' ? 'style="background: #000000;"':'';?>><span> </span></div>
<?php } ?>
<!-- 角标END -->
<a class="TFC" href="<?php echo $link['url']; ?>" target="_blank" <?php echo $protectA; ?> title = "<?php echo $link['description']; ?>">

View File

@@ -2,8 +2,8 @@
"name":"默认主题(加强)",
"description":"默认主题(加强)",
"homepage":"https://gitee.com/tznb/OneNav",
"version":"2.0.2",
"update":"2023/05/20",
"version":"2.0.3",
"update":"2023/07/31",
"author":"落幕",
"screenshot":"https://s3.bmp.ovh/imgs/2022/04/17/8cac968a8cc8135c.png",
"config": {

View File

@@ -33,17 +33,19 @@ var menu = {
var link_id = $(this).attr('id');
link_id = link_id.replace('id_','');
var tempwindow=window.open('_blank');
tempwindow.location='./index.php?c=click&id='+link_id+"&u="+u;
tempwindow.location = $(this).attr('link-url');
}},
"edit": {name: "编辑", icon: "edit",callback:function(key,opt){
var link_id = $(this).attr('id');
link_id = link_id.replace('id_','');
if(link_id == '0'){mdui.alert('非常规链接,无法操作');return true;}
var tempwindow=window.open('_blank');
tempwindow.location='./index.php?c=admin&page=link_edit&id='+link_id+"&u="+u;
}},
"delete": {name: "删除", icon: "delete",callback:function(){
var link_id = $(this).attr('id');
link_id = link_id.replace('id_','');
if(link_id == '0'){mdui.alert('非常规链接,无法操作');return true;}
mdui.confirm('确认删除?'
,function(){
$.post(get_api('write_link','del'),{lid:link_id},function(data,status){

View File

@@ -1,4 +1,5 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}?>
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}
$LoginConfig = unserialize($USER_DB['LoginConfig']);?>
<!DOCTYPE html>
<html>
<head>
@@ -29,16 +30,21 @@
<form class="layui-form login-bottom">
<div class="center">
<div class="item">
<span class="icon icon-2"></span>
<span class="icon layui-icon layui-icon-username"></span>
<input type="text" name="User" lay-verify="required" placeholder="请输入账号">
</div>
<div class="item">
<span class="icon icon-3"></span>
<span class="icon layui-icon layui-icon-password"></span>
<input type="password" name="Password" lay-verify="required" placeholder="请输入密码">
<span class="bind-password icon icon-4"></span>
</div>
<?php if(!empty($LoginConfig['totp_key'])){ ?>
<div class="item">
<span class="icon layui-icon layui-icon-vercode"></span>
<input type="text" name="otp_code" lay-verify="required" placeholder="请输入OTP验证码">
</div>
<?php }?>
</div>
<div class="tip">
<?php

View File

@@ -1,8 +1,8 @@
{
"name": "默认",
"name": "默认模板",
"description": "默认",
"homepage": "https://gitee.com/tznb/TwoNav",
"version": "2.0.2",
"update": "2023/04/25",
"version": "2.0.4",
"update": "2023/08/09",
"author": "TwoNav"
}

View File

@@ -1,5 +1,5 @@
{
"name": "默认",
"name": "默认模板",
"description": "默认",
"homepage": "https://gitee.com/tznb/TwoNav",
"version": "2.0.0",

View File

@@ -1,15 +1,16 @@
<!DOCTYPE html>
<html lang="zh-cn" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta charset="utf-8">
<title><?php echo $link['title']; ?> - <?php echo $site['title']; ?></title>
<meta name="keywords" content="<?php echo $link['keywords']; ?>" />
<meta name="description" content="<?php echo $link['description']; ?>" />
<meta name="keywords" content="<?php echo $link['keywords']; ?>">
<meta name="description" content="<?php echo $link['description']; ?>">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="<?php echo $libs?>/bootstrap4/css/bootstrap.min.css" type="" media=""/>
<meta http-equiv = "X-UA-Compatible" content = "IE=edge" >
<link rel="stylesheet" href="<?php echo $libs?>/bootstrap4/css/bootstrap.min.css" crossorigin="anonymous">
<link rel="shortcut icon" href="<?php echo $favicon;?>">
<!--<script src="<?php echo $libs?>/jquery/jquery-2.2.4.min.js"></script>-->
<!--<script src="<?php echo $libs?>/bootstrap4/js/bootstrap.min.js"></script>-->
<script src="<?php echo $libs?>/jquery/jquery-2.2.4.min.js"></script>
<script src="<?php echo $libs?>/bootstrap4/js/bootstrap.min.js" crossorigin="anonymous"></script>
<style>
.a_d img{
max-width:100%;

View File

@@ -1,5 +1,5 @@
{
"name":"OneNav1",
"name":"默认模板",
"description":"OneNav旧版过渡页",
"homepage":"https://www.xiaoz.me",
"version":"2.0.2",

View File

@@ -0,0 +1,91 @@
<?php if(!defined('DIR')){header('HTTP/1.1 404 Not Found');header("status: 404 Not Found");exit;}?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php echo $data['title'];?> - <?php echo $site['subtitle']?></title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="format-detection" content="telephone=no">
<link rel="stylesheet" href="<?php echo $layui['css']; ?>">
<link rel="stylesheet" href="<?php echo $libs?>/Other/login.css">
<link rel="shortcut icon" href="<?php echo $favicon;?>">
</head>
<body>
<div class="main-body">
<div class="login-main">
<div class="login-top">
<span><?php echo $data['tip'];?></span>
<span class="bg1"></span>
<span class="bg2"></span>
</div>
<form class="layui-form login-bottom">
<div class="center">
<div class="item">
<span class="icon icon-3"></span>
<input type="password" name="Password" id="Password" lay-verify="required" placeholder="<?php echo $data['input_tip'];?>" value="<?php echo $_GET['pwd'];?>">
<span class="bind-password icon icon-4"></span>
</div>
</div>
<div class="tip">
<?php if(!empty($data['get_tip'])){ ?>
<a href="javascript:;" onclick="showInfo('<?php echo base64_encode($data['get_tip'])?>')">如何获取?</a>
<?php }?>
</div>
<div class="layui-form-item" style="text-align:center; width:100%;height:100%;margin:0px;">
<button class="login-btn"id="verify">验证</button>
</div>
</form>
</div>
</div>
<div class="footer"><?php echo $copyright;?></div>
<script src="<?php echo $libs?>/jquery/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="<?php echo $libs?>/Layer/v3.3.0/layer.js"></script>
<script>
$('#verify').on('click', function () {
Password = $("#Password").val();
if( Password == ''){
layer.msg("<?php echo $data['input_tip'];?>", {icon: 5});
$('#Password').focus();
return false;
}
$.post('<?php echo $data['post_url']; ?>',{'Password':Password},function(re,status){
if(re.code == 1) {
layer.msg('正在验证..', {icon: 16,shade: [0.1, '#f5f5f5'],scrollbar: false,offset: 'auto',time: 888,
end: function() {
window.location.reload();
return false;
}
});
}else{
layer.msg(re.msg, {icon: 5});
}
});
return false;
});
// 显示密码
$('.bind-password').on('click', function () {
if ($(this).hasClass('icon-5')) {
$(this).removeClass('icon-5');
$("input[name='Password']").attr('type', 'password');
} else {
$(this).addClass('icon-5');
$("input[name='Password']").attr('type', 'text');
}
});
function showInfo($base64) {
var content =decodeURIComponent(escape(window.atob($base64)));
if(content.startsWith("http")){
window.open(content);
return false;
}
layer.open({type: 1,title: '如何获取',btn: ['知道了'],
content: '<div style="padding: 20px; line-height: 22px; font-weight: 300;"><?php echo $data['get_tip'];?></div>'
});
}
</script>
</body>
</html>

View File

@@ -0,0 +1,8 @@
{
"name": "默认模板",
"description": "默认",
"homepage": "https://gitee.com/tznb/TwoNav",
"version": "2.0.0",
"update": "2023/08/25",
"author": "TwoNav"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB