私は最新のPHPパッケージを https://launchpad.net/~ondrej/+archive/ubuntu/php から入手できます)を使用しています。
OCI8拡張機能をビルドしてインストールすると、すべてが正常に表示されますが、PHP-FPM構成で拡張機能を有効にしているにもかかわらず、その存在はphpinfo()
からの出力に反映されません。
次の要点は、OCI8 PHP拡張機能の構成、ビルド、およびインストールに使用している正確なプロセスの詳細です。
https://Gist.github.com/cbj4074/fa761f60b6f8db431539d76ebfba828e
まったく同じプロセスと構成がUbuntu16.04 LTSで完全に機能するため、オペレーティングシステムでも、問題のPHPパッケージでも)、Ubuntu 18.04LTSにはいくつかの根本的な違いがあるようです。
少し重要な(そしてこの問題に関連していると思われる)背景情報として、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
_
PHP-FPM環境構成に_LD_LIBRARY_PATH
_を追加すると、同等の問題が解決する可能性があると思いました。
_# 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
_値がphpinfo()
のEnvironment
セクションの両方に反映されます(PHP-FPM + NGINXを介してレンダリングされ、ブラウザーから要求された場合) )および_PHP Variables
_セクション(_$_SERVER['LD_LIBRARY_PATH']
_)。
奇妙なことに、PHP-FPMのログがdebug
に設定されていても、CLIで発生する_libmql1.so
_エラーの痕跡は見られません。 OCI8拡張機能は、サイレントにロードに失敗するだけです。 PHPの_display_startup_errors = On
_- 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 に関するコメントに基づくと、 Ubuntu17.10およびUbuntu18.04LTSで変更されました。
特にUbuntu18.04 LTSで、他の誰かがこれを試しましたか?
_laravel/Homestead
_ボックス6.0.0と_ubuntu/bionic64
_ボックスv20180509.0.0の2つの異なるVagrant VMでこれを試しましたが、動作はどちらも同じです。
他のアイデアは大歓迎です!
編集1:
パッケージメンテナーのGitHubトラッカーでこの問題について質問しました そして彼は、問題はコンパイル時に適切なRPATH
を設定できなかったことが原因であると示唆しました。
私はamが適切な値を設定していると返信で説明していますが、問題は解決されていません。
ただし、Ubuntu18.04でコンパイルされた拡張機能がRUNPATH
を使用している(Ubuntu16.04で使用されているRPATH
ではない)という興味深い詳細に気づきました。 PHP-FPMがRUNPATH
を無視し、RPATH
のみを検索する場合、この動作を説明します。
編集2:
このまだ開かれているレポートは、観察された動作を紹介した優れた候補のように見えます。
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=859732
( RUNPATHではなくRPATHを使用しますか? に関するコメントを通じて発見されました)
編集3:
コメント提供者のアドバイスにより、拡張機能をビルドする前にld
構成を更新することを再検討したところ、問題は解決しました。私は以前にこれを試しましたが、ビルドの試行の間に何かを見落としていたに違いありません。
_# echo /opt/Oracle/instantclient_12_2 > /etc/ld.so.conf.d/Oracle-instantclient.conf
# ldconfig
_
_LD_LIBRARY_PATH
_がこの場合のように機能しない理由はまだわかりませんが、リンカー構成にインスタントクライアントライブラリパスを追加する方が良いアプローチのようです。
編集4:
以前の編集で、ldconfig
を変更する方が良いアプローチであると述べましたが、影響はシステム全体に及ぶため、変更すると望ましくないライブラリの競合が発生する可能性があることに気付きました(コメント投稿者の良いアドバイスに基づいて)。
後から考えると、ランタイムライブラリリンケージの変更による「巻き添え被害」を_LD_LIBRARY_PATH
_を介して実行環境に限定することで最小限に抑えることは理にかなっています。したがって、Ubuntu 18.04LTSでこれが機能しない理由を特定することに意欲的です。
PHP-FPMデーモンがUbuntuの_LD_LIBRARY_PATH
_を無視することを明確に確立したと感じています(少なくともUbuntu 16.04 LTSがあります。説明についてはコメントを参照してください)。
ld.so(8)
マンページの状態(ランタイムライブラリパスが検索される順序に関連して):
環境変数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
_ 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-FPMは_LD_LIBRARY_PATH
_を無視するのでしょうか。
編集5(解決策):
鋭敏なコメント投稿者@ vinc17は、systemd
を実行しているシステムでは、_LD_LIBRARY_PATH
_などの環境変数が必ずしもsystemd
ユニットを介して開始されるプロセスに伝播されるとは限らないと指摘しています。 。
言い換えれば、PHP-FPMは_LD_LIBRARY_PATH
_を「無視」しているのではなく、プロセスに伝達されていません。また、PHP-FPM構成内で_LD_LIBRARY_PATH
_を設定しようとしても、値を使用して有用なことを行うには遅すぎるため、無駄です。
このアドバイスで、_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
で指定されたディレクトリに1つあります)。実行パスで指定されたディレクトリに別のものがあります)が、ダイナミックリンカーによって間違ったものが選択されています。
あなたの場合、問題は、要求されたライブラリが検索パスのどこにも見つからないことです。あなたの場合、メッセージがで始まるので、ライブラリを開こうとしているように見えるのは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
は、ライブラリを検索するために考慮されるディレクトリを確認するのに役立つ場合があります。 EDIT:ldd
とobjdump -p
は、検索パスで何が起こっているかを見つけるための他の便利なツールです。
編集2:実行パスの使用を選択する際のもう1つの注意点は、RPATH
を使用すると、間接的なライブラリの依存関係が見つかることです。 RUNPATH
が使用されている場合ではありません(したがって、後者の場合、すべての依存関係alsoが他のライブラリに依存している場合は、すべてのライブラリが実行できるように実行パスが必要です。 LD_LIBRARY_PATH
に頼らずに見つけられます)。これは、ld.so(8)のマニュアルページの最近のバージョンに記載されています。
バイナリの
DT_RUNPATH
動的セクション属性で指定されているディレクトリが存在する場合はそれを使用します。このようなディレクトリは、DT_NEEDED
(直接依存関係)エントリに必要なオブジェクトを見つけるためにのみ検索され、独自のDT_RUNPATH
エントリが必要なオブジェクトの子には適用されません。これは、依存関係ツリー内のすべての子の検索に適用されるDT_RPATH
とは異なります。
これがおそらく、LD_LIBRARY_PATH
を使用せずに、16.04(RPATH
が使用される)では機能したが、18.04(RUNPATH
が使用される)では機能しなかった理由です。