refactor: 拆分 config.php 为 lib/ 模块,消除页面层重复代码

纯结构性重构,不改变任何功能。

- config.php 由 739 行缩减为 42 行,改为纯引导入口;新增 ROOT_DIR 常量
  统一拼接绝对路径(lib/ 内模块的 __DIR__ 会指向 lib/,必须替换)
- 新增 lib/ 五个模块 db.php / helpers.php / auth.php / movies.php / stats.php,
  由 config.php 按 db → helpers → auth → movies → stats 顺序加载
- add.php、edit.php 各自约 80 行重复的 POST 处理改为调用
  resolveCinemaId / resolvePersonIds / linkViewers / uploadImageFile /
  saveBase64Image / uploadMultiplePhotos / deleteStoredFile
- cinemas.php、persons.php 中重复 4 次的颜色校验改用 normalizeHexColor()
- toggleNewViewer / removeViewerRow / toggleNewCinema 下沉至 js/main.js,
  add.php 中的 removeViewer 统一更名为 removeViewerRow
- 删除死代码:imageUrl()(全项目无调用);cinemas.php 配色数组中本就会被
  array_slice 丢弃的 extra 颜色逻辑,简化为单条扁平 50 元素数组
- README 目录结构补充 lib/ 说明

验证方式:以便携 PHP 8.4 搭建 A/B 回归环境,播种固定数据后遍历 47 个
GET/POST 端点录制「状态码 + 响应体」。重构前后 42 个逐字节相同、2 个仅
上传文件名时间戳不同、3 个差异均为内联脚本下沉(已单独校验函数体逐字符
等价,剥离脚本后 HTML 标记完全一致)。24 个 PHP 文件语法检查全部通过。
This commit is contained in:
2026-09-21 12:56:30 +08:00
parent 40e1bc5e56
commit dd957d45bd
13 changed files with 1002 additions and 1022 deletions
+37 -133
View File
@@ -36,87 +36,61 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$cinema_id = $_POST['cinema_id'] ?? '';
$viewer_selects = $_POST['viewer_select'] ?? [];
$viewer_news = $_POST['viewers_new'] ?? [];
$poster_crop = $_POST['poster_crop'] ?? '';
$ticket_crop = $_POST['ticket_crop'] ?? '';
$photo_crops = $_POST['photo_crop'] ?? [];
// 新建影院
$new_cinema_place = trim($_POST['new_cinema_place'] ?? '');
$new_cinema_name = trim($_POST['new_cinema_name'] ?? '');
$new_cinema_address = trim($_POST['new_cinema_address'] ?? '');
if ($cinema_id === 'new' && !empty($new_cinema_name)) {
$stmt = $db->prepare("INSERT INTO cinemas (place, name, address) VALUES (?, ?, ?)");
$stmt->execute([$new_cinema_place, $new_cinema_name, $new_cinema_address]);
$cinema_id = $db->lastInsertId();
} elseif ($cinema_id === 'new') {
$cinema_id = null;
} elseif (!empty($cinema_id) && is_numeric($cinema_id)) {
$cinema_id = (int)$cinema_id;
} else {
$cinema_id = null;
}
// 电影院:选择已有影院、新建影院或留空
$cinema_id = resolveCinemaId(
$cinema_id,
trim($_POST['new_cinema_place'] ?? ''),
trim($_POST['new_cinema_name'] ?? ''),
trim($_POST['new_cinema_address'] ?? '')
);
if (empty($title)) {
$error = '请输入电影名称';
} elseif (empty($watch_date)) {
$error = '请选择观影日期';
} else {
// ----- 处理海报裁剪/上传 -----
// ----- 海报裁剪结果优先,其次上传新文件 -----
$poster_path = $movie['poster_path'];
if (!empty($poster_crop)) {
$new_path = saveBase64Image($poster_crop, POSTER_DIR, 'poster');
if ($new_path) {
if ($poster_path && file_exists(__DIR__ . '/' . $poster_path)) {
unlink(__DIR__ . '/' . $poster_path);
}
deleteStoredFile($poster_path);
$poster_path = $new_path;
} else {
$error = '海报裁剪保存失败,请重试';
}
} elseif (isset($_FILES['poster']) && $_FILES['poster']['error'] === UPLOAD_ERR_OK) {
// 上传新海报替换
$ext = strtolower(pathinfo($_FILES['poster']['name'], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
$filename = uniqueFilename($_FILES['poster']['name']);
$target = POSTER_DIR . $filename;
if (move_uploaded_file($_FILES['poster']['tmp_name'], $target)) {
if ($poster_path && file_exists(__DIR__ . '/' . $poster_path)) {
unlink(__DIR__ . '/' . $poster_path);
}
$poster_path = 'uploads/posters/' . $filename;
}
} else {
$uploaded = uploadImageFile('poster', POSTER_DIR, 'uploads/posters/');
if ($uploaded) {
deleteStoredFile($poster_path);
$poster_path = $uploaded;
}
}
// ----- 处理票根裁剪/上传 -----
// ----- 票根裁剪结果优先,其次上传新文件 -----
$ticket_path = $movie['ticket_path'];
if (!empty($ticket_crop)) {
$new_path = saveBase64Image($ticket_crop, TICKET_DIR, 'ticket');
if ($new_path) {
if ($ticket_path && file_exists(__DIR__ . '/' . $ticket_path)) {
unlink(__DIR__ . '/' . $ticket_path);
}
deleteStoredFile($ticket_path);
$ticket_path = $new_path;
} else {
$error = '票根裁剪保存失败,请重试';
}
} elseif (isset($_FILES['ticket']) && $_FILES['ticket']['error'] === UPLOAD_ERR_OK) {
$ext = strtolower(pathinfo($_FILES['ticket']['name'], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
$filename = uniqueFilename($_FILES['ticket']['name']);
$target = TICKET_DIR . $filename;
if (move_uploaded_file($_FILES['ticket']['tmp_name'], $target)) {
if ($ticket_path && file_exists(__DIR__ . '/' . $ticket_path)) {
unlink(__DIR__ . '/' . $ticket_path);
}
$ticket_path = 'uploads/tickets/' . $filename;
}
} else {
$uploaded = uploadImageFile('ticket', TICKET_DIR, 'uploads/tickets/');
if ($uploaded) {
deleteStoredFile($ticket_path);
$ticket_path = $uploaded;
}
}
// 如果前面处理没有错误,继续更新数据库
// 前面处理没有错误,更新数据库
if (empty($error)) {
// 更新电影基本信息
$stmt = $db->prepare("
@@ -125,8 +99,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
WHERE id = ?
");
$stmt->execute([$title, $info, $poster_path, $ticket_path, $cinema_id, $watch_date, $id]);
// ----- 处理合影裁剪 -----
// ----- 合影:替换已裁剪的图片 -----
if (!empty($photo_crops)) {
foreach ($photo_crops as $photo_id => $base64_data) {
if (empty($base64_data)) continue;
@@ -136,66 +110,22 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($old) {
$new_path = saveBase64Image($base64_data, PHOTO_DIR, 'photo');
if ($new_path) {
if ($old['photo_path'] && file_exists(__DIR__ . '/' . $old['photo_path'])) {
unlink(__DIR__ . '/' . $old['photo_path']);
}
deleteStoredFile($old['photo_path']);
$stmt = $db->prepare("UPDATE movie_photos SET photo_path = ? WHERE id = ?");
$stmt->execute([$new_path, $photo_id]);
}
}
}
}
// ----- 新增合影照片 -----
if (isset($_FILES['new_photos']) && is_array($_FILES['new_photos']['tmp_name'])) {
$photo_files = $_FILES['new_photos'];
for ($i = 0; $i < count($photo_files['tmp_name']); $i++) {
if ($photo_files['error'][$i] === UPLOAD_ERR_OK) {
$ext = strtolower(pathinfo($photo_files['name'][$i], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
$filename = uniqueFilename($photo_files['name'][$i]);
$target = PHOTO_DIR . $filename;
if (move_uploaded_file($photo_files['tmp_name'][$i], $target)) {
$photo_path = 'uploads/photos/' . $filename;
$stmt = $db->prepare("INSERT INTO movie_photos (movie_id, photo_path) VALUES (?, ?)");
$stmt->execute([$id, $photo_path]);
}
}
}
}
}
// ----- 处理观影人 -----
uploadMultiplePhotos('new_photos', $id);
// ----- 一起看的人 -----
$stmt = $db->prepare("DELETE FROM viewers WHERE movie_id = ?");
$stmt->execute([$id]);
$person_ids = [];
foreach ($viewer_selects as $idx => $val) {
if ($val === 'new') {
$new_name = trim($viewer_news[$idx] ?? '');
if (!empty($new_name)) {
$chk = $db->prepare("SELECT id FROM persons WHERE name = ?");
$chk->execute([$new_name]);
$existing = $chk->fetch();
if ($existing) {
$person_ids[] = $existing['id'];
} else {
$ins = $db->prepare("INSERT INTO persons (name) VALUES (?)");
$ins->execute([$new_name]);
$person_ids[] = $db->lastInsertId();
}
}
} elseif (is_numeric($val) && $val > 0) {
$person_ids[] = (int)$val;
}
}
$person_ids = array_unique($person_ids);
if (!empty($person_ids)) {
$stmt = $db->prepare("INSERT INTO viewers (movie_id, person_id, name) VALUES (?, ?, ?)");
foreach ($person_ids as $pid) {
$stmt->execute([$id, $pid, '']);
}
}
linkViewers($id, resolvePersonIds($viewer_selects, $viewer_news));
header('Location: detail.php?id=' . $id);
exit;
}
@@ -480,6 +410,7 @@ if (empty($current_person_ids)) {
</div>
</div>
<script src="js/main.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>
<script>
// ============================================================
@@ -508,31 +439,11 @@ if (empty($current_person_ids)) {
container.appendChild(div);
}
function toggleNewViewer(select) {
var parent = select.parentElement;
var input = parent.querySelector('input[name="viewers_new[]"]');
if (select.value === 'new') {
input.style.display = 'block';
input.required = true;
} else {
input.style.display = 'none';
input.required = false;
input.value = '';
}
}
function addViewerRow(value) {
value = value || '';
createViewerRow(value);
}
function removeViewerRow(btn) {
var container = document.getElementById('viewerContainer');
if (container.children.length > 1) {
btn.parentElement.remove();
}
}
document.addEventListener('DOMContentLoaded', function() {
var container = document.getElementById('viewerContainer');
container.innerHTML = '';
@@ -547,13 +458,6 @@ if (empty($current_person_ids)) {
toggleNewCinema();
});
// ---------- 电影院 ----------
function toggleNewCinema() {
var select = document.getElementById('cinemaSelect');
var group = document.getElementById('newCinemaGroup');
group.style.display = select.value === 'new' ? 'block' : 'none';
}
// ---------- 裁剪 ----------
let cropper = null;
let currentTarget = '';