安装向导 + PHP 8.5 兼容修复

新增 install.php:全新部署时自动接管,用户只需上传文件、打开站点即进入
安装向导。安装页自己做三件事:
  - 建 db/ 与 uploads/{posters,tickets,photos,avatars}/,权限调到 775
  - 逐目录真写临时文件实测可写,不靠 is_writable 猜
  - 建库、建管理员、写 db/.installed 锁、自删本文件

配套改动:
  - config.php 把安装检查前置于建库之前,未安装一律 302 到 install.php。
    原实现无条件调用 initDB(),导致「打开首页」就等于建库并种下 admin/123456。
  - lib/db.php 的 initDB(\$seedDefaultAdmin = true);安装向导传 false,
    管理员由用户自己设,绝不种弱口令。新增 isInstalled()。
  - login.php / nav.php 接上 siteName(),站点名称不再只存不用。
  - lib/settings.php 新增 siteName(),缺省回退「电影日志」。

PHP 8.5 兼容:
  - 删掉 fetch_movie.php 与 lib/storage/http.php 的 curl_close()。
    8.5 起该函数 deprecated,调用会往输出插一行警告,把 JSON 响应污染成
    「警告 + JSON」,前端 JSON.parse 失败 → 电影名联想功能完全失灵。
  - config.php 的 display_errors 由 1 改为 0(生产环境不应向浏览器吐错误),
    错误仍写日志;需要调试时设 MOVIELOG_DEBUG=1 打开。

线上验证(movie.yangyq.net,PHP 8.5.12):
  未安装时 / 、/login.php 均 302 → install.php;
  安装页 200、体检 10/10 通过、自动建好 5 个目录;
  安装后 install.php 404、管理员登录成功、首页 200 无报错;
  联想接口带会话请求「流浪地球/星际穿越/霸王别姬」均返回纯 JSON(首字符 {)。
This commit is contained in:
2026-10-31 21:35:41 +08:00
parent ee256adc4b
commit 3a3c5890cc
8 changed files with 587 additions and 15 deletions
+23 -8
View File
@@ -17,7 +17,13 @@ function getDB() {
}
// 初始化数据库
function initDB() {
//
// $seedDefaultAdmin:admins 表为空时要不要插入默认管理员 admin/123456。
// 默认 true —— 保持老站点、老脚本的原有行为不变(它们都靠这个账号首次登录)。
// 安装向导传 false:管理员由用户在 install.php 里自己设,绝不种弱口令。
// ⚠️ 这一点很关键:若安装页也走 true,则「打开安装页」就等于「库已建好且有默认账号」,
// 弱口令会直接暴露在公网,而且「是否已安装」的判断也被这件事本身污染。
function initDB($seedDefaultAdmin = true) {
$db = getDB();
// 管理员表
@@ -191,12 +197,21 @@ function initDB() {
$update = $db->prepare("UPDATE viewers SET person_id = (SELECT id FROM persons WHERE persons.name = viewers.name) WHERE person_id IS NULL AND name IS NOT NULL");
$update->execute();
// 默认管理员
$stmt = $db->prepare("SELECT COUNT(*) FROM admins");
$stmt->execute();
if ($stmt->fetchColumn() == 0) {
$hashed = password_hash('123456', PASSWORD_DEFAULT);
$stmt = $db->prepare("INSERT INTO admins (username, password) VALUES (?, ?)");
$stmt->execute(['admin', $hashed]);
// 默认管理员(仅当调用方允许时;安装向导会传 false,由用户自己设账号)
if ($seedDefaultAdmin) {
$stmt = $db->prepare("SELECT COUNT(*) FROM admins");
$stmt->execute();
if ($stmt->fetchColumn() == 0) {
$hashed = password_hash('123456', PASSWORD_DEFAULT);
$stmt = $db->prepare("INSERT INTO admins (username, password) VALUES (?, ?)");
$stmt->execute(['admin', $hashed]);
}
}
}
// 系统是否已完成安装。
// 判据是锁文件 db/.installed(由 install.php 写入),**不看库文件是否存在** ——
// 空库、半成品库都该允许重新安装,用「库在不在」当判据会把用户永久挡在门外。
function isInstalled() {
return is_file(ROOT_DIR . '/db/.installed');
}
+8
View File
@@ -244,6 +244,14 @@ function getSetting($name, $default = null) {
return array_key_exists($name, $cache) ? $cache[$name] : $default;
}
// 站点名称(安装向导里填的那个)。
// 没填过 / 装的是老库(settings 里没有这一项)时,退回默认「电影日志」——
// 这样任何页面的标题都不会因为缺这一项而空掉。
function siteName() {
$v = trim((string)getSetting('site_name', ''));
return $v !== '' ? $v : '电影日志';
}
// 读取布尔型设置
function getSettingBool($name, $default = false) {
$v = getSetting($name, null);
+2 -1
View File
@@ -104,7 +104,8 @@ function storageHttp($method, $url, array $headers = [], $body = null, $timeout
$err = curl_error($ch);
$errno = curl_errno($ch);
$status = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
// 不调用 curl_close():PHP 8.0 起句柄由 GC 回收;8.5 起该函数被标记 deprecated,
// 调用会在输出里插入警告,污染本模块返回给前端的 JSON。
if ($out === false) {
return [