游客发表
php -m 看不到扩展,看不块phpinfo() 里却明晃晃地列着一大串。到扩这事儿我碰上过不下十次,展模每次都有新手同事抓着头皮来问。看不块别急着怀疑自己眼瞎,到扩多半是展模 CLI 和 FPM 用的不是同一份 php.ini。
拿上次帮一个客户排查为例。看不块他服务器上装了个 imagick 扩展,到扩网页里跑得欢,展模但命令行里执行 php -m 就是看不块不见影。我让他 php -i | grep php.ini 一看,到扩CLI 加载的展模是 /usr/local/php/etc/php.ini,而 phpinfo() 页面显示的看不块却是 /usr/local/php/etc/php-fpm.d/../php.ini。同一个文件?到扩不,路径里藏了个软链接,展模指向了另一份配置文件。这种事在编译安装的 PHP 环境里太常见了。
还有一种情况,扩展文件本身没问题,但编译时 API 版本不匹配。PHP 扩展有 ZEND_MODULE_API_NO 这个编号,比如 PHP 7.4 的是 20190902,PHP 8.0 的是 20200930。如果你把为 7.4 编译的 .so 文件硬塞给 8.0 的 CLI,启动时它会直接报错,根本不会出现在 -m 列表里。但 phpinfo() 呢?它显示的是 FPM 进程加载的模块,而 FPM 可能还在用旧版本 PHP,或者你改错了 extension_dir。
再往深处挖,有些扩展是“按需加载”的。比如 opcache 和 apcu,它们可以在 php.ini 里用 zend_extension 或 extension 指令启用,但也可以被 PECL 安装脚本自动写进独立的 ini 文件里,比如 /etc/php/7.4/cli/conf.d/20-imagick.ini。如果这个 conf.d 目录的扫描配置在 CLI 和 FPM 间不一致——比如 CLI 的扫描路径被注释掉了——那 -m 自然看不到。而 phpinfo() 加载的是 FPM 的完整配置链,所以一切正常。
别忽略环境变量。你手动跑 php -m 时,当前 shell 可能设置了 PHPRC 指向了别的 ini 目录。我就见过有人为了测试,在 .bashrc 里 export 了 PHPRC,结果忘了。而 phpinfo() 是在 FPM 进程里执行的,它继承的是系统级环境,不受你 shell 影响。这种“看不见”其实是你自己造成的。
最后说个冷门的——扩展加载顺序。有些扩展依赖其他模块先加载,比如 imap 需要 openssl 提前就位。如果你在 CLI 的配置里把 imap 放在 openssl 前面,它可能静默失败。但 FPM 的配置顺序恰好正确,于是 phpinfo() 里一切正常。这种问题排查起来最费劲,因为 -m 不报错,只是缺失。
所以下次碰上这种“幽灵扩展”,先跑三句话:php -i | grep 'Loaded Configuration File',php -i | grep extension_dir,再对比一下 phpinfo() 里对应的两行。如果路径不同,问题就在这儿。如果路径相同,那就检查 .so 文件的编译 API 版本,用 php -v 看 CLI 版本,再比对你下载扩展时的兼容性说明。实在不行,强制在 php.ini 里指定绝对路径加载 extension=/full/path/to/foo.so,能出就是配置问题,出不了就是扩展本身和 CLI 不兼容。
友情链接