如何在带有PHP-FPM和NGINX的Ubuntu 18.04 LTS中使用Oracle Instant Client启用OCI8 PHP扩展?

本·约翰逊

我正在使用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_PATHPHP添加到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.soCLI遇到的任何错误痕迹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_SECUREis 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不一定会传播到通过systemdUnit启动的进程

换句话说,PHP-FPM并不是“忽略” LD_LIBRARY_PATH,而是没有传达给流程。尝试LD_LIBRARY_PATH在PHP-FPM配置中进行设置是徒劳的,因为现在对该值做任何有用的事情为时已晚。

根据这个建议,我想到LD_LIBRARY_PATHsystemd上下文中进行设置,即在启动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

vinc17

首先,Debian错误859732是一个完全不同的问题(我什至会说一个相反的问题):对于该错误,搜索路径中存在库的多个版本(一个在指定的某个目录中,LD_LIBRARY_PATH一个在指定的某个目录中另一个)通过运行路径),但动态链接器选择了错误的路径。

对于您而言,问题在于在搜索路径中的任何位置都找不到请求的库。另请注意,在您的情况下,PHP似乎试图通过(通过dlopen?)打开该库,因为该消息以“ PHP警告:”开头。但是,机制似乎与通常的动态链接相同。

安装库之后,您需要的至少是以下之一:

  • 如果库已安装在默认搜索的目录中,则没什么特别的。由于出现错误,因此情况并非如此。
  • 在运行路径中提供目录,该目录必须在需要该库的软件的编译时指定。问题在于,在Linux下,构建工具没有按标准进行此操作,并且正确操作而不破坏其他内容可能很复杂。但是,在的情况下dlopen,该软件(此处为PHP)可能已经设置了可以称为“插件搜索路径”的位置,您可以在其中放置库。
  • 在中提供目录LD_LIBRARY_PATH这是您尝试过的方法,但您LD_LIBRARY_PATH似乎不正确。库通常安装在命名的子目录中liblib32lib64在特定情况下)。所以,export LD_LIBRARY_PATH=/opt/oracle/instantclient_12_2似乎错了。搜索库的完整路径名oci8.so,并将该路径名的目录用作LD_LIBRARY_PATH

注意:strace可能有用以查看要搜索库的目录。编辑: lddobjdump -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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

安装PHP OCI8 Linux Centos 8时使用的路径

如何使用PHP-FPM和Nginx Docker容器解析未知的PHP-FPM主脚本?

在Ubuntu中使用nginx和php7.0-fpm的Laravel 5.4的502错误网关

oci8,php7和Oracle 10.1兼容性

PHP Oracle OCI8查询以保留/处理数组中的空列

将映像作为BLOB上载到Oracle DB时出现PHP OCI8警告

如何在Ubuntu 18:04上使用QT5安装CGAL?

在docker上使用Nginx,php 7.4 fpm和mysql 8的Laravel 6比在php 7.1上的Laravel 4慢

无法在Ubuntu 13.10(Nginx,PHP-FPM)中使用PHP扩展Mcrypt

重新启动后无法加载PHP OCI8扩展

PHP,PEAR和oci8配置

ubuntu-minimal 18:04如何通过ssh登录?

如何在带有PHP和XPath的foreach语句中使用多个数组

加载PHP OCI8扩展时出错

Centos 6 PHP OCI8扩展无法正常工作(未定义函数oci_connect())

安装并配置OCI8以将oracle连接到php

PHP 5.6 OCI8安装问题:

如何在Ubuntu 16.04 LTS中安装Mongodb PHP扩展

无法启用oci8 PHP模块

PHP OCI8无法从NCHAR(Oracle 11g)读取Unicode字符

PHP OCI8扩展不适用于PHP 7 64位

php oci8模块未加载(ubuntu 16)

使用带有分页功能的PHP oci8从多个Oracle数据库作为单个结果集获取数据

PHP7.0-FPM 与 Docker:无法加载动态库 OCI8

php oracle客户端oci8安装有什么问题

使用 OCI8 连接到 Oracle 18c 数据库

在 centOs 上使用 PHP 5.6 安装 OCI8 (vagrant)

如何在 php-fpm 中启用套接字扩展?

在 Dockerfile 中为 php:8.1-fpm 安装并启用 OCI8 扩展