NewHome/index.php
2026-09-14 22:06:21 +08:00

343 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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>当前时间&nbsp;</span><span class="val js-clock">--</span></div>
<div class="hm-row"><span>上次更新&nbsp;</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">&gt;</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>