laoyang dd957d45bd 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 文件语法检查全部通过。
2026-09-21 12:56:30 +08:00

MovieLog_Server · 电影全纪录

一个轻量级的个人/家庭观影记录系统。纯 PHP 编写,使用 SQLite 作为数据库,无需任何框架、无需 Composer、无需配置数据库服务,上传到支持 PHP 的空间即可运行。

记录每一帧感动 —— 观影记录、影院、同行人、票根与照片,以及属于你的年度观影报告。


功能特性

观影记录管理

  • 瀑布流首页:按观影日期倒序展示所有电影,卡片显示海报、日期、影院(影院专属配色)、同行人头像。
  • 添加电影:支持电影名、剧情简介、观影日期、电影院、同行人、海报、票根、多张观影照片。
  • 编辑 / 删除:编辑页可替换或裁剪已有图片;删除电影时同步清理关联的图片文件。
  • 电影详情:海报大图、基本信息、备注、同行人列表(含头像)、影院信息、影像记录画廊(票根 + 观影照片,点击可查看原图)。

图片处理

  • 内置裁剪器:基于 Cropper.js,票根 / 海报 / 观影照片 / 观影人头像均可在浏览器内裁剪后再保存,服务端接收 Base64 图片落盘。
  • 多图上传:观影照片支持一次选择多张。
  • 头像兜底:未上传头像的观影人自动生成"首字母 + 配色"的 SVG 头像,配色由姓名哈希决定,同名同色。
  • 上传目录按类型分离:uploads/posters/uploads/tickets/uploads/photos/uploads/avatars/

信息辅助

  • OMDb 自动获取:在添加页输入片名后点击「📡 自动获取」,自动填充年份、类型、片长、导演、主演、IMDb 评分与剧情简介,并预览海报(海报仅供参考,仍需本地上传)。
  • CSV 批量导入:一次性导入历史数据,自动识别 UTF-8 / GBK / GB2312 编码,自动创建不存在的影院,影院名去重,全程事务保护(出错自动回滚),并输出逐行错误报告。

检索与统计

  • 首页快捷搜索:按片名模糊搜索。
  • 高级搜索:片名 + 影院 + 观影人 + 日期区间,多条件组合筛选。
  • 统计仪表板:总览卡片(电影数 / 影院数 / 观影人数 / 观影人次 / 时间跨度),按影院、按观影人、按年份、最近 12 个月的条形图排行。

年度报告

  • 个性化年度报告:以「当前登录账号所关联的观影人」为视角生成,而非全站数据。
  • 报告内容:年度观影总数、观影天数、最常去的影院、最常一起观影的人、单场最多人的电影、首末场日期、月均频率、平均间隔天数、备注关键词云、今年共同观影人排行、年末最近观看、年度观影记录墙(含海报与同行人头像)。
  • 可视化:月度观影分布、星期观影偏好(Chart.js 双图),整体为深色"影院感"主题。

多用户与权限

  • Session 登录password_hash / password_verify 加盐哈希存储口令,全站页面均需登录。
  • 用户管理:可新增、编辑、删除管理员账号,可修改用户名与密码。
  • 账号 ↔ 观影人绑定:每个管理员账号可关联一个观影人,绑定后即可查看个人年度报告。
  • 安全约束:不允许删除最后一个管理员,也不允许删除自己。
  • 个人资料:修改自己的用户名与密码(需验证旧密码)。

基础数据维护

  • 影院管理:增删改查,支持「所在地方 / 影院名称 / 详细地址」三段式信息,内置 50 种预设配色,每个影院可用专属颜色区分;删除已被引用的影院时会给出醒目提示并要求二次确认(关联电影的影院字段将被置空)。
  • 观影人管理:增删改查,支持头像裁剪上传与专属配色;已被电影引用的观影人不允许直接删除。

