Community研究与数据分析github.com

dbravoan/opencode-skills

将遗留的 PHP 5.x/7.x 代码库(自定义 CMS、TemplatePower、mysql_*、ereg、短标签、PHP4 构造函数)就地升级至 PHP 8.3/8.4,并通过 .env 配置和 FTP/rsync 的 deploy.sh 部署(无需 Docker)。适用于现代化改造遗留 PHP CMS/站点及类似项目,或需将遗留站点迁移至支持 FTP 的共享主机(cPanel/Plesk)的场景。

opencode-skills 是什么?

该技能提供了一套完整的自动化流程和脚本集合,用于将运行在 PHP 5.x/7.x 上的老旧 PHP 项目(尤其是自定义 CMS)升级至 PHP 8.3/8.4,同时支持将其部署到共享主机环境。它解决了从已废弃的 `mysql_*`、`ereg` 函数到短标签、PHP4 构造函数、裸词数组键等一系列不兼容问题,通过提供一个兼容性 shim 层来让代码快速运行,再逐步进行机械修复和重构。该技能支持多个平台(如 Claude Code、Cursor),并自带 lint 检查、HTTP 冒烟测试、安全加固和基于 FTP 或 rsync 的部署脚本。其工作流程从创建 Git 基线开始,安装 shim,然后使用专用脚本自动化处理常见代码问题,最后通过持续验证确保站点稳定运行。

兼容平台~Claude Code~Codex CLI~Cursor✓OpenCode
npx skills add https://github.com/dbravoan/opencode-skills/tree/HEAD/skills/legacy-php8-modernizer

Installed? Explore more 研究与数据分析 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

遗留 PHP → PHP 8.3/8.4 现代化工具

何时使用本工具

当遇到一个必须满足以下条件的遗留 PHP 项目(通常是针对 PHP 5.x 编写的自定义 CMS)时,应使用此技能:

  • 无需完全重写即可在 PHP 8.3 / 8.4 上运行,且/或
  • 必须部署到 共享主机(cPanel/Plesk) 且不使用 Docker,并通过 FTP 进行。

典型特征:mysql_*、ereg/eregi、<? 短标签、PHP4 风格的构造函数、 裸词数组键 ($row[Id])、$$var['key']、sizeof(null)、MyISAM 导出、 TemplatePower 模板、config/defines*.php 中的明文凭据。

本技能提供的资产

资产用途
scripts/compat.php兼容层:mysql_*→mysqli,ereg*/split→preg,userErrorHandler
scripts/fix_barewords.php基于 Tokenizer 的安全裸词数组键引号化
scripts/fix_variable_variables.php修复 PHP 8 $$var['key'] 统一变量语法破坏
scripts/check_signatures.php静态 LSP 方法签名检查器
scripts/lint-all.shphp -l 全面检查
scripts/smoke-test.shURL 列表的 HTTP 冒烟测试
templates/defines.php.env 加载器 + 数据库常量(兼容有无 Docker 环境)
templates/env.example.env 模板(DB_* + FTP_*)
templates/htaccess现代 Apache/PHP-FPM .htaccess
templates/user.ini适用于共享主机的 PHP-FPM 覆盖配置
templates/timthumb.php安全的 GD 缩略图生成器(替换有漏洞的 TimThumb)
deploy/deploy.shFTP 或 rsync 部署;排除开发文件;写入远程 .env

黄金法则

  1. 安全第一:在进行任何操作前,先 git init 并提交基线版本。备份数据库。
  2. 先解除阻塞再重构:兼容层能立即让整个代码库运行起来。
  3. 一个中心数据库层:首先替换/限制 dbClass;兼容层会覆盖原始的 mysql_* 调用。
  4. 尽早进行安全加固:一旦站点能渲染,立即移除危险工具和 TimThumb。
  5. 持续验证:每批修改后执行 php -l,然后对所有 URL 进行冒烟测试。

操作步骤

0. 建立基线

git init -q && git add -A && git commit -qm "baseline: legacy PHP"
find . -name '*.php' -not -path './node_modules/*' | wc -l

保存一份真实的公开 URL 列表(从数据库/站点地图获取),用于 scripts/smoke-test.sh。

1. 安装兼容层 shim

  • 将 scripts/compat.php 复制到比如 includes/compat.php。
  • 在引导文件的最顶部,在任何遗留代码之前加载它:
    include_once(__DIR__.'/../includes/compat.php');
    
  • 它提供了 mysql_*、ereg/eregi/ereg_replace/eregi_replace/split、 mysqli_report(MYSQLI_REPORT_OFF)(SQL 错误返回 false 而非抛出异常)、 以及 userErrorHandler()(抑制 PHP 5 时代旧的 E_NOTICE "未定义索引/变量")。
  • 注册一次处理程序:
    if (function_exists('userErrorHandler')) set_error_handler('userErrorHandler');
    

2. 机械修复(使用脚本)

php scripts/fix_barewords.php            # 试运行
php scripts/fix_barewords.php --apply
php scripts/fix_variable_variables.php   # 试运行
php scripts/fix_variable_variables.php --apply
scripts/lint-all.sh

