Part 1: macOS 10.14 Mojave Web Development Environment

Developing web applications on macOS is a real joy. There are plenty of options for setting up your development environments, including the ever-popular MAMP Pro that provides a nice UI on top of Apache, PHP and MySQL. However, there are times when MAMP Pro has slow downs, or out of date versions, or is simply behaving badly due to its restrictive system of configuration templates and non-standard builds.

It is times like these that people often look for an alternative approach, and luckily there is one, and it is relatively straight-forward to setup.

In this blog post, we will walk you through setting up and configuring Apache 2.4 and multiple PHP versions. In the second blog post in this two-post series, we will cover MySQL, Apache virtual hosts, APC caching, and Xdebug installation.

[Updated 01/10/2019] Updated to add back PHP 5.6 and PHP 7.0 from and external deprecated keg
[Updated 12/12/2018] Updated to reflect the latest release of PHP 7.3 and the removal of PHP 7.0 from Brew.

If you have followed this guide in the past with the Homebrew/php tap, and are looking to upgrade to the new Homebrew/core approach, then you should first clean-up your current installation by following our new Upgrading Homebrew.

This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.

XCode Command Line Tools

If you don't already have XCode installed, it's best to first install the command line tools as these will be used by homebrew:

$ xcode-select --install

Homebrew Installation

This process relies heavily on the macOS package manager called Homebrew. Using the brew command you can easily add powerful functionality to your mac, but first we have to install it. This is a simple process, but you need to launch your Terminal (/Applications/Utilities/Terminal) application and then enter:

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Just follow the terminal prompts and enter your password where required. This may take a few minutes, but when complete, a quick way to ensure you have installed brew correctly, simply type:

$ brew --version
Homebrew 1.7.6
Homebrew/homebrew-core (git revision a1ed; last commit 2018-09-25)

You should probably also run the following command to ensure everything is configured correctly:

$ brew doctor

It will instruct you if you need to correct anything.

Mojave Required Libraries

When installing fresh on Mojave, I ran into a few libraries that were missing when completing all the steps below. To make things easier, please simply run these now:

$ brew install openldap libiconv

Apache Installation

The latest macOS 10.14 Mojave comes with Apache 2.4 pre-installed, however, it is no longer a simple task to use this version with Homebrew because Apple has removed some required scripts in this release. However, the solution is to install Apache 2.4 via Homebrew and then configure it to run on the standard ports (80/443).

If you already have the built-in Apache running, it will need to be shutdown first, and any auto-loading scripts removed. It really doesn't hurt to just run all these commands in order - even if it's a fresh installation:

$ sudo apachectl stop $ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null

Now we need to install the new version provided by Brew:

$ brew install httpd

Without options, httpd won't need to be built from source, so it installs pretty quickly. Upon completion you should see a message like:

🍺  /usr/local/Cellar/httpd/2.4.35: 1,648 files, 26.9MB

Now we just need to configure things so that our new Apache server is auto-started

$ sudo brew services start httpd

You now have installed Homebrew's Apache, and configured it to auto-start with a privileged account. It should already be running, so you can try to reach your server in a browser by pointing it at http://localhost:8080, you should see a simple header that says "It works!".

Troubleshooting Tips

If you get a message that the browser can't connect to the server, first check to ensure the server is up.

$ ps -aef | grep httpd

You should see a few httpd processes if Apache is up and running.

Try to restart Apache with:

$ sudo apachectl -k restart

You can watch the Apache error log in a new Terminal tab/window during a restart to see if anything is invalid or causing a problem:

$ tail -f /usr/local/var/log/httpd/error_log

Apache is controlled via the apachectl command so some useful commands to use are:

$ sudo apachectl start
$ sudo apachectl stop
$ sudo apachectl -k restart

The -k will force a restart immediately rather than asking politely to restart when apache is good and ready

Visual Studio Code

In past guides, I've always provided instructions to edit files using the default TextEdit application that comes pre-installed. However, this is not what I use myself as it's a terrible editor and when testing my guide for Mojave, I kept running into problems with encoding, finding line numbers etc. The better solution is to simply install a better editor. So please install the amazingly versatile yet, 100% free, Visual Studio Code. It's available on Mac, Windows, and Linux, but right now we only care about the mac version.

Go to the Visual Studio Code site and click Download for Mac

