Upgrading to PHP 7.3 on Ubuntu Bionic 18.04 LTS

Ubuntu 18.04 ships with PHP 7.2 by default but there are various reasons why you may wish to upgrade to newer versions. For example, active support for it ends later this year – far sooner than the 2023 support window for the OS.

In addition, applications will be released that will require newer versions in that 2018 – 2023 window. For IXP Manager, we are releasing v5 this month and mandating PHP 7.3 support. We do this to stay current and to prevent developer apathy – insisting on legacy frameworks and packages that have been EOL’d provides a major stumbling block for bringing on new developers and contributors. There’s also a real opportunity cost – I have a couple free hours, will I work on project A or project B? If project A uses an old stale toolchain where everything is that much more awkward that project B then which would you choose?

So, from a typical LAMP stack install of Ubuntu 18.04, you’ll find something like the following packages for PHP:

root@ubuntu:/var/www/html# dpkg -l | grep php | cut - -b 1-65
 ii  libapache2-mod-php                    1:7.2+60ubuntu1
 ii  libapache2-mod-php7.2                 7.2.17-0ubuntu0.18.04.1
 ii  php-common                            1:60ubuntu1
 ii  php-mysql                             1:7.2+60ubuntu1
 ii  php7.2-cli                            7.2.17-0ubuntu0.18.04.1
 ii  php7.2-common                         7.2.17-0ubuntu0.18.04.1
 ii  php7.2-json                           7.2.17-0ubuntu0.18.04.1
 ii  php7.2-mysql                          7.2.17-0ubuntu0.18.04.1
 ii  php7.2-opcache                        7.2.17-0ubuntu0.18.04.1
 ii  php7.2-readline                       7.2.17-0ubuntu0.18.04.1

Obviously your exact list will vary depending on what you installed. I find the easiest way to upgrade is to start by removing all installed PHP packages. Based on the above:

dpkg -r libapache2-mod-php libapache2-mod-php7.2 php-common   \
  php-mysql php7.2-cli php7.2-common php7.2-json php7.2-mysql \
  php7.2-opcache php7.2-readline

The goto place for current versions of PHP on Ubuntu is Ondřej Surý’s PPA (Personal Package Archive). Ondřej maintains this in his own time so don’t be afraid to tip him here.

It’s easy to add this to 18.04 as follows:

add-apt-repository ppa:ondrej/php
apt-get update

Then install the PHP 7.3 packages you want / need. For example we can just take the package removal line above and install the 7.3 equivalents with:

apt install libapache2-mod-php libapache2-mod-php7.3 php-common \
    php-mysql php7.3-cli php7.3-common php7.3-json php7.3-mysql \
    php7.3-opcache php7.3-readline

And voilà:

php -v
 PHP 7.3.5-1+ubuntu18.04.1+deb.sury.org+1 (cli) (built: May  3 2019 10:00:24) ( NTS )

One post-installation check is to replicate and custom php.ini changes you may have made (max upload size, max post size, max memory usage, etc.).

Migrating Legacy Web Applications to Laravel

I gave a talk on migrating legacy web applications to Laravel at last year’s Laravel Live UK conference in London. Those that rated it gave it high marks which is always brilliant feedback to receive.

2018 was Laravel Live UK’s inaugural conference and it was a packed house. They’ve just announced the dates for 2019 and I would strongly recommend attending for anyone using or interested in use Laravel.

Following the conference, I wrote up the talk as an article and it has just been published in the March 2019 edition of php[architect]. This is an excellent magazine which I’ve subscribed to for a few years now – the digital edition is very reasonable and comes as a DRM-free PDF onto an app on your phone/pad or downloaded to your computer.

As it happens, they chose this article as the teaser for this issue and so it is freely available online here and downloadable as a PDF here. But seriously, if you are a PHP developer, you need to subscribe to this magazine.

Lastly, if you are interested in the slide deck from the conference, you can download them here – but the article is a much better way to understand this material.

Switching Between PHP Versions on MacOS

When switching between different PHP projects (or different branches of one PHP project), you often need to switch PHP versions. Particularly as older libraries will not run on newer versions of PHP. After losing patience with how the otherwise excellent Homebrew handles this, I stumbled upon this super-useful tool: switch-php.

This seems to have been written for PHP developers and integrates brilliantly with Laravel Valet. Here’s an example of switching from PHP 7.3 to 7.2:

UI Tests with Laravel Dusk for IXP Manager

We use standard PHPUnit tests for IXP Manager for some mission critical aspects. These take data from a test database filled with known sample data (representing a range of different member configurations). The tests then use this information to generate configurations and compare these against known-good configurations.

This way, we know that for a given set of data, we will get a predictable output so long as we haven’t accidentally broken anything in development.

But, as an end user, how do you know that what you stick in a web-based form gets put into the database correctly? And conversely, how do you know that form represents the database data correctly when editing?

This is an issue we ran into recently around some checkbox logic and a dropdown showing the wrong selected element. These issues are every bit as dangerous to mission critical elements as the output tests we do with PHPUnit.

To test the frontend, we turn to Laravel Duskan expressive, easy-to-use browser automation and testing API. What this actually means is that we can right code like this:

We have now added Dusk tests for UI elements that involve adding, editing and deleting all aspects of a member interface and all aspects of adding, editing and delete a router object. Here’s an example of the latter:

Laravel Dusk - Animated Gif Example

Doctrine2 with GROUP_CONCAT and non-related JOIN

Doctrine2 ORM is a fantastic and powerful object relational mapper (ORM) for PHP. We use it for IXP Manager to great effect and we only support MySQL so our hands are not tied to pure Doctrine2 DQL supported functions. We also use the excellent Laravel Doctrine project with the Berberlei extensions.

Sometimes time is against you as a developer and the documentation (and StackOverflow!) lacks the obvious solutions you need and you end up solving what could be a single elegant query very inefficiently in code with iterative database queries. Yuck. 

I spent a bit of time last night trying to unravel one very bad example of this where the solution would require DQL that could:

  1. group / concatenate multiple column results from a one-to-many relationship;
  2. join a table without a relationship;
  3. ensure the joining of the table without the relationship would not exclude results where the joint table had no matches;
  4. provide a default value for (3).

Each of these was solved as follows:

  1. via MySQL’s GROUP_CONCAT() aggregator. The specific example here is that when a MAC address associated with a virtual interface can be visible in multiple switch ports. We want to present the switch ports to the user and GROUP_CONCAT() allows us to aggregate these as a comma separated concatenated string (e.g. "Ethernet1,Ethernet8,Ethernet9").
  2. Normally with Doctrine2, all relationships would be well-defined with foreign keys. This is not always practical and sometimes we need to join tables on the result of some equality test. We can do this using a DQL construct such as: JOIN Entities\OUI o WITH SUBSTRING( m.mac, 1, 6 ) = o.oui.
  3. This is as simple as ensuring you LEFT JOIN.
  4. The COALESCE() function is used for this: COALESCE( o.organisation, 'Unknown' ) AS organisation.

We have not yet pushed the updated code into IXP Manager mainline but the above referenced function / code is not replaced with the DQL query: