如何延长老版PHP应用的生命周期
PHP 正在稳步发展。每年都会有一个主要的新版本,其中包含新功能、性能改进、相当多的弃用,甚至语法更改。PHP 核心开发人员维护两个最新的 PHP 版本,其中包括活跃的 bug 修复和安全修复,然后是安全修复。这实际上意味着每个主要的PHP 版本最多支持三年,现有的 PHP 应用就要被迫升级。
虽然更新现有的 PHP 应用是理想和推荐的方法,但不可避免的是,有些应用/网站无法证明进行更新所需的人力、政治和财务成本是合理的。对于运行在 PHP 5 系列或 PHP 7 系列上的遗留 PHP 应用,情况尤其如此。例如,WordPress.org 报告称,只有 16% 的 WordPress 站点运行在 PHP 核心开发人员支持的 PHP 版本上。
更新 PHP 应用以使其与最新的 PHP 版本兼容是非常困难的。有一些无需修改或只需少量修改,也有一些几乎需要完全重写。十多年前开发的 PHP 应用构成了最大的挑战,因为它们倾向于使用不再受支持、没有类型支持且通常也没有自动测试来验证更改的 PHP 扩展。
Rector 等工具可以自动完成一些必要的更改(如果不是大多数的话),但非常旧的 PHP 版本往往需要大量的手动代码更新。
在某些情况下,升级的成本所要付出的努力和费用是不值得的。其中一些示例包括仅在专用网络中使用的内部应用程序、计划重写的应用,以及原始开发人员不再在公司工作的应用。实际上,这些应用可能永远不会更新;最终只会被替换掉。
由于 PHP 版本的官方更新时间只有三年,这可能会使应用容易受到安全漏洞的影响,而这些安全漏洞通常也会影响这些未维护的 PHP 版本。PHP 平台即产品(PAAS)产品和共享托管提供商也强制更新到最新的 PHP 版本,这可能会使应用在新的 PHP 版本上崩溃。
本文讨论了在安全的 PHP 环境中运行遗留 PHP 应用的策略,以及额外的安全预防措施和维护,从而延长所述 PHP 应用寿命。
PHP 应用越是锁定在 PHP 版本中,更新速度就越快。然而,与更新一个已有几十年历史的 PHP 应用相比,在旧应用被替换之前,再从旧应用中挤出几年时间有时更现实可行。
共享主机和平台到专用服务器
大多数共享和托管托管平台以及 PHP PaaS 产品通常只提供当前的 PHP 版本,但从长远来看不支持旧的 PHP 版本。这是绝对有意义的,因为旧的 PHP 版本未维护,如果发现影响这些未维护的 PHP 版本的漏洞,可能会危及其服务器的安全。
如果托管提供商/PaaS 提供商不再支持所需的 PHP 版本,那么寻找支持多种 PHP 版本的提供商可能是有意义的。
CloudLinux 是共享/托管托管提供商在其服务器上使用的商业操作系统之一,这些提供商可能会启用 CloudLinux 的硬化 PHP 功能。硬化 php 是 CloudLinux 中的一个特性,即使在官方 php.net 团队将 php 版本标记为 EOL 之后,CloudLinux 后台端口也会修复该特性。
另一种方法是维护私有服务器/云服务器并自行配置。维护 VPS/Cloud 服务器会带来维护负担,但现在大多数操作系统都具有正常的默认值、自动更新等功能,以减轻部分负担。但是,这种服务器维护可能不适合每个人。
Debian LTS、Ubuntu LTS、Rocky Linux 和 RHEL 是一些基于 Linux 的操作系统,它们在默认存储库中提供 PHP。他们不会从上游接收错误修复,但安全修复会在适用的情况下进行反向移植。
例如,Ubuntu 20.04 LTS 在其默认存储库中包含 PHP 7.4.3。Ubuntu 20.04 LTS 将在 2025年之前接收硬件和维护更新。PHP 7.4 目前被官方 php.net 团队标记为“生命终结”,但 Ubuntu 20.04 背后的开发人员将任何安全补丁移植到存储库中可用的PHP版本。任何非安全性错误修复都不会被反向移植。这本质上意味着 Ubuntu 20.04 的 PHP 版本将保持为 PHP 7.4.3,但应用了所有安全修复。Ubuntu 的付费(五台个人电脑免费)Ubuntu Pro 产品将其延长了五年,这意味着可以在 2030 年之前安全运行 PHP 7.4 应用。
Web 服务器集成
PHP 与 Apache、Nginx、Litespeed、Caddy 等 web 服务器集成。当运行遗留 PHP 应用时,建议切换到 php-fpm 作为服务器 API。例如,Apache 支持将 PHP 作为 Apache 模块运行,这阻碍了在应用必须在较旧的 PHP 版本上运行的情况下升级 Apache 版本的能力。
Nginx 和 Caddy 只与 php-fpm 集成,因此不需要对它们进行任何更改。
PHP 还有一个内置服务器。生产服务器不太可能使用它,但请确保使用完全成熟的 web 服务器来在 PHP 和 web 服务器之间添加分隔。
容器化 PHP
当运行完整的 LTS 操作系统(如 Ubuntu LTS)不可行时,另一种方法是使用容器来运行所需的 PHP 版本。
对于容器,除非明确允许,否则文件系统和网络的其余部分将保持完整。PHP-FPM 进程可以在一个容器内运行,只需要最小的文件系统访问(允许会话存储、临时文件、文件上载等)、FPM 端口(用于 web 服务器集成)和数据库端口,但其他所有内容都保留在容器内。
PECL 扩展替换件
即使操作系统或第三方存储库提供了 PHP 更新,它们也不太可能为 EOL PHP 扩展提供安全更新。
- 与外部服务(如 SSH、FTP、电子邮件、LDAP 等)连接的 PECL 扩展最好使用用户端 PHP 实现。
- 提供加密操作的扩展(例如 mcrypt 和 openssl)最好用 Sodium 或其用户端 PHP polyfills 等较新的扩展替换。
- PDF 库(如 DomPDF)可以用无头浏览器或命令行工具(如 wkhtmltopdf)代替。
图像生成扩展(如 Imagick 和 GD)可以替换为提供图像处理的 CDN。
Composer LTS
Composer,PHP 的依赖关系管理器最近提高了最低 PHP 版本要求。然而,Composer 2.2 是 Composer 2 的 LTS 版本,应该至少在 2023 年底支持该版本。
Composer 在升级最低要求的PHP版本时相当保守,因此即使在较旧的 PHP 版本上也应该相对无故障。
LTS 框架、库和本地分叉
PHP 框架和库(如 Laravel 和 Nette)往往是快速更新的框架,而 Symfony 和 Slim 则更为保守。
- 虽然 Laravel 以前提供的 LTS 版本提供了五年的安全更新,但最近的 Laravel 版本只提供了一年的主动支持,然后是一年的安全修复,因此可能需要手动移植安全更新。
- 最近的 Drupal 版本(如 Drupal 10)需要最新的 PHP 版本。Drupal 7 目前仍在获得支持,但有一些免费的商业 Drupal LTS 项目,即使在正式达到 EOL 之后,也可以提供协调的安全版本。对于 Drupal 7,还有 BackDrop CMS,它提供了一个简单的升级路径。
- WordPress 试图保持与旧 PHP 版本的兼容性,因此即使在旧 PHP 版本上也可以更新到 WordPress。
Symfony(及其组件)为 LTS 版本提供至少三年的安全更新。
当 PHP 库/框架放弃了 PHP 应用所依赖的版本时,PHP 应用程序的维护人员就可以在进行存储库和后端安全更新时进行分叉。将这项工作作为公共项目进行共享,可以为其他人维护其他 LTS 包所付出的努力付出代价。对于私有包,本地克隆的存储库或私有 Composer 存储库可以使 Composer 集成工作。