界面与体验

  • 复古票根色系(主色 #e67e22 橙)的响应式设计,移动端断点适配(600 / 768px)。
  • 导航为下拉菜单,自动高亮当前页;顶部始终显示当前用户头像与用户名。
  • 登录页为深色渐变 + 毛玻璃风格。

技术栈

项目 说明
语言 PHP(过程式 + PDO
数据库 SQLitedb/movies.db,首次运行自动建表)
前端 原生 HTML / CSS / JavaScript,无构建步骤
第三方库 Cropper.js 1.5.13(图片裁剪)、Chart.js 4.4.0(图表),均由 CDN 引入
外部 API OMDb API(电影信息查询,需申请 API Key)

目录结构

MovieLog_Server/
├── config.php              # 引导入口:错误报告、会话、路径常量、上传目录,并加载 lib/ 各模块
├── lib/                    # 功能模块(被 config.php 统一引入,页面无需单独 require)
│   ├── db.php              #   DB 连接、建表、字段与历史数据迁移、默认管理员
│   ├── helpers.php         #   输出转义、文件名、颜色校验、上传/删除文件、图片 URL
│   ├── auth.php            #   登录校验、管理员账号增删改
│   ├── movies.php          #   电影/影院读取、搜索,以及表单关联数据的解析
│   └── stats.php           #   统计仪表板与年度报告查询
├── index.php               # 首页:观影列表(瀑布流)+ 快捷搜索
├── add.php                 # 添加电影
├── edit.php                # 编辑电影
├── detail.php              # 电影详情
├── delete.php              # 删除电影(连带清理图片文件)
├── search.php              # 高级搜索
├── stats.php               # 统计仪表板
├── annual_report.php       # 年度报告
├── cinemas.php             # 影院管理
├── persons.php             # 观影人管理
├── import.php              # CSV 批量导入
├── users.php               # 用户(管理员)管理
├── change_password.php     # 修改自己的用户名/密码
├── login.php               # 登录
├── logout.php              # 退出
├── nav.php                 # 导航栏组件(被各页面 include
├── fetch_movie.php         # OMDb 代理接口,返回 JSON
├── test_crop.php           # 开发调试页:验证 Base64 图片落盘是否正常
├── css/style.css           # 全局样式
├── js/main.js              # 公共脚本(含各页面共用的表单联动函数)
├── assets/.gitkeep         # 静态占位资源目录
├── db/movies.db            # SQLite 数据库(运行时自动生成,不纳入版本控制)
└── uploads/                # 上传图片(运行时自动生成,不纳入版本控制)
    ├── posters/            # 海报
    ├── tickets/            # 票根
    ├── photos/             # 观影照片
    └── avatars/            # 观影人头像

页面只需 require_once 'config.php'lib/ 下的模块会由引导文件统一加载,并保证依赖顺序(db → helpers → auth → movies → stats)。


数据库结构

建表逻辑集中在 config.phpinitDB(),每次请求都会执行 CREATE TABLE IF NOT EXISTS 与幂等的 ALTER TABLE 迁移,因此升级代码无需手动改库

作用 关键字段
admins 管理员账号 username(唯一)、password(哈希)、avatarperson_id(关联观影人)
cinemas 电影院 place(所在地方)、nameaddresscolor(专属配色)
movies 电影记录 titleinforemarkposter_pathticket_pathphoto_path(历史遗留单图)、cinema_idwatch_datecreated_at
persons 观影人 name(唯一)、coloravatar
viewers 电影 ↔ 观影人关联 movie_idperson_idname(历史遗留字段)
movie_photos 电影多图 movie_idphoto_pathcreated_at

外键约束:movies.cinema_id → cinemas.idON DELETE SET NULL)、viewers.movie_id → movies.idON DELETE CASCADE)、movie_photos.movie_id → movies.idON DELETE CASCADE)。

历史数据迁移initDB() 会自动把早期版本存在 viewers.name 里的姓名去重后写入 persons,并回填 viewers.person_id,老库可直接升级。


安装部署

环境要求

  • PHP 7.4+(推荐 8.x),需启用扩展:pdo_sqlitefileinfombstringcurl
  • Web 服务器:Apache / Nginx / PHP 内置服务器均可

步骤

  1. 放置代码:将项目文件放到 Web 根目录或其子目录。

  2. 确保可写:保证项目根目录可写,程序会自动创建 db/uploads/ 及其子目录;或手动创建并授权:

    mkdir -p db uploads/posters uploads/tickets uploads/photos uploads/avatars
    chmod -R 755 db uploads
    
  3. 配置 OMDb API Key(可选,仅影响「自动获取」功能):编辑 fetch_movie.php,将 OMDB_API_KEY 换成你在 omdbapi.com 申请的免费 Key。

  4. 访问站点:浏览器打开 login.php

  5. 首次登录:数据库为空时会自动创建默认管理员:

    • 用户名 admin
    • 密码 123456

    登录后请立即在「修改密码」中更换。

本地快速运行

php -S localhost:8000
# 浏览器访问 http://localhost:8000/login.php

用 PHP 内置服务器时,config.phpposterUrl() 等函数返回的是以 / 开头的根路径,建议直接从项目根目录启动,或通过站点根目录访问。

Nginx 参考配置

