php7-to-php85-cover-1200.webp

不知不觉,用 PHP 7 跑博客已经十个年头了 滑稽.png ,服务器上的版本还停留在 PHP 7.4.x。

这套环境用了这么多年,也是时候升级到 PHP 8 了! 哈哈.png 这次选的是 PHP 8.5.10,顺便把之前的 Dockerfile 整理了一下。

从一键安装包到 Docker

最开始,我用 LNMP 一键包在服务器上直接编译安装运行环境。后来虽然换成了 OneinStack,但还是在宿主机上编译安装,本质上没什么变化。

这样用起来倒也方便,就是时间一长,各种依赖和配置都堆在宿主机上,升级、迁移都不太省心。稍有不慎环境就搞挂了,恢复起来简直就是灾难。

后来容器化流行起来,我就把运行环境都搬进了 Docker,一直沿用到现在。

换成容器之后,确实省心了不少。以前换台服务器,还得重新装环境、配依赖、改配置;现在把镜像、配置和网站文件准备好,启动容器就能继续用。后面再升级或者迁移,也不用在宿主机上折腾一遍依赖了。

顺手整理一下 Dockerfile

现在博客的 PHP 就跑在 Docker 容器里。之前用的是 php:7.4-fpm 官方镜像,在上面安装了 GD、Imagick、Memcached 等一堆扩展。这次升级,我也借助 AI 把 Dockerfile 梳理了一遍,按现在博客和插件的使用情况,去掉了用不上的依赖。

新的 Dockerfile 如下:

# PHP 版本和 FPM 基础镜像。
ARG PHP_VERSION=8.5.10
FROM php:${PHP_VERSION}-fpm-bookworm

# 腾讯云内网 Debian 镜像,仅用于部署在腾讯云内的生产构建。
ARG DEBIAN_MIRROR=http://mirrors.tencentyun.com/debian
ARG DEBIAN_SECURITY_MIRROR=http://mirrors.tencentyun.com/debian-security

# 容器时区和 apt 非交互模式。
ENV TZ=Asia/Shanghai \
    DEBIAN_FRONTEND=noninteractive

# Typecho 和已安装插件所需扩展;XML、OPcache 等由 PHP 8.5 基础镜像提供。
# 构建时验证扩展并清理缓存;PHP 8.5 中 OPcache 名称为 Zend OPcache。
RUN set -eux; \
    for source_file in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources; do \
        if [ -f "${source_file}" ]; then \
            sed -ri \
                -e "s@https?://(deb|security)\.debian\.org/debian-security@${DEBIAN_SECURITY_MIRROR}@g" \
                -e "s@https?://deb\.debian\.org/debian@${DEBIAN_MIRROR}@g" \
                "${source_file}"; \
        fi; \
    done; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
        unzip \
        libicu-dev; \
    docker-php-ext-install -j"$(nproc)" \
        intl \
        mysqli \
        pdo_mysql; \
    php -r 'foreach (["curl", "fileinfo", "intl", "json", "mbstring", "mysqli", "openssl", "pdo_mysql", "Reflection", "xml", "Zend OPcache"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, $extension . " is missing" . PHP_EOL); exit(1); } }'; \
    apt-get clean; \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# 使用官方 PHP-FPM 镜像默认 CMD,保持 FPM 在前台运行。

这里把 PHP 版本提成了 PHP_VERSION 参数,后续升级小版本,可以通过构建参数指定版本,再检查一下依赖是否需要调整,重新构建就行。

另外加了一步扩展检查,缺少列出的扩展就直接让构建失败,免得等容器启动之后才发现少了东西。

这份扩展列表是按我这次的使用情况整理的,换了主题、插件,或者启用新的功能,还是得看各自需要什么。APT 源用的也是腾讯云内网地址,在其他环境构建时需要换成能访问的源。

构建并启动 PHP 8

Docker Compose 配置如下:

