Developing a Local addon – 02

More discovery and container games and a first version.

Previously

I’ve presented, in the article preceding this one, my convoluted way to start developing an add-on for Local, a free xAMP alternative and the evolution of PressMatic.
In my first installment, I’ve tried to detail, following my understanding, the technology stack below it and found a way to interact with it.
My current objective is to develop an add-on that will allow me, from Local UI, to enable and disable XDebug on the machine hosting the site, and to set some relevant XDebug fields.
Being a WordPress backend developer the environment variable based approach will simply not work.

A simple first operation

Before I delve into my tentative React code for the add-on it’s worth spending some time understanding what is happening on a Docker container level when I enable or disable XDebug or set some settings.
In the simplest example if I want to enable XDebug for a site managed by Local this is what will happen:

  1. check whether XDebug is active on the site already or not
  2. if not update the entry, in the current PHP version configuration file the site is using, that reads zend_extension=...xdegbug.so to ;zend_extension=...xdebug.so
  3. restart the PHP service to make sure the updated PHP configuration is parsed and read
  4. check whether XDebug is now really active or not on the site and update some UI to show it

Bullet point 2 is the way I handle enabling and disabling XDebug on any machine and system I work on; commenting out, ; at the start of the line represents a comment in the context of .ini file, the line that indicates the extension to load will prevent that extension from being loaded.
While this is a rather simple operation doing it through a UI that talks to a virtual machine that then issues a command to a Docker container might prove a little more challenging.
So: how would I do this had I to do it using the terminal?

Enabling XDebug using the terminal

I’ve shown, in my first post, this first operation exactly but it’s worth repeating for the sake of continuity:

ssh -i ~/.docker/machine/machines/local-by-flywheel/id_rsa docker@192.168.94.100

Now use the docker ps command and find the container that is running the site:

docker ps

Provided a list of currently running containers I find the id of the container to be fa6541c8e5c1; this time, in place of logging into the container, I will run the command from outside of it using docker exec.
My site is currently running PHP version 7.1.4 so, as I found out while writing the first article, the first step is finding that PHP version executable file with the command:

docker exec fa6541c8e5c1 find / -name php | grep bin | grep 7.1.4

Which yields /opt/php/7.1.4/bin/php.
What I’ve done there is: 1. execute a command in the fa6541c8e5c1 container using docker exec fa6541c8e5c1 2. the first command, find / -name php, means “find, starting from the / root folder, any file whose name is php” 3. the output of that command, a newline separated list of files containing php in the name is filtered using grep bin to reduce the list to only those lines that contain bin 4. now reduce the list again to only those lines, hopefully, one, that contains 7.1.4

To check whether XDebug is active or not on the site the only really reliable way is not to check in the PHP initialization file (php.ini) neither in the output of the php --version command, instead [the phpinfo() function] is my friend here.
Specifically, I will check that the function output HTML contains the with XDebug string; this is the page output, rendered by the browser when XDebug is active:

And this is the same output when XDebug is not active:

Each site managed by Local will provide a /local-phpinfo.php file that can be hit to gather the PHP information.
The reason this is a more reliable way to get the XDebug status is that the request will hit the web-server before hitting the PHP executable as a service. While XDebug might be active or inactive for the PHP executable the CGI PHP service needs to be restarted for any configuration change to take place.
The way I will detect whether the XDebug extension is active or not will, then, consist of getting the HTML output of the localhost/local-phpinfo.php and looking for the Xdebug string;

docker exec fa6541c8e5c1 wget -qO- localhost/local-phpinfo.php | grep Xdebug

So get, using the wget command, the output of localhost/local-phpinfo.php route and then see if there is a line containing Xdebug. The output will be empty if XDebug is inactive or something like this if XDebug is active:

This program makes use of the Zend Scripting Language Engine:<br />Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies<br />    with Zend OPcache v7.1.4, Copyright (c) 1999-2017, by Zend Technologies<br />    with Xdebug v2.5.3, Copyright (c) 2002-2017, by Derick Rethans<br /></td></tr>

Supposing XDebug is not active then to activate it I will uncomment the relevant zend_extension entry.
Before that I need to know the path to the PHP version ini file; to do that I will use the php_ini_loaded_file function:

docker exec fa6541c8e5c1 /opt/php/7.1.4/bin/php -r "echo php_ini_loaded_file();"

The command will output /conf/php/7.1.4/php.ini.
Now that I know the path to the relevant PHP version initialiazation file I can uncomment the extension entry if needed:

docker exec fa6541c8e5c1 sed -i '/^;zend_extension.*xdebug.so/ s/;zend_ex/zend_ex/' /conf/php/7.1.4/php.ini

In plain english terms it means: “find the line, in the file /conf/php/7.1.4/php.ini, that contains ;zend_extension=...xdebug.so and remove the ; if found”. The final step is restarting the PHP service; in the specific case of PHP version 7.1.4 this means using Ubuntu service manager to do so:

docker exec fa6541c8e5c1 service php-7.1.4-fpm restart 

Putting it all together in a first version

I will delve, next time, into the actual translation in React code of the addon.
For the time being my need for the addon surpassed my chronicling of it so here is a first version of the add-on.
Here is the main screen just to convey the idea: