本文基于实际环境整理:Debian 13、宝塔 PHP 8.3.31、PHP 安装目录 /www/server/php/83,系统已安装 libffi-dev 3.4.8。目标是不重新编译整套 PHP,而是利用 PHP 源码目录中的 ext/ffi 单独编译出 ffi.so,并在 CLI 与 PHP-FPM 中启用 FFI。
1. 最终目标与适用环境
|----------|--------------------------------|
| 项目 | 实际环境 |
| 操作系统 | Debian 13 |
| PHP | 8.3.31(宝塔安装) |
| PHP 路径 | /www/server/php/83 |
| PHP API | 20230831 |
| FFI 源码目录 | /www/server/php/83/src/ext/ffi |
| libffi | 3.4.8 |
| 目标扩展 | ffi.so |
2. 先确认 PHP 当前没有启用 FFI
/www/server/php/83/bin/php -m | grep -i ffi
// 如果没有任何输出,说明当前 PHP 没有加载 FFI。
/www/server/php/83/bin/php -i | grep extension_dir
// 本环境扩展目录为:
/www/server/php/83/lib/php/extensions/no-debug-non-zts-20230831
3. 不要直接写 extension=ffi
如果扩展目录里没有 ffi.so,就不要先在 php.ini 中开启:
extension=ffi
否则 PHP 启动时会报类似:
PHP Startup: Unable to load dynamic library 'ffi' ... ffi.so: cannot open shared object file
**说明:**应先把 ffi.so 编译并安装到 extension_dir,再修改 php.ini。
4. 确认 libffi 开发库
bash
apt update
apt install -y libffi-dev
pkg-config --modversion libffi
// 本环境输出:3.4.8; 这表示 FFI 编译所需的系统依赖已经满足。
5. 确认 PHP 编译参数
bash
/www/server/php/83/bin/php -i | grep "Configure Command"
当前宝塔 PHP 8.3.31 的原始编译参数中没有 --with-ffi,因此默认没有 FFI 支持。由于宝塔保留了 PHP 源码和 ext/ffi,可以优先单独编译扩展,无需重编整个 PHP。
6. 确认 FFI 源码完整
进入:
bash
cd /www/server/php/83/src/ext/ffi
// 正常可看到类似文件:
config.m4
config.w32
CREDITS
ffi.c
ffi.g
ffi.stub.php
ffi_arginfo.h
ffi_parser.c
php_ffi.h
tests/
7. 使用宝塔 PHP 8.3 的 phpize
bash
/www/server/php/83/bin/phpize
/**本环境输出:
Configuring for:
PHP Api Version: 20230831
Zend Module Api No: 20230831
Zend Extension Api No: 420230831
8.3.31
这一步非常重要,它说明编译环境与当前 PHP 8.3.31 的 ABI 完全匹配。*/
// 清理一下旧构建文件:
/www/server/php/83/bin/phpize --clean
// 再执行
/www/server/php/83/bin/phpize
8. 配置 FFI 为共享扩展
bash
./configure \
--with-php-config=/www/server/php/83/bin/php-config \
--with-ffi=shared
// 如果 configure 成功,再进行编译。
make -j$(nproc)
// 编译成功后会看到类似:
// Build complete.
// Do Not forget to run 'make test'.
// 并检查 modules 目录:
ls -lh modules/
// 本环境已经成功生成:ffi.la,ffi.so; 其中 ffi.so 即 PHP 要加载的 FFI 动态扩展。
// disable_functions 中包含 shell_exec; 请删除; 然后执行:make test
// 安装 ffi.so
make install
// /www/server/php/83/lib/php/extensions/no-debug-non-zts-20230831/
// 确保ffi.so存在
ls -lh /www/server/php/83/lib/php/extensions/no-debug-non-zts-20230831/ffi.so
9. 修改 php.ini
bash
extension=ffi
[ffi]
ffi.enable=true
;ffi.preload=
说明:
extension=ffi:加载刚编译好的 ffi.so。
ffi.enable=true:允许 Web/FPM 与 CLI 使用 FFI。
ffi.enable=preload:更严格,只允许 CLI 和预加载场景,不适合普通 ThinkPHP/FPM 请求直接调用 FFI。
ffi.preload:当前无需配置。
10. CLI 验证 FFI
bash
/www/server/php/83/bin/php -m | grep -i ffi
// 应输出:FFI
/www/server/php/83/bin/php --ri ffi
// 重点确认:
// FFI support => enabled
// ffi.enable => true
/www/server/php/83/bin/php -r "var_dump(class_exists('FFI'));"
// 预期:bool(true)