chore(upgrade): 收尾——compose 镜像 tag、php-jwt 7、升级报告

- docker-compose.yml php 镜像指向 kuaifan/php:8.4-swoole-8.0.rc21
 (dockerfile 仓库 phpswoole/8.4.Dockerfile 的 CI 变体产物,本地已构建同名 tag)
- firebase/php-jwt ^6.9 → ^7.1:消除 CVE-2025-45769(composer audit 清零);
  唯一调用点 FileController JWT::encode(HS256) 实测兼容
 (注意:7.x 强制 HMAC 密钥 ≥32 字节,标准 APP_KEY 51 字符无虞)
- 新增 UPGRADE-L13-REPORT.md:改动清单、依赖矩阵、验证证据、遗留风险

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kuaifan 2026-06-12 19:55:13 +00:00
parent cbe00f1284
commit 8fb6d331f8
4 changed files with 122 additions and 11 deletions

108
UPGRADE-L13-REPORT.md Normal file
View File

@ -0,0 +1,108 @@
# DooTask Laravel 8 → 13 升级报告
> 执行时间2026-06-12 夜间(过夜任务)。分支:`light-spring`(本地 commits未 push
> 配套镜像仓库:`/home/coder/workspaces/dockerfile`(本地 commit未 push
## 结果总览
| 项目 | 结果 |
|---|---|
| 框架 | Laravel 8.83 → **13.15.0**,采用 13 新精简目录结构 |
| PHP / 运行时 | 8.0 → **8.4.21**Swoole 4.x → **6.2.1**phpswoole/swoole:6.2-php8.4 基底) |
| LaravelS | 3.7.19 → **3.8.7**WebSocket / 21 个 Swoole Task / Swoole Table 架构**零重写** |
| 迁移 | `migrate:fresh --seed` **213 个全过**(含修复 2 个受 L11 `change()` 语义影响的历史迁移) |
| 测试 | phpunit 9 → 11.5`php artisan test` **145 passed / 1 skipped / 0 failed**skip 为套件自带的"无 Swoole 环境跳过" |
| 安全 | `composer audit` **0 公告**php-jwt 升 7.1 消除 CVE-2025-45769 |
| 运行时冒烟 | /health、登录、token 认证、WebSocket 握手(101+open帧)、Swoole Task 投递执行、头像生成、动态裁剪、404 兜底 **全过** |
| 运行中的现有实例 | **零接触**(全部验证在独立一次性容器栈完成) |
## Commits
dootask 仓库light-spring 分支):
1. `chore(upgrade): Laravel 8 直升 13旧结构跑通+ PHP 8.4 + 依赖升级与兼容修复`
2. `refactor(skeleton): 平移 Laravel 13 新目录结构`
3. `chore(upgrade): 收尾——compose 镜像 tag、php-jwt 7、升级报告`(本提交)
dockerfile 仓库main 分支):
- `feat(phpswoole): 新增 8.4 变体 Dockerfile``phpswoole/8.4.Dockerfile`
## 容器镜像
- 新 Dockerfile`dockerfile/phpswoole/8.4.Dockerfile`CI 变体构建规则产出 tag **`kuaifan/php:8.4-swoole-8.0.rc21`**= `8.4-` + config.ini 的 imageTag
- ⚠️ tag 里的 "swoole-8.0" 来自现有 config.ini命名易混淆。如想要更干净的 tag`kuaifan/php:swoole6-php8.4`),需调整 build.sh 变体命名规则或 config.ini建议你定夺。
- 本地已构建并打好同名 tag含 8.4-test 别名),`docker-compose.yml` 已指向新 tag。
- 本地构建时 dooso 阶段用旧镜像提取的 doo.so 预编译产物替代(本机无 private-repo 源码);**Dockerfile 本身的 golang 构建阶段与现行完全一致**CI 会照常从源码构建。
- 关键变化redis 扩展用 base 自带 6.3.0(弃 phpredis-5.3.2 tarballimagick 走 pecl3.8.1);移除显式 libzip4。
- 镜像验证PHP 8.4.21 / swoole 6.2.1 / redis 6.3.0 / imagick 3.8.1 / gd / ffi / ldap / gmp / pdo_mysql 等 12 个关键扩展齐全doo.so + /entrypoint.sh 就位。
## 依赖变更composer.json
**移除**fideloper/proxy→框架内置 TrustProxies、fruitcake/laravel-cors→内置 HandleCorsabandoned、facade/ignition13 内置错误页、laravel/sail、madnest/madzipper→原生 ZipArchive`Base::zipAddFiles`)、手动钉的 symfony/mailer ^6。
**升级**laravel/framework ^13.0、laravel/tinker ^3.0、predis ^2.32.4.1、maatwebsite/excel ^3.1.69、mews/captcha ^3.5、laravolt/avatar ^6.5、directorytree/ldaprecord-laravel ^4.0、overtrue/pinyin ^5.3、orangehill/iseed ^3.8、firebase/php-jwt ^7.1、phpoffice/phpword ^1.4、phppresentation ^1.2、smalot/pdfparser、matomo/device-detector ^6.5devphpunit ^11.5、collision ^8.6、ide-helper ^3.7、migrations-generator ^7.4、mockery ^1.6、faker ^1.24、hhxsv5/laravel-s ~3.8.0。
**锁定**guanguans/notify ~1.28.05.x API 全重写,另行排期);**symfony/console ^7.4**关键LaravelS Portal 与 symfony/console 8 的 `configure(): void` 类型断言不兼容7.4 LTS 是 Laravel 13 官方支持区间)。
## 主要代码改动
### 兼容性修复(阶段 1
- `$dates` 属性移除L10`AbstractModel``getCasts()` 合并默认 datetime 列(子模型 `$casts` 同名键优先保持原全局语义UserTaskBrowse/UserRecentItem/ManticoreSyncFailure 改 `$casts`
- Carbon 34 处 `diffInSeconds` 显式 absolute + `(int)`C3 默认返回**带符号浮点**
- LdapRecord v4`config/ldap.php` `use_ssl/use_tls``use_tls/use_starttls`**env 变量名保持 LDAP_SSL/LDAP_TLS 不变**,老部署无感);`LdapUser::$objectClasses` 补 array 类型
- pinyin v5 静态 API`Base::getFirstCharter`abbr+surname`Base::cn2pinyin`permalink
- laravolt/avatar 6.5 上游 bug纵向对齐传 `middle` 而 intervention 4.1.3 枚举只认 `center``App\Module\PatchedAvatar` 子类覆写 `buildAvatar()`;头像响应改 `response()->file()`v6 `save()` 返回 Image 对象)
- Symfony Console 8 兼容(保留在代码里,虽然最终锁了 7.4`ManticoreSyncLock::handleSignal` 新签名 + pcntl 回调解耦
- **非 Swoole 运行时守卫**artisan/测试上下文原本会炸 `Target class [swoole] does not exist``AbstractTask::task()`(覆盖全部 21 个 Task 类的投递)、`PushTask::push()``AbstractData/OnlineData`swoole table 缺失时返回默认值)
- PHP 8 警告硬化(测试中警告转异常暴露的老问题):`Setting::getSettingAttribute``Ihttp::ihttp_request` 缺键访问加 `??` 守卫;`Report::getLastOne` 隐式可空参数PHP 8.4 deprecation
### 迁移修复(重要!影响全新安装)
Laravel 11+ 的 `change()` 会**丢弃未重申的修饰符**(旧版 doctrine/dbal 会保留)。两个历史迁移在 fresh 安装时会产出错误 schemaNOT NULL 无默认值,曾导致后续 backfill 迁移失败):
- `2023_12_07_160642_update_owner_add_index_some_20231217.php`15 个 `integer(...)->change()` 全部重申 nullable/default/comment原始值从迁移历史链逐列还原
- `2025_08_10_215202_update_files_name_length_to_200.php``files.name` 重申 nullable/default/comment
**已部署的生产库不受影响**(这两个迁移早已在 L8 下执行过,不会重跑)。
### 新目录结构(阶段 3
- `bootstrap/app.php``Application::configure()` 链式withRouting/withMiddleware/withExceptions
- 删除Http/Console Kernel、Exceptions/Handler、RouteServiceProvider、EventServiceProvider、AuthServiceProvider、BroadcastServiceProvider、7 个框架默认中间件子类 + TrustHosts
- 迁入新位置:`webapi` 别名、信任代理/TrimStrings/CSRF 排除(配置 API、api 限流 + 14 个模型观察者 + Registered 监听 → `AppServiceProvider::boot`、图片裁剪 → `App\Exceptions\ImagePathHandler`withExceptions 调用)
- `config/app.php` 移除 providers/aliases 数组(用框架默认集,补齐 9~13 新增 providerRedis alias 因 ext-redis 原生类存在不会触发冲突)
- `artisan``public/index.php` 换 13 骨架版;新增 `bootstrap/providers.php`
- 保留InvokeController 动态路由模式项目约定、WebApi 中间件、routes/web.php 全部路由
### 测试
- `phpunit.xml` 迁移 11 schemacoverage→source`.gitignore``/.phpunit.cache`
- `UserImportParseTest`:部门存在性断言改为自建数据 + DatabaseTransactions原测试硬编码部门 ID 3/5fresh 库上与升级无关地必败——同一提交引入的测试与查库逻辑脱节)
## 验证证据一次性容器栈l13-mariadb 10.7.3 + l13-redis + l13-php
```
php artisan --version → Laravel Framework 13.15.0
migrate:fresh --seed → 213 DONE, exit 0两库各验一次
php artisan test → 145 passed, 1 skipped (368 assertions)
GET /health → 200 "ok"
POST /api/users/login错误密码 → {"ret":0,...}(结构化错误,含验证码策略)
GET /api/users/info + token → {"ret":1,"msg":"success","userid":1,"identity":["admin"]}
WS /ws?action=web&token=... → upgrade=true status=101收到 {"type":"open","data":{"fd":4,"ud":1}}
Swoole Task → LineTask×2/PushTask 投递执行完毕task_workers 软删 + error NULL
GET /avatar/张三.png → 200合法 PNGintervention v4 + imagick 3.8
GET /uploads/.../crop/percentage=40x0 → 200新结构 withExceptions 路径)
composer audit → 0 advisories
```
一次性栈尚在运行(供你晨检复现)。清理命令:
```bash
docker rm -f l13-php l13-mariadb l13-redis && docker network rm l13-net
# 仓库根目录的 .env 是为一次性栈造的测试配置(已 gitignore可删
```
## 遗留风险与 TODO
1. **LaravelS 3.8.7 + Laravel 13 属"约束开放、未经上游宣告"的组合**——本次 HTTP/WS/Task/Timer-free 路径全部实测通过,但建议在测试环境全功能回归后再发版;上游如发 3.8.8+ 留意跟进。
2. **未实测路径**(缺外部服务,代码层面已确认 API 未变SMTP 邮件guanguans/notify 1.28 + SystemController 的 symfony mailer DSN 直连、LDAP 登录/同步ldaprecord 2→4 是大版本跳跃,**建议优先人工回归**、友盟推送、OnlyOffice JWTphp-jwt 7 强制 HMAC 密钥 ≥32 字节Laravel 标准 APP_KEY 51 字符无虞,仅自定义短 APP_KEY 的部署会受影响)。
3. **guanguans/notify 1.28**2024-01 停更)在 PHP 8.4 上游未声明测试;邮件链路回归时留意。建议排期迁 5.x。
4. **`php artisan route:list` 会因 ApproveController 构造器在"审批应用未安装"时抛异常而失败**——既有行为L8 同样如此),与本次升级无关,但新人易误判。
5. **镜像 tag 命名**`kuaifan/php:8.4-swoole-8.0.rc21` 中 "swoole-8.0" 历史包袱,见上文容器章节。
6. L13 的 `cache.serializable_classes` 加固未在本项目 config/cache.php 显式配置(保持升级前行为);如未来要启用白名单,需排查缓存对象的代码。
7. 前端Vue/Electron、ai-kb 未动——本次为纯后端框架/运行时升级,无用户可见功能变化。
8. 发版前建议:测试环境用新镜像跑 `./cmd update` 全流程 + Playwright 回归;`bin/inotify` 开发热重载路径未实测dev 场景)。

