96 lines
3.6 KiB
PHP
96 lines
3.6 KiB
PHP
<?php
|
||||
|
|
/**
|
|||
|
|
* 启动引导:加载配置、注册自动加载、开启会话、初始化数据库。
|
|||
|
|
* 所有页面(index/thread/new/api)都以此为入口。
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
if (!defined('FB_ROOT')) {
|
|||
|
|
define('FB_ROOT', dirname(__DIR__));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ------------------------------------------------------------------
|
|||
|
|
* 错误显示策略必须最先设置:
|
|||
|
|
* 任何被打印到页面的 Warning/Deprecated 都会让响应头提前发出,
|
|||
|
|
* 从而令随后的 session_start() 失败(表现为「会话已过期」、CSRF 全部失效)。
|
|||
|
|
* 所以这里在 require 任何库文件之前就把 display_errors 关掉。
|
|||
|
|
* ------------------------------------------------------------------ */
|
|||
|
|
@ini_set('display_errors', '0');
|
|||
|
|
@ini_set('log_errors', '1');
|
|||
|
|
error_reporting(E_ALL);
|
|||
|
|
|
|||
|
|
// 兜底:捕获致命错误时也不要向页面输出堆栈(生产环境)
|
|||
|
|
if (!defined('FB_BOOTSTRAPPED')) {
|
|||
|
|
define('FB_BOOTSTRAPPED', 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 后台改设置后自增,用来让 fb_cfg 的进程内缓存失效
|
|||
|
|
if (!isset($GLOBALS['__fb_cfg_stamp'])) {
|
|||
|
|
$GLOBALS['__fb_cfg_stamp'] = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!function_exists('fb_cfg')) {
|
|||
|
|
/**
|
|||
|
|
* 读取配置(点分路径,如 fb_cfg('smtp.host'))
|
|||
|
|
* 取值顺序:settings 表(后台改过的)> config.php(本地配置)> config.example.php(出厂默认)> $default
|
|||
|
|
*
|
|||
|
|
* config.php 不参与版本管理(见 .gitignore),新部署时可从 config.example.php 复制一份;
|
|||
|
|
* 若不存在则直接以 config.example.php 为默认值运行,保证 clone 下来即可跑。
|
|||
|
|
*/
|
|||
|
|
function fb_cfg($path = null, $default = null) {
|
|||
|
|
static $merged = null;
|
|||
|
|
static $stamp = -1;
|
|||
|
|
$now = isset($GLOBALS['__fb_cfg_stamp']) ? (int)$GLOBALS['__fb_cfg_stamp'] : 0;
|
|||
|
|
if ($merged === null || $stamp !== $now) {
|
|||
|
|
$local = FB_ROOT . '/config.php';
|
|||
|
|
$example = FB_ROOT . '/config.example.php';
|
|||
|
|
if (is_file($local)) {
|
|||
|
|
$cfg = (array)(require $local);
|
|||
|
|
} elseif (is_file($example)) {
|
|||
|
|
$cfg = (array)(require $example);
|
|||
|
|
} else {
|
|||
|
|
$cfg = [];
|
|||
|
|
}
|
|||
|
|
// 后台设置以嵌套数组形式叠加在文件配置之上(只覆盖同名键)
|
|||
|
|
$tree = function_exists('fb_setting_tree') ? fb_setting_tree() : [];
|
|||
|
|
$merged = is_array($tree) && $tree ? array_replace_recursive($cfg, $tree) : $cfg;
|
|||
|
|
$stamp = $now;
|
|||
|
|
}
|
|||
|
|
if ($path === null || $path === '') { return $merged; }
|
|||
|
|
$cur = $merged;
|
|||
|
|
foreach (explode('.', (string)$path) as $k) {
|
|||
|
|
if (is_array($cur) && array_key_exists($k, $cur)) {
|
|||
|
|
$cur = $cur[$k];
|
|||
|
|
} else {
|
|||
|
|
return $default;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return $cur;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
require_once FB_ROOT . '/lib/util.php';
|
|||
|
|
require_once FB_ROOT . '/lib/db.php';
|
|||
|
|
require_once FB_ROOT . '/lib/oss.php';
|
|||
|
|
require_once FB_ROOT . '/lib/attach.php';
|
|||
|
|
require_once FB_ROOT . '/lib/captcha.php';
|
|||
|
|
require_once FB_ROOT . '/lib/mailer.php';
|
|||
|
|
require_once FB_ROOT . '/lib/layout.php';
|
|||
|
|
|
|||
|
|
// 会话(CLI 下不启用)
|
|||
|
|
if (PHP_SAPI !== 'cli' && session_status() !== PHP_SESSION_ACTIVE) {
|
|||
|
|
$p = session_get_cookie_params();
|
|||
|
|
$https = (!empty($_SERVER['HTTPS']) && strtolower((string)$_SERVER['HTTPS']) !== 'off');
|
|||
|
|
@session_set_cookie_params([
|
|||
|
|
'lifetime' => 0,
|
|||
|
|
'path' => !empty($p['path']) ? $p['path'] : '/',
|
|||
|
|
'domain' => '',
|
|||
|
|
'secure' => $https,
|
|||
|
|
'httponly' => true,
|
|||
|
|
'samesite' => 'Lax',
|
|||
|
|
]);
|
|||
|
|
@session_start();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化数据库(建表)
|
|||
|
|
fb_db();
|