diff --git a/README.md b/README.md index 3d1bdd8..c6d8c44 100755 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ docker run -itd --name="onenav" -p 80:80 \ * `PASSWORD`:设置密码,上述设置为`xiaoz.me` * `/data/onenav`:本机挂载目录,用于持久存储Onenav数据 -> 更多说明,请参考帮助文档:https://www.yuque.com/helloz/onenav +> 更多说明,请参考帮助文档:https://dwz.ovh/onenav ## Demo diff --git a/class/Api.php b/class/Api.php index df1a17e..f8b2365 100755 --- a/class/Api.php +++ b/class/Api.php @@ -15,14 +15,15 @@ class Api { /** * name:创建分类目录 */ - public function add_category($token,$name,$property = 0,$weight = 0,$description = ''){ + public function add_category($token,$name,$property = 0,$weight = 0,$description = '',$font_icon = ''){ $this->auth($token); $data = [ 'name' => htmlspecialchars($name,ENT_QUOTES), 'add_time' => time(), 'weight' => $weight, 'property' => $property, - 'description' => htmlspecialchars($description,ENT_QUOTES) + 'description' => htmlspecialchars($description,ENT_QUOTES), + 'font_icon' => $font_icon ]; //插入分类目录 $this->db->insert("on_categorys",$data); @@ -46,7 +47,7 @@ class Api { * 修改分类目录 * */ - public function edit_category($token,$id,$name,$property = 0,$weight = 0,$description = ''){ + public function edit_category($token,$id,$name,$property = 0,$weight = 0,$description = '',$font_icon = ''){ $this->auth($token); //如果id为空 if( empty($id) ){ @@ -63,7 +64,8 @@ class Api { 'up_time' => time(), 'weight' => $weight, 'property' => $property, - 'description' => htmlspecialchars($description,ENT_QUOTES) + 'description' => htmlspecialchars($description,ENT_QUOTES), + 'font_icon' => $font_icon ]; $re = $this->db->update('on_categorys',$data,[ 'id' => $id]); //var_dump( $this->db->log() ); @@ -417,27 +419,59 @@ class Api { } /** * 查询链接 + * 接收一个数组作为参数 */ - public function link_list($page,$limit,$token = ''){ - $offset = ($page - 1) * $limit; + public function link_list($data){ + $limit = $data['limit']; + $token = $data['token']; + $offset = ($data['page'] - 1) * $data['limit']; + $fid = @$data['category_id']; + + //如果存在分类ID,则根据分类ID进行查询 + if ($data['category_id'] != null) { + + $cid_sql = "WHERE fid = $fid"; + //统计链接总数 + $count = $this->db->count('on_links','*',[ + 'fid' => $fid + ]); + } + else{ + //统计链接总数,没有分类ID的情况 + $count = $this->db->count('on_links','*'); + } //如果成功登录,但token为空 if( ($this->is_login()) && (empty($token)) ){ - //统计总数 - $count = $this->db->count('on_links','*'); - $sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}"; + $sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links ${cid_sql} ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}"; } //如果token验证通过 elseif( (!empty($token)) && ($this->auth($token)) ) { - //统计总数 - $count = $this->db->count('on_links','*'); - $sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}"; + $sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links ${cid_sql} ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}"; } + //如果即没有登录成功,又没有token,则默认为游客 else{ - //统计总数 - $count = $this->db->count('on_links','*',[ 'property' => 0 ]); - $sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links WHERE property = 0 ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}"; + $cid_sql = empty($fid) ? null : "AND fid = $fid"; + if($cid_sql == null) { + //统计链接总数,不存在分类ID的情况 + $count = $this->db->count('on_links','*',[ 'property' => 0 ]); + } + else{ + //统计链接总数,存在分类ID的情况 + $count = $this->db->count('on_links','*',[ + 'property' => 0, + 'fid' => $fid + ]); + } + + $sql = "SELECT *,(SELECT name FROM on_categorys WHERE id = on_links.fid) AS category_name FROM on_links WHERE property = 0 ${cid_sql} ORDER BY weight DESC,id DESC LIMIT {$limit} OFFSET {$offset}"; } + + //打印SQL + //echo $sql; + + //如果查询的总数大于limit,则以limit为准 + $count = ( $count > $limit) ? $limit : $count; //原生查询 $datas = $this->db->query($sql)->fetchAll(); @@ -449,6 +483,47 @@ class Api { ]; exit(json_encode($datas)); } + /** + * 查询单个链接 + * 此函数接收一个数组 + */ + public function get_a_link($data) { + $id = $data['id']; + $token = $data['token']; + $link_info = $this->db->get("on_links","*",[ + "id" => $id + ]); + //打印链接信息 + //var_dump($link_info); + //如果是公开链接,则直接返回 + if ( $link_info['property'] == "0" ) { + $datas = [ + 'code' => 0, + 'data' => $link_info + ]; + + } + //如果是私有链接,并且认证通过 + elseif( $link_info['property'] == "1" ) { + if ( $this->auth($token) ) { + $datas = [ + 'code' => 0, + 'data' => $link_info + ]; + } + + //exit(json_encode($datas)); + } + //如果是其它情况,则显示为空 + else{ + $datas = [ + 'code' => 0, + 'data' => [] + ]; + //exit(json_encode($datas)); + } + exit(json_encode($datas)); + } /** * 验证是否登录 */ @@ -558,6 +633,119 @@ class Api { $this->err_msg(-1,'Weak password!'); } } + /** + * 获取SQL更新列表 + * 循环读取db/sql/目录下的.sql文件 + */ + public function get_sql_update_list($data) { + //鉴权 + if( !$this->is_login() ) { + $this->err_msg(-1002,'Authorization failure!'); + } + //待更新的数据库文件目录 + $sql_dir = 'db/sql/'; + //待更新的sql文件列表,默认为空 + $sql_files_all = []; + //打开一个目录,读取里面的文件列表 + if (is_dir($sql_dir)){ + if ($dh = opendir($sql_dir)){ + while (($file = readdir($dh)) !== false){ + //排除.和.. + if ( ($file != ".") && ($file != "..") ) { + array_push($sql_files_all,$file); + + } + } + //关闭句柄 + closedir($dh); + } + } + //判断数据库日志表是否存在 + $sql = "SELECT count(*) AS num FROM sqlite_master WHERE type='table' AND name='on_db_logs'"; + //查询结果 + $q_result = $this->db->query($sql)->fetchAll(); + //如果数量为0,则说明on_db_logs这个表不存在,需要提前导入 + $num = intval($q_result[0]['num']); + if ( $num === 0 ) { + $data = [ + "code" => 0, + "data" => ['on_db_logs.sql'] + ]; + exit(json_encode($data)); + }else{ + //如果不为0,则需要查询数据库更新表里面的数据进行差集比对 + $get_on_db_logs = $this->db->select("on_db_logs",[ + "sql_name" + ],[ + "status" => "TRUE" + ]); + //声明一个空数组,存储已更新的数据库列表 + $already_dbs = []; + foreach ($get_on_db_logs as $value) { + array_push($already_dbs,$value['sql_name']); + } + + //array_diff() 函数返回两个数组的差集数组 + $diff_result = array_diff($sql_files_all,$already_dbs); + //去掉键 + $diff_result = array_values($diff_result); + sort($diff_result); + + $data = [ + "code" => 0, + "data" => $diff_result + ]; + exit(json_encode($data)); + } + } + /** + * 执行SQL更新语句,只执行单条更新 + */ + public function exe_sql($data) { + //鉴权 + if( !$this->is_login() ) { + $this->err_msg(-1002,'Authorization failure!'); + } + //数据库sql目录 + $sql_dir = 'db/sql/'; + $name = $data['name']; + $sql_name = $sql_dir.$name; + //如果文件不存在,直接返回错误 + if ( !file_exists($sql_name) ) { + $this->err_msg(-2000,$name.'不存在!'); + } + //读取需要更新的SQL内容 + try { + $sql_content = file_get_contents($sql_name); + $result = $this->db->query($sql_content); + //如果SQL执行成功,则返回 + if( $result ) { + //将更新信息写入数据库 + $insert_re = $this->db->insert("on_db_logs",[ + "sql_name" => $name, + "update_time" => time() + ]); + if( $insert_re ) { + $data = [ + "code" => 0, + "data" => $name."更新完成!" + ]; + exit(json_encode($data)); + } + else { + $this->err_msg(-2000,$name."更新失败,请人工检查!"); + } + + } + else{ + //如果执行失败 + $this->err_msg(-2000,$name."更新失败,请人工检查!"); + } + } catch(Exception $e){ + $this->err_msg(-2000,$e->getMessage()); + } + } + } diff --git a/controller/api.php b/controller/api.php index ed01b77..c9745a1 100755 --- a/controller/api.php +++ b/controller/api.php @@ -54,6 +54,15 @@ switch ($method) { case 'check_weak_password': check_weak_password($api); break; + case 'get_a_link': + get_a_link($api); + break; + case 'get_sql_update_list': + get_sql_update_list($api); + break; + case 'exe_sql': + exe_sql($api); + break; default: # code... break; @@ -75,7 +84,9 @@ function add_category($api){ $description = empty($_POST['description']) ? '' : $_POST['description']; //描述过滤 $description = htmlspecialchars($description); - $api->add_category($token,$name,$property,$weight,$description); + //获取字体图标 + $font_icon = htmlspecialchars($_POST['font_icon'],ENT_QUOTES); + $api->add_category($token,$name,$property,$weight,$description,$font_icon); } /** * 修改分类目录入口 @@ -96,7 +107,9 @@ function edit_category($api){ $description = empty($_POST['description']) ? '' : $_POST['description']; //描述过滤 $description = htmlspecialchars($description); - $api->edit_category($token,$id,$name,$property,$weight,$description); + //字体图标 + $font_icon = htmlspecialchars($_POST['font_icon'],ENT_QUOTES); + $api->edit_category($token,$id,$name,$property,$weight,$description,$font_icon); } /** * 删除分类目录 @@ -173,11 +186,19 @@ function link_list($api){ $limit = empty(intval($_GET['limit'])) ? 10 : intval($_GET['limit']); //获取token $token = $_POST['token']; - $api->link_list($page,$limit,$token); + //获取分类ID + $category_id = empty($_POST['category_id']) ? null : intval($_POST['category_id']); + $data = [ + 'page' => $page, + 'limit' => $limit, + 'token' => $token, + 'category_id' => $category_id + ]; + $api->link_list($data); } /** - * 获取链接信息 + * 获取链接标题、描述等信息 */ function get_link_info($api) { //获取token @@ -187,6 +208,17 @@ function get_link_info($api) { $api->get_link_info($token,$url); } +/** + * 获取一个链接的信息,指存储在数据库的信息 + */ +function get_a_link($api) { + //获取token + $data['token'] = htmlspecialchars($_POST['token']); + //获取链接的ID + $data['id'] = intval(htmlspecialchars($_GET['id'])); + $api->get_a_link($data); +} + /** * 添加自定义js */ @@ -219,4 +251,16 @@ function check_weak_password($api) { //获取token $token = $_POST['token']; $api->check_weak_password($token); +} + +//获取sql更新列表 +function get_sql_update_list($api){ + $data = []; + $api->get_sql_update_list($data); +} + +//执行SQL更新 +function exe_sql($api) { + $data['name'] = htmlspecialchars(trim($_GET['name'])); + $api->exe_sql($data); } \ No newline at end of file diff --git a/controller/login.php b/controller/login.php index f7a7fde..bb4b851 100755 --- a/controller/login.php +++ b/controller/login.php @@ -23,7 +23,8 @@ if( $_GET['check'] == 'login' ) { header('Content-Type:application/json; charset=utf-8'); if( ($user === $username) && ($pass === $password) ) { $key = md5($username.$password.'onenav'); - setcookie("key", $key, time()+30 * 24 * 60 * 60,"/"); + //开启httponly支持 + setcookie("key", $key, time()+30 * 24 * 60 * 60,"/",NULL,false,TRUE); $data = [ 'code' => 0, 'msg' => 'successful' diff --git a/data/update.log b/data/update.log index 4083a65..d42f791 100755 --- a/data/update.log +++ b/data/update.log @@ -37,4 +37,14 @@ CREATE INDEX on_options_key_IDX ON on_options ("key"); 1. 修复默认主题字体图标不显示 20220225 -1. 修复一处安全漏洞 \ No newline at end of file +1. 修复一处安全漏洞 + +20220304 +1. 新增HttpOnly支持 +2. API新增查询单个链接信息get_a_link +3. API支持查询指定分类下的链接link_list,传递参数category_id + +20220308 +1. 新增数据库更新功能 +2. 初始数据库更新 +3. 分离分类图标字体设置 \ No newline at end of file diff --git a/db/index.html b/db/index.html new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/db/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/db/onenav.simple.db3 b/db/onenav.simple.db3 old mode 100755 new mode 100644 index 895d56f..dfb5cae Binary files a/db/onenav.simple.db3 and b/db/onenav.simple.db3 differ diff --git a/db/sql/20220308.sql b/db/sql/20220308.sql new file mode 100644 index 0000000..c1d8dab --- /dev/null +++ b/db/sql/20220308.sql @@ -0,0 +1,7 @@ +-- 分类目录增加字体图标列 +ALTER TABLE on_categorys ADD font_icon TEXT(32); +-- 链接表新增字段topping,默认值0(不置顶),1为置顶,先保留后续使用 +ALTER TABLE on_links ADD topping INTEGER DEFAULT 0 NOT NULL; +-- 增加一个备用链接字段 +ALTER TABLE on_links ADD url_standby TEXT(256); + diff --git a/db/sql/on_db_logs.sql b/db/sql/on_db_logs.sql new file mode 100644 index 0000000..5e08fa3 --- /dev/null +++ b/db/sql/on_db_logs.sql @@ -0,0 +1,11 @@ +-- 2022/03/07数据库升级脚本 +-- 创建数据库升级记录表,用于新增的SQL升级成功后记录到表,方便下次比对 +CREATE TABLE on_db_logs ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + sql_name TEXT(32) NOT NULL, + update_time NUMERIC NOT NULL, + status TEXT(5) DEFAULT "TRUE" NOT NULL, + extra TEXT(512), + CONSTRAINT on_db_logs_UN UNIQUE (sql_name) +); +CREATE UNIQUE INDEX on_db_logs_sql_name_IDX ON on_db_logs (sql_name); diff --git a/templates/admin/add_category.php b/templates/admin/add_category.php index a9b2624..03d831d 100755 --- a/templates/admin/add_category.php +++ b/templates/admin/add_category.php @@ -12,6 +12,14 @@ + +
+ +
+ +
+
+
@@ -40,6 +48,7 @@
+

