Как включить расширение PHP OCI8, используя Oracle Instant Client, в Ubuntu 18.04 LTS с PHP-FPM и NGINX? - PullRequest
0 голосов
/ 17 мая 2018

Я использую последние доступные пакеты PHP от https://launchpad.net/~ondrej/+archive/ubuntu/php.

Когда я собираю и устанавливаю расширение OCI8, кажется, что все в порядке, но, несмотря на включение расширения в конфигурации PHP-FPM, его наличие не отражается в выводе phpinfo().

В следующем Gist подробно описан процесс, который я использую для настройки, сборки и установки расширения 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 * нет 1018 *

Я решил проблему следующим образом:

# echo 'LD_LIBRARY_PATH="/opt/oracle/instantclient_12_2"' >> /etc/environment

Я думал, что, возможно, добавление LD_LIBRARY_PATH в конфигурацию среды 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: невозможно открыть общий объектный файл: такого файла или каталога нет) ), /usr/lib/php/20170718/oci8.so.so (/usr/lib/php/20170718/oci8.so.so: невозможно открыть общий объектный файл: такой файл или каталог отсутствуют)) в поле «Неизвестно» в строке 0

Ничто из этого дела с 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, laravel/homestead box 6.0.0 и ubuntu/bionic64 box 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.04LTS; см. Комментарии для объяснения).

Состояние man-страницы 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 равно 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или его дочерние процессы имеют реальные и эффективные идентификаторы пользователей или групп, которые отличаются (спасибо 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-FPM игнорирует LD_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, и в этом случае 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.

1 Ответ

0 голосов
/ 01 июня 2018

Во-первых, Ошибка Debian 859732 - это совершенно другая проблема (я бы даже сказал, противоположная проблема): для этой ошибки в пути поиска присутствует несколько версий библиотеки (одна в указанном каталогеLD_LIBRARY_PATH и другим в некотором каталоге, указанном в пути выполнения), но динамический компоновщик выбирает неправильный.

В вашем случае проблема в том, что запрошенная библиотека нигде не найденав пути поиска.Также обратите внимание, что в вашем случае это PHP пытается открыть библиотеку (через dlopen?), Поскольку сообщение начинается с «PHP Warning:».Однако, похоже, что механизмы такие же, как и при обычном динамическом связывании.

После установки библиотеки вам понадобится как минимум одно из:

  • Ничего особенного, если библиотекабыл установлен в каталог, который ищется по умолчанию.Поскольку вы получаете сообщение об ошибке, это не ваш случай.
  • Указание каталога в пути выполнения, который должен быть указан во время компиляции программного обеспечения, которому потребуется библиотека.Проблема в том, что в Linux это не делается стандартными средствами сборки, и может быть сложно сделать это правильно, не нарушая другие вещи.Однако в контексте 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, это работало с 16.04 (где RPATHиспользуется), но не с 18.04 (где используется RUNPATH).

...