services:
  php8:
    image: php:8.5.10-fpm
    build:
      context: /data/docker/php8
      dockerfile: Dockerfile
      args:
        PHP_VERSION: "8.5.10"
    container_name: php8
    working_dir: /data/wwwroot
    volumes:
      - "/data/wwwroot:/data/wwwroot"
      - "./config/custom-php.ini:/usr/local/etc/php/conf.d/zz-custom.ini:ro"
      - "./config/custom-php-fpm.conf:/usr/local/etc/php-fpm.d/zz-custom.conf:ro"
    expose:
      - "9001"
    environment:
      - TZ=Asia/Shanghai
    networks:
      - local_network
    restart: unless-stopped
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "5"
    healthcheck:
      test: ["CMD-SHELL", "php-fpm -tt >/dev/null 2>&1"]
      interval: 30s
      timeout: 5s
      retries: 3

networks:
  local_network:
    name: local_network
    external: true

这份配置沿用了我的网站目录、配置文件和 Docker 网络。照着用的话,需要先准备好挂载的两个配置文件和 local_network 网络,再把路径改成自己的。

还有一个容易忽略的地方:expose 里写了 9001,并不会自动把 PHP-FPM 的监听端口改成 9001。FPM 配置里的监听端口,以及 Web 服务连接 PHP-FPM 的地址和端口,都要对应上。

接下来重新构建、启动容器,检查扩展、FPM 配置和日志:

docker compose build --pull --no-cache php8
docker compose up -d php8
docker compose exec php8 php -m
docker compose exec php8 php-fpm -tt
docker compose logs --tail=200 php8

再看一下版本:

[root@SKY-Debian php8]# docker compose exec php8 php -v
PHP 8.5.10 (cli) (built: Sep 19 2026 00:26:35) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.10, Copyright (c) Zend Technologies
    with Zend OPcache v8.5.10, Copyright (c), by Zend Technologies

到这里,新的 PHP 环境就起来了。不过,命令行里显示 PHP 8.5.10,还不代表博客和插件都能正常工作。

上面的 php-fpm -tt 检查的是 FPM 配置,Compose 里的健康检查用的也是这条命令。首页、后台、评论和附件上传这些功能,还得打开网站实际试一下。

环境换好了,老插件还得折腾

容器化让环境升级简单了不少,但软件兼容性的问题还是绕不过去。升级前,最好先看一下自己用的 Typecho 版本、主题和插件对目标 PHP 版本的支持情况。

这次让我费心的主要是几个老插件。验证码、表情这些插件还好,主要是一些旧函数调用需要修修补补。比较麻烦的是原来的七牛云上传插件,修起来工作量不小 呀咩爹.png ,索性把静态文件迁到了腾讯云。毕竟是腾讯云老用户,还有免费的存储额度可以用。 挖鼻.png

后来又偶然发现了一个上传插件:PicUp

支持的第三方存储服务不少,腾讯云、七牛云都有,后台也做得挺好看。
screenshot-20260922-002947.png
我在这次的 PHP 8.5 环境下试了试,用着不错,给作者点个赞! 真棒.png

顺便补一句,PicUp 的图片压缩、WebP 转换和水印功能需要 GD。我上面的 Dockerfile 没有安装 GD,如果要用这些功能,还得把对应扩展补上,WebP 转换也要有相应支持。具体要求可以看插件的项目说明。

博客继续折腾着

这次升级整体还算顺利,时间主要花在了老插件上。

以前碰到报错,基本就是查文档、搜 Google、翻 GitHub Issue,再一点点读源码。现在多了 AI 帮忙,定位问题快了不少,改完再自己验证一下,确实省了不少工夫。

从手动编译 LNMP,到 Docker 容器化,再到如今用 AI 辅助开发,工具一直在变,折腾博客这件事倒是一直没变。

PHP 7 陪我走过了十年,这次也算正式迈进 PHP 8 时代了。环境更新了,博客继续折腾着。 太开心.png