Я использую последние пакеты 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 нет.
Я решил проблему следующим образом:
# 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 VM, laravel/homestead
поле 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.04 LTS; см. Комментарии для объяснения).
ld.so(8)
Состояния man-страницы (в зависимости от порядка поиска путей к библиотекам времени выполнения):
Использование переменной среды LD_LIBRARY_PATH (если исполняемый файл не запущен в режиме безопасного выполнения; см. Ниже). [так] в этом случае это игнорируется.
Пока я не могу придумать ни одной другой причины, по которой этот путь был бы проигнорирован. из 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
Блок.
Другими словами, 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 .
Первый, Ошибка Debian 859732 это совершенно другая проблема (я бы даже сказал противоположную проблему): для этой ошибки несколько версий библиотеки присутствуют в пути поиска (одна в некотором каталоге, указанном LD_LIBRARY_PATH
и другой в некотором каталоге, указанном в пути выполнения), но динамический компоновщик выбрал неправильный.
В вашем случае проблема в том, что запрошенная библиотека не найдена нигде в пути поиска. Также обратите внимание, что в вашем случае это PHP пытается открыть библиотеку (через dlopen
?), так как сообщение начинается с «PHP Warning:». Однако, похоже, что механизмы такие же, как и при обычном динамическом связывании.
После установки библиотеки вам нужно как минимум одно из:
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
используется).
Других решений пока нет …