前言
最近将一个对接 人大金仓kingbase
国产数据库的 PHP 项目从 php7
升级到 php8
,结果遇到在 PHP8 环境下,Kingbase的 PDO
扩展无法加载的问题,这里记录以下处理和解决过程;
PHP7 安装 KingBase 驱动步骤
项目原本使用的是 php 7.2.0
安装KingBase驱动扩展的步骤非常简单
- 直接官网下载对应 PHP 版本的驱动包,
- 解压缩驱动包直接将其中的
pdo_kdb.so
和libpq.so.5
这两个文件丢到 PHP 的扩展目录 - 编辑
php.ini
配置文件,添加pdo_kdb
扩展 - 执行
php -m
就可以看到pdo_kdb
已经成功加载可以正常使用了
PHP8 下的 KingBase 驱动问题
重新编译安装了新版本的 PHP 8.2.20
(一定要选择与 Kingbase 驱动所支持和匹配的 PHP 版本)
下载对应版本的 Kingbase
驱动包 v8r6_pdo_kdb_for_php-8.2.0_x86_64_uzts.tar.gz 的驱动扩展包
使用与 PHP7 相同的步骤安装 KingBase 驱动扩展;
同样是将其中的 pdo_kdb.so
和 libpq.so.5
放到PHP的扩展路径下,
然后编辑 php.ini
添加 pdo_kdb.so
扩展
结果执行 php -m
查看加载的扩展时,意料之外的一幕发生了
PHP 8.2.20 提示 pdo_kdb 无法加载,因为 libpq.so.5 文件找不到
PHP Warning: PHP Startup: Unable to load dynamic library 'pdo_kdb' (tried: /xxx/lib/php/extensions/no-debug-non-zts-20220829/pdo_kdb (/xxxx/lib/php/extensions/no-debug-non-zts-20220829/pdo_kdb: cannot open shared object file: No such file or directory), /xxxx/lib/php/extensions/no-debug-non-zts-20220829/pdo_kdb.so (libpq.so.5: cannot open shared object file: No such file or directory
)) in Unknown on line 0
在次确认 pdo_kdb.so
和 libpq.so.5
明明都已经一起放在 PHP 的扩展目录下了,为什么会提示找不到 libpq.so.5 这个库文件呢?
从错误提示看 pdo_kdb.so
这个扩展应该是有被 php 尝试加载,但 pdo_kdb.so
所依赖的 libpq.so.5
找不到;
那么就应该是 pdo_kdb.so
找不到它的依赖库 libpq.so.5
文件。
于是我用 ldd 指令分别对比查看了 PHP7
和 PHP8
版本下 pdo_kdb.so
的动态链接库
果然只有 PHP8 的 pdo_kdb.so
找不到外部链接库 libpq.so.5
到这里就基本可以确定是新的 kingbase驱动 pdo_kdb.so 的问题了,可以排除掉 PHP8 环境的问题了;
定位原因
安装 chrpath
工具,一个专门用于查看和修改编译后的二进制文件 RPATH
外部链接库路径的工具
dnf install chrpath.x86_64
分别查看 PHP7 和 PHP8 两个版本的kingbase驱动扩展 pdo_kdb.so
的外部依赖哭路径定义
# -l 参数是 list 列出当前的 RPATH 依赖库路径
chrpath -l pdo_kdb.so
结果发现这两个版本的 pdo_kdb.so
的 RPATH 定义明显不一样
PHP8 的 pdo_kdb.so
中 RPATH 定义是: /home/docker/xiewy/code/KES_Server/release/lib
这看起来应该是 Kingbase数据库服务器的安装路径或是编译该扩展的机器上的安装路径,但是在我的系统上并不存在这个路径,所以自然也就无法在这个路径下正确找到 libpq.so.5
这个依赖库了;
PHP7 的 pdo_kdb.so
中 RPATH 定义是:$ORIGIN/./
这里引用的是一个路径变量,并且能让 pdo_kdb.so 在自身当前的目录下正确找到 libpq.so.5
这个依赖库,所以能正常加载驱动扩展;
问题原因已经确定,就是因为 PHP8 版本的 kingbase 驱动扩展库 pdo_kdb.so
编译时定义了固定的 RPATH 路径,导致无法加载外部链接库;
解决方案
1. 将 libpq.so.5 文件放到能被正确定位加载的路径下
如果不想修改驱动文件本身,那么就需要按照 RPATH 的定义,将 libpq.so.5
文件放在与 RPATH 定义一致的路径目录下,才能被 pdo_kdb.so
正常加载;
2. 修改 pdo_kdb.so 的 RPATH 路径让其在当前路径下
通常对于独立的PHP
环境或项目来说,并不希望将 pdo_kdb.so
和 libpq.so.5
这两个文件分开不同的路径存放,不利于统一管理和维护,所以还是希望能跟 PHP7 的驱动一样,默认就从 pdo_kdb.so
所在的同一目录下加载,这是就需要我们修改 pdo_kdb.so
的 RPATH 指向到我们希望的目录路径,或者是修改成跟 PHP7 的驱动一样,指向 $ORIGIN/
这个路径变量;
我个人是倾向于第2种修改方式,如下:
# 参数 -r replace RPATH 替换当前的 rpath 为指定的路径
chrpath -r '$ORIGIN/' pdo_kdb.so
成功将 RPATCH 从原本的 /home/docker/xiewy/code/KES_Server/release/lib
替换为 $ORIGIN/
重新执行 php -m
确认 PHP8 已经可以正确加载了 pdo_kdb
扩展模块
PS 后话
希望国产数据库能更加发展强大!
同时也更希望 Kinbbase 的官方开发人员能多多上心!
数据库的驱动程序应该要做到让用户都能开箱即用,而不需要额外花费大量的精力来处理这些本不该出现的问题;
说实话,动态链接库的路径编译为为静态路径,而且还是指向数据库开发环境下的静态路径,这属实太 Low 了点..