How to install PHP extension into cli

Oleksii Chekulaiev
Docksal Maintainers Blog
5 min readOct 16, 2019

--

Since the switch to official PHP images — which is better in the long run — installing PHP extensions became rather cumbersome. This is because, in most cases, you actually have to compile the extension from sources, first figuring out the dependencies and then using special utilities to do that inside the Docker image. It is not something the Docksal team wanted to impose on users, but rather a decision of the PHP team to make images better optimized for production environments.

Anyway, how does one install yet another extension? Let’s look at a real example here. Recently in the chat, someone has asked how to install mysql_xdevapi extension.

1. Getting sources

First, I need to check if I have the extension sources already available inside the image. I run a sample Docksal project with a PHP version needed, then inside the cli I run:

docker-php-ext-install

It will just print usage help, but in the background it will un-archive PHP source code into the /usr/src/php/ directory. I then check /usr/src/php/ext directory for the sources of the desired extension.

In my case, I used docksal/cli:2-php7.2. There were no sources of mysql_xdevapi extension inside the image, so I needed to download them first.

Since mysql_xdevapi is a PECL extension, I downloaded sources using PECL utility. Inside fin bash:

cd /tmp# Download sources
pecl download mysql_xdevapi
# Untar sources
tar xzf mysql_xdevapi-<version>.tgz
# Copy sources to the proper location where the compiler will find them
sudo cp /tmp/mysql_xdevapi-<version> /usr/src/php/ext/mysql_xdevapi

Now I have sources stored under the /usr/src/php/ext/mysql_xdevapi directory, where the installer will be looking for them (more on that in step 3).

2. Installing dependencies

If I try to compile extension at this point, I would probably encounter compilation errors.

This is normal! This is expected!

If this is the first time you are installing the extension, then there is no way around reading through the actual error output and figuring out what the issues are there and what is missing.

Or you could google “installing PHP extension <whatever>”, and chances are you will find the page that contains clues about the dependencies. In this case, I easily found the page https://www.php.net/manual/en/mysql-xdevapi.installation.php that shows which dependencies need to be installed.

There is no need to install php-* itself or build-essentials tools because base cli image already has them, so I just installed extension specific dependencies:

sudo apt install libprotobuf-dev libboost-dev openssl protobuf-compiler

Installing dependencies is probably the most complicated step. It may often take a long time figuring out all the required dependencies since it is a process of compiling the extension, reading through the error messages when it does not compile, and figuring out what else (WHAT ELSE?!?!) is needed…

At least we all have Google.

3. Compiling the extension

This step is rather easy, if you know the trick. To compile an extension inside the official Docker PHP image, you need to use docker-php-ext-install utility rather than just make. It compiles and installs the extension properly.

There is another trick. Just running sudo will not cut it; you will encounter the error at the end:

/usr/local/bin/docker-php-ext-enable: 108: /usr/local/bin/docker-php-ext-enable: cannot create /conf.d/docker-php-ext-mysql_xdevapi.ini: Directory nonexistent

This is because docker-php-ext-install runs docker-php-ext-enable at the end, but sudo does not inherit the environment by default, PHP_INI and other variables will be empty, and docker-php-ext-enable will look for conf.d/ in all the wrong location. So I need to use sudo -E to work around that.

sudo -E docker-php-ext-install mysql_xdevapi

Now I go brew a cup of tea or coffee or both, since it will take some time. But once it finishes, I am actually done. Let us do a final check that extension is compiled and loaded.

docker@cli:/tmp$ php -m
[PHP Modules]
apcu
bcmath
...
mbstring
memcached
mysql_xdevapi
mysqli
mysqlnd
openssl
...
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
blackfire

4. Creating your custom image for future use

Okay that was good, but you probably don’t really want to repeat all these steps in case you need to re-build cli for some reason, right?

Right. I will demonstrate how to pack all the things above into Dockerfile to extend the stock cli image, and use the resulting image in your project.

Basics of extending stock images are described in the documentation on extending stock images page, but actually scripting certain steps will require some knowledge.

.docksal/services/cli/Dockerfile

FROM docksal/cli:2-php7.2# Install dependencies
RUN apt-get install -y --no-install-recommends libboost-dev libprotobuf-dev openssl protobuf-compiler
# Get sources and put them in proper place
RUN mkdir -p /usr/src/php/ext && \
mkdir /tmp/mysql_xdevapi && \
cd /tmp && \
pecl download mysql_xdevapi && \
tar xf mysql_xdevapi-*.tgz -C mysql_xdevapi --strip-components 1 && \
mv ./mysql_xdevapi /usr/src/php/ext/ && \
rm /tmp/mysql_xdevapi-*.tgz
# Install the extension
RUN docker-php-ext-install mysql_xdevapi

Several points to note here: I had to create /usr/src/php/ext manually because, remember, inside the cli image, PHP sources are initially tar-gzipped, and only get un-archived when docker-php-ext-install is run first. But it has not run here yet, so I will create that dir manually because un-archived sources will not overwrite it, but rather append to it. Also it is worth mentioning that since everything is run as root, there is no need to use sudo.

.docksal/docksal.yml

version: "2.1"services:
cli:
image: ${COMPOSE_PROJECT_NAME_SAFE}_cli
build: services/cli

Nothing really special here.

Run fin project start , brew another couple of cups of coffee, and you will have your own image that you don’t need to re-create every time you need to reset cli in the project. Or commit it and share with a colleague, who would not need to run all those tedious steps manually.

--

--