Using phpenv and php-build On Your Ubuntu

Why?

I needed to install PHP 5.4 on an Ubuntu box, in order to mess around with Drupal 8.

It turns out, however, that Ubuntu only has PHP 5.3 as of 12.04 LTS. There are a few other options available at this point for 5.4 (and 5.5), but I wanted to experiment with phpenv and php-build.

Note that I'm just trying to run phpunit and other PHP command line tools with this setup, so these instructions don't include info about setting up a server. I really have no idea whether that's possible. Further experimentation will no doubt tell us.

Meanwhile: What are phpenv and php-build? Good question.

phpenv

As far as I know, phpenv is used by the Travis-CI team to allow their continuous integration tools to work. It lives here: https://github.com/CHH/phpenv

phpenv is for PHP what rbenv is for Ruby. In fact, when you install phpenv it will install rbenv.

Basically, it's a command-line tool that makes it relatively easy to swap out different versions of PHP. You can say things like phpenv global 5.4.26 and then the next time you type php --version you'll see v.5.4.26. It does this by managing some symbolic links in the shell path.

In a continuous integration environment, you'd want to be able to test against different versions of PHP, which is what you can do on Travis-CI. So you make a script that says phpenv global [your version here] and you're off.

But wouldn't it be great to have a tool to manage the building of all those different PHP versions, and storing them in the proper place? Well here it is:

php-build

php-build allows you to build PHP to a specific directory, in such a way that it can be self-contained within that directory and not touch other parallel installations. It lives here: https://github.com/CHH/php-build

So, for instance, if you want to build PHP 5.4.26 so that phpenv can use it, you'd do something like this:

php-build -i development 5.4.26 $HOME/.phpenv/versions/5.4.26

And then if you have all the PHP build requirements, it does it, and you're done. You can say $HOME/.phpenv/versions/5.4.26/bin/php --version and get back v.5.4.26.

The Process

OK, so that was the lecture portion of this post, now for the practicum.

I use a bare-bones virtualized Ubuntu for various tasks.

This virtual Ubuntu is managed by vagrant, so I vagrant up and vagrant ssh, which might or might not be useful information to the reader.

Installing phpenv and php-build is pretty easy. Use git to clone them from GitHub, and then do what the READMEs say.

The hassle comes when it's time to start building PHP. Does your system have all the requirements? Let's find out.

You can pick a version to target. You can say:

php-build --definitions

You'll get a list of build targets that php-build knows about. Pick one... I chose 5.4.26 because that's what I was trying to accomplish.

Now do this:

php-build -i development 5.4.26 $HOME/.phpenv/versions/5.4.26

This tells php-build to build PHP 5.4.26 in phpenv's special directory that lets it manage the versions.

If your Ubuntu is as lightweight as mine, you'll get a lot of errors. Unfortunately, it takes quite a bit of time for those errors to happen. So sit tight.

I found this helpful giant list of requirements for building PHP on Ubuntu, but it seems pretty scattershot: http://www.litespeedtech.com/support/forum/threads/solved-cannot-find-openssls-libraries.7396/

That link has a giant list of packages to install which seems excessive, but here it is in copypastable form, along with a few more I needed:

make re2c bison libxml2-dev libssl-dev libbz2-dev libcurl3-dev libdb5.1-dev libjpeg-dev libpng-dev libXpm-dev libfreetype6-dev libt1-dev libgmp3-dev libc-client-dev libldap2-dev libmcrypt-dev libmhash-dev freetds-dev libz-dev libmysqlclient15-dev ncurses-dev libpcre3-dev unixODBC-dev postgresql-server-dev-9.1 libsqlite-dev libaspell-dev libreadline6-dev librecode-dev libsnmp-dev libtidy-dev libxslt-dev libt1-dev

So now that you've added all this stuff to your Ubuntu, you can try it again:

php-build -i development 5.4.26 $HOME/.phpenv/versions/5.4.26

This will build PHP in its special place. And then you can look at it with phpenv versions:

$ phpenv versions
* system (set by /home/vagrant/.phpenv/version)
  5.4.26

This will show you a list containing system, which is natively supplied by Ubuntu if you installed PHP, and 5.4.26, because yay, it worked.

The only problem is that the asterisk was in front of system, which means it's the current PHP, and that's not what we want. So we say:

phpenv rehash
phpenv global 5.4.26

phpenv rehash tells phpenv that we have a new binary to deal with, so do some internal accounting on it.

phpenv global 5.4.26 tells phpenv to go ahead and switch over to the PHP we just built. If we say phpenv versions again, we see the same list, but now the asterisk is in front of our new version.

Woot!

So now I can do cd drupal/core/ and then ./vendor/bin/phpunit and it works.

I'm sure you can think of creative things to do, as well.

Comments

Nice to see you're blogging again. More cogent: did you consider using Vagrant, and if so, why didn't you?

Well, like it says above. I'm using Vagrant. :-)

You can shorten your dependency list a bit by installing build-essential.

sudo apt-get install build-essential linux-headers-$(uname -r)

should get you everything you need in a vagrant box to build (for example) a kernel module.

... That's what I get for reading blogs at work. Sorry. Meant to ask why phpenv helps/is needed here if you're using vagrant. I'm asking because I basically gave up on rbenv/rvm for Ruby development when I started using vagrant; I had no reason to pollute the host system with multiple installs when I could just spin up a VM with the version I need for a project.

Also, have you thought about creating a Vagrantfile for this deploy? Seems like it would be pretty easy to convert your instructions.

This is the beginning of a proof of concept for a CI type thing, where I'll need to swap out PHP versions from time to time. There's another tool called PHP-FPM that does a good job of swapping out requirements, but I'm experimenting with phpenv.

The vagrant box I'm using has a Puppet-based list of requirements, and I'll eventually get around to adding this stuff to it.

Thanks for the comments. :-)