Once downloaded, drag the application to your preffered Applications location. Next, you want to install the command line tools, so follow the official step-by-step instructions so that you can use the code command from the Terminal.

Apache Configuration

Now that we have a working web server, we will want to do is make some configuration changes so it works better as a local development server.

In the latest version of Brew, you have to manually set the listen port from the default of 8080 to 80, so we will need to edit Apache's configuration file.

/usr/local/etc/httpd/httpd.conf

If you followed the instructions above you should be able to use Visual Studio Code to edit your files using the code Terminal command. However, if you want to use the default TextEditor application to perform edits, you can use the open -e command followed by the path to the file.

$ code /usr/local/etc/httpd/httpd.conf

VSC

Find the line that says

Listen 8080

and change it to 80:

Listen 80

Next we'll configure it to use the to change the document root for Apache. This is the folder where Apache looks to serve file from. By default, the document root is configured as /usr/local/var/www. As this is a development machine, let's assume we want to change the document root to point to a folder in our own home directory.

Search for the term DocumentRoot, and you should see the following line:

DocumentRoot "/usr/local/var/www"

Change this to point to your user directory where your_user is the name of your user account:

DocumentRoot /Users/your_user/Sites

You also need to change the <Directory> tag reference right below the DocumentRoot line. This should also be changed to point to your new document root also:

<Directory /Users/your_user/Sites>

We removed the optional quotes around the directory paths as TextEdit will probably try to convert those to smart-quotes and that will result in a Syntax error when you try to restart Apache. Even if you edit around the quotes and leave them where they are, saving the document may result in their conversion and cause an error.

In that same <Directory> block you will find an AllowOverride setting, this should be changed as follows:

#   AllowOverride controls what directives may be placed in .htaccess files.
#   It can be "All", "None", or any combination of the keywords:
#   AllowOverride FileInfo AuthConfig Limit
#  
AllowOverride All

Also we should now enable mod_rewrite which is commented out by default. Search for mod_rewrite.so and uncomment the line by removing the leading # :

LoadModule rewrite_module lib/httpd/modules/mod_rewrite.so

User & Group

Now we have the Apache configuration pointing to a Sites folder in our home directory. One problem still exists, however. By default, apache runs as the user daemon and group daemon. This will cause permission problems when trying to access files in our home directory. About a third of the way down the httpd.conf file there are two settings to set the User and Group Apache will run under. Change these to match your user account (replace your_user with your real username), with a group of staff:

User your_user
Group staff

Servername

Apache likes to have a server name in the configuration, but this is disabled by default, so search for:

#  ServerName www.example.com:8080

and replace it with:

ServerName localhost

Sites Folder

Now, you need to create a Sites folder in the root of your home directory. You can do this in your terminal, or in Finder. In this new Sites folder create a simple index.html and put some dummy content in it like: <h1>My User Web Root</h1>.

$ mkdir ~/Sites
$ echo "<h1>My User Web Root</h1>" > ~/Sites/index.html

Restart apache to ensure your configuration changes have taken effect:

$ sudo apachectl -k restart

If you receive an error upon restarting Apache, try removing the quotes around the DocumentRoot and Directory designations we set up earlier.

Pointing your browser to http://localhost should display your new message. If you have that working, we can move on!

PHP Installation

If you have existing PHP installations via Brew, you need to first cleanup your setup with our Upgrading Homebrew guide before continuing with this section.

Up until the end of March 2018, all PHP related brews were handled by Homebrew/php tab, but that has been deprecated, so now we use what's available in the Homebrew/core package. This should be a better maintained, but is a much less complete, set of packages.

Both PHP 5.6 and PHP 7.0 has been deprecated and removed from Brew because they are out of support, and while it's not recommended for production, there are legitimate reasons to test these unsupported versions in a development environment.

Remember only PHP 7.1 through 7.3 are officially supported by Brew so if you want to install PHP 5.6 or PHP 7.0 you will need to add this tap:

$ brew tap exolnet/homebrew-deprecated

We will proceed by installing various verions of PHP and using a simple script to switch between them as we need. Feel free to exclude any versions you don't want to install.

$ brew install php@5.6
$ brew install php@7.0
$ brew install php@7.1
$ brew install php@7.2
$ brew install php@7.3

The first one will take a little bit of time as it has to install a bunch of brew dependencies. Subsequent PHP versions will install faster.

You no longer have to unlink each version between installing PHP versions as they are not linked by default

