This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Set up PHP With Docker, PHPStorm, and XDebug

Description

Until now, PHP debugging involved a fragile balance between the IDE, the server, and the debugger, each with overly verbose configuration. On top of that, using Docker introduced the wrinkle that you were technically debugging on a remote server rather than on the "real" localhost. It's been a long journey, but it's finally a <i>lot</i> easier to set up PHP debugging with a server running in a Docker container. Once you use the most modern tools, everything works with a couple of lines of configuration. <abstract><abbr title="too long; didn't read">tl;dr</abbr>: <ul> Ignore anything you find on StackOverflow from before November of 2020 and use <a href="https://github.com/mlocati/docker-php-extension-installer">the install-php-extensions project</a> instead (see example below). Set environment variables in the docker-compose file to indicate the client and the default mode (debug) Use the latest PHPStorm, which supports XDebug 3.x </ul></abstract> My setup is as follows: <ul> PHPStorm 2020.3.1 running on MacOS Docker 3.0.4 running on MacOS "db" container running MySql 5.7.24 "web" container running PHP 7.2.24 on Apache </ul> So far, so good: it's basically a standard developer setup for PHP where I have an IDE on my machine and am running servers in Docker containers. XDebug initiates a connection from the server in the "web" container back to the IDE on the docker host. Without further ado, these are the magic configuration files to install extensions and set up XDebug for PHP. <h>web/Dockerfile</h> After much searching and rigamarole and fighting with <c>docker-php-ext-install</c> and <c>docker-php-ext-enable</c> and <c>PECL</c> and where the <c>PHP.INI</c> is and whether I need to move one of the default files somewhere so that PECL can update it and downloading dependencies with <c>apt-get</c> and getting the right dependencies, depending on the PHP version and passing the right flags to <c>docker-php-ext-configure</c> if the version is a bit older and, and, and... After trying a ton of no-longer-relevant and now-overly-complex suggestions on StackOverflow, I finally returned to <a href="https://hub.docker.com/_/php/">php on dockerhub</a> and discovered a hint to use <a href="https://github.com/mlocati/docker-php-extension-installer">the install-php-extensions project</a>, which basically takes care of everything for you. It does. End of story. <code> FROM php:7.2.24-apache ENV DEBIAN_FRONTEND=noninteractive ADD https://github.com/mlocati/docker-php-extension-installer/releases/ latest/download/install-php-extensions /usr/local/bin/ RUN chmod +x /usr/local/bin/install-php-extensions && sync && \ install-php-extensions gd xdebug mysqli exif zip </code> I pin the PHP version to the one on my server, download the latest version of <c>install-php-extensions</c><fn> and then call it to install the non-standard extensions I use on earthli: <ul> <c>exif</c>: Extract date information from pictures <c>gd</c>: Generate thumbnails <c>mysqli</c>: Provide access to MySql using a legacy API <c>xdebug</c>: Debugging support on the server <c>zip</c>: Open and read files from ZIP archives </ul> See the <a href="https://github.com/mlocati/docker-php-extension-installer">web site</a> for the list of supported packages. Your site will likely use different ones (but you should definitely install <c>xdebug</c> because it's totally easy to use now). <h>docker-compose.yaml</h> Finally, you just need to set two environment variables to enable debugging for PHP: <ul> <c>XDEBUG_CONFIG</c>: accepts a list of settings, but we only need to set the <c>client_host</c> to tell XDebug which machine hosts the IDE to which to connect (Docker handily provides the <c>host.docker.internal</c> alias for MacOS and Windows) <c>XDEBUG_MODE</c>: this sets up the tool for step-debugging (see <a href="https://xdebug.org/docs/all_settings#mode">XDEBUG mode</a> for more information). </ul> I've included nearly the full <c>Dockerfile</c> from earthli, but the only relevant part for debugging is in the <c>environment</c>. <code> web: build: web container_name: "${COMPOSE_PROJECT_NAME}-web" restart: unless-stopped ports: - 80:80 volumes: - ../site:/var/www/html - ../lib:/var/tmp/earthli.com-lib - ../../earthli-webcore/site:/var/tmp/webcore-site - ../../earthli-webcore/lib:/var/tmp/webcore-lib - ../../earthli-data:/var/tmp/earthli-data - ../../earthli-logs:/var/tmp/logs - ../config/apache-dev.conf:/etc/apache2/sites-available/000-default.conf depends_on: - db environment: XDEBUG_CONFIG: client_host=host.docker.internal XDEBUG_MODE: debug </code> <h>PHPStorm and Browser</h> At this point, you're well on your way to debugging with PHPStorm. From here, follow the instructions in the settings dialog, shown below. <img src="{att_link}phpstormdebugsettings.png" href="{att_link}phpstormdebugsettings.png" align="none" caption="PHPStorm Debug Settings" scale="35%"> <ul> You can click the "Validate" link in the dialog to verify that your XDebug is recognized and working in principle Activate step debugging from the browser. You can pass <c>XDEBUG_SESSION=PHPSTORM</c> in the query string, but that gets a bit tedious. Instead, <a href="https://www.jetbrains.com/help/phpstorm/2020.3/browser-debugging-extensions.html?utm_source=product&utm_medium=link&utm_campaign=PS&utm_content=2020.3">install a browser-debugging extension</a>, which simply injects the cookie <c>XDEBUG_SESSION=PHPSTORM</c> into the request so that PHPStorm knows that debugging is desired. See <a href="https://xdebug.org/docs/step_debug">XDebug's documentation</a> for more information on other ways of triggering debugging, including from the command line (e.g. when running unit tests). Make sure PHPStorm is listening for incoming PHP Debug Connections (you can toggle in the dialog shown above or from the toolbar in the IDE). </ul> That's it. A long and kind of painful journey has finally led to a solid and easy-to-configure debugging experience for PHP. <hr> <ft>I will probably pin the version to the one I'm using <i>right now</i> because I know it works.</ft>