server {
    listen 80;
    server_name movielog.local;
    root /path/to/MovieLog_Server;
    index index.php;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

使用说明

添加一部电影

  1. 顶部导航点击「 添加电影」。
  2. 输入片名后点「📡 自动获取」可自动填充影片信息(可选)。
  3. 填写观影日期(必填)、选择或新建电影院。
  4. 「一起看的人」逐行添加:选择已有观影人,或在下拉框中选「 新增」并输入姓名,新姓名会自动进入观影人库。
  5. 上传海报(推荐 2:3);上传票根会弹出裁剪框,裁剪结果以 Base64 提交。
  6. 观影照片支持一次多选。
  7. 保存后自动跳转到详情页。

生成年度报告

年度报告是按人生成的,需要先建立账号与观影人的绑定:

  1. 进入「用户管理」,找到自己的账号,在「关联观影人」中选择对应的观影人并保存。
  2. 进入「年度报告」,页面顶部切换年份即可查看。
  3. 未绑定观影人时报告为空并给出提示。

CSV 批量导入

CSV 共 9 列,顺序固定

电影名称, 地点(忽略), 电影院名称, 观影日期, 观影人(空格分隔), 电影票图片路径, 海报图片路径, 备注, 合影图片路径
  • 观影人:多个姓名用空格分隔,例如 张三 李四 王五
  • 图片路径:可带目录,系统只取最后一个 / 后的文件名;若整段被括号包裹(如 (电影票/阿甘正传.jpg)),会先取括号内内容再取文件名。
  • 观影日期可为空,空日期的记录会排在列表最后。
  • 导入前需先把图片文件放入 uploads/tickets/uploads/posters/uploads/photos/,文件名与 CSV 中提取出的保持一致。
  • 编码支持 UTF-8 / GBK / GB2312,自动识别转换。
  • 导入在事务中执行,失败会整体回滚;成功后显示「导入 N 条 / 跳过 M 条」及逐行错误原因。

示例行:

阿甘正传, , 万达影城, 2024-01-15, 张三 李四, (电影票/阿甘正传.jpg), (海报/阿甘正传.jpg), 经典励志片, (合影/阿甘正传.jpg)

接口:fetch_movie.php

供添加页前端调用,服务端代请求 OMDb 避免浏览器跨域。

  • 请求GET fetch_movie.php?q=电影名称
  • 响应Content-Type: application/json
  • 成功
    {
      "title": "Forrest Gump",
      "year": "1994",
      "rated": "PG-13",
      "released": "06 Jul 1994",
      "runtime": "142 min",
      "genre": "Drama, Romance",
      "director": "Robert Zemeckis",
      "actors": "Tom Hanks, Robin Wright, Gary Sinise",
      "plot": "...",
      "poster": "https://...",
      "imdbRating": "8.8"
    }
    
  • 失败{"error": "错误说明"}(如「未找到相关电影,请尝试更准确的关键词」)

安全注意事项

部署到公网前请务必处理以下事项:

  1. 修改默认口令:默认账号 admin / 123456 必须在首次登录后立即更换。
  2. 更换 OMDb API Keyfetch_movie.php 中当前硬编码的 Key 为开发期临时使用,请替换为你自己的 Key;若仓库需要公开,建议将该值改为从环境变量读取。
  3. 删除或保护 test_crop.php:该文件是开发调试页,没有登录校验,仅用于验证 Base64 图片能否落盘,生产环境应直接删除。
  4. 关闭调试输出config.php 顶部当前为 error_reporting(E_ALL) + display_errors=1,上线前请改为关闭或仅写日志,避免泄露路径与数据库信息。
  5. 启用 HTTPS 并校正证书校验fetch_movie.phpCURLOPT_SSL_VERIFYPEER 被设为 false,生产环境应改为 true
  6. 保护数据目录db/(含 movies.db)与 uploads/ 应禁止直接目录列举;SQLite 文件更应通过 Web 服务器规则拒绝任何 HTTP 访问。Nginx 示例:
    location ~ ^/(db|uploads/.*\.(db|sqlite)) { deny all; }
    
  7. 限制上传目录执行权限:确保 uploads/ 下不允许执行 PHP。

已知限制与待改进

  • movies.photo_pathviewers.name 是历史遗留字段,保留用于兼容旧数据与 CSV 导入,新代码统一使用 movie_photosperson_id
  • delete.php 通过 GET 触发(带前端 confirm)外,其余写操作均为 POST;删除类接口未做 CSRF Token 校验。
  • 暂无分页,数据量增大后首页与统计页需要补充分页或懒加载。
  • config.phpinitDB() 在每次请求都会跑一遍建表与迁移,数据量或并发上升后可改为一次性迁移脚本。
  • 无「回收站」,删除电影与其图片文件不可恢复。
  • assets/placeholder-poster.jpgassets/default-avatar.png 为代码中的兜底引用,当前仓库未包含这两个文件;由于页面在检测到 placeholder 时会改用 CSS 占位块渲染,正常使用不受影响。

版本控制说明

以下内容为运行时产物或敏感数据,不纳入版本控制(见 .gitignore):

  • db/SQLite 数据库文件)
  • uploads/(用户上传的图片)
  • *.log、编辑器与系统临时文件

许可

个人项目,未指定开源许可。

S
Description
电影记录系统服务器端
Readme
158 KiB
Languages
PHP 95.4%
CSS 4%
JavaScript 0.6%