P/PHORAP

PHORAP / CAMPUS

phorap r3-r9更新日志

已发布
# Phorap 网站更新日志

本文档记录 Phorap 校园网网站的版本迭代历史。版本号采用“日期-序列”格式(例如 `20260921-r9`),列表按时间倒序排列,最新版本在最上方。

---

## 项目概览

- **定位**:校园网互动社区,包含账号、好友私信、校园新闻、论坛、校园委托、社团、反馈和审核后台。
- **形态**:从 Phorap 测试站(ChatGPT Sites)导出的独立 PHP 版本,不再依赖 ChatGPT Sites、Cloudflare D1 或 R2。
- **技术栈**:PHP 8.3 + SQLite + 本地图片上传;支持 Docker、宝塔 Linux 面板、宝塔 Windows 面板三种部署方式。
- **运行要求**:PHP 8.3,并启用 `pdo_sqlite`、`sqlite3`、`mbstring`、`fileinfo` 扩展(宝塔部署),不需要开启 `putenv`。
- **管理员**:由服务器 `.env` 的 `ADMIN_EMAILS` 指定;首次使用管理员邮箱注册后可进入 `/admin` 审核后台。公开注册页不允许注册管理员邮箱,避免他人抢注。
- **数据与备份**:Docker 部署时数据库和图片分别保存在命名卷 `phorap-data`、`phorap-uploads`;宝塔部署时分别位于 `data` 与 `uploads` 目录。升级前必须备份。
- **审核机制**:保留本地规则初筛 + 人工审核,未配置任何 OpenAI API 密钥。
- **部署形态**:
- Docker + Caddy 自动申请和续期 HTTPS 证书。
- 宝塔 Linux:站点运行目录为 `/www/wwwroot/phorap/public`,伪静态保留 `try_files $uri $uri/ /index.php?$query_string;`。
- 宝塔 Windows:站点根目录为 `C:\wwwroot\phorap-php\public`,由项目内 `public/web.config` 负责 IIS 路由。
- **数据边界**:独立 PHP 站点不会自动同步或迁移 ChatGPT Site 的账号与云端内容,两边数据各自保存。

---

## 20260921-r9 · 2026-09-21

类型:功能新增(成员管理与封禁)

### 新增内容

- 审核后台新增“成员管理”,入口为 `/admin/members`,展示头像、昵称、用户 ID、邮箱、注册时间和账号状态。
- 支持分页、昵称 / ID / 邮箱搜索,以及正常、临时封禁、永久封禁状态筛选。
- 成员详情显示当前状态和完整封禁记录;管理员可填写原因并二次确认临时 / 永久封禁,也可填写说明人工解封。
- 临时封禁必须设置未来的北京时间,到期后自动恢复;永久封禁只能由管理员人工解除。
- 封禁会提升账号会话版本,使该账号所有既有登录会话立即失效。
- 登录、发帖、回复、认领、好友和私信等所有使用 `require_user` 的服务端入口统一拒绝被封禁账号。
- 被封禁账号在会话失效或使用正确密码登录时看到封禁原因,临时封禁同时显示到期时间;错误密码仍只显示统一的“账号或密码错误”,避免账号探测。
- 管理员不能封禁自己或其他管理员;封禁与解封均有 CSRF、重复状态检查和事务保护,并记录操作者、目标、动作、原因、时间和期限审计记录。
- 账号、内容、好友、私信和上传文件不因封禁而删除。

### 数据库迁移

首次访问时在事务中自动执行 schema v6:

- 为 `accounts` 表增加会话版本和封禁相关字段。
- 新建 `account_ban_events` 审计表及索引。

安装脚本在覆盖文件前会备份 SQLite 数据库,无需手工运行 SQL。

### 验证结果

- PHP 应用文件语法检查通过。
- `tests/account-bans.py` 隔离测试通过 62 项检查,覆盖:成员分页、搜索、状态筛选、普通用户越权、临时 / 永久封禁、重复请求保护、已有会话失效、直接接口写入拒绝、正确密码登录提示、自动到期、人工解封、自封禁 / 封禁其他管理员拦截、审计记录和敏感字段不渲染。
- 测试邮件使用本地测试通道,没有发送真实邮件;制作过程中未改动线上 r8 或真实数据库。

### 上线注意