View File

@ -21,7 +21,7 @@
"ext-simplexml": "*",
"ext-zip": "*",
"directorytree/ldaprecord-laravel": "^4.0",
"firebase/php-jwt": "^6.9",
"firebase/php-jwt": "^7.1",
"guanguans/notify": "~1.28.0",
"guzzlehttp/guzzle": "^7.3.0",
"hedeqiang/umeng": "^2.1",

21
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "5b1376e3fe172d716e0f87fec7f69c23",
"content-hash": "27bf8f16ef5c8e3d75a68a7b666531b6",
"packages": [
{
"name": "brick/math",
@ -867,16 +867,16 @@
},
{
"name": "firebase/php-jwt",
"version": "v6.11.1",
"version": "v7.1.0",
"source": {
"type": "git",
"url": "https://github.com/googleapis/php-jwt.git",
"reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66"
"reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/googleapis/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
"reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66",
"url": "https://api.github.com/repos/googleapis/php-jwt/zipball/b374a5d1a4f1f67fadc2165cdb284645945e2fc0",
"reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0",
"shasum": ""
},
"require": {
@ -884,6 +884,8 @@
},
"require-dev": {
"guzzlehttp/guzzle": "^7.4",
"phpfastcache/phpfastcache": "^9.2",
"phpseclib/phpseclib": "~3.0",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"psr/cache": "^2.0||^3.0",
@ -892,7 +894,8 @@
},
"suggest": {
"ext-sodium": "Support EdDSA (Ed25519) signatures",
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present",
"phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures"
},
"type": "library",
"autoload": {
@ -917,16 +920,16 @@
}
],
"description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
"homepage": "https://github.com/firebase/php-jwt",
"homepage": "https://github.com/googleapis/php-jwt",
"keywords": [
"jwt",
"php"
],
"support": {
"issues": "https://github.com/googleapis/php-jwt/issues",
"source": "https://github.com/googleapis/php-jwt/tree/v6.11.1"
"source": "https://github.com/googleapis/php-jwt/tree/v7.1.0"
},
"time": "2025-04-09T20:32:01+00:00"
"time": "2026-06-11T17:54:14+00:00"
},
{
"name": "fruitcake/php-cors",

View File

@ -1,7 +1,7 @@
services:
php:
container_name: "dootask-php-${APP_ID}"
image: "kuaifan/php:swoole-8.0.rc21"
image: "kuaifan/php:8.4-swoole-8.0.rc21"
shm_size: 2G
ulimits:
core: