From de78d7de0706a0cdde7c068b7a22a468ddeeb157 Mon Sep 17 00:00:00 2001 From: MasonLiu <2857911564@qq.com> Date: Wed, 1 Jul 2026 00:47:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0UI=E5=92=8C=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=90=8E=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .htaccess | 0 admin.php | 1487 +++++++++++++++++++++++++++++------------ assets/css/admin.css | 545 +++++++++++++++ assets/db/sechub.db | Bin 77824 -> 77824 bytes assets/json/blue.json | 5 + assets/json/info.json | 5 + config.php | 12 + db.php | 398 +++++++++++ nginx.htaccess | 0 9 files changed, 2020 insertions(+), 432 deletions(-) create mode 100644 .htaccess create mode 100644 assets/css/admin.css create mode 100644 config.php create mode 100644 nginx.htaccess diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..e69de29 diff --git a/admin.php b/admin.php index 64a3c4b..7d77973 100644 --- a/admin.php +++ b/admin.php @@ -1,21 +1,16 @@ SecHub - 管理登录 +
-

🔐 SecHub 管理后台

+

SecHub 管理后台

@@ -69,494 +131,1055 @@ if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) { exit; } -// 处理保存排序 +// 初始化 CSRF token +if (!isset($_SESSION['csrf_token'])) { + $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); +} + +// 初始化数据库 +try { + $database = new SecHubDatabase(DB_PATH, JSON_DIR); + $database->syncJsonToDatabase(); +} catch (Exception $e) { + $error = '数据库初始化失败: ' . $e->getMessage(); +} + +// 消息提示 +$message = ''; +$messageType = 'success'; + +// ======================== 处理POST动作 ======================== + +// CSRF 校验(对非登录请求) +$csrfOk = true; +if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_POST['login'])) { + $token = $_POST['csrf_token'] ?? ''; + if ($token !== $_SESSION['csrf_token']) { + $csrfOk = false; + $message = '安全令牌无效,请刷新页面重试'; + $messageType = 'error'; + } +} + +if ($csrfOk) { + +// --- 保存排序 --- if (isset($_POST['save_order']) && isset($_POST['orders'])) { - $success = false; - $message = ''; - try { - // orders 数组已经按拖拽后的顺序排列 $newOrder = 1; foreach ($_POST['orders'] as $filename) { - $filePath = $jsonDir . $filename; - + $filePath = JSON_DIR . $filename; if (file_exists($filePath)) { - // 读取JSON文件(保持原始格式) $content = file_get_contents($filePath); $data = json_decode($content, true); - if (json_last_error() === JSON_ERROR_NONE && is_array($data) && !empty($data)) { - // 只更新第一个数据项的 no 字段 $data[0]['no'] = $newOrder; - - // 写回JSON文件(保持原有格式,不转义) $newContent = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); file_put_contents($filePath, $newContent . "\n"); - $newOrder++; } } } - - $success = true; - $message = '排序保存成功!'; - - // 重新同步数据库 - $database = new SecHubDatabase($dbPath, $jsonDir); $database->syncJsonToDatabase(); - + $message = '排序保存成功!'; + $messageType = 'success'; } catch (Exception $e) { $message = '保存失败: ' . $e->getMessage(); + $messageType = 'error'; } } -// 处理删除数据库 +// --- 添加工具 --- +if (isset($_POST['add_item'])) { + $tableName = $_POST['table_name'] ?? ''; + $name = trim($_POST['name'] ?? ''); + $url = trim($_POST['url'] ?? ''); + $description = trim($_POST['description'] ?? ''); + if (empty($name)) { + $message = '工具名称不能为空'; + $messageType = 'error'; + } else { + $result = $database->addItemToSection($tableName, $name, $url, $description); + if ($result['success']) { + $message = '工具添加成功!'; + } else { + $message = '添加失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } + } +} + +// --- 更新工具 --- +if (isset($_POST['update_item'])) { + $tableName = $_POST['table_name'] ?? ''; + $itemIndex = intval($_POST['item_index'] ?? 0); + $name = trim($_POST['name'] ?? ''); + $url = trim($_POST['url'] ?? ''); + $description = trim($_POST['description'] ?? ''); + if (empty($name)) { + $message = '工具名称不能为空'; + $messageType = 'error'; + } else { + $result = $database->updateItemInSection($tableName, $itemIndex, $name, $url, $description); + if ($result['success']) { + $message = '工具更新成功!'; + } else { + $message = '更新失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } + } +} + +// --- 删除工具 --- +if (isset($_POST['delete_item'])) { + $tableName = $_POST['table_name'] ?? ''; + $itemIndex = intval($_POST['item_index'] ?? 0); + $result = $database->deleteItemFromSection($tableName, $itemIndex); + if ($result['success']) { + $message = '工具已删除!'; + } else { + $message = '删除失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } +} + +// --- 新增栏目 --- +if (isset($_POST['add_section'])) { + $sectionName = trim($_POST['section_name'] ?? ''); + if (empty($sectionName)) { + $message = '栏目名称不能为空'; + $messageType = 'error'; + } else { + $result = $database->createSection($sectionName); + if ($result['success']) { + $message = '栏目 "' . htmlspecialchars($sectionName) . '" 创建成功!'; + } else { + $message = '创建失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } + } +} + +// --- 删除栏目 --- +if (isset($_POST['delete_section'])) { + $tableName = $_POST['table_name'] ?? ''; + $confirm = $_POST['confirm'] ?? ''; + if ($confirm !== 'yes') { + $message = '请确认删除操作'; + $messageType = 'error'; + } else { + $result = $database->removeSection($tableName); + if ($result['success']) { + $message = '栏目已删除!'; + } else { + $message = '删除失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } + } +} + +// --- 重命名栏目 --- +if (isset($_POST['rename_section'])) { + $tableName = $_POST['table_name'] ?? ''; + $newName = trim($_POST['new_name'] ?? ''); + if (empty($newName)) { + $message = '栏目名称不能为空'; + $messageType = 'error'; + } else { + $result = $database->renameSection($tableName, $newName); + if ($result['success']) { + $message = '栏目重命名成功!'; + } else { + $message = '重命名失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } + } +} + +// --- 批量导入 --- +if (isset($_POST['batch_import'])) { + $tableName = $_POST['table_name'] ?? ''; + $importData = trim($_POST['import_data'] ?? ''); + $format = $_POST['import_format'] ?? 'csv'; + + if (empty($importData)) { + $message = '导入数据不能为空'; + $messageType = 'error'; + } else { + $lines = explode("\n", str_replace("\r\n", "\n", $importData)); + $items = []; + + foreach ($lines as $line) { + $line = trim($line); + if (empty($line)) continue; + + if ($format === 'csv') { + // CSV格式: 名称,URL,描述 + $parts = str_getcsv($line); + $items[] = [ + trim($parts[0] ?? ''), + trim($parts[1] ?? ''), + trim($parts[2] ?? '') + ]; + } else { + // 竖线格式: 名称 | URL | 描述 + $parts = explode('|', $line); + $items[] = [ + trim($parts[0] ?? ''), + trim($parts[1] ?? ''), + trim($parts[2] ?? '') + ]; + } + } + + $result = $database->batchAddItems($tableName, $items); + if ($result['success']) { + $message = "批量导入成功!成功添加 {$result['count']} 个工具(共 {$result['total']} 条数据)"; + } else { + $message = '导入失败: ' . ($result['error'] ?? '未知错误'); + $messageType = 'error'; + } + } +} + +// --- 导出JSON --- +if (isset($_POST['export_json'])) { + $tableName = $_POST['table_name'] ?? 'all'; + if ($tableName === 'all') { + $data = $database->exportAllSections(); + $filename = 'sechub_all_sections.json'; + $json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + } elseif ($database->getSectionInfo($tableName)) { + $filePath = JSON_DIR . $tableName . '.json'; + if (file_exists($filePath)) { + $json = file_get_contents($filePath); + $filename = $tableName . '.json'; + } else { + $message = '文件不存在'; + $messageType = 'error'; + $json = null; + } + } else { + $message = '无效的栏目'; + $messageType = 'error'; + $json = null; + } + + if (isset($json)) { + header('Content-Type: application/json; charset=utf-8'); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + echo $json; + $database->close(); + exit; + } +} + +// --- 导出CSV --- +if (isset($_POST['export_csv'])) { + $tableName = $_POST['table_name'] ?? ''; + + if (empty($tableName)) { + $message = '请选择要导出的栏目'; + $messageType = 'error'; + } else { + $csv = $database->exportSectionToCsv($tableName); + if (!empty($csv)) { + $info = $database->getSectionInfo($tableName); + $filename = ($info['title'] ?? $tableName) . '.csv'; + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename="' . $filename . '"'); + echo "\xEF\xBB\xBF" . $csv; + $database->close(); + exit; + } else { + $message = '导出失败或栏目为空'; + $messageType = 'error'; + } + } +} + +// --- 强制重新同步 --- +if (isset($_POST['resync_db'])) { + try { + $database->syncJsonToDatabase(); + $message = '数据库重新同步成功!'; + } catch (Exception $e) { + $message = '同步失败: ' . $e->getMessage(); + $messageType = 'error'; + } +} + +// --- 删除数据库 --- if (isset($_POST['delete_db'])) { - if (file_exists($dbPath)) { - unlink($dbPath); - $success = true; - $message = '数据库已删除!刷新页面后将重新创建。'; + if (file_exists(DB_PATH)) { + unlink(DB_PATH); + $message = '数据库已删除!刷新后自动重建。'; } else { $message = '数据库文件不存在。'; + $messageType = 'error'; } } -// 获取所有JSON文件信息 -$jsonFiles = glob($jsonDir . '*.json'); -$fileInfos = []; +// --- 修改密码 --- +if (isset($_POST['change_password'])) { + $oldPwd = $_POST['old_password'] ?? ''; + $newPwd = $_POST['new_password'] ?? ''; + $confirmPwd = $_POST['confirm_password'] ?? ''; -foreach ($jsonFiles as $filePath) { - $filename = basename($filePath); - $content = file_get_contents($filePath); - $data = json_decode($content, true); - - if (json_last_error() === JSON_ERROR_NONE && is_array($data) && !empty($data)) { - $firstItem = $data[0]; - $fileInfos[] = [ - 'filename' => $filename, - 'section' => $firstItem['section'] ?? pathinfo($filename, PATHINFO_FILENAME), - 'no' => $firstItem['no'] ?? 0, - 'item_count' => count($data) - 1 // 减去第一个配置项 - ]; + if ($oldPwd !== ADMIN_PASSWORD) { + $message = '当前密码错误'; + $messageType = 'error'; + } elseif (strlen($newPwd) < 6) { + $message = '新密码长度不能少于6位'; + $messageType = 'error'; + } elseif ($newPwd !== $confirmPwd) { + $message = '两次密码输入不一致'; + $messageType = 'error'; + } else { + // 更新config.php中的密码 + $configPath = __DIR__ . '/config.php'; + $configContent = file_get_contents($configPath); + $newContent = preg_replace( + "/define\('ADMIN_PASSWORD',\s*'[^']*'\)/", + "define('ADMIN_PASSWORD', '" . addslashes($newPwd) . "')", + $configContent + ); + if (file_put_contents($configPath, $newContent)) { + $message = '密码修改成功!'; + // 更新当前session中的标记(不需要改密码,因为会话还在) + } else { + $message = '密码修改失败(文件写入错误)'; + $messageType = 'error'; + } } } -// 按当前 no 排序 -usort($fileInfos, function($a, $b) { - return $a['no'] - $b['no']; -}); +} // end CSRF check + +// 获取栏目列表 +$allSections = $database->getAllSectionsWithInfo(); + +// 当前选中的栏目(从URL参数或第一个) +$currentTab = $_GET['tab'] ?? 'sort'; +$selectedSection = $_GET['section'] ?? ($allSections[0]['name'] ?? ''); + +// 获取选中栏目的工具列表 +$currentItems = []; +$currentSectionInfo = null; +if ($selectedSection) { + $currentItems = $database->getItemsBySection($selectedSection); + $currentSectionInfo = $database->getSectionInfo($selectedSection); +} ?> - - SecHub - 排序管理 - + SecHub - 管理后台 +
-
+ +
-