- r9 为确保会话版本可信,升级后会让升级前已登录的所有账号重新登录一次;这是预期的一次性行为,不删除账号、内容、好友或私信。
- 建议先用非重要测试账号完成一次“临时封禁 → 重新登录提示 → 解封”验证,再处理真实账号。
- SMTP / Resend 配置继续保存在服务器 `.env`,本包不包含也不会覆盖密钥。

---

## 20260921-r8 · 2026-09-21

类型:交互优化(卡片进入详情)

### 新增内容

- 委托、论坛帖子与专区、校园新闻及活动、社团、个人内容列表和收藏列表中的卡片,点击标题、摘要或卡片空白处均可进入正确详情页。
- 卡片继续使用真实标题链接,保证键盘操作和新标签页行为;头像、昵称、按钮、表单等独立控件不会触发卡片跳转,选择复制文字时也不会误跳。
- 桌面端增加适度的悬停、指针和焦点提示;移动端保持可靠的大块点击区域与蓝白灰浅色主题。

### 数据库迁移

无新增迁移。

### 验证结果

- PHP 语法与 JavaScript 语法检查通过。
- 私信专项集成测试在本机此前已通过(好友关系、会话权限、拉黑、消息节流和公开作者入口);本次环境缺少 Python 运行时,未能再次执行该脚本。

### 已知边界

- 完整集成测试因自动审核规则改变,“普通内容必须待审核”的旧预期不再适用;未宣称当前整包完成全部回归或线上验收。

---

## 20260921-r7 · 2026-09-21

类型:功能新增(邮箱验证码注册与 SMTP)

### 新增内容

- 新注册改为“邮箱验证码确认后创建账号”,保留既有 PHP / SQLite 登录体系和已有账号。
- 邮件通过服务端 SMTP 发送,密钥仅保存在 `.env`;验证码 10 分钟有效、单次使用、最多 5 次尝试,重发冷却 60 秒。
- 限流策略:同一邮箱每小时 5 封、同一 IP 每小时 100 封、全站每小时 500 封;IP 只作宽松辅助,降低校园网共享出口误伤。
- 注册已存在的邮箱返回相同页面且不发送邮件,不向访客透露邮箱是否注册。
- 未通过验证的注册只保存在待验证表中,不会创建正式账号。

### 邮件服务配置

需要在服务器 `.env` 中配置以下 SMTP 参数(示例为 Resend):

```dotenv
APP_KEY=替换为64位随机十六进制字符串
MAIL_ENABLED=true
MAIL_TRANSPORT=smtp
MAIL_HOST=smtp.resend.com
MAIL_PORT=465
MAIL_ENCRYPTION=ssl
MAIL_USERNAME=resend
MAIL_PASSWORD=Resend中创建的API_Key
MAIL_FROM=no-reply@phorap.com
MAIL_FROM_NAME=Phorap
```

- 优先使用 587 + STARTTLS;服务商只提供 465 时使用 `MAIL_PORT=465` 和 `MAIL_ENCRYPTION=ssl`。
- 发件域名建议配置 SPF、DKIM,并建议配置 DMARC;不要使用个人邮箱密码。
- SMTP 未配置前保持 `MAIL_ENABLED=false`,此时新注册会明确提示邮件服务不可用,不会绕过验证创建账号。

### 数据库迁移

首次访问自动执行迁移,为邮箱验证码流程增加待验证注册存储及相关字段;已有账号不受影响。

### 验证结果

- PHP 语法与 JavaScript 语法检查通过。
- 邮件验证相关流程通过隔离测试;测试邮件使用本地测试通道,未发送真实邮件。

### 已知边界

- 旧测试版使用 Supabase Auth 默认邮件通道,低额度导致 `email rate limit exceeded`;r7 起不再依赖该通道,改由维护者配置 SMTP,但仍受 SMTP 服务商自身日 / 月额度限制。
- 找回密码尚未开放;后续可复用同一邮件模块,但必须使用独立、单次有效的重置令牌。

---

## 20260921-r6 · 2026-09-21

类型:功能新增 + 界面调整(好友私信与公开作者入口)

### 新增内容