Also, you may have the need to tweak configuration settings of PHP to your needs. A common thing to change is the memory setting, or the date.timezone configuration. The php.ini files for each version of PHP are located in the following directories:

/usr/local/etc/php/5.6/php.ini
/usr/local/etc/php/7.0/php.ini
/usr/local/etc/php/7.1/php.ini
/usr/local/etc/php/7.2/php.ini
/usr/local/etc/php/7.3/php.ini

Let's switch back to the first PHP version now:

$ brew unlink php@7.3 && brew link --force --overwrite php@5.6

At this point, I strongly recommend closing ALL your terminal tabs and windows. This will mean opening a new terminal to continue with the next step. This is strongly recommended because some really strange path issues can arise with existing terminals (trust me, I have seen it!).

Quick test that we're in the correct version:

php -v
PHP 5.6.39 (cli) (built: Dec  7 2018 08:27:47)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

Apache PHP Setup - Part 1

You have successfully installed your PHP versions, but we need to tell Apache to use them. You will again need to edit the /usr/local/etc/httpd/httpd.conf file scroll to the bottom of the LoadModule entries.

If you have been following this guide correctly, the last entry should be your mod_rewrite module:

LoadModule rewrite_module lib/httpd/modules/mod_rewrite.so

Below this add the following libphp modules:

LoadModule php5_module /usr/local/opt/php@5.6/lib/httpd/modules/libphp5.so
#  LoadModule php7_module /usr/local/opt/php@7.0/lib/httpd/modules/libphp7.so
#  LoadModule php7_module /usr/local/opt/php@7.1/lib/httpd/modules/libphp7.so
#  LoadModule php7_module /usr/local/opt/php@7.2/lib/httpd/modules/libphp7.so
#  LoadModule php7_module /usr/local/opt/php@7.3/lib/httpd/modules/libphp7.so

We can only have one module processing PHP at a time, so for now, so we have left our php@5.6 entry uncommented while all teh others are commented out. This will tell Apache to use PHP 5.6 to handle PHP requests. (We will add the ability to switch PHP versions later).

Also you must set the Directory Indexes for PHP explicitly, so search for this block:

<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>

and replace it with this:

<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

Save the file and stop Apache then start again, now that we have installed PHP:

$ sudo apachectl -k stop
$ sudo apachectl start

Validating PHP Installation

The best way to test if PHP is installed and running as expected is to make use of phpinfo(). This is not something you want to leave on a production machine, but it's invaluable in a development environment.

Simply create a file called info.php in your Sites/ folder you created earlier with this one-liner.

echo "<?php phpinfo();" > ~/Sites/info.php

Point your browser to http://localhost/info.php and you should see a shiny PHP information page:

If you see a similar phpinfo result, congratulations! You now have Apache and PHP running successfully. You can test the other PHP versions by commenting the LoadModule ... php@5.6 ... entry and uncommenting one of the other ones. Then simply restart apache and reload the same page.

PHP Switcher Script

We hard-coded Apache to use PHP 5.6, but we really want to be able to switch between versions. Luckily, some industrious individuals have already done the hard work for us and written a very handy little PHP switcher script.

We will install the sphp script into brew's standard /usr/local/bin:

$ curl -L https://gist.githubusercontent.com/rhukster/f4c04f1bf59e0b74e335ee5d186a98e2/raw > /usr/local/bin/sphp
$ chmod +x /usr/local/bin/sphp

Check Your Path

Homebrew should have added its preferred /usr/local/bin and /usr/local/sbin to your path as part of its installation process. Quickly test this by typing:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

If you don't see this, you might need to add these manually to your path. Depending on your shell your using, you may need to add this line to ~/.profile, ~/.bash_profile, or ~/.zshrc. We will assume you are using the default bash shell, so add this line to a your .profile (create it if it doesn't exist) file at the root of your user directory:

export PATH=/usr/local/bin:/usr/local/sbin:$PATH

Testing the PHP Switching

After you have completed these steps, you should be able to switch your PHP version by using the command sphp followed by a two digit value for the PHP version:

$ sphp 7.1

You will probably have to enter your administrator password, and it should give you some feedback:

