PHP Deployments: cannot open shared object file: no such file or directory
This post will cover “cannot open shared object file: no such file or directory” messages seen at startup for PHP applications.
Prerequisites
IMPORTANT: Make sure App Service Logs are enabled first. You can then view logging in a few different ways:
- LogStream
- Retrieving logs directly from the Kudu site, or directly view/download via an FTP client
- Diagnose and Solve Problems -> Application Logs detector, Container Crash detector, or Container Issues detector
If App Service Logs are not enabled, only docker.log
files will be generated, which will not show application related stdout / stderr and will make troubleshooting issues more complicated.
Overview
Sometimes, certain PHP packages may rely on “shared object files” (.so
extension files) thay may not be present in the current environment - on PHP with App Service Linux, that environment would be a Debian-based Docker Container. This may look something like this:
cannot open shared object file: no such file or directory) /usr/local/lib/php/extensions/no-debug-non-zts-20200930/opache.so
Or
PHP Startup: Unable to load dynamic library '/home/site/ext/rdkafka-6.0.3/rdkafka.so' (tried: /home/site/ext/rdkafka-6.0.3/rdkafka.so (/home/site/ext/rdkafka-6.0.3/rdkafka.so: cannot open shared object file: No such file or directory), /usr/local/lib/php/extensions/no-debug-non-zts-20220829//home/site/ext/rdkafka-6.0.3/rdkafka.so.so (/usr/local/lib/php/extensions/no-debug-non-zts-20220829//home/site/ext/rdkafka-6.0.3/rdkafka.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
The message about which .so
file is not present will depend on your application. Below is some reasons why this may appear and how to resolve them.
Reasons
Bad syntax or misconfigured .ini file
Assuming that you know the extension you need to install, but it is failing with the above message, it is likely to be one of these scenarios:
- Following the
PHP_INI_SCAN_DIR
App Setting (documentation), you may have created a custom.ini
file with theextension=
property pointing to the wrong.so
location. Example:/home/site/ext/libgomp/modules/libgomp.so
is the full path that contains a needed.so
- However, your
.ini
is pointing to/home/site/libgomp/libgomp.so
- The location name may have been mispelled
- There may be a syntax error in your path
- If using a custom startup script, the package may be failing to install
Pecl:
If installing via Pecl - this may install to directories outside of /home
. If you then have your .ini
pointing to an .so
, eg., simply extension=mysharedlib.so
- this would obviously likely fail:
-
- Because of the path difference locations and the possibility this does not fall under one of the paths that PHP tries to use for dynamic libraries
-
- After any container restart, changes outside of
/home
are reverted
- After any container restart, changes outside of
You can validate where Pecl will install extensions with the pear config-show
command and looking at the ext_dir
column with PEAR extension directory
.
root@b37f5b3aca46:/home# pear config-show
Configuration (channel pear.php.net):
=====================================
Auto-discover new Channels auto_discover 0
Default Channel default_channel pear.php.net
HTTP Proxy Server Address http_proxy <not set>
PEAR server [DEPRECATED] master_server pear.php.net
Default Channel Mirror preferred_mirror pear.php.net
Remote Configuration File remote_config <not set>
PEAR executables directory bin_dir /usr/local/bin
PEAR documentation directory doc_dir /usr/local/lib/php/doc
PHP extension directory ext_dir /usr/local/lib/php/extensions/no-debug-non-zts-20220829
PEAR directory php_dir /usr/local/lib/php
If installing extensions this way, ensure to copy the contents from ` /usr/local/lib/php/extensions/no-debug-non-zts-yyymmdd to
/home/site/ext` (or your relevant extension direcotry), for example:
cp /usr/local/lib/php/extensions/no-debug-non-zts-20220829/rdkafka.so /home/site/ext
NOTE: If you’re manually uploading .gz
packages from Pecl, or, their extracted contents, ensure that if these are being manually built with phpize
/ ./config
/ ./make
- that these properly build. Packages that are incorrectly built, or fail to build, may show the same Unable to load dynamic library
message.
Additionally, attempting to use a Shared Library that is not compatible with the application package (eg., a package under vendor/
) may also show Unable to load dynamic library
.
Missing packages
Aside from the potential of a misconfiguration - there may be a chance that the PHP libraries being used may rely on .so
files that can be installed through a Custom Startup Script instead of configuring it as an PHP extension.
NOTE: In some cases, you may have to use both a configured PHP extension and also install commands via custom startup file/script - this however depends on the application and packages being used
This will require reviewing which .so
package is missing and seeing which Linux packages need to be installed on startup to resolve this. Typically, doing a quick google search of the missing .so
file will normally show which package(s) need to be installed.
An an example of a startup command could just be:
apt-get install -y librdkafka-dev
Or a startup file:
#!/bin/bash
apt-get install -y librdkafka-dev
Note that, in either case, for a PHP image using Apache or NGINX - we don’t need to explicitly invoke any apache
or nginx
commands as they’re implicitly ran to start after the startup command or file is done.
Further resources
These below resources can help properly set up installing PHP extensions.
- Configure PHP applications - Customize php.ini settings
- Pecl - PHP extension repository
- Pecl can be used as a simple way to find and install extensions
-
You can use the
php -m
command to view the currently loaded modules. Below is example output:root@2a4e1b76038d:/home# php -m [PHP Modules] bcmath calendar Core ctype curl date dom exif fileinfo filter ftp ... more modules ...
-
You can use the
php -i | grep ini
command to view all the.ini's
currently loaded. For example:root@2a4e1b76038d:/home# php -i | grep ini Configuration File (php.ini) Path => /usr/local/etc/php Scan this dir for additional .ini files => /usr/local/etc/php/conf.d Additional .ini files parsed => /usr/local/etc/php/conf.d/20-sqlsrv.ini, /usr/local/etc/php/conf.d/30-pdo_sqlsrv.ini, /usr/local/etc/php/conf.d/docker-php-ext-bcmath.ini, /usr/local/etc/php/conf.d/docker-php-ext-calendar.ini, /usr/local/etc/php/conf.d/docker-php-ext-exif.ini, /usr/local/etc/php/conf.d/docker-php-ext-gd.ini, /usr/local/etc/php/conf.d/docker-php-ext-gettext.ini, ...more inis...
- Lastly, creating a
.php
page with aphpinfo()
function in it can potentially be helpful for additional information on loaded extensions.