面向公开仓库做一次脱敏,去掉与开发者个人绑定的域名、内网入口与环境路径。 - db.php:默认数据里的个人地址全部换成通用示例(原先是开发者的私有基础设施: 带路径令牌的面板地址、若干内网服务入口,以及暴露学校身份的校内系统如教务 / BB / VPN / 财务)。 分组结构(2 个网格板块 + 3 个合集板块)与条目数量保持不变,新装仍是一份可用的示例导航。 - README.md:去掉「复刻某站风格」的表述与示例路径里的个人域名;部署步骤改为通用写法 (不再指向仓库外的私有脚本目录),并补上 Nginx 的 /data/ 拦截规则。 顺带修正一处与实际不符的描述:原文档称「页面缓存插件无需任何特殊配置」,实测该插件读不到 FastCGI 的 Cache-Control,实际是靠根 .htaccess 在请求侧注入 X_CACHE=1 才旁路掉的。 - .htaccess / config.php / functions.php / assets/css/style.css:注释里的个人域名改为通用表述。 - .gitignore:去掉开发者本机目录约定。 - LICENSE:版权署名由个人昵称改为 The SimpleNav Authors。 默认数据只在空库时写入,线上现有数据不受影响;本次无运行期行为变更。 验证:本地 php -l 全过;e2e 93/93;部署(双版本 php -l + 静态断言 + 文件哈希逐字节一致 + HTTP 冒烟 + 缓存旁路自检 + Web 身份诊断)全绿,退出码 0。
79 lines
2.8 KiB
PHP
79 lines
2.8 KiB
PHP
<?php
|
||
/**
|
||
* 简航 SimpleNav —— 基础配置
|
||
* 面向个人的轻量级网站导航系统
|
||
*/
|
||
declare(strict_types=1);
|
||
|
||
date_default_timezone_set('Asia/Shanghai');
|
||
if (function_exists('mb_internal_encoding')) {
|
||
mb_internal_encoding('UTF-8');
|
||
}
|
||
|
||
define('APP_NAME', '简航');
|
||
define('APP_PATH', __DIR__);
|
||
define('DATA_PATH', APP_PATH . '/data'); // 数据库等敏感数据(禁止 Web 访问)
|
||
define('DB_PATH', DATA_PATH . '/nav.db');
|
||
define('ICON_PATH', APP_PATH . '/uploads/icons'); // 抓取的网站图标(可公开访问)
|
||
define('ICON_URL', 'uploads/icons'); // 相对站点根
|
||
define('ICON_STORE', 128); // 图标统一存成 128×128(高清屏下 45~64px 显示仍锐利)
|
||
|
||
/**
|
||
* 是否「由 PHP 再发一颗」绕开服务器侧页面缓存的标记 cookie。
|
||
*
|
||
* 背景(2026-09-28 线上实测):服务器装了宝塔面板的「网站加速」,它是一层基于
|
||
* memcached 的整页缓存,本站实测其过期时间是 30 秒。实测它
|
||
* **读不到** FastCGI 后端返回的 `Cache-Control` 响应头,所以 `no-store` 之类对它
|
||
* 无效;它唯一认的信号是**请求** cookie `X_CACHE=1`。
|
||
*
|
||
* 主要解法在根目录 `.htaccess` 里(用 `RequestHeader` 在请求侧注入该标记),
|
||
* 对所有访客一次生效、无需 PHP 配合;下面这个开关是**第二道保险**,
|
||
* 用于 Nginx 等不读 .htaccess 的环境。
|
||
*
|
||
* true = 动态页顺带把该 cookie 种到访客浏览器(首次访问各发一次)
|
||
* false = 只发响应头,完全依赖 .htaccess / 服务器配置
|
||
*/
|
||
define('BYPASS_PAGE_CACHE', true);
|
||
|
||
/**
|
||
* 自动探测应用根 URL,兼容「放在子目录 /simplenav」与「放在根目录」两种部署。
|
||
* 返回形如 ''(根目录)或 '/simplenav'。
|
||
*/
|
||
function app_base(): string
|
||
{
|
||
$dir = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '/';
|
||
$dir = str_replace('\\', '/', dirname($dir));
|
||
$dir = preg_replace('#/admin$#', '', $dir); // admin/ 下的脚本回退到应用根
|
||
$dir = rtrim($dir, '/');
|
||
return $dir === '/' ? '' : $dir;
|
||
}
|
||
|
||
/** 生成带应用根的 URL */
|
||
function url(string $path = ''): string
|
||
{
|
||
return app_base() . '/' . ltrim($path, '/');
|
||
}
|
||
|
||
/** 站点名(可在后台设置里覆盖) */
|
||
function site_name(): string
|
||
{
|
||
return setting('site_name', APP_NAME);
|
||
}
|
||
|
||
/** 读取设置项 */
|
||
function setting(string $key, string $default = ''): string
|
||
{
|
||
static $cache = null;
|
||
if ($cache === null) {
|
||
$cache = [];
|
||
try {
|
||
foreach (db()->query('SELECT k, v FROM settings') as $row) {
|
||
$cache[$row['k']] = $row['v'];
|
||
}
|
||
} catch (Throwable $e) {
|
||
$cache = [];
|
||
}
|
||
}
|
||
return array_key_exists($key, $cache) && $cache[$key] !== '' ? $cache[$key] : $default;
|
||
}
|