$ sphp 7.0
Switching to php@7.0
Switching your shell
Unlinking /usr/local/Cellar/php@5.6/5.6.39... 25 symlinks removed
Unlinking /usr/local/Cellar/php@7.0/7.0.33... 0 symlinks removed
Unlinking /usr/local/Cellar/php@7.1/7.1.25... 0 symlinks removed
Unlinking /usr/local/Cellar/php/7.3.1... 0 symlinks removed
Linking /usr/local/Cellar/php@7.0/7.0.33... 25 symlinks created

If you need to have this software first in your PATH instead consider running:
echo 'export PATH="/usr/local/opt/php@7.0/bin:$PATH"' >> ~/.bash_profile
echo 'export PATH="/usr/local/opt/php@7.0/sbin:$PATH"' >> ~/.bash_profile
You will need sudo power from now on
Switching your apache conf
Restarting apache

PHP 7.0.33 (cli) (built: Dec 14 2018 16:20:36) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
with Zend OPcache v7.0.33, Copyright (c) 1999-2017, by Zend Technologies

All done!

Test to see if your Apache is now running PHP 7.0 by again pointing your browser to http://localhost/info.php. With a little luck, you should see something like this:

Updating PHP and other Brew Packages

Brew makes it super easy to update PHP and the other packages you install. The first step is to update Brew so that it gets a list of available updates:

$ brew update

This will spit out a list of available updates, and any deleted formulas. To upgrade the packages simply type:

$ brew upgrade

You will need to switch to each of your installed PHP versions and run update again to get updates for each PHP version and ensure you are running the version of PHP you intend.

Activating Specific/Latest PHP Versions

Due to the way our PHP linking is set up, only one version of PHP is linked at a time, only the current active version of PHP will be updated to the latest version. You can see the current active version by typing:

$ php -v

And you can see the specific versions of a PHP package by typing:

$ brew info php@7.1
php@7.1: stable 7.1.25 (bottled) [keg-only]
General-purpose scripting language
...

OK, that wraps up Part 1 of this 3 part series You now have a fully functional Apache 2.4 installation with a quick-and-easy way to toggle between PHP 5.6, 7.0, 7.1, 7.2, and 7.3. Check out Part 2 to find out how to setup your environment with MySQL, Virtual Hosts, APC caching, YAML, and Xdebug. Also take a gander at Part 3 to find out how to setup SSL for your Apache Virtual Hosts.

Part 2: macOS 10.14 Mojave Web Development Environment

In Part 1 of this 3-part series, we covered configuring Apache on macOS to work better with your local user account, as well as the installation process for installing multiple versions of PHP.

In this Part 2, we will cover installing MySQL, Virtual Hosts, APC caching, YAML, and Xdebug. After finishing this tutorial, be sure to check out how to enable SSL in Part 3 of the series.

[Updated 01/10/2019] Updated to add back PHP 5.6 and PHP 7.0 from and external deprecated keg
[Updated 12/12/2018] Updated to reflect the latest release of PHP 7.3 and the removal of PHP 7.0 from Brew.

This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.

MySQL

Although not required for development of Grav, there are times you definitely need an installation of MySQL. In the original guide, we used the Oracle MySQL installation package. However, we now have switched to MariaDB which is a drop-in replacement for MySQL and is easily installed and updated with Brew. Detailed information on the HomeBrew installation process can be found on the mariadb.org site but the essentials are as follows:

Install MariaDB with Brew:

$ brew update
$ brew install mariadb

After a successful installation, you can start the server ane ensure it autostarts in the future with:

$ brew services start mariadb

You should get some positive feedback on that action:

==> Successfully started `mariadb` (label: homebrew.mxcl.mariadb)

