Debugging is an essential task of software development in any programming language. Unfortunately, the out-of-the-box experience with debugging in PHP is not always great. The “stock” PHP binaries available at php.net do not come configured with either of the two popular debug servers Xdebug and Zend Debugger. Developers are required to do additional configuration to make debugging possible with their PHP stack. This can be a significant hurdle for developers who are new to PHP.
Alternatively, developers can use a professional PHP stack like Zend Server, which comes configured with both Xdebug and Zend Debugger.
Docker, a technology that’s all the rage these days, provides another possible solution – debug your PHP web app in a Docker container, created from a predefined image of a PHP stack with a debug server. These predefined images are available in the Docker Hub. Developers with basic understanding of Docker can use the technology to debug their PHP web apps without the need to know how to install and configure a debug server in their PHP stack.
Below is a comprehensive walkthrough of pulling an appropriate image from Docker Hub, running a container and then debugging PHP code on it. The walkthough uses the Zend Studio 13 Early Access, which introduces the new Docker Tooling.
Note. The scenario described is still possible with earlier versions of Zend Studio, but any Docker management operations would need to be executed in a command terminal.
1. Install the Docker Engine on the Operating System
The first prerequisite is to install and configure the Docker Engine. We need it to be able to pull images from Docker Hub and to run the container. The Docker web site provides a comprehensive installation guide for each operating system.
2. Install the Docker Support in Zend Studio
Once we have the Docker Engine installed, we need to have the Docker Tooling installed in Zend Studio. It is available as a an extra feature and can be found under the Enhancements category on the Welcome screen.
After restarting Zend Studio, we can switch to the Docker Tooling perspective. This new perspective has several views for managing Docker images and containers:
- Docker Explorer – view for creating/managing connections to Docker daemons
- Docker Images – view for managing Docker images
- Docker Containers – view for managing Docker containers
3. Connect the Docker Tooling to the Docker Daemon
Clicking on the link inside the Docker Explorer view launches the wizard for creating new Docker connection. The default settings may work in some cases, especially on Linux. So, it is worth clicking first on the Test Connection button. If the test fails then custom configuration must be provided.
On Windows and Mac OS X where boot2docker is used the TCP connection configuration must be provided. The Docker host and certificates path can be found in the boot2docker console.
On Linux the Unix socket configuration must be provided. The location of the socket is usually unix:///var/run/docker.sock.
Clicking again on the Test Connection button should result in a “Success” message. Clicking on the Finish button will establish the connection to the Docker daemon and will display it in the Docker Explorer view.
4. Pull an Image from Docker Hub
Now we need to pull an image from Docker Hub. We will use the tommylau/xdebug image, which has Apache HTTP Server, PHP and Xdebug inside. This can be done using the Pull Image tool button in the Docker Images view. It will display the Pull Image dialog where we need to enter “tommylau/xdebug” in the Name field. Clicking the Finish button will pull the image to the local machine. The image is quite large, so this operation can take a while. When done, the new image will be displayed in the Docker Explorer and Docker Images views.
5. Run a Docker Container from the Image
We have the Docker image on our local system. Now we need to launch a Docker container out of it and map the HTTP port of the container’s Apache server to a port on our local system. We also need to map the document root of the container’s Apache server to a folder on the local system. These mappings are essential for debugging PHP code on the Docker container.
Creating a container is done by selecting the tommylau/xdebug image in the Docker Image view and then clicking on the Run Image tool button. There are a couple of important settings we need to do in the wizard that will pop up:
- Map the HTTP port of the container’s Apache server to a port on our local system:
- Deselect the “Publish all exposed ports to random ports on the host interfaces” checkbox.
- (Don’t miss this one!) Select the checkbox of the first row in the table below (Container Port 80).
- Click on the Edit… button
- Set the Host Port to some free port on the local machine, e.g. 8080.
- Click the OK button to close the Exposing a Container Port dialog.
- Map the document root of the container’s Apache server to a folder on the local system:
- Click on the Next button to advance to the second wizard page.
- Click on the Add button of the Data Volumes group.
- Enter “/var/www/html” as Container Path.
- Select the “Mount a host directory or host file” radio box.
- Click on the Directory button and browse some empty directory on the local file system, e.g. /home/raev/www
- Click on the OK button to close Data Volume dialog.
- (Don’t miss this one!) Select the checkbox of the newly added data volume in the table.
We can test if the container is working by requesting the HTTP port of the container we mapped to the local system, i.e. requesting http://localhost:8080 in a web browser. The browser should display a “Forbidden” page. This is OK because this is how the Apache server is configured in the Docker image we used. This error is actually a proof that the web browser requested the Apache server running in our Docker container. Additional access logs are printed in the Console view.
6. Configure a PHP Server to Represent the Docker Container
Now we need to configure the PHP tooling in Zend Studio to run and debug PHP code in the our Docker container. The PHP tooling uses the abstraction of PHP Servers as the environment of deploying, running and debugging PHP code. Therefore, we need to create a new PHP Server entity in Zend Studio that represents our Docker container. So, we need to switch to the PHP perspective and click the Add tool button on the PHP Servers view. In the PHP Server Creation wizard we have to select the Generic PHP Server view and make the following settings on the next wizard page:
- Give some name in the Server Name field, e.g. “Docker Xdebug”.
- Set the Base URL to “http://<host>:<port>” where:
- <host> is the host where the Docker Engine is running. On Linux it is localhost. On Windows and Mac OS X where boot2docker is used it is the IP displayed in the DOCKER_HOST environment variable, usually 192.168.59.103.
- <port> is the port we used to map the container’s HTTP port to the local system, e.g. we use 8080 in this tutorial.
- Set the Document Root to the folder we used to map the container’s document root to the local file system.
On the next wizard page, we must configure the debugger settings of the server. Select “XDebug” in the Debugger drop-down list. We choose this option because the Docker image we pulled from Docker Hub has Xdebug preconfigured. If we use another image where Zend Debugger is preconfigured then we should choose the “Zend Debugger” option, or “<none>” in case the image has no PHP debug server preconfigured. Clicking on the Finish button creates the new PHP server and displays it in the PHP Servers view.
7. Create a PHP Project with Some Code
Now, let’s create some PHP code! We need a new project. It can be created by calling New > File > Local PHP Project from the main menu. In the displayed wizard we must make sure that the project is targeted on the PHP server we’ve just created and the project’s location points to the PHP server’s document root.
After creating the project we can place some code in the index.php file. Even a simple printing of “Hello World!” would be enough.
8. Debug It!
Now let’s debug it. Right-clicking on the index.php file and choosing Debug As > PHP Web Application will request the web application in the Zend Studio internal browser and will connect the Zend Studio debug client to the Xdebug server running in the Docker container. You can see the execution breaks on the first line of index.php and a dialog pops up to propose switching to the Debug perspective.
We can call this a success!
In this article we have seen how we can use predefined Docker images to setup complex PHP stack environments and use Zend Studio and its new Docker support to develop, run and debug PHP code on them.
Note. You can also use the zend/php-zendserver Docker image that comes with a completely installed and configured Zend Server.