Files
SimpleNav/config.php
T
laoyang 5f38df80b7 副标题允许为空:清空后前台不再回退显示默认文案
根因:setting() 把「空串」当成「从未配置」,于是后台删掉副标题后前台照样
显示默认的「个人网站导航」——删不掉。

改动:
- config.php: setting() 改为「只有键不存在才回退 default」;空串是一等公民。
  site_name() 改为唯一显式「空则回退 APP_NAME」的设置(页面不能没名字)。
- index.php: 副标题按空串读取(默认值取 ),hero 与 <title> 两处都判空;
  空时不输出 <p>、不拼「·」分隔符。
- admin/index.php: 输入框回显不传默认文案(清空后不回弹),加 placeholder 与说明。
2026-09-28 23:38:13 +08:00

125 lines
4.9 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
/**
* 简航 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 显示仍锐利)
/**
* 「站点整体图标」(浏览器标签页 favicon + 首页品牌图标)—— 用户上传后自动生成的一整套尺寸。
*
* ⚠️ 与上面的 ICON_PATH 是**两件事**,目录也刻意分开:
* ICON_PATH = 导航格子里**某个网站**自己的小图标,一个网站一份(键 = icon_key(网址));
* SITE_ICON_PATH = **本站自己**的图标,全局唯一(键 = 随机 16 位 hex)。
* 混在一起的话,清理图标目录时两边会互相误伤。
*/
define('SITE_ICON_PATH', APP_PATH . '/uploads/site');
define('SITE_ICON_URL', 'uploads/site');
/**
* 是否「由 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, '/');
}
/** 站点名(可在后台设置里覆盖)
*
* ⚠️ 这是**唯一**允许「空则回退默认」的设置:站点名留空会让 <title> / <h1> / alt
* 变成空白,页面连名字都没有。
* 这里显式写出来,而不是指望 setting() 全局回退 —— 那正是「副标题删不掉」的病根。
*/
function site_name(): string
{
$n = setting('site_name');
return $n !== '' ? $n : APP_NAME;
}
/**
* 设置表缓存(可失效)。
*
* ⚠️ 为什么必须能失效:这个缓存只在**首次读取**时查库,之后整进程复用。
* 后台「保存设置 → 重定向」是两次请求,所以以前没暴露问题;但只要有**同一次请求里
* 先写设置、再读回来**的路径(上传站点图标就是:写完马上要用新键拼 URL),
* 就会读到写之前的旧值 —— 表现为「上传成功但图标没变」。
* 任何写入设置的地方,写完都要调 settings_reload()。
*/
function settings_cache(bool $reload = false): array
{
static $cache = null;
if ($cache === null || $reload) {
$cache = [];
try {
foreach (db()->query('SELECT k, v FROM settings') as $row) {
$cache[$row['k']] = $row['v'];
}
} catch (Throwable $e) {
$cache = [];
}
}
return $cache;
}
/** 写入设置后调用,让本次请求后续的 setting() 读到新值 */
function settings_reload(): void
{
settings_cache(true);
}
/**
* 读取设置项。
*
* ⚠️ 空串是一等公民:**只有「这一行不存在」才回退 $default**。
* 曾经这里写的是 `$cache[$key] !== ''`,把「用户主动清空」和「从未配置过」当成一回事,
* 于是后台删掉副标题后前台照样显示默认的「个人网站导航」——删不掉。
* 需要「空则回退」的设置请在自己的读取点显式写明(如 site_name()),
* 不要把这个语义塞回函数里。
*/
function setting(string $key, string $default = ''): string
{
$cache = settings_cache();
return array_key_exists($key, $cache) ? $cache[$key] : $default;
}