Files
FamilyBook/install.php
T
laoyang 1669ab48d0 五项家庭化改造:以个人为中心 · 家谱 · 三种角色 · 附件存储可配置 · 独立页样式
1. 独立页(登录/安装/错误)套上 HTML 骨架 —— 修「首页为什么没有样式」:
   新增 templates/layout-bare.php,View::render 对独立页也走完整 <head> + CSS。
2. 以个人为中心:Kinship::label() 现算称呼、Auth::homeTitle() 出「X的家书」;
   同一批人在不同登录者眼里自动变成公公婆婆 / 岳父岳母(不存一次性称谓)。
3. 附件存储可配置:Storage 门面(local / 阿里云 OSS),库里只存相对键,
   云端失败自动回退本地;设置页可选驱动并填 OSS 参数(照 MovieLog 的方案)。
4. 三种角色:admin / member / guest,访客只读、写操作一律 403;
   accounts.role 枚举扩容,老库靠 Schema::ensure() 自动升级。
5. 家谱:只存相邻两代的边(parent / spouse),其余称呼全部推导 ——
   兄弟姐妹不存边(共同父母 + birth_rank 排行推长子/次女、哥哥/妹妹),
   认不清的人用虚拟人物 is_placeholder 占位,关系天然双向。

顺带修掉本地 e2e 挖出的 8 个线上级 bug(性别写死、长幼方向反、关系方向静默写反、
birth_rank 不从表单取回、隐式可空参数致响应头失效、无文件字段被误判为上传失败、
layout 变量撞车覆盖 $me、世代 0 显示成「下 0 代」)。

验证:kinship 单测 37/0 · HTTP e2e 81/0 · 老库升级专测 14/0 ·
反向验证 11/11(把每个修复改回旧写法,对应断言都会变红)。
2026-09-30 08:13:07 +08:00

98 lines
3.1 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
/**
* 安装向导:建表 → 建家庭 → 建第一个人(同时是他/她的管理员账号)。
*
* 「是否已安装」以**数据库里的四张表**为准,不以某个文件是否存在为准 ——
* 文件可能被删、可能被恢复,表在就是装过了。
*/
declare(strict_types=1);
require __DIR__ . '/app/bootstrap.php';
use App\Account;
use App\Crypto;
use App\Database;
use App\Family;
use App\Person;
use App\Schema;
use App\View;
if (Database::hasTables()) {
// 装过之后这个入口就该消失:给 404,别让它在公网一直挂着、也别让爬虫收录
http_response_code(404);
View::renderBare('error', [
'title' => '已经装好了',
'message' => '「家书」已经安装过。如果要重新安装,请先清空数据库里的 families / persons / accounts / settings 四张表。',
]);
exit;
}
$dbName = $GLOBALS['config']['db']['name'];
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
csrf_check();
$familyName = trim((string)($_POST['family_name'] ?? ''));
$motto = trim((string)($_POST['motto'] ?? ''));
$name = trim((string)($_POST['name'] ?? ''));
$phone = trim((string)($_POST['phone'] ?? ''));
$password = (string)($_POST['password'] ?? '');
$errors = [];
if ($familyName === '') { $errors['_'] = '家庭名称不能为空'; }
if ($name === '') { $errors['name'] = '请填写你的姓名'; }
if (!preg_match('/^\+?[0-9\-]{6,20}$/', $phone)) {
$errors['phone'] = '手机号格式看起来不对';
}
$pwErr = Account::validatePassword($password);
if ($pwErr) { $errors['password'] = implode(';', $pwErr); }
if (!$errors) {
try {
// ensure() 而不是逐条 exec(statements()):它还会补齐后加的列与枚举值,
// 所以老库重新跑一次就能自动升级,不必手工改表。
Schema::ensure();
$familyId = Family::create($familyName, $motto);
$personId = Person::create($familyId, [
'name' => $name,
'nickname' => '',
'gender' => '',
'birthday' => '',
'avatar' => '',
'phone' => $phone,
'id_card' => '',
'email' => '',
'address' => '',
'note' => '',
'sort_order'=> 1,
'kind' => 'member',
]);
Account::create($personId, $password, 'admin');
// 装完就删掉自己 —— 避免把安装入口长期暴露在公网
@unlink(__FILE__);
header('Location: index.php?r=auth/login');
exit;
} catch (\Throwable $ex) {
$errors['_'] = '安装失败:' . $ex->getMessage();
}
}
set_old($_POST);
View::renderBare('install', [
'title' => '安装家书',
'dbName' => $dbName,
'errors' => $errors,
]);
exit;
}
clear_old();
View::renderBare('install', [
'title' => '安装家书',
'dbName' => $dbName,
'errors' => [],
]);