📊 SecHub 排序管理

-

调整栏目显示顺序

+

SecHub 管理后台

+

排序管理 / 数据管理 / 批量操作 / 系统设置

-
+ -
+
- -
- ✅ -
- -
- ⚠️ + + +
+
-
- 💡 提示:拖动行左侧的 ⋮⋮ 图标来调整顺序,序号会自动更新。修改后点击“保存排序”按钮即可生效。 + +
+ + + +
-
+ +
+
+
拖动行左侧的 ⋮⋮ 图标来调整栏目顺序,修改后点击"保存排序"生效。
+
+ +
+ + + + + + + + + + + + $sec): ?> + + + + + + + + + +
序列文件名称栏目名称工具数
⋮⋮
+
+ +
+ +
+
+
+
+ + +
+
+
+ +
+
+

栏目列表

+ +
+
+ +
+
+
+
个工具
+
+
+ + +
+
+ + +
暂无栏目
+ +
+
+ + +
+
+

+ 工具列表 + + - + +

+ + + +
+ + +
请从左侧选择一个栏目
+ +
+ 此栏目暂无工具数据 +

+ +
+ +
+ + + + + + + + + + + + $item): ?> + + + + + + + + + +
#名称URL描述操作
+ + + + +
+
+ +
+
+
+
+ + +
+
+
+ +
+

批量导入

+
+ 支持两种格式导入,每行一个工具。支持CSV上传和粘贴文本。 +
+
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
输入数据后点击"预览"查看解析结果
+
+ +
+ + +
+
+
+ + +
+

批量导出

+
+
+ +
+ + +
+
+ + +
+
+
+
+
+
+
+ + +
+
+
+

修改管理密码

+
+ + +
+ + +
+
+ + +
+
+ + +
+ +
+
+ +
+

数据库维护

+
+ 数据库位置:
+ JSON目录:
+ 栏目数量: +
+
+
+ + +
+
+ + +
+
+
+
+
+ +
+ © SecHub - 网络安全工具集 +
+
+ + +
+ + + + +