I won’t do PHP for love or money. Since it’s known that I’m a Software Person, friends and relatives will occasionally ask for help with some random issues and I’m always happy to take a swing at it. To take some of the pain out of it, I have a docker-compose setup that makes it easy to run PHP without polluting my laptop with a lot of dependencies.

Basic Setup

Obviously, you’ll need to have Docker installed.

Presuming you have a directory with your PHP scripts and any supporting HTML, CSS, assets, etc, you’ll need a docker-compose.yml file and possibly a Dockerfile.

If you just need to run a script with no dependencies

Create the following docker-compose.yml file:

1
2
3
4
5
6
7
8
9
10
11
version: "3.8"

services:
  php:
    image: php:7.2-apache
    stdin_open: true
    tty: true
    ports:
      - "80:80"
    volumes:
      - .:/var/www/html/

Run docker-compose up. That’s it, you can now connect to http://localhost/, if your entry point is index.php or index.html. Otherwise, you can connect to http://localhost/filename.php (or filename.html if your working with a form). Edit, test, repeat. When you’re done, just hit Control-C.

If you need additional PHP Extensions

The PHP Docker image ships with a fair number of extensions preinstalled and enabled. You can see the out of the box configuration with:

1
docker-compose run php php -i

(The first php is the name of the service, the second is the start of the command.)

However, some extensions, typically ones that require additional libraries are not installed by default. In this case, you’ll need a Dockerfile to install dependencies and enabled the extension. For example, let’s install the PHP GD Image Processing extension.

Dockerfile:

1
2
3
4
5
6
7
FROM php:7.2-apache
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev zlib1g-dev git zip
RUN docker-php-ext-configure gd \
        --with-png-dir=/usr/include \
        --with-jpeg-dir=/usr/include \
    && docker-php-ext-install gd \
    && docker-php-ext-enable gd

The Dockerfile does the following:

  • FROM php:7.2-apache - start with the PHP 7.2 image, anything after will be layered on that.
  • RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev zlib1g-dev git zip - install the required dependencies to build the GD extension.
  • RUN docker-php-ext-configure gd [...] - Configure, build, and enable the GD extension.

Obviously, your dependencies and the arguments to docker-php-ext-* will vary with the extension you are installing, but a little searching should fine you the right invocation.

Once the Dockerfile is setup, update docker-compose.yml to us it by changing:

1
image: php:7.2-apache

to:

1
build: .

Now run docker-compose build followed by docker-compose up. The build step is only needed when the Dockerfile changes.

If you just need to install dependencies with Composer

Composer is a PHP dependency manager for installing packages. For example, I’ve used it to install PHPMailer. Again, you will need a Dockerfile:

1
2
3
4
5
6
7
8
9
FROM php:7.2-apache

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

COPY . /var/www/html
WORKDIR /var/www/html

RUN composer require phpmailer/phpmailer
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"

Walking through this:

  • FROM php:7.2-apache - again, start with the PHP 7.2 image an layer on top of that.
  • COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer install Composer from the composer Docker image.
  • COPY . /var/www/html and WORKDIR /var/www/html - copy all of our files to /var/www/html and, in effect, cd there. This insures Composer will install packages in the right place and find it’s config, if any.
  • RUN composer require phpmailer/phpmailer - Install the package.
  • ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}" - Insure that any executables installed by Composer will be found.

Composer can optionally read a composer.json for a list of dependencies. If you have one of those, you would call composer install instead of using the require command above.

Again docker-compose build and docker-compose up get you going.

Need both?

If you need to enable extensions and install packages, simply put both in the Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM php:7.2-apache
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev zlib1g-dev libfreetype6-dev git zip

RUN docker-php-ext-configure gd \
        --with-png-dir=/usr/include \
        --with-jpeg-dir=/usr/include \
    && docker-php-ext-install gd \
    && docker-php-ext-enable gd

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer

COPY . /var/www/html
WORKDIR /var/www/html

RUN composer require phpmailer/phpmailer
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"

Infrastructure

Once you need databases or other services, you’ve gone beyond a small favor. Still, it happens… You’ll need to add the additional infrastructure to the docker-compose.yml file. Here’s an example for PostgreSQL and Redis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: "3.8"

services:
  php:
    image: php:7.2-apache
    stdin_open: true
    environment:
      - DATABASE_URL=postgres://postgres@database
      - REDIS_URL=redis://redis:6379/1
    tty: true
    ports:
      - "80:80"
    volumes:
      - .:/var/www/html/

  database:
    image: postgres
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust
    volumes:
      - db_data:/var/lib/postgresql/data

  redis:
    image: redis

volumes:
  db_data:

This sets up Docker containers running Postgres and Redis which can be accessed using the hostnames postgres and redis respectively. Using the environment section of the PHP host, I’ve injected the connection strings. How you’d use/configure them is, of course, totally dependent on your code.

This example doesn’t use a Dockerfile, but it could. Doing so is left as an exercise to the reader.

Docker Cheat Sheet

Finally, a few handy commands to help you get by.

  • docker-compose ps - See what’s running
  • docker-compose stop - Shut it down. Same as hitting Control-C in the window you ran start in.
  • docker-compose exec php bash - Get a shell on the running PHP container.
  • docker-compose run php bash - Start a PHP container and get a shell. Shuts down when you exit.

Hopefully, this will make it a little easier when you want to help a friend with their PHP adventures!

Comments