Articles

Creating isolated environments for PHP applications with PEAR dependencies


A simple roadmap for a portable and self contained PHP Application

First of all, this is just one way to do it. It can be used as a skeleton and improved. So it's not my intention to be absolutist here saying that everything should be this way. But it's a good start.

Many times php applications need some special configuration in their ini files (like extra modules, or any option that can be tweaked) and of course different versions of pear packages (some may use a deprecated package, or a special version that fixes some bug, etc). And of course all of them need to "live together" in the same server (even maybe mixed with some beta versions that sometimes we need as developers).

So this article is about how you can structure your applications so they can be deployed and upgraded in a more easy way. Also, it is useful for allowing developers to share a server and try different versions of the pear dependencies or even php (versions or ini settings).

Specifically, this is about cli applications. This is so, because I dont really do webapps, but also because you can actually configure a lot of things for a web application right there in your virtual host configuration, .htaccess file or equivalents, etc. That aside, this stuff should apply to both worlds.

Requirements for the PHP dependencies

The requirements are simple actually:

  • In this case, this is for unix environments (tested on linux). But can be ported to .bat files.
  • A working PHP/PEAR installation (tested with pear 1.9.4 and PHP 5.3.3). Note that this specific cli application example needs PHP 5.3, but it is not a requirement for this concept to work.

A little shell script knowledge wont hurt if you want to change things, of course!

The basic idea of how to make your PHP Application portable and standalone

  • Use the -c flag of the php cli to specify our own php.ini file.
  • Setup or own copy of pear.
  • Have our own 3rd party libraries installed, separated from the ones installed in the system itself. All dependencies will be specified in the config/setup/dependencies file.
  • The include_path will be reduced to what our application needs.
  • All of the above will ensure an isolated environment for our application (it will not intefere with the system's own settings or other libraries installed by 3rd parties).
  • To deploy the applications and install all of the dependencies, you would run a script in bin/setup/install-dependencies.sh.
  • A vendor directory will be generated where the fresh copy of pear and every pear dependency will be installed.
  • To run your jobs (or cli applications) you would use the file bin/run.sh
  • The bin/run.sh script would launch a php script with the correct configuration file, that acts as a stub (jobRunner.php).
  • The script jobRunner.php will receive the name of the job to execute and do everything needed to bootstrap things and run it.

The Quickstart

  • Download the code
  • Edit config/cli.properties to suit your needs (just the locations of your php and pear binaries)
  • Run "bin/setup/install-dependencies.sh"
  • Run "bin/run.sh jobRunner Job"

The tree layout of your standalone PHP Application

Note: You can find the source code for this article at github.

The src directory where your Standalone PHP Application is

This directory will hold your source code. I've chosen something similar to maven, putting the language name as a subdirectory (src/php).

The config directory of your PHP Application

Everything starts in the config directory. The php.ini file is well known, this is where you actually configure the php with any settings you may need. We're going to use the -c flag for the php cli to run our scripts.

The cli.properties file is where "the trick" is done, it will need to be included by every shell script in the application:

Our cli applications will be run through a shell script, and not directly by invoking php by ourselves. This script will include cli.properties and then have access to the paths for all the executables and directories needed.

In the config/setup/dependencies file, the application pear dependencies are declared:

It will be read and used by the bin/setup/install-dependencies.sh script. In this case, no versions are specified for these dependencies, but you could specify the exact versions needed.

The bin directory

This is where all your entry points should be. Let's start by the file bin/install-dependencies.sh

As you can see, it is a very very basic script that will just use the installed pear in the system to install new fresh copy of it under the vendors directory, creating also a configuration file with the desired default options to assure isolation. Then it will use the new installed pear to install all the pear dependencies found in the file config/setup/dependencies. Quite easy. It should only be run once, at deployment time (or every other time you update your dependencies).

Running the stub and the PHP jobs

We will use the file run.sh as the standard entry point for our php scripts. It will receive the name of the php script as argument (without the .php extension) and try to run it using our own php ini file, passing all command line arguments received (except for the name of the stub itself).

It doesnt matter where and how you invoke this shell script, it will always find its way to the absolute paths needed. Cool.

The stub itself will do nothing more than receive a list of command line arguments and use the first one to try to instantiate the job class. Remember, this is just an example application and not the point of the article. Your job structure should be a little smarter than just doing this.

So this is the code for the stub that will run our jobs:

To bootstrap the code, we use bootstrap.php, which does nothing more than the very basic stuff

An example run:

So from now on, you can concentrate in coding what you need inside the src/php directory (or whatever path you've chosen) and be sure that your system or applications will be easily deployable and wont conflict with other stuff in the target server, even when having esoteric setup needs, leaving room for the sysadmins to tweak things as needed.

Enjoy your standalone PHP application

Everything in this article can be applied to webapps and cli apps. It will allow you to easily control which dependencies are installed for the applications, and share a server without getting sucked into "dependency hell" issues. If you are a developer and share the server with others, everyone can use whatever php configuration and pear dependencies need, even messing up with them wont hurt other applications. When deploying and upgrading applications, you can be sure you are just messing around with one application at the time, and not affecting others.

Improvements? Probably many :) But this will get you started on the right path. I hope you liked it.