我正在使用https://launchpad.net/~ondrej/+archive/ubuntu/php中提供的最新PHP软件包。
当我构建和安装OCI8扩展时,一切似乎都井井有条,但是尽管在PHP-FPM配置中启用了该扩展,但它的存在并未反映在的输出中phpinfo()
。
以下要点详细介绍了我用于配置,构建和安装OCI8 PHP扩展的确切过程:
https://gist.github.com/cbj4074/fa761f60b6f8db431539d76ebfba828e
完全相同的过程和配置在Ubuntu 16.04 LTS上可以很好地正常工作,因此看来Ubuntu 18.04 LTS上存在一些根本差异,无论是所讨论的操作系统还是PHP软件包。
作为一点重要的背景信息(我怀疑与此问题有关),在Ubuntu 18.04 LTS上,扩展无法立即在CLI环境中加载,并显示以下错误:
PHP警告:PHP启动:无法加载动态库'/usr/lib/php/20160303/oci8.so'-libmql1.so:无法打开共享库文件:在第0行的Unknown中没有这样的文件或目录
我这样解决了这个问题:
# echo 'LD_LIBRARY_PATH="/opt/oracle/instantclient_12_2"' >> /etc/environment
我认为,也许将LD_LIBRARY_PATH
PHP添加到PHP-FPM环境配置中可能会解决那里的等效问题:
# echo "env['LD_LIBRARY_PATH'] = /opt/oracle/instantclient_12_2" >> /etc/php/7.2/fpm/pool.d/www.conf
# systemctl restart php7.2-fpm
实际上,确实会导致LD_LIBRARY_PATH
指定的值同时反映在的Environment
部分phpinfo()
(通过PHP-FPM + NGINX呈现并从浏览器请求时)和的PHP Variables
部分中$_SERVER['LD_LIBRARY_PATH']
。
奇怪的是,即使将PHP-FPM的日志记录设置为debug
,我也看不到libmql1.so
CLI遇到的任何错误痕迹。OCI8扩展根本无法以静默方式加载。display_startup_errors = On
在PHP-FPM中也有效php.ini
。
我选择查看OCI8扩展名是否可以在同一服务器上的Apache中工作,并且可以,只要添加export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2
到/etc/apache2/envvars
;在缺乏的情况下,Apache抱怨启动:
PHP警告:PHP启动:无法加载动态库“ oci8.so”(尝试:/usr/lib/php/20170718/oci8.so(libmql1.so:无法打开共享对象文件:无此类文件或目录),/第0行上的usr / lib / php / 20170718 / oci8.so.so(/usr/lib/php/20170718/oci8.so.so:无法打开共享的对象文件:没有这样的文件或目录))
LD_LIBRARY_PATH
在Ubuntu 16.04 LTS上无需进行任何此项业务,根据我在本文中的观察以及有关https://stackoverflow.com/a/45242468/1772379的评论,在Ubuntu 17.10和Ubuntu 18.04 LTS中进行了更改。
有人在Ubuntu 18.04 LTS上进行过尝试吗?
我已经在两个不同的Vagrant VM上尝试了此操作,分别是laravel/homestead
框6.0.0和ubuntu/bionic64
框v20180509.0.0,两者的行为是相同的。
任何其他想法将不胜感激!
编辑1:
我在软件包维护者的GitHub跟踪器上询问了此问题,他建议该问题起因于RPATH
在编译时未设置适当的代码。
我在答复中解释说我正在设置适当的值,但是问题仍然存在。
我确实注意到一个有趣的细节,那就是在Ubuntu 18.04上使用的是编译后的扩展名RUNPATH
(而不是RPATH
在Ubuntu 16.04中使用的不是)。如果PHP-FPM忽略RUNPATH
,而仅查找RPATH
,它将解释此行为。
编辑2:
这份尚未公开的报告看起来像是介绍已观察到的行为的优秀候选者:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732
(通过使用RPATH而不是RUNPATH的注释发现吗?)
编辑3:
根据评论者的建议,我ld
在构建扩展程序之前重新检查了更新配置,从而解决了该问题!我之前曾尝试过此方法,但在构建尝试之间一定忽略了一些东西:
# echo /opt/oracle/instantclient_12_2 > /etc/ld.so.conf.d/oracle-instantclient.conf
# ldconfig
我仍然不知道为什么LD_LIBRARY_PATH
在这种情况下不能正常工作,但是将Instant Client库路径添加到链接器配置中似乎是一种更好的方法。
编辑4:
我在之前的编辑中说过,修改ldconfig
结构是一种更好的方法,但后来(根据评论者的忠告)意识到,这样做会导致不良的库冲突,因为这种影响在整个系统范围内。
事后看来,通过将运行时库链接修改限制在执行环境中来最大程度地减少“附带损害”是有意义的LD_LIBRARY_PATH
。因此,我有理由确定为什么这在Ubuntu 18.04 LTS上不起作用。
我觉得我已经确定地建立了PHP-FPM守护程序LD_LIBRARY_PATH
在Ubuntu上忽略的功能(并且至少从Ubuntu 16.04 LTS开始;请参阅注释以获取解释)。
手册ld.so(8)
页状态(与运行时库路径的搜索顺序有关):
使用环境变量LD_LIBRARY_PATH(除非可执行文件以安全执行模式运行;请参见下文)。[sic]在这种情况下,它将被忽略。
到目前为止,我还没有想到该路径会被忽略的任何其他原因。的secure-execution mode
,同一份文件显示:
Secure-execution mode
For security reasons, the effects of some environment variables are voided or modified if the dynamic linker determines that the binary
should be run in secure-execution mode. (For details, see the discussion of individual environment variables below.) A binary is exe‐
cuted in secure-execution mode if the AT_SECURE entry in the auxiliary vector (see getauxval(3)) has a nonzero value. This entry may
have a nonzero value for various reasons, including:
* The process's real and effective user IDs differ, or the real and effective group IDs differ. This typically occurs as a result of
executing a set-user-ID or set-group-ID program.
* A process with a non-root user ID executed a binary that conferred capabilities to the process.
* A nonzero value may have been set by a Linux Security Module.
首先,安全执行模式似乎无效,因为PHP可执行文件不显示此标志(AT_SECURE
is 0
):
LD_SHOW_AUXV=1 /usr/sbin/php-fpm7.1 -daemonize --fpm-config /etc/php/7.1/fpm/php-fpm.conf
AT_SYSINFO_EHDR: 0x7ffc569e1000
AT_HWCAP: 178bfbff
AT_PAGESZ: 4096
AT_CLKTCK: 100
AT_PHDR: 0x55ceab0c4040
AT_PHENT: 56
AT_PHNUM: 9
AT_BASE: 0x7f823c77f000
AT_FLAGS: 0x0
AT_ENTRY: 0x55ceab19e360
AT_UID: 0
AT_EUID: 0
AT_GID: 0
AT_EGID: 0
AT_SECURE: 0
AT_RANDOM: 0x7ffc56962349
AT_HWCAP2: 0x0
AT_EXECFN: /usr/sbin/php-fpm7.1
AT_PLATFORM: x86_64
在我看来,子FPM池进程可能显示不同的AT_SECURE
值,但是PHP-FPM守护程序本身以及任何子进程的输出是相同的。父级和子级都具有以下值:
# od -t d8 /proc/851/auxv
0000000 33 140722944548864
0000020 16 395049983
0000040 6 4096
0000060 17 100
0000100 3 93903778242624
0000120 4 56
0000140 5 9
0000160 7 140365152313344
0000200 8 0
0000220 9 93903779136352
0000240 11 0
0000260 12 0
0000300 13 0
0000320 14 0
0000340 23 0
0000360 25 140722944193929
0000400 26 0
0000420 31 140722944196579
0000440 15 140722944193945
0000460 0 0
其次,鉴于以下原因,这些原因似乎都不适用:
1)没有迹象表明PHP-FPM或其子进程具有真实有效的用户或组ID,这些ID有所不同(此命令的https://unix.stackexchange.com/a/202359感谢):
# ps -e -o user= -o ruser= | awk '$1 != $2'
systemd+ systemd-timesync
systemd+ systemd-resolve
beansta+ beanstalkd
message+ messagebus
daemon root
systemd+ systemd-network
# ps -e -o group= -o rgroup= | awk '$1 != $2'
systemd+ systemd-timesync
systemd+ systemd-resolve
beansta+ beanstalkd
message+ messagebus
daemon root
systemd+ systemd-network
2)有问题的二进制文件不具有任何功能(以下命令不产生任何输出):
# getcap /usr/lib/php/20170718/oci8.so
# getcap -r /opt/oracle/instantclient_12_2/
3)我确保已禁用AppArmor(无论如何,它没有应影响PHP-FPM的策略):
# systemctl disable apparmor
Synchronizing state of apparmor.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable apparmor
# reboot
# aa-status
apparmor module is loaded.
0 profiles are loaded.
0 profiles are in enforce mode.
0 profiles are in complain mode.
0 processes have profiles defined.
0 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
那么,为什么PHP-FPMLD_LIBRARY_PATH
出于上述任何原因而忽略?
编辑5(解决方案):
敏锐的注释者@ vinc17指出,在运行的系统上systemd
,诸如的环境变量LD_LIBRARY_PATH
不一定会传播到通过systemd
Unit启动的进程。
换句话说,PHP-FPM并不是“忽略” LD_LIBRARY_PATH
,而是没有传达给流程。尝试LD_LIBRARY_PATH
在PHP-FPM配置中进行设置是徒劳的,因为现在对该值做任何有用的事情为时已晚。
根据这个建议,我想到要LD_LIBRARY_PATH
在systemd
上下文中进行设置,即在启动PHP-FPM守护程序的Unit文件中进行设置,在这种情况下,PHP-FPM成功加载OCI8扩展。
不用说,我们要避免编辑软件包维护者的文件(以避免将来升级时发生冲突),因此我们将其扩展:
# mkdir /etc/systemd/system/php7.1-fpm.service.d
# touch /etc/systemd/system/php7.1-fpm.service.d/environment.conf
在此文件中,我们添加以下内容:
[Service]
Environment=LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2
并使更改生效:
# systemctl daemon-reload
# systemctl restart php7.1-fpm
有关涉及多个共同安装的PHP版本的更完整的示例,请参阅我的帖子,网址为https://github.com/oerdnj/deb.sury.org/issues/865#issuecomment-395441936。
首先,Debian错误859732是一个完全不同的问题(我什至会说一个相反的问题):对于该错误,搜索路径中存在库的多个版本(一个在指定的某个目录中,LD_LIBRARY_PATH
一个在指定的某个目录中另一个)通过运行路径),但动态链接器选择了错误的路径。
对于您而言,问题在于在搜索路径中的任何位置都找不到请求的库。另请注意,在您的情况下,PHP似乎试图通过(通过dlopen
?)打开该库,因为该消息以“ PHP警告:”开头。但是,机制似乎与通常的动态链接相同。
安装库之后,您需要的至少是以下之一:
dlopen
,该软件(此处为PHP)可能已经设置了可以称为“插件搜索路径”的位置,您可以在其中放置库。LD_LIBRARY_PATH
。这是您尝试过的方法,但您LD_LIBRARY_PATH
似乎不正确。库通常安装在命名的子目录中lib
(lib32
或lib64
在特定情况下)。所以,export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2
似乎错了。搜索库的完整路径名oci8.so
,并将该路径名的目录用作LD_LIBRARY_PATH
。注意:strace
可能有用以查看要搜索库的目录。编辑: ldd
和objdump -p
是其他有用的工具,以查找正在发生的搜索路径。
编辑2:选择使用运行路径时要注意的另一点是,在RPATH
使用时会发现间接库依赖关系,而在RUNPATH
使用时则找不到(因此,在后一种情况下,如果所有依赖项都依赖于它们,则还需要具有运行路径)在其他图书馆上,这样就可以找到所有图书馆而无需诉诸LD_LIBRARY_PATH
)。ld.so(8)手册页的最新版本中对此进行了记录:
使用
DT_RUNPATH
二进制文件的动态部分属性中指定的目录(如果存在)。仅搜索此类目录以查找DT_NEEDED
(直接依赖项)条目所需的那些对象,并且不适用于那些必须具有自己的DT_RUNPATH
条目的对象的子对象。这与有所不同DT_RPATH
,后者适用于在依赖关系树中搜索所有子项。
这可能就是为什么不使用LD_LIBRARY_PATH
,它RPATH
只能在16.04(使用)上使用,而不能在18.04(RUNPATH
使用)上使用的原因。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句