未安装时自动跳转安装向导(修「打开首页不跳转」)
现象:全新部署后打开域名,看到的是一个空导航站(没有任何提示), 必须自己猜 /install.php 这个网址才能安装。 原因:index.php 一进来就 db() 建库并渲染前台,全站没有任何 「还没装」的引导逻辑;install.php 只能靠手输网址触达。 改动: - functions.php 新增 app_installed():全站唯一的「已安装」判断源 (有管理员账号 = 已安装),内部 try/catch 兜住建库失败 - index.php 开头:未安装且 install.php 存在 → 302 到安装页 · 只在 install.php 真存在时跳,用户装完删掉后自动失效,不会 404 - install.php 复用 app_installed(),删掉自己那套 is_file(DB_PATH) 推断, 避免「首页说没装、install 说装了」的口径分裂 测试(都在 _tooling/): - _sn_install_redirect_e2e.py 19 项:未安装跳转 / 已安装不跳 / install.php 删了不跳 / 已装拒重装,四态全覆盖 - _sn_install_redirect_falsify.py 6 变体全精确命中(含「无条件跳转→死循环」) - _sn_install_e2e.py 41 项回归全绿(顺手修 6 条因新逻辑过时的断言)
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
// 前台数据
|
||||
|
||||
+2
-9
@@ -91,15 +91,8 @@ 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) {
|
||||
// 库文件存在但读不出来(损坏 / 不可写)—— 环境检查会报,这里不重复喊
|
||||
}
|
||||
}
|
||||
// 与前台共用同一个判断源(functions.php 的 app_installed),避免两边口径不一致
|
||||
$hasAdmin = app_installed();
|
||||
$installed = is_file($lockFile) || $hasAdmin;
|
||||
|
||||
$err = '';
|
||||
|
||||
Reference in New Issue
Block a user