343 lines
15 KiB
PHP
343 lines
15 KiB
PHP
<?php
|
||
/**
|
||
* index.php —— 首页区(最前置页面)
|
||
* 结构:Hero 展示栏 / 名言条 / 四大板块 / 页脚
|
||
*/
|
||
$P = '';
|
||
require_once __DIR__ . '/includes/layout.php';
|
||
|
||
$siteName = setting_get('site_name', 'SecHome');
|
||
$siteSlogan = setting_get('site_slogan', '');
|
||
$heroBg = setting_get('hero_bg', ''); // 后台自定义顶部背景(纯色 / CSS 渐变)
|
||
// 首页顶部组件模式:weather=天气(默认) / info=信息 / blank=精简 / red=渗透测试 / blue=安全巡检
|
||
// / posture=安全态势 / trend=访问趋势 / clock=大字时钟 / notice=公告滚动 / slogan=打字机标语
|
||
$heroMode = setting_get('hero_mode', 'weather');
|
||
if (!in_array($heroMode, ['weather', 'info', 'blank', 'red', 'blue', 'posture', 'trend', 'clock', 'notice', 'slogan'], true)) {
|
||
$heroMode = 'weather';
|
||
}
|
||
$visitor = [];
|
||
if ($heroMode === 'info') {
|
||
$visitor = visitor_brief();
|
||
}
|
||
$lastUpdated = setting_get('last_updated', '');
|
||
if ($lastUpdated === '') {
|
||
$lastUpdated = '暂无更新记录';
|
||
}
|
||
|
||
// 名言:服务端随机一条 + 全量池(供点击格言本身切换)
|
||
$quoteFile = DATA_DIR . '/quota.txt';
|
||
$quotes = [];
|
||
if (is_file($quoteFile)) {
|
||
$raw = @file($quoteFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||
if (is_array($raw)) {
|
||
foreach ($raw as $ln) {
|
||
$ln = trim($ln);
|
||
if ($ln !== '' && strpos($ln, '#') !== 0) {
|
||
$quotes[] = $ln;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
$quoteText = $quotes ? $quotes[array_rand($quotes)] : '知识就是力量。';
|
||
|
||
// 安全态势 / 访问趋势:汇总统计数据(仅对应模式时查询,避免无谓开销)
|
||
$secStats = null;
|
||
if ($heroMode === 'posture' || $heroMode === 'trend') {
|
||
$secStats = home_security_stats(7);
|
||
}
|
||
// 公告滚动:置顶优先、发布时间倒序
|
||
$heroNotices = [];
|
||
if ($heroMode === 'notice') {
|
||
$heroNotices = db()->query('SELECT title, pinned, created_at FROM notices WHERE enabled = 1 ORDER BY pinned DESC, created_at DESC, id DESC')->fetchAll();
|
||
}
|
||
|
||
// 四大板块(按后台排序输出)
|
||
$cats = db()->query('SELECT * FROM categories ORDER BY sort ASC, id ASC')->fetchAll();
|
||
// 首页快捷站点(后台配置,新标签页跳转本域名其它网站)
|
||
$quickLinks = db()->query('SELECT * FROM quick_links WHERE enabled = 1 ORDER BY sort ASC, id ASC')->fetchAll();
|
||
|
||
$catLink = [
|
||
'popular' => 'nav.php?cat=popular',
|
||
'red' => 'nav.php?cat=red',
|
||
'blue' => 'nav.php?cat=blue',
|
||
'tool' => 'func/index.php',
|
||
'article' => 'article/index.php',
|
||
];
|
||
$catIcon = [
|
||
'popular' => '📖',
|
||
'red' => '⚔️',
|
||
'blue' => '🛡️',
|
||
'tool' => '🧰',
|
||
'article' => '📚',
|
||
];
|
||
$catHint = [
|
||
'popular' => '入门·科普·前沿',
|
||
'red' => '攻防演练资源',
|
||
'blue' => '防御·应急·溯源',
|
||
'tool' => '进入功能区',
|
||
'article' => '进入文章库',
|
||
];
|
||
|
||
layout_head('');
|
||
?>
|
||
<!-- Hero 顶部展示栏 -->
|
||
<header class="hero<?= $heroMode === 'blank' ? ' hero-slim' : '' ?>" <?php if ($heroBg !== ''): ?>
|
||
style="background:<?= he($heroBg) ?>" <?php endif; ?>>
|
||
<div class="wrap hero-inner">
|
||
<div class="hero-top">
|
||
<div class="brand">
|
||
<?php layout_logo_img('logo', $siteName); ?>
|
||
<div>
|
||
<div class="site-name"><?= he($siteName) ?></div>
|
||
<?php if ($siteSlogan !== ''): ?>
|
||
<div class="site-slogan"><?= he($siteSlogan) ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<div class="hero-meta">
|
||
<div class="hm-row"><span>当前时间 </span><span class="val js-clock">--</span></div>
|
||
<div class="hm-row"><span>上次更新 </span><span class="val"><?= he($lastUpdated) ?></span></div>
|
||
</div>
|
||
</div>
|
||
<?php if ($heroMode === 'weather'): ?>
|
||
<!-- 天气模式(默认):第三方天气条 -->
|
||
<div class="weather-box">
|
||
<iframe width="800" height="150" src="https://i.tianqi.com/?c=code&a=getcode&id=48&num=6&icon=1"
|
||
frameborder="0"></iframe>
|
||
</div>
|
||
<?php elseif ($heroMode === 'info'): ?>
|
||
<!-- 访客信息模式:IP / 浏览器 / 系统 / 内核 / 屏幕 / 语言 -->
|
||
<div class="visitor-box js-visitor-box">
|
||
<div class="vb-grid">
|
||
<div class="vb-cell"><span>访问者 IP</span><b><?= he((string) ($visitor['ip'] ?? '未知')) ?></b></div>
|
||
<div class="vb-cell"><span>浏览器</span><b><?= he((string) ($visitor['browser'] ?? '未知')) ?></b></div>
|
||
<div class="vb-cell"><span>操作系统</span><b><?= he((string) ($visitor['os'] ?? '未知')) ?></b></div>
|
||
<div class="vb-cell"><span>内核 / 渲染引擎</span><b><?= he((string) ($visitor['kernel'] ?? '未知')) ?></b></div>
|
||
<div class="vb-cell"><span>屏幕分辨率</span><b class="js-vscreen">--</b></div>
|
||
<div class="vb-cell"><span>系统语言</span><b class="js-vlang">--</b></div>
|
||
</div>
|
||
</div>
|
||
<?php elseif ($heroMode === 'red'): ?>
|
||
<!-- 红队 · 渗透测试流程(动态步进) -->
|
||
<div class="ptflow ptflow-red js-ptflow">
|
||
<div class="ptflow-head">
|
||
<span class="ptflow-title">红队 · 渗透测试<span class="ptflow-tag">RED TEAM</span></span>
|
||
<span class="ptflow-phase js-ptflow-phase">当前阶段:侦察(1/8)</span>
|
||
</div>
|
||
<ol class="ptflow-track">
|
||
<?php
|
||
$redSteps = [
|
||
['侦察', '🔍', '信息收集', '域名 / 子域 / 指纹 / 社工面'],
|
||
['武器化', '🧰', '载荷准备', '利用链与免杀载荷'],
|
||
['投递', '✉️', '边界投递', '钓鱼 / 暴露服务入口'],
|
||
['利用', '💥', '漏洞利用', '获取初始立足点'],
|
||
['提权', '⬆️', '权限提升', '本地提权至最高权限'],
|
||
['横移', '🌐', '内网横向', '隧道与凭据横向移动'],
|
||
['维持', '📌', '权限维持', '后门与持久化驻留'],
|
||
['达成', '🎯', '目标达成', '取证留痕并输出报告'],
|
||
];
|
||
foreach ($redSteps as $s): ?>
|
||
<li class="ptflow-step" data-phase="<?= he($s[0]) ?>">
|
||
<span class="ptflow-ic"><?= he($s[1]) ?></span>
|
||
<b><?= he($s[2]) ?></b>
|
||
<small><?= he($s[3]) ?></small>
|
||
</li>
|
||
<?php endforeach; ?>
|
||
</ol>
|
||
</div>
|
||
<?php elseif ($heroMode === 'blue'): ?>
|
||
<!-- 蓝队 · 渗透测试(动态步进) -->
|
||
<div class="ptflow ptflow-blue js-ptflow">
|
||
<div class="ptflow-head">
|
||
<span class="ptflow-title">蓝队 · 安全巡检<span class="ptflow-tag">BLUE TEAM</span></span>
|
||
<span class="ptflow-phase js-ptflow-phase">当前阶段:测绘(1/8)</span>
|
||
</div>
|
||
<ol class="ptflow-track">
|
||
<?php
|
||
$blueSteps = [
|
||
['测绘', '🗺', '资产测绘', '暴露面与资产台账'],
|
||
['基线', '🧭', '基线核查', '配置与合规核查'],
|
||
['收敛', '🧱', '攻击面收敛', '暴露服务治理'],
|
||
['布防', '📡', '监测布防', '流量 / 主机 / 日志'],
|
||
['研判', '🚨', '告警研判', '规则命中与降噪'],
|
||
['处置', '🧯', '应急处置', '隔离封禁与止损'],
|
||
['溯源', '🎯', '溯源反制', '攻击者画像定位'],
|
||
['复盘', '🔒', '加固复盘', '策略加固与总结'],
|
||
];
|
||
foreach ($blueSteps as $s): ?>
|
||
<li class="ptflow-step" data-phase="<?= he($s[0]) ?>">
|
||
<span class="ptflow-ic"><?= he($s[1]) ?></span>
|
||
<b><?= he($s[2]) ?></b>
|
||
<small><?= he($s[3]) ?></small>
|
||
</li>
|
||
<?php endforeach; ?>
|
||
</ol>
|
||
</div>
|
||
<?php elseif ($heroMode === 'posture'): ?>
|
||
<!-- 安全态势简报:今日/累计访问、独立 IP、拦截、黑名单、最近登录(数字动态增长) -->
|
||
<div class="visitor-box js-posture">
|
||
<div class="vb-grid">
|
||
<div class="vb-cell"><span>今日访问</span><b class="js-count" data-to="<?= (int) ($secStats['today'] ?? 0) ?>">0</b>
|
||
</div>
|
||
<div class="vb-cell"><span>今日独立 IP</span><b class="js-count"
|
||
data-to="<?= (int) ($secStats['ips_today'] ?? 0) ?>">0</b></div>
|
||
<div class="vb-cell"><span>累计访问</span><b class="js-count" data-to="<?= (int) ($secStats['total'] ?? 0) ?>">0</b>
|
||
</div>
|
||
<div class="vb-cell"><span>拦截次数</span><b class="js-count"
|
||
data-to="<?= (int) ($secStats['blocked_total'] ?? 0) ?>">0</b></div>
|
||
<div class="vb-cell"><span>黑名单</span><b class="js-count" data-to="<?= (int) ($secStats['ban'] ?? 0) ?>">0</b>
|
||
</div>
|
||
<div class="vb-cell"><span>最近登录</span><b><?php
|
||
$ll = $secStats['last_login'] ?? null;
|
||
if (is_array($ll) && (string) ($ll['time'] ?? '') !== '') {
|
||
echo he(substr((string) $ll['time'], 0, 16));
|
||
} else {
|
||
echo '暂无记录';
|
||
}
|
||
?></b></div>
|
||
</div>
|
||
</div>
|
||
<?php elseif ($heroMode === 'trend'): ?>
|
||
<!-- 访问趋势:近 7 天访问量柱状图(逐柱动态生长) -->
|
||
<?php
|
||
$daily = $secStats['daily'] ?? [];
|
||
$maxCnt = 0;
|
||
foreach ($daily as $d) {
|
||
if ((int) $d['cnt'] > $maxCnt) {
|
||
$maxCnt = (int) $d['cnt'];
|
||
}
|
||
}
|
||
$weekMap = ['日', '一', '二', '三', '四', '五', '六'];
|
||
?>
|
||
<div class="trend-box js-trend">
|
||
<div class="trend-head">
|
||
<span class="trend-title">近 7 天访问趋势</span>
|
||
<span class="trend-sub">累计 <b><?= (int) ($secStats['total'] ?? 0) ?></b> 次 · 今日
|
||
<b><?= (int) ($secStats['today'] ?? 0) ?></b> 次</span>
|
||
</div>
|
||
<div class="trend-chart">
|
||
<?php foreach ($daily as $d):
|
||
$cnt = (int) $d['cnt'];
|
||
$h = $maxCnt > 0 ? (int) round($cnt / $maxCnt * 100) : 0;
|
||
$ts = (int) strtotime((string) $d['day']);
|
||
?>
|
||
<div class="trend-col" title="<?= he((string) $d['day']) ?>:<?= $cnt ?> 次">
|
||
<span class="trend-val"><?= $cnt ?></span>
|
||
<span class="trend-bar-wrap"><i class="trend-bar" style="--h:<?= $h ?>%"></i></span>
|
||
<span class="trend-lbl"><?= he(date('m-d', $ts)) ?></span>
|
||
<span class="trend-wk">周<?= he($weekMap[(int) date('w', $ts)]) ?></span>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php elseif ($heroMode === 'clock'): ?>
|
||
<!-- 大字时钟:大号时间 + 日期 + 时段问候(前端实时刷新) -->
|
||
<div class="clock-box js-hero-clock">
|
||
<div class="ch-greet js-ch-greet">--</div>
|
||
<div class="ch-time js-ch-time">--:--:--</div>
|
||
<div class="ch-date"><span class="js-ch-date">----年--月--日</span><span class="js-ch-week"></span></div>
|
||
<div class="ch-extra">
|
||
<span class="ch-lunar"><span class="js-ch-lunar">农历 --</span><span class="ch-fest js-ch-fest"></span></span>
|
||
<span class="ch-count js-ch-count"><span class="cc-label js-cc-label">距下一个节日</span><span
|
||
class="cc-time js-cc-time">--</span></span>
|
||
</div>
|
||
</div>
|
||
<?php elseif ($heroMode === 'notice'): ?>
|
||
<!-- 公告滚动:横向无缝滚动当前启用的公告(置顶优先) -->
|
||
<div class="ticker-box">
|
||
<span class="tk-label">公告</span>
|
||
<?php if ($heroNotices): ?>
|
||
<div class="tk-viewport js-tk-viewport">
|
||
<div class="tk-track js-tk-track">
|
||
<?php foreach ($heroNotices as $n):
|
||
$nt = trim((string) $n['title']);
|
||
$nt = $nt !== '' ? $nt : '公告';
|
||
?>
|
||
<a class="tk-item" href="notice.php"><?php if ((int) $n['pinned'] === 1): ?><span
|
||
class="tk-pin">置顶</span><?php endif; ?><?= he($nt) ?></a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php else: ?>
|
||
<span class="tk-empty">暂无更新公告<span class="st-tip">,可在后台「更新公告管理」中添加</span>。</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php elseif ($heroMode === 'slogan'): ?>
|
||
<!-- 打字机标语:逐字打印轮播(复用「滚动信息栏」名言库内容) -->
|
||
<div class="slogan-box">
|
||
<span class="sg-mark">></span>
|
||
<span class="sg-text js-sg-text"></span><span class="sg-caret"></span>
|
||
<span class="js-sg-pool" hidden>
|
||
<?php foreach ($quotes as $q): ?><span><?= he($q) ?></span><?php endforeach; ?>
|
||
</span>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</header>
|
||
|
||
<?php if ($heroMode !== 'slogan'): // 打字机标语模式已复用同一信息栏内容,此处不再重复展示 ?>
|
||
<!-- 名言条 -->
|
||
<div class="quote-bar">
|
||
<div class="wrap quote-inner">
|
||
<span class="quote-mark"></span>
|
||
<span class="quote-text js-quote" data-current="0" title="点击换一条"><?= he($quoteText) ?></span>
|
||
<span class="quote-mark"></span>
|
||
</div>
|
||
<div class="quote-pool js-quote-pool">
|
||
<?php foreach ($quotes as $q): ?>
|
||
<span><?= he($q) ?></span>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<!-- 四大板块区 -->
|
||
<section class="board-section">
|
||
<div class="wrap">
|
||
<?php if ($quickLinks): ?>
|
||
<div class="quick-strip">
|
||
<?php foreach ($quickLinks as $ql):
|
||
$qIcon = trim((string) ($ql['icon'] ?? ''));
|
||
$qIcon = $qIcon !== '' ? $qIcon : '🔗';
|
||
$qNote = trim((string) ($ql['note'] ?? ''));
|
||
?>
|
||
<a class="quick-tile" href="<?= he((string) $ql['url']) ?>" target="_blank" rel="noopener noreferrer"
|
||
title="<?= he($qNote !== '' ? $qNote : (string) $ql['name']) ?>">
|
||
<span class="q-tile-ic"><?= site_icon($qIcon, '') ?></span>
|
||
<span class="q-tile-b">
|
||
<b><?= he((string) $ql['name']) ?></b>
|
||
<?php if ($qNote !== ''): ?><small><?= he($qNote) ?></small><?php endif; ?>
|
||
</span>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div class="boards">
|
||
<?php foreach ($cats as $c):
|
||
$k = (string) $c['key'];
|
||
$href = $catLink[$k] ?? 'index.php';
|
||
$bIcon = trim((string) ($c['icon'] ?? ''));
|
||
$bIcon = $bIcon !== '' ? $bIcon : ($catIcon[$k] ?? '●');
|
||
$descTxt = trim((string) ($c['description'] ?? ''));
|
||
if ($descTxt === '') {
|
||
$descTxt = $catHint[$k] ?? '';
|
||
}
|
||
?>
|
||
<a class="board-card" href="<?= he($href) ?>" title="<?= he($c['name']) ?>:<?= he($descTxt) ?>">
|
||
<span class="board-icon"><?= site_icon($bIcon, '') ?></span>
|
||
<span class="board-name"><?= he($c['name']) ?></span>
|
||
<!-- 说明文案直接常显(原悬停展开浮层已取消) -->
|
||
<span class="board-hint"><?= he($descTxt) ?></span>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<?php layout_theme_fab(); ?>
|
||
<?php layout_footer(); ?>
|
||
|
||
<script src="assets/js/common.js"></script>
|
||
</body>
|
||
|
||
</html>
|