关于字体图标的说明请参考帮助文档:https://dwz.ovh/7nr1f

diff --git a/templates/admin/edit_category.php b/templates/admin/edit_category.php index c18f254..df99207 100755 --- a/templates/admin/edit_category.php +++ b/templates/admin/edit_category.php @@ -18,6 +18,14 @@ ' placeholder="请输入分类名称" autocomplete="off" class="layui-input"> + +
+ +
+ ' placeholder="请输入字体图标,如:fa fa-bookmark-o" autocomplete="off" class="layui-input"> +
+
+
@@ -46,9 +54,11 @@
+

关于字体图标的说明请参考帮助文档:https://dwz.ovh/7nr1f

+ diff --git a/templates/admin/index.php b/templates/admin/index.php index 9b3bbd0..3bdc2a5 100755 --- a/templates/admin/index.php +++ b/templates/admin/index.php @@ -34,6 +34,14 @@
捐赠地址: https://dwz.ovh/donation
+ + +
+

日志输出:

+ +
+ + @@ -42,4 +50,5 @@ diff --git a/templates/admin/static/embed.js b/templates/admin/static/embed.js index 29ece02..94c6d88 100755 --- a/templates/admin/static/embed.js +++ b/templates/admin/static/embed.js @@ -430,3 +430,40 @@ function check_weak_password(){ } }); } + +//获取待更新数据库列表,http://onenav.com/index.php?c=api&method=exe_sql&name=on_db_logs.sql +function get_sql_update_list() { + $("#console_log").append("正在检查数据库更新...\n"); + $.get("index.php?c=api&method=get_sql_update_list",function(data,status){ + + if ( data.code == 0 ) { + //如果没有可用更新,直接结束 + if ( data.data.length == 0 ) { + $("#console_log").append("当前无可用更新!\n"); + return false; + } + else{ + $("#console_log").append("检查到可更新SQL列表:\n"); + $("#console_log").append("正在准备更新...\n"); + for(i in data.data) { + sqlname = data.data[i]; + //$("#console_log").append(data.data[i] + "\n"); + exe_sql(sqlname); + } + } + } + }); +} + +//更新SQL函数 +function exe_sql(sqlname) { + $.ajax({ url: "index.php?c=api&method=exe_sql&name=" + sqlname, async:false, success: function(data,status){ + if( data.code == 0 ){ + $("#console_log").append(sqlname + "更新完毕!\n"); + } + else { + $("#console_log").append(sqlname + "更新失败!\n"); + } + }}); +} + diff --git a/templates/default/index.php b/templates/default/index.php index 8902f5a..7caea44 100755 --- a/templates/default/index.php +++ b/templates/default/index.php @@ -86,11 +86,11 @@ //遍历分类目录并显示 foreach ($categorys as $category) { //var_dump($category); - + $font_icon = empty($category['font_icon']) ? '' : " "; ?>
  • -
    +
  • @@ -137,6 +137,7 @@ "; //如果分类是私有的 if( $category['property'] == 1 ) { $property = ''; @@ -146,6 +147,7 @@ } ?>
    +
    @@ -194,6 +196,7 @@
    + diff --git a/version.txt b/version.txt index 4f936b1..bbc01fb 100755 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v0.9.15-20220225 \ No newline at end of file +v0.9.16-20220308 \ No newline at end of file