- 好友列表增加发私信入口,会话列表、消息存储、未读数量和消息中心提醒。
- 聊天记录分页和每 15 秒增量轮询;校验登录、好友关系、会话双方权限、拉黑、空消息、1000 字限制和 3 秒发送间隔。
- 聊天页使用普通 HTTPS 定时请求,每 15 秒只拉取序号更大的消息,无需 WebSocket 配置,也不会重复追加已加载消息。
- 论坛、新闻、社团、委托和通用内容卡片的公开作者头像 / 昵称统一链接到个人主页;匿名内容和已删除账号不会暴露可访问的身份入口。
- 个人主页复用好友、拉黑和私信权限:本人不显示加好友,未登录引导登录,申请中与好友状态明确,任一方拉黑时不透露具体拉黑方且禁止私信 / 新增好友。
- 点赞、评论及更多操作的可点击区域、间距、焦点样式和移动端触控目标统一改善;表单提交期间禁用重复按钮,点赞 / 收藏等服务端操作补充成功反馈。
- 浅色主题调整为蓝、白、灰配色,并保留成功、失败等语义色。
- 将已知邮件限流异常转换为中文通用提示。

### 数据库迁移

首次访问自动执行迁移,增加 `direct_messages`、`user_blocks` 及相关索引;无需额外环境变量,安装前由脚本备份数据库。

### 验证结果

- PHP 语法与 JavaScript 语法检查通过。
- 私信专项集成测试在本机此前已通过(好友关系、会话权限、拉黑、消息节流和公开作者入口);本次环境缺少 Python 运行时,未能再次执行该脚本。

### 已知边界

- 完整集成测试因自动审核规则改变,“普通内容必须待审核”的旧预期不再适用;未宣称当前整包完成全部回归或线上验收。
- 代码搜索确认 r6 阶段项目内没有邮箱验证码、找回密码、SMTP 或第三方邮件 SDK,`email rate limit exceeded` 并非该 PHP 源码产生,实际触发服务需按 `邮件问题核查.md` 定位。

---

## 20260921-r5 · 2026-09-21

类型:功能新增(好友私信)

### 新增内容

- 好友列表的发私信入口,会话列表、消息存储、未读数量和消息中心提醒。
- 聊天记录分页和每 15 秒增量轮询;校验登录、好友关系、会话双方权限、拉黑、空消息、1000 字限制和 3 秒发送间隔。
- 保留已有的自动规则审核、统一审核中心、举报撤稿和按时间切换默认主题。

### 数据库迁移

首次访问自动执行迁移,增加 `direct_messages`、`user_blocks` 及相关索引;安装前由脚本备份数据库。

### 验证结果

- 私信专项集成测试 46 项断言通过。
- 应用 PHP 语法和 JavaScript 语法检查通过。

### 已知边界

- 邮箱验证码尚未实现,注册仅检查邮箱格式,不发送验证码。
- 此前完整集成测试因自动审核规则改变,“普通内容必须待审核”的旧预期不再适用;未宣称当前整包完成全部回归或线上验收。

---

## 20260920-r3 · 2026-09-20

类型:整合版 / 独立 PHP 版本

### 新增内容

从 Phorap 测试站导出独立 PHP 版本,改用 PHP 8.3、SQLite、本地图片上传和 Docker,不再依赖 ChatGPT Sites、Cloudflare D1 或 R2。共完成并恢复 22 项页面与业务功能:

1. 消息中心:独立页面、未读标记、跳转、全部已读、分页
2. 我的委托:我发布 / 我认领、状态筛选、分页、详情
3. 我的帖子:投稿状态、自己的专区、分页
4. 我的社团:社团列表、状态、修改审核记录
5. 我的收藏:内容列表、详情跳转、撤下提示
6. 我的好友:昵称搜索、申请、接受 / 拒绝、好友列表、移除
7. 社团列表:分类、标记、招新状态、空状态、分页
8. 社团详情:介绍 / 加入方式分栏、图片、主人编辑入口
9. 社团创建与编辑:标记、类别、图片、字段限制;修改审核后替换公开内容
10. 论坛列表与专区:公共 / 专区分开、专区列表和帖子数、专区详情
11. 发布帖子和创建专区:独立页面、实名 / 匿名、配图、规则确认、审核
12. 讨论详情与回复:正文、图片、回复分页、身份、待审核回复、互动
13. 委托列表:回报 / 模式筛选、金额与时间排序、分页、刷新
14. 发布委托:单人 / 多人、人民币 / 其他回报、北京时间截止、配图
15. 委托详情与状态:原子认领、重复 / 单人限制、过期限制、认领记录、完成 / 关闭
16. 校园新闻:最新新闻、明确标注的原版示例文章、详情、图片、分页
17. 投稿页面:规则侧栏、计数、身份、图片预览、提交结果
18. 个人资料:头像预览 / 移除、昵称、简介、保存状态、离开提醒、版本冲突保护
19. 反馈:相关页面、说明、提交成功反馈
20. 审核后台:各类别和状态、完整正文 / 图片、规则提示、通过 / 拒绝 / 撤下、修改审核
21. 首页更多:反馈、制作人、合作、返回子菜单、关闭 / 遮罩 / Esc、焦点返回
22. 全站工具与交互:SVG 图标、返回 / 首页 / 主题 / 消息 / 个人中心、深浅色、移动布局、动效、点赞 / 收藏计数、举报

