PHP CLI 能用扩展但 PHP-FPM 不能用时怎么对比环境
来源:17golang原创
时间:2026-11-11 06:59:16 354浏览 收藏
我遇到过一类很容易误判的 PHP 问题:命令行里能执行某个扩展的函数,网站请求经过 PHP-FPM 却提示函数不存在。第一反应通常是重装扩展,结果 CLI 和 FPM 继续各说各话。真正要对比的不是“机器上有没有这个 so 文件”,而是两个 SAPI 最终加载了什么。
官方地址:https://www.php.net/manual/en/configuration.file.php
PHP CLI 与 PHP-FPM 可以使用不同的二进制、主 php.ini、附加扫描目录和扩展集合。先把这四组证据分别记下来,再只修改 FPM 对应配置;配置改完要重启或重新加载 FPM,不能拿 CLI 的结果代替 FPM 复查。
php --ini只能说明 CLI 的配置入口,不能证明 FPM 使用同一份文件。- 扩展差异要连同
extension_dir、附加 ini 文件和 SAPI 身份一起比较。 - 修复时保存 FPM 配置副本,重启后再检查加载结果,回滚也只回 FPM 变更。
先固定四组对比字段
这次排查我会把问题拆成四张小表:运行二进制、主配置文件、附加扫描目录、已加载扩展。它们分别回答“谁在运行”“读了哪份 php.ini”“还读了哪些 .ini”“最终有哪些模块”。只看最后一项,最容易把路径问题误判成扩展安装问题。

先看 CLI,再拿到 FPM 的同名字段
CLI 的入口比较直接,先记录可执行文件、SAPI、主配置和扫描目录。下面的命令只输出诊断信息,注释说明每一组字段的用途。
# 记录 CLI 使用的二进制、主 php.ini 和附加扫描目录
command -v php
php --ini
# 记录 CLI 的 SAPI、主配置路径、扫描文件和已加载扩展
php -r '
// 把四组对比字段放在同一份输出里,便于和 FPM 结果逐项比较
echo "SAPI=" . PHP_SAPI . PHP_EOL;
echo "ini=" . (php_ini_loaded_file() ?: "none") . PHP_EOL;
echo "scanned=" . (php_ini_scanned_files() ?: "none") . PHP_EOL;
echo "extensions=" . implode(",", get_loaded_extensions()) . PHP_EOL;
'
# 使用实际的 FPM 二进制读取 FPM 侧信息;名称按发行版替换
command -v php-fpm || command -v php-fpm8.3
php-fpm -i | grep -E 'Server API|Loaded Configuration File|Scan this dir for additional .ini files|Additional .ini files parsed|extension_dir|^\w+ support'
如果系统里的 FPM 程序名是 php-fpm8.2 或带完整版本号,就把最后一行换成实际路径。这里最重要的不是命令长短,而是 CLI 和 FPM 使用同一套字段:Server API 对应 SAPI,Loaded Configuration File 对应主配置,扫描目录和 extension_dir 则解释附加模块从哪里来。
差异出现在哪里,就在哪里处理
我通常按下面的顺序读结果。若二进制路径不同,先不要把一个版本的扩展复制给另一个版本;若主 php.ini 不同,优先确认 FPM 服务启动参数或发行版配置;若扫描目录不同,检查 FPM 是否读到了启用扩展的独立 ini;只有四项路径一致而扩展仍缺失时,才继续看扩展文件本身和加载错误。
| 差异 | 通常说明 | 处理方向 |
|---|---|---|
| 二进制不同 | CLI 与 FPM 可能来自不同 PHP 安装 | 确认 FPM 服务使用的版本和模块目录 |
| 主 php.ini 不同 | 同名配置项没有作用在两个 SAPI 上 | 修改 FPM 对应的主配置 |
| 扫描目录不同 | 启用扩展的独立 .ini 只被 CLI 读到 | 补齐 FPM 的扫描目录或独立 ini |
| 扩展集合不同 | 加载顺序、文件名或扩展目录仍有差异 | 检查 FPM 启动日志与扩展路径 |
PHP 官方文档说明,主配置文件之后还可能扫描 PHP_INI_SCAN_DIR 或编译时指定的目录,并按文件名顺序读取 .ini 文件。因此,CLI 的 php --ini 显示“已解析某文件”,并不能替代 FPM 侧的同名检查。
修复、重启和回滚都只围绕 FPM
确认差异后,我会先复制 FPM 要修改的配置,再改最小范围:补正确的 extension=... 行、修正扫描目录,或把服务指向正确的 PHP-FPM 二进制。不要把 CLI 的完整 php.ini 覆盖过去,因为它可能携带不同的路径、权限和开发环境设置。
# 先保存 FPM 配置副本,文件名带时间便于回滚 sudo cp /etc/php/8.3/fpm/php.ini /etc/php/8.3/fpm/php.ini.before-extension-change # 修改 FPM 对应的独立 ini;路径按发行版实际目录替换 sudo editor /etc/php/8.3/fpm/conf.d/20-example.ini # 让 FPM master 重新读取配置,再检查服务状态 sudo systemctl restart php8.3-fpm sudo systemctl is-active php8.3-fpm # 回滚时只恢复 FPM 文件,然后再次重启并复查 sudo cp /etc/php/8.3/fpm/php.ini.before-extension-change /etc/php/8.3/fpm/php.ini sudo systemctl restart php8.3-fpm
图中的 master 与 children 是一个很实用的边界:配置修复后,已经存在的 FPM 进程不一定自动获得新模块,重启或按现场规范 reload 后才有复查意义。生产环境应按服务管理策略选择动作,并把变更前后的四组输出保存到工单或发布记录。

值班复查清单
- CLI 和 FPM 的二进制路径是否属于同一安装或同一版本。
- 两边的主 php.ini、扫描目录和
extension_dir是否分别记录。 - 目标扩展是否出现在 FPM 的已加载集合中,而不是只出现在 CLI 输出。
- 修改后是否重启或重新加载了正确的 FPM 服务,旧 worker 是否已经退出。
- 回滚副本、服务状态和复查输出是否留在同一条变更记录中。
如果四组字段已经一致而扩展仍然缺失,再看 FPM 的启动日志和模块加载错误;如果只有 CLI 正常,优先回到 SAPI、配置文件和扫描目录这三层,不要先改业务代码。
相关问题
为什么 php -m 有扩展,网页仍提示不存在?
php -m 读取的是 CLI 进程的模块集合。网页通常经过 PHP-FPM,必须在 FPM 的运行环境中重新确认。
改了 php.ini 为什么马上不生效?
FPM 由 master 管理 worker,修改配置后需要按服务管理方式重启或重新加载,再检查新 worker 的配置和扩展集合。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
152 收藏
-
405 收藏
-
468 收藏
-
303 收藏
-
340 收藏
-
244 收藏
-
222 收藏
-
430 收藏
-
400 收藏
-
370 收藏
-
173 收藏
-
433 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习