J'utilise les derniers packages PHP disponibles à partir de https://launchpad.net/~ondrej/+archive/ubuntu/php .
Lorsque je construis et installe l'extension OCI8, tout semble être en ordre, mais malgré l'activation de l'extension dans la configuration PHP-FPM, sa présence n'est pas reflétée dans la sortie de phpinfo()
.
Le Gist suivant détaille le processus exact que j'utilise pour configurer, compiler et installer l'extension OCI8 PHP:
https://Gist.github.com/cbj4074/fa761f60b6f8db431539d76ebfba828e
Le même processus et la même configuration fonctionnent parfaitement sous Ubuntu 16.04 LTS. Il semble donc y avoir une différence fondamentale entre Ubuntu 18.04 LTS, qu’il s’agisse du système d’exploitation ou des packages PHP en question.
En tant qu'information de base importante (et je soupçonne qu'elle est pertinente à ce problème), sur Ubuntu 18.04 LTS, l'extension ne parvient pas à se charger dans l'environnement CLI immédiatement, avec l'erreur suivante:
Avertissement PHP: PHP Démarrage: impossible de charger la bibliothèque dynamique '/usr/lib/php/20160303/oci8.so' - libmql1.so: impossible d'ouvrir le fichier d'objet partagé: aucun fichier ou répertoire de ce type dans Inconnu sur ligne 0
J'ai résolu le problème comme suit:
# echo 'LD_LIBRARY_PATH="/opt/Oracle/instantclient_12_2"' >> /etc/environment
J'ai pensé que l'ajout du LD_LIBRARY_PATH
à la configuration de l'environnement PHP-FPM pourrait peut-être résoudre le problème équivalent ici:
# echo "env['LD_LIBRARY_PATH'] = /opt/Oracle/instantclient_12_2" >> /etc/php/7.2/fpm/pool.d/www.conf
# systemctl restart php7.2-fpm
Cela provoque effectivement la valeur LD_LIBRARY_PATH
, telle que spécifiée, dans la section Environment
de phpinfo()
(lorsqu’elle est rendue via PHP-FPM + NGINX et demandée à partir d’un navigateur) et dans la section PHP Variables
, en tant que $_SERVER['LD_LIBRARY_PATH']
.
Bizarrement, même si la journalisation de PHP-FPM est définie sur debug
, je ne vois aucune trace de l'erreur libmql1.so
que je rencontre avec l'interface de ligne de commande. L'extension OCI8 ne parvient tout simplement pas à se charger, en silence. display_startup_errors = On
dans le php.ini
effectif de PHP-FPM.
J'ai choisi de voir si l'extension OCI8 fonctionne dans Apache, sur le même serveur, et c'est le cas, à condition que j'ajoute export LD_LIBRARY_PATH=/opt/Oracle/instantclient_12_2
à /etc/Apache2/envvars
; en son absence, Apache se plaint au démarrage:
Avertissement PHP: PHP Démarrage: impossible de charger la bibliothèque dynamique 'oci8.so' (tentative: /usr/lib/php/20170718/oci8.so (libmql1.so: impossible d'ouvrir le fichier objet partagé: aucun fichier ou répertoire), /usr/lib/php/20170718/oci8.so.so (/usr/lib/php/20170718/oci8.so.so: impossible d'ouvrir le fichier objet partagé: aucun fichier ou répertoire de ce type)) dans Unknown à la ligne 0
Aucune de ces affaires avec le LD_LIBRARY_PATH
n'est nécessaire sur Ubuntu 16.04 LTS, et sur la base de mes observations ici et des commentaires concernant https://stackoverflow.com/a/45242468/1772379 , ce qui a changé dans Ubuntu 17.10 et Ubuntu 18.04 C'EST.
Quelqu'un d'autre a-t-il déjà essayé cela, sur Ubuntu 18.04 LTS, en particulier?
J'ai essayé ceci sur deux machines virtuelles Vagrant différentes, laravel/Homestead
box 6.0.0 et ubuntu/bionic64
box v20180509.0.0, et le comportement est le même dans les deux cas.
Toute autre idée serait la plus appréciée!
EDIT 1 :
J'ai posé des questions sur ce problème dans l'outil de suivi GitHub du mainteneur du paquet et il a suggéré que le problème venait de la non-définition d'une RPATH
appropriée au moment de la compilation.
J'explique dans ma réponse que je am définissant une valeur appropriée, mais le problème reste clos.
Je remarque toutefois un détail intéressant, à savoir que l'extension compilée sous Ubuntu 18.04 utilise RUNPATH
(et non RPATH
, utilisée dans Ubuntu 16.04). Si PHP-FPM ignore RUNPATH
et ne recherche que RPATH
, cela expliquerait ce comportement.
EDIT 2 :
Ce rapport encore ouvert semble être un excellent candidat pour avoir introduit le comportement observé:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732
(découvert grâce aux commentaires sur utilise RPATH mais pas RUNPATH? )
EDIT 3 :
Sur les conseils d'un commentateur, j'ai réexaminé la mise à jour de la configuration ld
avant de construire l'extension, ce qui a résolu le problème! J'avais déjà essayé cela auparavant, mais j'ai dû oublier quelque chose entre les tentatives de construction:
# echo /opt/Oracle/instantclient_12_2 > /etc/ld.so.conf.d/Oracle-instantclient.conf
# ldconfig
Je ne sais toujours pas pourquoi LD_LIBRARY_PATH
ne fonctionne pas comme il se doit dans ce cas, mais l'ajout du chemin de la bibliothèque Instant Client à la configuration de l'éditeur de liens semble également une meilleure approche.
EDIT 4 :
Dans ma précédente édition, j’avais déclaré que la modification de la variable ldconfig
constituait une meilleure approche, mais j’ai réalisé (sur le bon conseil du commentateur) que cela pouvait entraîner des conflits indésirables entre bibliothèques, car les effets s’appliquaient à l’ensemble du système.
En rétrospective, il est logique de minimiser les "dommages collatéraux" résultant des modifications de liaison des bibliothèques d’exécution en les limitant à l’environnement d’exécution via le LD_LIBRARY_PATH
. En conséquence, je suis motivé pour déterminer pourquoi cela ne fonctionne pas sur Ubuntu 18.04 LTS.
Je sens que j'ai définitivement établi que le démon PHP-FPM ignore LD_LIBRARY_PATH
sur Ubuntu (et depuis au moins Ubuntu 16.04 LTS; voir Commentaires pour des explications).
La page de manuel ld.so(8)
indique (en fonction de l'ordre dans lequel les chemins d'accès aux bibliothèques d'exécution sont recherchés):
Utilisation de la variable d'environnement LD_LIBRARY_PATH (sauf si le fichier exécutable est exécuté en mode d'exécution sécurisée; voir ci-dessous). dans ce cas, il est ignoré.
Pour le moment, je ne peux penser à aucune autre raison pour laquelle le chemin serait ignoré. De secure-execution mode
, le même document dit:
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.
Tout d’abord, le mode d’exécution sécurisée semble ne pas être en vigueur, car les exécutables PHP ne présentent pas cet indicateur (AT_SECURE
est 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
Il m'est apparu que les processus du pool FPM enfant pouvaient présenter des valeurs AT_SECURE
différentes, mais la sortie était identique pour le démon PHP-FPM lui-même, ainsi que pour tous les processus enfants. Le parent et les enfants ont tous les valeurs suivantes:
# 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
Deuxièmement, aucune de ces raisons ne semble s'appliquer, compte tenu de ce qui suit:
1) Rien n'indique que PHP-FPM ou ses processus enfants aient des identifiants d'utilisateur ou de groupe réels et effectifs différents (grâce à https://unix.stackexchange.com/a/202359 pour cette commande):
# 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) Les fichiers binaires en question n’ont aucune capacité (les commandes suivantes ne produisent aucune sortie):
# getcap /usr/lib/php/20170718/oci8.so
# getcap -r /opt/Oracle/instantclient_12_2/
3) Je me suis assuré qu'AppArmor est désactivé (il n'a pas de stratégie qui devrait affecter PHP-FPM, de toute façon):
# 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.
Alors, pourquoi PHP-FPM ignore-t-il LD_LIBRARY_PATH
, si ce n’est pour l’une des raisons susmentionnées?
EDIT 5 (Solution) :
Un commentateur astucieux, @ vinc17, souligne que sur les systèmes exécutant systemd
, les variables d'environnement, telles que LD_LIBRARY_PATH
, ne sont pas nécessairement propagées aux processus démarrés via une unité systemd
.
En d'autres termes, PHP-FPM n'est pas "ignorant" LD_LIBRARY_PATH
, mais plutôt, il n'est pas transmis au processus. Et les tentatives visant à définir LD_LIBRARY_PATH
dans la configuration de PHP-FPM sont vaines, car il est trop tard pour faire quoi que ce soit d’utile avec la valeur.
Sur ce conseil, je me suis mis à définir LD_LIBRARY_PATH
dans le contexte systemd
, à savoir dans le ou les fichiers Unit qui démarrent le ou les démons PHP-FPM, auquel cas PHP-FPM charge correctement l'extension OCI8.
Il va sans dire que nous souhaitons éviter de modifier le fichier du mainteneur du paquet (afin d'éviter les conflits lors de futures mises à niveau), nous l'étendons donc à la place:
# mkdir /etc/systemd/system/php7.1-fpm.service.d
# touch /etc/systemd/system/php7.1-fpm.service.d/environment.conf
A ce fichier, nous ajoutons les éléments suivants:
[Service]
Environment=LD_LIBRARY_PATH=/opt/Oracle/instantclient_12_2
Et pour que le changement soit effectif:
# systemctl daemon-reload
# systemctl restart php7.1-fpm
Pour un exemple plus complet, qui concerne plusieurs versions co-installées PHP, veuillez consulter mon message à l’adresse https://github.com/oerdnj/deb.sury.org/issues/865#issuecomment- 395441936 .
Tout d'abord, le bogue Debian 859732 est un problème complètement différent (je dirais même un problème opposé): pour ce bogue, plusieurs versions de la bibliothèque sont présentes dans le chemin de recherche (une dans un répertoire spécifié par LD_LIBRARY_PATH
un dans un répertoire spécifié par le chemin d’exécution), mais le mauvais est choisi par l’éditeur de liens dynamique.
Dans votre cas, le problème est que la bibliothèque demandée n’est trouvée nulle part dans le chemin de recherche. Notez également que dans votre cas, c’est PHP qui semble essayer d’ouvrir la bibliothèque (via dlopen
?), Car le message commence par "PHP Warning:". Cependant, il semble que les mécanismes soient les mêmes qu'avec les liens dynamiques habituels.
Après avoir installé la bibliothèque, vous avez besoin d'au moins l'un des éléments suivants:
dlopen
, le logiciel (ici, PHP) peut avoir mis en place ce que l’on peut appeler un "chemin de recherche de plug-in", dans lequel vous pouvez placer vos bibliothèques.LD_LIBRARY_PATH
. C’est ce que vous avez essayé, mais votre LD_LIBRARY_PATH
semble incorrect. Les bibliothèques sont généralement installées dans des sous-répertoires nommés lib
(ou lib32
ou lib64
dans des cas spécifiques). Donc, export LD_LIBRARY_PATH=/opt/Oracle/instantclient_12_2
semble faux. Recherchez le chemin complet de la bibliothèque oci8.so
et prenez simplement la partie répertoire de ce chemin pour LD_LIBRARY_PATH
.Remarque: strace
peut être utile pour connaître les répertoires pris en compte pour la recherche des bibliothèques. EDIT: ldd
et objdump -p
sont d’autres outils utiles pour trouver ce qui se passe dans les chemins de recherche.
EDIT 2: Un autre point à noter lorsque vous choisissez d'utiliser un chemin d'exécution est que des dépendances de bibliothèque indirectes sont trouvées lorsque RPATH
est utilisé, mais pas lorsque RUNPATH
est utilisé (donc, dans ce dernier cas, toutes les dépendances aussi devez avoir un chemin d’exécution s’ils dépendent d’autres bibliothèques afin que toutes les bibliothèques puissent être trouvées sans recourir à LD_LIBRARY_PATH
). Ceci est documenté dans les versions récentes de la page de manuel ld.so (8):
Utilisation des répertoires spécifiés dans l'attribut
DT_RUNPATH
dynamic section du fichier binaire, le cas échéant. Ces répertoires ne sont recherchés que pour rechercher les objets requis par les entréesDT_NEEDED
(dépendances directes) et ne s'appliquent pas aux enfants de ces objets, qui doivent eux-mêmes avoir leurs propres entréesDT_RUNPATH
. Ceci diffère deDT_RPATH
, qui est appliqué aux recherches pour tous les enfants de l'arbre de dépendance.
C'est probablement pourquoi, sans utiliser LD_LIBRARY_PATH
, cela fonctionnait avec 16.04 (où RPATH
est utilisé) mais pas avec 18.04 (où RUNPATH
est utilisé).