### 验证结果

- PHP 8.3.33 本地运行;所有应用 PHP 文件语法检查通过。
- `tests/integration.py` 一次完整运行通过 156 个断言(包括请求状态与业务数据断言)。
- 覆盖匿名 CSRF 攻击、非管理员访问、管理员邮箱抢注阻止、存储 HTML 转义、隐藏专区阻断、个人资料过期版本覆盖阻止。
- 验证真实 PNG 上传记录及 HTTP 读取、无效图片回滚、新闻分页、原始与旧式详情链接。
- 对旧版源码与数据库副本执行安装脚本,确认数据库一致快照可生成,现有账号、`.env` 与上传文件保留,旧委托回报 / 模式正确升级。
- 浏览器实际操作:首页更多打开 → 制作人子页 → Esc 关闭;深浅主题;登录回到个人资料;修改简介后启用保存;保存成功后按钮禁用。
- 390px 手机首页无横向溢出;已检查桌面首页和个人资料的实际渲染。

### 已知边界

- 服务器面板自动化操作连续超时,未上传或更改线上文件;线上 PHP 8.3.8、宝塔缓存、真实图片目录与真实账号需上线后验收。
- 本地验证不等于线上验证。

---

## 早期增量补丁 · 2026-09-20

在整合版发布前,工作目录中保留了若干增量补丁包,用于局部的主题、动效、控件、弹窗和一键更新调整:

- `phorap-theme-update`
- `phorap-motion-update`
- `phorap-controls-update`
- `phorap-modal-fix`
- `phorap-one-click-update`

这些补丁未单独保留文字更新说明,后续功能已并入 `20260920-r3` 及之后的完整更新包。

---

## 通用升级与回退

### 升级方式

完整更新包(r5 起)解压后直接包含 `install.ps1`、`manifest.json`、`app` 和 `public`,无需依次安装旧补丁。推荐在 Windows 宝塔服务器执行:

```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File "C:\phorap-release\install.ps1"
```

安装脚本会先校验包内 SHA256,再通过 SQLite `VACUUM INTO` 生成一致的数据库备份,备份将被覆盖的代码,最后逐文件覆盖并校验;备份保存在 `C:\wwwroot\phorap-backups\时间戳`。数据库快照失败时不会修改网站文件。

该方式在文件复制与重启期间存在极短暂的新旧文件交替窗口,并非请求层面的严格零中断;如需请求级零中断,应部署到新目录后切换站点根目录。

### 手动覆盖

如不能运行脚本,先备份整个项目(含 `data`、`.env`、`uploads` 和 `public/uploads`),再把包内 `app`、`public` 合并复制到对应目录并允许同名覆盖。不要删除整个 `public`,不要覆盖 `data` 或 `.env`。覆盖后以 `app/ui.php` 中的版本号和 `/assets/app.js?v=版本号` 为准确认。

### 回退

停止网站并另行保存更新后产生的数据,把备份目录内 `app` / `public` 原文件复制回对应目录。数据库回退会丢失备份后新增内容;只有确实需要时才在 PHP 完全停止后恢复 `database.sqlite`,并将原数据库及其同名 `-wal` / `-shm` 文件移到另一个备份文件夹,不要把旧数据库与新 WAL 混用。

### 数据与密钥保护

升级保留 `.env`、数据库、账号、投稿、头像和上传图片;不覆盖宝塔 / Nginx / IIS 配置,也不修改现有 SSL、DNS。SMTP 密码和 `APP_KEY` 不得写入前端、更新包或日志。

回复

还没有公开回复。

登录后回复