Good Practice for Adapting PHP Code to Alternative Storage Schemes, Including OS X Server’s

Photo of Greg
Photo by USDAgov -

A few checks and some simple modifications can get your PHP code ready to adapt itself to a wide range of different server architectures, including OS X’s.

Getting Ready for the Move

If you’ve been following along with this series of articles on setting up OS X Server, you’ll know that by this point we’ve already completed quite a few of the background tasks necessary for getting great performance from the underlying Mac hardware. I haven’t yet covered the job of actually moving existing sites from a WHM/cPanel or other Linux-based server, but there’s something else that should be done first — namely, making any necessary adjustments to existing PHP code you might be running to enable it to adapt itself to the different directory structure of OS X Server.

Self-adapting code won’t care whether it’s running on OS X without a public_html or home in sight, or whether it’s on Linux with its familiar /home/username/public_html structure. The good news is that the changes required to make your code self-adapting will likely be relatively minimal, and you’ll only have to do it once. Best of all, making your code work this way will also innoculate it against future side effects of other directory structure changes, whether on OS X or other operating systems.

The Problem With Relative Paths

In theory, using relative paths to refer to code resources and other files your application might need seems like a great idea; it means that wherever you drop your piece of code, provided that everything stays in the same place relatively speaking, it will continue to work just fine. The reality, however, is that once you’re talking about features of server architecture that are out of your control — rather than your own files — things don’t always stay in the same relative place. Assuming that they will is a brilliant way to save time and effort now only at the potential cost of having to spend even more time and even more effort later on.

When I first started moving sites to OS X Server, I needed to spend some time thinking about how best to handle one particular change in architecture — namely, the fact that the files for individual sites are stored within /Library/Server/Web/Data/Sites in directories that take the name of the domain, like so:

  1. .../Sites/
  2. .../Sites/
  3. .../Sites/

This doesn’t match the types of structures familiar from other Unix-based or Linux-based hosting environments, one common example of which is this:

  1. /home/username1/public_html
  2. /home/username2/public_html
  3. /home/username3/public_html

The specifics differ between different environments — the directory holding site files is not always called public_html, for example, and the top level directory is not always called home, etc. — but two important differences between any of these types of structures and the OS X Server structure are:

  1. the directory holding site files has a different name for each site, and
  2. the directory above the directory holding site files is shared between all sites, rather than being siloed in separate user directories

The significance of this difference, especially the second one, is that relative paths used by different sites may ‘collide’. For example, suppose you’re running a WordPress installation in and another in In both cases, you may have already followed the advice handed down by many in the WordPress world and moved wp-config.php up one level to ensure it is not sitting in a web-accessible location. (I’ll be coming back to this in a little more detail in a future article.) Using the common directory structure I mentioned above, this means these files sit here:

  1. /home/username1/wp-config.php
  2. /home/username2/wp-config.php

But in the context of OS X Server, this common advice is entirely unsuitable. Using that same method would mean they would sit here:

  1. .../Sites/wp-config.php
  2. .../Sites/wp-config.php

Oops — collision.

In my own case, some of my sites use WordPress, while others use a higher performance CMS which I wrote to deliver particular types of sites without all the WordPress extras. But even though my own code, unlike WordPress, was written from the start to ensure separation between site delivery code, support and administration code, configuration details, content, and theme files, I still encountered the same problem with relative paths: I had assumed that configuration could live in a directory one level above public_html, and I had assumed that support and maintenance scripts could live in that same type of location and then reach locations in the main part of the site itself by passing through a directory called public_html. Both assumptions are false under OS X server, and one or both may also be false under other server platforms.

A Simple Solution: One Path to Rule Them All

At first glance, it might seem like a real mess, but at least one solution turns out to be remarkably simple and straightforward, requiring changing only a few lines of code here and there to accommodate both a change to a server architecture like OS X Server’s and any future changes to other architectures. The solution I decided to adopt frees me from reliance on any specific structure and means that should Apple decide to re-organise where site files get stored at some point in the future, or should I decide to move to a different Unix-based or Linux-based environment, or should I simply want to run the same code base on two different servers with two different architectures, it’s never a problem.

The solution is to decide on one place, anywhere on the server, where I’m going to store site support material (config files, maintenance scripts, etc.), and reference everything I need in that location not via relative paths, but via an absolute path read once from a single configuration file accessible via my PHP include path. Files for separate sites can be separated into separate sub-directories by site name. By retaining the original relative path references as a fallback option in case that single configuration file is absent or deliberately switched off, I can ensure fallback functionality which is identical to what it was before making any changes.

Here’s an example of loading a site configuration file from the new central location, with a fallback to load it directly from a directory named site_constants living one level above:

@include('path/to/map.php'); // grab our server map, if there is one, from PHP include path

if ( defined( 'SUPPORT_FILES_LOCATION' ) )
	$require_prefix = SUPPORT_FILES_LOCATION . '';
	$require_prefix = '../site_constants/';

require_once( "{$require_prefix}constants.php" );

(I’ve omitted a couple of extras here. For example, any time you grab sensitive configuration information with something like require_once(), it’s good practice to wrap it with ob_start() and ob_end_clean() to protect against a security flaw which can send out the content of includes in raw form if headers get corrupted. In addition, if you prefer not to hard code the domain name, that part of the path can be constructed in other ways.)

And the server map file itself just holds this:

define( 'SUPPORT_FILES_LOCATION', '/path/to/support/files/' );
define( 'SITE_FILES_LOCATION', '/path/to/site/files/' );

(If you’re running APC or a similar cache, as I described in “Boost PHP Performance on OS X by Installing APC”, this server map file will naturally get cached and so will always be grabbed from memory, reducing any overheads otherwise associated with the additional include().)

The end result of this simple change is that I can now move this code to any server architecture and maintain fully functioning file references by simply changing one include file — or by disabling it altogether, I can get back my chosen default behaviour. (Thus the ‘@’ in front of the initial include(): by deliberately suppressing errors when including that file, we make it possible to run the same code even if the map is missing or deliberately switched off.) In addition, I can store support files anywhere I like, with whatever protections and isolations I like, and I can move them at will without breaking anything.

I’m sure there are many other ways to maintain seamless separation of code from configuration, regardless of where the server likes to store things, but as far as I’m aware this is among the cleanest, safest, and lowest-maintenance ways of achieving that goal.

All material on this site is carefully reviewed, but its accuracy cannot be guaranteed, and some suggestions offered here might just be silly ideas. For best results, please do your own checking and verifying. This specific article was last reviewed or updated by Greg on .

This site is provided for informational and entertainment purposes only. It is not intended to provide advice of any kind.