diff --git a/functions.php b/functions.php index 163d9eb..b477e4b 100644 --- a/functions.php +++ b/functions.php @@ -7,6 +7,31 @@ declare(strict_types=1); require_once __DIR__ . '/config.php'; require_once __DIR__ . '/db.php'; +/** + * 是否已完成安装(= 至少存在一个管理员账号)。 + * + * **这是全站唯一的「已安装」判断源**,前台跳转、install.php 守卫、登录页文案都走这里。 + * 不要各处自己写 `is_file(DB_PATH)` 或 `SELECT COUNT(*) FROM users` —— 判断口径不一会出现 + * 「首页说装了、install 说没装」这类互相矛盾的状态。 + * + * 为什么要 try/catch:库还建不出来(data/ 不可写、SQLite 扩展缺失)时, + * db() 会抛异常。此时应视为「未安装」,让用户走到 install.php 看到环境检查的报错, + * 而不是在前台白屏或 500。 + */ +function app_installed(): bool +{ + static $cached = null; + if ($cached !== null) { + return $cached; + } + try { + $cached = (int)db()->query('SELECT COUNT(*) FROM users')->fetchColumn() > 0; + } catch (Throwable $e) { + $cached = false; + } + return $cached; +} + /** HTML 转义 */ function e(?string $s): string { diff --git a/index.php b/index.php index 8af5a66..de150ac 100644 --- a/index.php +++ b/index.php @@ -9,6 +9,20 @@ declare(strict_types=1); require_once __DIR__ . '/functions.php'; send_no_cache(); +/** + * 未安装就先去装:库里还没有任何一个管理员账号时,前台没有意义 + * (打开只会看到一个空导航,既没有提示也不知道去哪)。 + * + * ⚠️ 只在 install.php 真的存在时才跳。用户装完删掉 install.php 后, + * 这个分支自动失效,不会跳到 404。 + * ⚠️ 必须放在 db() 之前判断的等价位置:app_installed() 内部会调 db(), + * 但那边有 try/catch 兜住建库失败的情况,不会把异常抛到前台。 + */ +if (!app_installed() && is_file(__DIR__ . '/install.php')) { + header('Location: ' . url('install.php')); + exit; +} + $pdo = db(); // 前台数据 diff --git a/install.php b/install.php index 6bcecae..f33d2cb 100755 --- a/install.php +++ b/install.php @@ -90,16 +90,9 @@ foreach ($checks as $ck) { * 安装状态 * ========================================================================= */ -$lockFile = DATA_PATH . '/install.lock'; -$dbExists = is_file(DB_PATH); -$hasAdmin = false; -if ($dbExists) { - try { - $hasAdmin = (int)db()->query('SELECT COUNT(*) FROM users')->fetchColumn() > 0; - } catch (Throwable $e) { - // 库文件存在但读不出来(损坏 / 不可写)—— 环境检查会报,这里不重复喊 - } -} +$lockFile = DATA_PATH . '/install.lock'; +// 与前台共用同一个判断源(functions.php 的 app_installed),避免两边口径不一致 +$hasAdmin = app_installed(); $installed = is_file($lockFile) || $hasAdmin; $err = '';