Download SequelPro and install it. (it's awesome and free!). You should be able to automatically create a new connection via the Socket option without changing any settings.

SequelPro Connection

It is advisable to change the MySQL server password and secure your installation. The simplest way to do this is to use the provided script:

$ /usr/local/bin/mysql_secure_installation

Just answer the questions and fill them in as is appropriate for your environment.

If you need to stop the server, you can use the simple command:

$ brew services stop mariadb

Apache Virtual Hosts

A very handy development option is to have multiple virtual hosts set up for you various projects. This means that you can set up names such as grav.mydomain.com which point to your Grav setup, or project-x.mydomain.com for a project-specific URL.

Apache generally performs name-based matching, so you don't need to configure multiple IP addresses. Detailed information can be found on the apache.org site.

Apache already comes preconfigured to support this behavior but it is not enabled. First you will need to uncomment the following lines in your /usr/local/etc/httpd/httpd.conf file:

LoadModule vhost_alias_module lib/httpd/modules/mod_vhost_alias.so

and:

# Virtual hosts
Include /usr/local/etc/httpd/extra/httpd-vhosts.conf

Then you can edit this referenced file and configure it to your needs:

$ code /usr/local/etc/httpd/extra/httpd-vhosts.conf

This file has some instructions already but the important thing to remember is that these rules are matched in order. When you set up virtual hosts, you will lose your older document root, so you will need to add back support for that first as a virtual host.

<VirtualHost *:80>
    DocumentRoot "/Users/your_user/Sites"
    ServerName localhost
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "/Users/your_user/Sites/grav-admin"
    ServerName grav-admin.test
</VirtualHost>

As you set up your .test virtual hosts, you may receive a warning such as Warning: DocumentRoot [/Users/your_user/Sites/grav-admin] does not exist when restarting Apache. This just lets you know that the source directory listed for your virtual hosts is not present on the drive. It's an issue that can be resolved by editing this file with the corrected DocumentRoot.

Dnsmasq

We used to recommend using .dev domain name, but since Chrome 63 forces all .dev domains to use SSL, this guide has been updated to use .test

In the example virtualhost we setup above, we defined a ServerName of grav-admin.test. This by default will not resolve to your local machine, but it's often very useful to be able to setup various virtual hosts for development purposes. You can do this by manually adding entries to /etc/hosts ever time, or you can install and configure Dnsmasq to automatically handle wildcard *.test names and forward all of them to localhost (127.0.0.1).

First we install it with brew:

$ brew install dnsmasq

Then we setup *.test hosts:

$ echo 'address=/.test/127.0.0.1' > /usr/local/etc/dnsmasq.conf

Start it and ensure it auto-starts on reboot in the future:

$ sudo brew services start dnsmasq

And lastly, add it to the resolvers:

$ sudo mkdir -v /etc/resolver
$ sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/test'

Now you can test it out by pinging some bogus .test name:

ping bogus.test
PING bogus.test (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.044 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.045 ms

Voila! we have successfully setup wildcard forwarding of all *.test DNS names to localhost.

APC Cache

Caching in PHP is a big part of the performance equation. There are two types of caching typically available, and both have a big impact on speed and performance.

The first type of cache is called an opcode cache, and this is what takes your PHP script and compiles it for faster execution. This alone can typically result in a 3X speed increase!.

The second type of cache is a user cache, and this is a data-store that PHP can use to quickly store and retrieve data from. These typically run in memory which means they are transient, but very fast.

All PHP packages now come pre-built with Zend OPcache by default, but you can still install APCu Cache as a data store.

Install APCu

Switch to PHP 5.6 mode, then run the following brew commands to install autoconf:

$ sphp 5.6
$ brew install autoconf

Then you can install APCu via PECL. PECL is a PHP package manager that is now the preferred way to install PHP packages. Using it requires a little more manual work than before when these packages were available via a single one-line brew install command.

For PHP 5.6 we have to install the latest 4.x version of APCu, as this is the last version to provide PHP 5.6 support:

$ pecl channel-update pecl.php.net
$ pecl install apcu-4.0.11

Answer any question by simply pressing Return to accept the default values

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes.

[Optional] APCu Configuration

This is probably enough for most people, but if you are like me and like a little more control over your settings, and also the ability to more easily enable/disable the extension, we have some extra optional steps.

You will now need to remove the extension="apcu.so" entry that PECL adds to the top of your php.ini. So edit this file and remove the top line:

$ code /usr/local/etc/php/5.6/php.ini

Once that line is removed, we can add a new file with a proper entry to the recently bulit apcu.so library:

$ code /usr/local/etc/php/5.6/conf.d/ext-apcu.ini

In this file paste the following:

[apcu]
extension="apcu.so"
apc.enabled=1
apc.shm_size=64M
apc.ttl=7200
apc.enable_cli=1

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes.

APCu for other PHP versions

For PHP 7.0 and above you can use the latest 5.x release of APCu, so the process is the same for all. First let's switch to PHP 7.0 and install the APCu library:

$ sphp 7.0
$ pecl uninstall -r apcu
$ pecl install apcu

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes.

The uninstall -r enables PECL to only remove registration, it does not actually uninstall anything.

Again if you are OK with the ACPu defaults, you can leave things as-is, but you can choose to repeat the Optional APCu Configuration steps to create an APCu configuration file fore each PHP version.

For PHP 7.1, just repeat these steps but use 7.1 instead of 7.0:

$ sphp 7.1
$ pecl uninstall -r apcu
$ pecl install apcu

For PHP 7.2:

$ sphp 7.2
$ pecl uninstall -r apcu
$ pecl install apcu

For PHP 7.3:

$ sphp 7.3
$ pecl uninstall -r apcu
$ pecl install apcu

YAML

With recent versions of Grav, we now make use of the native PECL YAML library that allow YAML processing to be done by highly efficient libYAML C library rather than by they Symfony PHP library. This can result in a 5X improvement in YAML processing times! Luckily this is a simple process to install for any PHP version:

Switch to PHP 5.6 mode, then run the following brew commands to install libyaml:

$ sphp 5.6
$ brew install libyaml

Then you can install YAML via PECL.

For PHP 5.6 we have to install the latest 1.3.x version of YAML, as this is the last version to provide PHP 5.6 support:

$ pecl install yaml-1.3.1

Answer any question by simply pressing Return to accept the default values

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes.

YAML for other PHP versions

For PHP 7.0 and above you can use the latest 2.x release of YAML, so the process is the same for all. First let's switch to PHP 7.0 and install the YAML library:

$ sphp 7.0
$ pecl uninstall -r yaml
$ pecl install yaml

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes.

The uninstall -r enables PECL to only remove registration, it does not actually uninstall anything.

For PHP 7.1, just repeat these steps but use 7.1 instead of 7.0:

$ sphp 7.1
$ pecl uninstall -r yaml
$ pecl install yaml

and for PHP 7.2:

$ sphp 7.2
$ pecl uninstall -r yaml
$ pecl install yaml

and for PHP 7.3:

$ sphp 7.3
$ pecl uninstall -r yaml
$ pecl install yaml

[Optional] YAML Configuration

If you are feeling adventurous, or you like to keep things uniform, you can follow the same procedure as APCu and remove the default extension-"yaml.so" entry in each PHP's php.ini and instead, create a conf.d/ext-yaml.ini file:

[yaml]
extension="yaml.so"

Xdebug

One of the most important aspects of any kind of development is the ability to debug and fix your code. PHP comes with limited support to dump variables or log to a file, but for more complex situations you need something more powerful.

Xdebug provides is a debugging and profiling extension for PHP that provides an HTML-friendly output for the var_dump() method that improves the readability of the default version. It also provides other useful dumping methods as well as displaying stack traces. One of the best features however, is the ability to remote debug your code. This means you can set breakpoints, and step through your PHP code inspecting as you go. Full documentation on Xdebug contains extensive information about all the functionality available. Let's switch back to PHP 5.6 and get started.

$ sphp 5.6

Then you can install Xdebug via PECL. For PHP 5.6 we have to install the latest 2.5.x version of Xdebug, as this is the last version to provide PHP 5.6 support:

$ pecl install xdebug-2.5.5

[Required] Xdebug Configuration

Like the other PECL-installed modules, this will create a simple entry in the php.ini file, but you really need to configure Xdebug for it to be useful. So let's just go ahead and create our configuration file as we'll need it shortly anyway.

You will now need to remove the zend_extension="xdebug.so"" entry that PECL adds to the top of your php.ini. So edit this file and remove the top line:

$ code /usr/local/etc/php/5.6/php.ini

Once that line is removed, we can add a new file with a proper entry to the recently bulit xdebug.so library:

$ code /usr/local/etc/php/5.6/conf.d/ext-xdebug.ini

In this file paste the following:

[xdebug]
zend_extension="xdebug.so"
xdebug.remote_enable=1
xdebug.remote_host=localhost
xdebug.remote_handler=dbgp
xdebug.remote_port=9000

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes. You should check the http://localhost/info.php to ensure that Xdebug information is displayed:

W00fz created a great tool for quickly enabling/disabling xdebug. Install this with brew:

$ curl -L https://gist.githubusercontent.com/rhukster/073a2c1270ccb2c6868e7aced92001cf/raw > /usr/local/bin/xdebug
$ chmod +x /usr/local/bin/xdebug

Using it is simple, you can get the current state with:

$ xdebug

And then turn it on or off with:

$ xdebug on
$ xdebug off

if Xdebug still shows up in php -v the most likely cause is you didn't remove the zend_extension="xdebug.so"" entry at the top of php.ini

Xdebug for other PHP versions

For PHP 7.0 and above you can use the latest 1.6.x release of Xdebug, so the process is the same for all. First let's switch to PHP 7.0 and install the Xdebug library:

$ sphp 7.0
$ pecl uninstall -r xdebug
$ pecl install xdebug

Afer this just repeat the Required Xdebug Configuration steps, with /usr/local/etc/php/7.0/php.ini as the PHP configuration file to remove the existing entry, and /usr/local/etc/php/7.0/conf.d/ext-xdebug.ini for the file you will create with the new Xdebug configuration.

Restart Apache with the standard sudo apachectl -k restart command to pick up your changes.

For PHP 7.1, just repeat these steps but use 7.1 instead of 7.0:

$ sphp 7.1
$ pecl uninstall -r xdebug
$ pecl install xdebug

For PHP 7.2:

$ sphp 7.2
$ pecl uninstall -r xdebug
$ pecl install xdebug

And again for PHP 7.3 (using the latest beta release):

$ sphp 7.3
$ pecl uninstall -r xdebug
$ pecl install xdebug-2.7.0beta1

Again, repeat the Required Xdebug Configuration steps with the same info you used for 7.2 except use 7.3

NOTE: As of Jan 10 2019, The Xdebug version 2.7.0beta1 appears to be pretty broken (at least with Grav), and I strongly recommend holding off on using it until a more robust versions is available.

Advanced Techniques

Here's a hot tip if you have done this before and want to speed-up the installation process. Simply install everything (apcu, yaml, xdebug) in one shot, and then perform the other non-installation steps. This is faster but less intuitive for newbies:

PHP 5.6

$ pecl install apcu-4.0.11 && pecl install yaml-1.3.1 && pecl install xdebug-2.5.5

PHP 7.0+

Repeat the following 2 steps for PHP 7.0 through PHP 7.3:

$ sphp 7.0
$ pecl uninstall -r apcu && pecl install apcu && pecl uninstall -r yaml && pecl install yaml && pecl uninstall -r xdebug && pecl install xdebug

Once you have created your configruation (conf.d/ext-[lbirary].ini) files, you can also easily copy the configuration files from one version of PHP to another.

$ cd /usr/local/php/5.6/conf.d
$ cp ext-apcu.ini ext-xdebug.ini ext-yaml.ini ../../7.0/conf.d
$ cp ext-apcu.ini ext-xdebug.ini ext-yaml.ini ../../7.1/conf.d
$ cp ext-apcu.ini ext-xdebug.ini ext-yaml.ini ../../7.2/conf.d
$ cp ext-apcu.ini ext-xdebug.ini ext-yaml.ini ../../7.3/conf.d

You should now be all set with a Rockin' PHP development environment! To find out how to enable SSL on Apache, check out Part 3 in the series.

NOTE: The brew installation actually creates configuration files in /usr/local/etc/php/5.6/conf.d, /usr/local/etc/php/7.0/conf.d, /usr/local/etc/php/7.1/conf.d, /usr/local/etc/php/7.2/conf.d, and /usr/local/etc/php/7.3/conf.d respectively. If you want to uninstall a PHP extension, simply rename the .ini file to .ini.bak and restart apache. Alternatively, you can simply use brew to uninstall it, and reinstall it again when you need it.

Part 3: macOS 10.14 Mojave Web Development Environment

In Part 1 of this 2-part series, we covered configuring Apache on macOS Sierra 10.14 High to work better with your local user account, as well as the installation process for installing multiple versions of PHP. In Part 2, we covered installing MySQL, Virtual Hosts, APC caching, YAML, and Xdebug.

In this Part 3, we will cover getting your site setup with SSL support for this setup.

This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.

SSL

It is often important to be able to test your local site setup under SSL (e.g. https://yoursite.com). There are a few steps that are needed to accomplish this with your Homebrew-based Apache setup. The first step is to make some modifications to your httpd.conf:

$ code /usr/local/etc/httpd/httpd.conf

In this file you should uncomment both the socache_shmcb_module, ssl_module, and also the include for the httpd-ssl.conf by removing the leading # symbol on those lines:

LoadModule socache_shmcb_module lib/httpd/modules/mod_socache_shmcb.so
...
LoadModule ssl_module lib/httpd/modules/mod_ssl.so
...
Include /usr/local/etc/httpd/extra/httpd-ssl.conf

Next we need to change the default 8443 port to the more standard 443 and comment out some sample code. So we need to open the SSL config file:

$ code /usr/local/etc/httpd/extra/httpd-ssl.conf

find:

Listen 8443

replace it with:

Listen 443

then find:

<VirtualHost _default_:8443>
#  General setup for the virtual host
    DocumentRoot "/usr/local/var/www"
    ServerName www.example.com:8443
/code>

and replace the 8443 references with 443 and note the commenting:

<VirtualHost _default_:443>
#  General setup for the virtual host
#  DocumentRoot "/usr/local/var/www"
#  ServerName www.example.com:443

After saving this file, you should then open up your /usr/local/etc/httpd/extra/httpd-vhosts.conf to add appropriate SSL based virtual hosts.

$ code /usr/local/etc/httpd/extra/httpd-vhosts.conf

Here you can create a VirtualHost entry for each virtual host that you wish to provide SSL support for.

<VirtualHost *:443>
    DocumentRoot "/Users/your_user/Sites"
    ServerName localhost
    SSLEngine on
    SSLCertificateFile "/usr/local/etc/httpd/server.crt"
    SSLCertificateKeyFile "/usr/local/etc/httpd/server.key"
</VirtualHost>

In this example we have created the VirtualHost for localhost, but it could be any of your existing or even a new VirtualHost. The important parts are the the 443 port, along with SSLEngine on and the SSLCertificateFile and SSLCertificateKeyFile entries that point to the certificate we now need to generate.

Certificates

To get this all to work with Apache, we need to create a self-signed certificate that we have already referenced in the VirtualHost definition.

The following commands will often prompt you for information regarding the certificates. You should fill these in with sensible values, however, the Common Name should match the ServerName entry in your httpd-vhosts.conf file you just added.

First generate a key and certificate:

$ cd /usr/local/etc/httpd
$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt

Then all you need to do now is double check your Apache configuration syntax:

$ sudo apachectl configtest

If all goes well, restart Apache:

$ sudo apachectl -k restart

You can tail -f /usr/local/var/log/httpd/error_log, the Apache error log while you restart to see if you have any errors.

Now simply point your browser at https://localhost. If you are prompted about a self-signed certificate, in Chrome you can hit the Advanced option on that page and proceed while in Firefox you need to expand the I Understand the Risks and add as exception. This is due to the fact that the self-signed certificates are not signed by any authority and for this reasons the browsers add warnings about it. Although, since you are the one who created the certificate, you understand it's safe to accept it.

Special Edition: macOS 10.14 Mojave Web Development Environment

This is a guide to help those with prior Homebrew mutliple PHP-based installations that are looking to upgrade to the new Hombrew/core PHP setup from the prior Homebrew/php keg which is now deprecated.

With the deprecation of Homebrew/php tap, many of the prior formulaes we used in this guide are no longer available. The cleanest way to migrate from the old brew formulae to the new pecl package approach is to remove everything PHP-related and reinstall with the new instructions.

The first step in this process is to update all the latest packages then upgrade them. This will acually 'migrate' the core PHP packages (which are the only ones supported), but there's a bunch of symlinks utilized that could cause problems down the road, so after upgrading, we'll remove all PHP packages, to provide a fresh start:

$ brew update
$ brew upgrade
$ brew cleanup

You can then double check the current installed PHP packages with:

$ brew list | grep php

Now we just need to remove everything:

$ brew uninstall --force php56 php56-apcu php56-opcache php56-xdebug php56-yaml
$ brew uninstall --force php70 php70-apcu php70-opcache php70-xdebug php70-yaml
$ brew uninstall --force php71 php71-apcu php71-opcache php71-xdebug php71-yaml
$ brew uninstall --force php72 php72-apcu php72-opcache php72-xdebug php72-yaml
$ brew cleanup

Don't worry if you don't have all these packages installed, this is just a cumulative list and it will skip over anything that's not installed.

Now we can check to see if anything PHP-related is left:

$ brew list | grep php

If you don't see anything you are all good. If something is still left, you can uninstall those individually using the same brew uninstall --force syntax as above.

Now we want to clean out the old configuration options for PHP:

$ rm -Rf /usr/local/etc/php/*

Now you've cleaned up your prior installation, you can jump to the PHP Installation section of Part 1 of the guide.