然后修复 lint 仍然报告的问题:

  • 短标签:<? → <?php(grep <\(?!php|=|xml))。
  • PHP4 构造函数:function ClassName() → function __construct()。
  • 花括号字符串偏移:$s{0} → $s[0]。
  • 循环/switch 外的游离 break(PHP 8 中为致命错误)。
  • ${...} 中的可变变量:引用裸词 / 使用 ${$var['k']}。

3. 签名、静态与空安全

php scripts/check_signatures.php

对于每个 MISMATCH,给子方法添加默认参数(例如 $tabla = null)。 然后在运行时修复出现的致命错误:

错误修复
ArgumentCountError: too few arguments为尾部参数提供默认值
静态方法中的 $this使用 self::/static:: 或传递应用上下文
method_exists(null, ...)is_object($x) && method_exists($x, ...)
Cannot access offset of type string on string在 $x['k'] 之前先检查 is_array($x)
Undefined constant "X"引用裸词键 / 常量
sizeof/count/array_keys(null)is_array($x) ? ... : ..., (array)$x
foreach(null)foreach ((array)$x as ...)
Accessing static property X as non static$this->prop → self::$prop

4. 针对真实数据库运行并迭代

将配置指向数据库,然后请求每个 URL。每次测试修复一个致命错误,直到 scripts/smoke-test.sh 报告零失败且日志中没有警告。

5. 安全加固(尽早进行)

  • 用 templates/timthumb.php 替换 TimThumb。
  • 删除 scanner.php、chmod777.php、info.php、多余的调试脚本。
  • 配置 .htaccess 拒绝访问 .env、.git、config/defines.php、点文件。
  • 轮换已提交的数据库密码;将机密信息移至 .env。
  • 建议添加 CSRF 令牌、CSP/HSTS、限速、预处理语句。

6. 配置 + 部署

  • 使用 templates/defines.php(.env 加载器)和 templates/env.example。
  • 使用 templates/htaccess 和 templates/user.ini。
  • 使用 deploy/deploy.sh 进行部署。

.env 系统

config/defines.php 从项目根目录加载 .env,回退到 getenv() 最后使用安全默认值。这保持了 Docker 的兼容性(相同的 DB_* 键),同时 使得 FTP 部署只需要编辑一个文件。

.env(永远不要提交):

DB_HOST=localhost
DB_NAME=cpaneluser_termospa
DB_USER=cpaneluser_termospa
DB_PASS=super-secret
DB_SUBDIRECTORIO=

部署(无 Docker)

共享主机(cPanel/Plesk)检查清单

  1. PHP:选择 8.3(或 8.1+);启用 mysqli、gd、mbstring、pdo_mysql。
  2. 数据库:创建数据库 + 用户,导入数据导出文件。对于 MySQL 8:
    SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION';
    
    预料到 utf8_spanish_ci → utf8mb3_spanish_ci 的警告(或执行 utf8mb4 迁移)。
  3. 文件:上传到 public_html/(排除 docker/、tools/、router.php、_DOCS/、.git/)。
  4. 权限:目录 755,文件 644;recursos/cache/、.cache/、upload/ 需要可写(775/777)。
  5. 配置:创建远程 .env(deploy.sh 会执行此操作)并验证 DB_*。
  6. 在 .htaccess 中拒绝访问 .env。

deploy.sh

./deploy.sh ftp          # lftp 反向镜像
./deploy.sh ftp --dry-run
./deploy.sh rsync        # 通过 SSH 的 rsync

它会读取 .env(FTP_HOST/USER/PASS/PATH/TLS 或 SSH_*),仅暂存运行时 文件,写入一个仅远程使用的 .env(仅包含 DB_*,因此 FTP 凭据永远不会 落在服务器上),上传,并打印权限/数据库操作步骤。


验证检查清单

  • scripts/lint-all.sh → 全部通过
  • scripts/smoke-test.sh urls.txt → 0 失败
  • 首页 / 产品 / 项目 / 新闻 / 联系页面正常渲染
  • /sitemap.xml 和 /rss 返回有效的 XML
  • /imagenes/thumbnail/... 返回一张图片(GD + 重写)
  • /administracion/login/ 加载;登录 + 内容管理器正常工作
  • 联系表单提交成功
  • 管理员图片上传写入 upload/
  • 错误日志中没有 PHP Warning/Fatal

总是会坑到你的陷阱

  • 默认情况下,PHP 8.1+ 中的 mysqli_query 会抛出异常;调用 mysqli_report(MYSQLI_REPORT_OFF) 以保持旧的 or die() / if($q=...) 模式继续工作。
  • .htaccess 中的 php_flag / php_value 在 PHP-FPM 下会导致 HTTP 500 — 请使用 .user.ini。
  • PHP 8 的统一变量语法会静默破坏 $$var['key'](写入错误的变量)— 请运行 fix_variable_variables.php。
  • include() 的相对路径相对于脚本目录/当前工作目录解析;推荐使用 __DIR__。
  • PHP 8 中已移除:mysql_*、ereg*、split、create_function、each、魔术引号。
  • OPcache 会缓存旧文件:在编辑后重启 FPM/Apache。
  • UTF-8:使用 SET NAMES utf8mb4;新项目推荐使用 InnoDB + utf8mb4_unicode_ci。

同类项目

这些 CMS 项目共享相同的架构。执行相同的过程,仅需调整 引导文件路径和缩略图重写目标。将 scripts/ 复制到目标项目的 tools/ 中,从项目根目录运行。

相关技能