Files
FamilyBook/app/bootstrap.php
T
laoyang 8eb19267bc 阶段 0 完整版:名册 + 账号 + 安装向导 + 设置(宣纸主题)
这一版把「家」的地基铺完:

功能
- 安装向导 install.php:建四张表 → 建家庭 → 建第一人(兼管理员),装完自删;
  「是否已装」以数据库四张表为准,不以文件是否存在为准
- 家庭名册:成员增删改查、头像上传(居中裁方 512×512 转 JPEG、finfo 校验、
  随机文件名)、生日自动算年龄与倒数天数
- 敏感信息加密存储:手机号双写(SHA-256 哈希用于登录 + AES-256-CBC 密文用于显示)、
  身份证只存密文;页面上永远只显示脱敏后的 138****8000 / 前 6 后 4
- 账号体系:人与账号分离(孩子可入名册但无需密码)、开通/停用/角色、
  防爆破(5 次失败锁 60 秒)、修改密码、最后一个管理员不可移除
- 设置页:家庭名称与座右铭、加密密钥状态
- 宣纸主题 UI:砖红取自图标,扁平、留白充足;移动端顶栏收紧不换行

安全
- 所有 POST 走 CSRF;输出全量 e() 转义;uploads/ 禁执行脚本
- app/ 与 templates/ 加 .htaccess 整体拒绝直连(直接请求模板会 Fatal 并
  把服务器绝对路径打在页面上 —— 这是线上真实抓到过的问题)
- 已安装的 install.php 返回 404;display_errors 线上关闭

工程
- 无框架无 Composer,query-string 路由(index.php?r=模块/动作),不依赖 rewrite
- 静态资源带 mtime+size 版本号,改版后浏览器不会吃旧缓存
- 配套部署与冒烟(_tooling/,不入库):部署脚本容忍 tar 对非属主目录的
  元数据回填失败;冒烟断言「状态码 + 正文无 PHP 错误 + </html> 收尾 +
  无绝对路径泄露 + 断言总数下限」—— 只看状态码会把「200 但正文中间
  Fatal」当成通过,这一版在线上真实抓到过一次
2026-09-30 00:49:53 +08:00

69 lines
2.4 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
/**
* 应用引导:配置加载、会话、自动加载、全局辅助函数。
* 每个页面/入口只需 require 这一个文件。
*/
declare(strict_types=1);
// ---------------- 自动加载(避免「新增类忘了 require」这类事故)----------------
spl_autoload_register(function ($class) {
if (strpos($class, 'App\\') !== 0) {
return;
}
$rel = str_replace('\\', '/', substr($class, 4));
$file = __DIR__ . '/' . $rel . '.php';
if (is_file($file)) {
require $file;
}
});
define('FB_ROOT', dirname(__DIR__));
define('FB_APP', __DIR__);
define('FB_UPLOADS', FB_ROOT . '/uploads');
// ---------------- 配置 ----------------
$configFile = FB_ROOT . '/config.php';
if (!is_file($configFile)) {
http_response_code(500);
echo '<!doctype html><meta charset="utf-8"><title>家书 · 未配置</title>'
. '<div style="max-width:520px;margin:12vh auto;padding:28px 32px;'
. 'background:#fff;border:1px solid rgba(47,36,30,.1);border-radius:16px;'
. 'font:15px/1.8 -apple-system,\'PingFang SC\',\'Microsoft YaHei\',sans-serif;color:#2F241E">'
. '<h1 style="font-size:18px;margin:0 0 12px">还差一步:没有找到 config.php</h1>'
. '<p style="color:#7C6A5B;margin:0 0 16px">'
. '请复制同目录下的 <code>config.example.php</code> 为 <code>config.php</code>,'
. '填好数据库连接与 app_key 后再访问。</p>'
. '</div>';
exit;
}
$GLOBALS['config'] = require $configFile;
// ---------------- 错误报告(线上不显示错误,避免泄露路径与库信息)----------------
$debug = !empty($GLOBALS['config']['debug']);
error_reporting(E_ALL);
ini_set('display_errors', $debug ? '1' : '0');
ini_set('log_errors', '1');
// ---------------- 时区:日期是家书的核心数据,一开始就必须明确 ----------------
date_default_timezone_set($GLOBALS['config']['timezone'] ?? 'Asia/Shanghai');
// ---------------- 会话 ----------------
$isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
|| (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https');
session_name('fbsid');
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => $isHttps,
'httponly' => true,
'samesite' => 'Lax',
]);
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
require FB_APP . '/helpers.php';