Mac, Apache, MySQL and PHP (MAMP)

Mac OS X serves as an excellent development environment, even if you are not actually developing Mac OS or iOS applications. It is the darling of many a LAMP (Linux, Apache, MySQL and PHP) developer, who enjoys a slick desktop operating system with good UNIX-like underpinnings but who don’t necessarily want to put up with all the various limitations and complications that running a Linux desktop brings, consistent improvements in this regard over recent years notwithstanding.

The only trouble with this is that if you want to develop LAMP applications and work on a Mac then traditionally you’ve needed a two-box setup; a Mac on your desk and Linux on a development server. For many this isn’t an issue, and indeed when you’ve got a team of developers, optimal, but what if you wanted a self-contained development environment that was restricted to just one box? What if you wanted that box to be your laptop so you could take it anywhere?


“Virtual machine!”, I hear you cry. Yes, this is a possible solution, and for many works well. Good virtualisation software is free these days, but using a local VM is cumbersome. Not only does it consume a large slice of your RAM but it also puts a lot of strain on the CPU, meaning that if you are running off your battery your battery life will be decreased. It’s also cumbersome; you have to start up the VM when you need it and there can be complications with the networking, for example, if you have connected to a public wireless network it’s possible that your VM might not be extended the same resource.

There is a software package for Mac OS called MAMP (the M for Mac OS replacing the L for Linux). This is a point-and-click installer which bundles Apache, Linux and PHP for installation on Mac OS. I don’t like this solution, for a number of reasons, including:

  1. Limited functionality unless you “go pro” (at quite considerable cost). Any self-respecting developer will require multiple virtual hosts as a minimum and won’t need or want a clicky-button interface to get what they want.
  2. You are entirely at the mercy of the distributors of MAMP with regards to component software versions that are made available to you and when.

Alternative solution

There’s an alternative to this. You don’t have to fork out £39 for a package of what it otherwise freely and widely available software. With the help of my friend and colleague Ben Nimmo I present the following assembled and tested instructions for turning your Mac into a native MAMP server without using the packages download.


  1. Download and install the latest .dmg and install both the *.pkgs within it (don’t use the TAR/GZ archives). You may wish to install the Workbench too, it’s really good these days.
  2. Find where the mysql.sock file is expected to be in /etc/php.ini (should be /var/mysql/mysql.sock)
  3. Create the folder and link the socket file to the expected location.
sudo mkdir /var/mysql
sudo ln -s /private/tmp/mysql.sock /var/mysql/mysql.sock
  1. Add MySQL to command line by editing /Users/username/.bash_profile and adding this line and then either restarting terminal or source-ing the file:
export PATH=$PATH:/usr/local/mysql/bin


PHP comes with Mac OS, so it’s not necessary to download and install it, however, there are a couple of necessary steps to configure it:

  1. Copy the default php.ini file:
sudo cp /etc/php.ini.default to /etc/php.ini
  1. Edit /etc/php.ini and uncomment this line to enable xdebug (not essential, but recommended):


Apache too comes with Mac OS, so again, no need to download and install it. Its configuration, however, is a little more complex, but nothing scary. The described configuration will provide a special Apache “sandbox” environment for your projects. It uses the existing “Sites” directory in your Mac OS home directory.

  1. Create a subdirectory in this directory for each of your projects, ensuring that the directory name does not contain any characters that would be illegal in a URL. Within each of these subdirectories create another subdirectory called “web”; this will be become the web root of each project. The extra subdirectory is in case you wish to use a framework in your projects which may keep some of its files outside of the web server root (Symfony is a good example of this).
  2. Create a subdirectory called “logs” in your “Sites” directory; Apache will maintain two log files, access and error, for all the sandbox sites.
  3. Enable PHP5 with Apache by editing /etc/apache2/httpd.conf and uncomment the following line:
LoadModule php5_module libexec/apache2/libphp5.so
  1. Change the user and group to your username and “staff” respectively, also in /etc/apache2/httpd.conf:
User sbf
Group staff
  1. While still in /etc/apache2/httpd.conf, find the following configuration and change “Deny from all” to “Allow from all”:
<Directory />
    Options FollowSymLinks
    AllowOverride None
    Order deny,allow
    Deny from all
  1. Create and edit /etc/apache/users/user.conf with the following, changing “sbf” to the username:
<VirtualHost *:80>

    ServerName dev.local
    DocumentRoot /Users/sbf/Sites/

    RewriteEngine on
    RewriteLogLevel 1
    RewriteLog /var/log/apache2/rewrite.log

    # sites in the format http://[site].dev.local
    RewriteCond %{HTTP_HOST} ^[^.]+\.dev\.local
    RewriteCond %{REQUEST_URI} !^/error/.*
    RewriteCond %{REQUEST_URI} !^/icons/.*
    RewriteRule ^(.+) %{HTTP_HOST}$1 [C]
    RewriteRule ^([^.]+)\.dev\.local/(.*) /Users/sbf/Sites/$1/web/$2

    # Logging
    CustomLog /Users/sbf/Sites/logs/sandbox.access.log combined
    ErrorLog /Users/sbf/Sites/logs/sandbox.error.log

  1. Restart Apache:
sudo apachectl restart

Then, for each of your sites, add an entry in /etc/hosts for with the format “name.dev.local” pointing to, where name corresponds to a subdirectory in your “Sites” directory. Don’t forget that the public subdirectory of each site is assumed to be “web”, so make a symlink to this if the framework you use has a different convention.

You should then be able to access each of your sites from URLs using the convention http://name.dev.local/ – where “name” again is a subdirectory within your “Sites” directory.

I’ve tested this setup procedure and It Works For Me [tm]. If, however, it doesn’t quite work for you as described, please let me know where you’re going wrong and how, if you were able, to resolve it, and I will update these instructions accordingly.


Python SimpleHTTPServer

I don’t use Python on a daily basis, barely at all in fact (knowingly), but I stumbled across a handy purpose for it today which I see myself using. Type this command in a Linux shell or a Mac OS terminal and it will start a local web server on port 8000 using the current working directory as the document root and sending access requests to STDOUT:

python -m SimpleHTTPServer 8000

Potential uses include:

  1. Developing local web applications on the local filesystem which use no server-side processing but do use Javascript and AJAX calls that a web browser would not normally allow without starting it with special flags (anyone who’s seen “XMLHttpRequest cannot load $RESOURCE. Origin null is not allowed by Access-Control-Allow-Origin” in their error console will know what I’m talking about).
  2. Quickly sharing a directory with a colleague on the same network rather than uploading files to a shared resource such as a file server or e-mail system. Obviously you’d need to ensure that whatever port you choose is allowed in your local incoming firewall if you have one.

There’s even better news for PHP users. PHP 5.4, released this week, includes a built-in web server which can be started with an equivalent command. The advantages of this of course is that it’ll also process PHP scripts instead of being limited to static files.


Flattening LaTeX source files for use with conversion software

I’ve been working with LaTeX quite a bit recently and I came across a very silly shortcoming that some of the programs that convert LaTeX to other formats suffer from. It’s moronic, but certain of them (pandoc, I’m looking at you), don’t follow includes (i.e. \input commands).

I have a PHP script which compiles all my LaTeX source files into various destination formats, including PDF, HTML, MediaWiki markup and text, and so in order to compensate for this ridiculous incapability I added this function which creates a “flattened” version of any LaTeX file by inserting the contents of any included files at the point they are included. It’s recursive, so if those included files also include files, they too are processed.

It’s simple but effective. Pass the path to the file to flatten. A string is returned with the entire flattened file. You may need to pay attention to relative paths in your \input commands if you includes are in sub-directories.

function FlattenLatexSourceFile($path) {
	// read in file
	$src = file($path);
	$flattened = "";

	// process each line
	foreach ($src as $line) {
		if (preg_match("/^\\\input/",$line)) {

			// include (input) line, extract filename and recurse
			$input = trim($line);
			$input = preg_replace("/^\\\input\{/","",$input);
			$input = preg_replace("/\}/","",$input);
			if (substr($input,-4,4) != ".tex") $input = "{$input}.tex";
			$flattened .= "% {$line}\n";
			$flattened .= FlattenLatexSourceFile($input);
			$flattened .= "\n% (end of included file {$input})\n";
		} else {
			// normal line
			$flattened .= $line;
	// return flattened file
	return $flattened;


Technical Notebook

If I have any regular readers, they will have noticed that I’ve started to use my WordPress as a notebook as well as a blog. This site is more or less a general dumping ground for my online stuff that I’m willing to show the world. If you don’t understand it, then don’t worry about it.


Gracefully degrade HTML5 “number” form elements

Use Modernizr to replace the a “number” INPUT element with an normal text box and two control buttons in older browsers:

if (!Modernizr.inputtypes.number) {
	document.write("<button type='button' onclick='number_field.value = parseInt(number_field.value) - 1'>-</button>");
	document.write(" <input type='text' size='10' id='number_field' value='0' /> ");
	document.write("<button type='button' onclick='number_field.value = parseInt(number_field.value) + 1'>+</button>");
} else {
	document.write("<input type='number' size='10' id='number_field' value='0' />");


Ternary PHP short-hand if/else statement

Saves using a cumbersome multi-line control structure for simple conditions like this:

// normal control structure
if (statement) {
	$variable = true;
} else {
	$variable = false;

// short-hand equivalent
$var = (statement) ? true : false;

// useful return statements in functions
return (statement) ? true : false;