y_uti のブログ

統計、機械学習、自然言語処理などに興味を持つエンジニアの技術ブログです

anyenv + phpenv + php-build で複数のバージョンの PHP を切り替える

phpenv を利用して、複数のバージョンの PHP を切り替えて使えるようにする手順を紹介します。phpenv についてはウェブに多くの情報が見つかりますが、ここでは、anyenv の配下に phpenv/phpenv をインストールして、そのプラグインとして CHH/php-build を利用する方法で PHP の環境を構築します。

anyenv の導入

はじめに、anyenv をインストールします。anyenv は、rbenv や pyenv など、phpenv を含む *env 系のコマンドを一元管理できるようにしたものです。作者の方による紹介記事と GitHubリポジトリは、それぞれ以下にあります。

GitHub の説明どおりにインストールします。

$ git clone https://github.com/riywo/anyenv ~/.anyenv
$ echo 'export PATH="$HOME/.anyenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(anyenv init -)"' >> ~/.bash_profile
$ exec $SHELL -l

以下のように anyenv コマンドが認識されます。

$ which anyenv
~/.anyenv/bin/anyenv

phpenv の導入

次に、phpenv をインストールします。anyenv を用いて以下のようにインストールできます。

$ anyenv install phpenv
$ exec $SHELL -l

これで、phpenv コマンドも認識されるようになります。anyenv を利用して *env をインストールすると、以下のように ~/.anyenv/envs ディレクトリに各 *env 環境が作成されます。

$ which phpenv
~/.anyenv/envs/phpenv/bin/phpenv

phpenv には CHH/phpenv と phpenv/phpenv の二種類があり、anyenv でインストールされるのは後者の phpenv/phpenv の方です*1。それぞれの GitHub リポジトリは以下になります。phpenv の情報を調べるときには、どちらの phpenv について書かれている情報かに注意してください。

php-build の導入

phpenv/phpenv は、rbenv に依存していない点や PHP をビルドしてインストールできる点など、CHH/phpenv に比べて有利な点があるようですが*2、私の環境では install コマンドが上手く動きませんでした。そこで、install コマンドの機能のみ CHH/php-build を導入して実現することにします。CHH/php-build のリポジトリは以下になります。

CHH/php-build を phpenv/phpenv のプラグインとして導入します。以下のように phpenv の plugins ディレクトリに php-build を置くことで、phpenv のプラグインとして利用できるようになります。

$ cd ~/.anyenv/envs/phpenv
$ git clone https://github.com/CHH/php-build.git plugins/php-build

phpenv が提供している install コマンドを削除することで、php-build 側の install コマンドが使われるようにします*3。削除ではなくファイル名を変更する方法でも問題ありません。

$ rm libexec/phpenv-install

これで、php-build が提供する install コマンドを利用できるようになりました。バージョンを指定せずに phpenv install と入力すると、インストール可能なバージョンの一覧が表示されます。

$ phpenv install
phpenv v0.0.4-dev

usage: phpenv install VERSION
       phpenv install /path/to/definition

Available versions:
  5.2.17
  5.3.10
  5.3.11

...

表示される一覧は、以下のディレクトリに存在するものです。これは PHP のリリースに応じて php-build のリポジトリが更新されています。したがって、新しい PHP をインストールするには、git pull して php-build のリモートリポジトリの変更を取り込む必要があります。

$ ls -1 ~/.anyenv/envs/phpenv/plugins/php-build/share/php-build/definitions | head
5.2.17
5.3.10
5.3.11
5.3.12
5.3.13
5.3.14
5.3.15
5.3.16
5.3.17
5.3.18

PHP のインストールと切り替え

ここまでの作業で導入された phpenv を用いて PHP のインストールと切り替えを試してみます。たとえば、現時点での 5.5 系の最新である 5.5.17 をインストールするには、次のようにコマンドを実行します。指定したバージョンの PHP がダウンロードされ、ビルドされます。ソースコードからビルドしてインストールすることになるので、ビルドに必要な環境はあらかじめ導入されている必要があります。

$ phpenv install 5.5.17
...

ビルドに成功すると、phpenv verions コマンドで以下のように確認できます。インストール済みの PHP の一覧が表示されます。行頭のアスタリスクは、現在の PHP のバージョンを示します。system は、phpenv で管理されていない、このシステムのデフォルトの PHP を表します。

$ phpenv versions
phpenv v0.0.4-dev

* system (set by /home/y-uti/.anyenv/envs/phpenv/version)
  5.5.17

PHP のバージョンを切り替えるには、phpenv global コマンドを実行します。

$ phpenv global 5.5.17
phpenv v0.0.4-dev

5.5.17

これで、php のバージョンが 5.5.17 になります。

$ php -v
PHP 5.5.17 (cli) (built: Oct 13 2014 17:34:29)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
    with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2014, by Zend Technologies
    with Xdebug v2.2.5, Copyright (c) 2002-2014, by Derick Rethans

デフォルトの PHP に戻すにはバージョンとして system を指定します。

$ phpenv global system
phpenv v0.0.4-dev

system

CentOS 7 の yum でインストールされる 5.4.16 に切り替わっていることを確認できます。

$ php -v
PHP 5.4.16 (cli) (built: Sep 30 2014 09:44:39)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
    with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies

ビルドされた PHP の実体は、たとえば 5.5.17 であれば下記のディレクトリにあります。php.ini ファイルなどもこのディレクトリの配下に置かれており、バージョンごとに編集できます。

~/.anyenv/envs/phpenv/versions/5.5.17

PHP のビルドオプション等の構成を変更するには、下記のディレクトリ配下にあるファイルを編集します。

~/.anyenv/envs/phpenv/plugins/php-build/share/php-build

具体的な編集方法は、詳細に書きはじめると長くなってしまうので省略します。以下の記事などが参考になると思います。

Apache module のインストール

phpenv install を実行したときに、Apache のモジュールもインストールされるように設定します。まず、次のようにファイルを編集して、PHP のビルドオプションに --with-apxs2 を追加します。

$ vi ~/.anyenv/envs/phpenv/plugins/php-build/share/php-build/default_configure_options
...
--with-apxs2=/usr/bin/apxs2

これで libphp5.so が作られるようになりますが、現在の php-build には問題があり、この状態でビルドすると libphp5.so を /etc/httpd/modules に出力してしまいます*4。この問題を修正するパッチが以下の記事で公開されています。

このパッチを適用して php-build を修正します。

$ cd ~/.anyenv/envs/phpenv/plugins/php-build/bin
$ curl https://gist.githubusercontent.com/tkuchiki/10112836/raw/php-build.patch | patch -u php-build -

phpenv install すると、たとえば 5.5.17 であれば以下の場所に libphp5.so が出力されるようになります。

~/.anyenv/envs/phpenv/versions/5.5.17/libexec/libphp5.so

phpenv global で環境を切り替えると、指定したバージョンの libphp5.so へのシンボリックリンクが以下の場所に作成されます。これを LoadModule で指定することで、Apache 側の設定を変更せずに PHP のバージョン切り替えを反映させられます。

$ LANG=C ls -l ~/.anyenv/envs/phpenv/lib/libphp5.so | cut -f9- -d' '
/home/y-uti/.anyenv/envs/phpenv/lib/libphp5.so -> /home/y-uti/.anyenv/envs/phpenv/versions/5.5.17/libexec/libphp5.so*

ただし、PHPyum でインストールしている環境では、phpenv global system でデフォルトのバージョンに切り替えたときに、/etc/httpd/modules/libphp5.so へのシンボリックリンクを作成してくれない問題があります*5。この問題は phpenv-global を修正して解決できます。

@@ -44,6 +44,9 @@
 
# Link Apache apxs lib
APXS=""
+if [ "${PHPENV_VERSION}" == "system" ]; then
+ APXS="$(which apxs 2>/dev/null)"
+fi
php-config --configure-options 2>/dev/null | grep -q apxs && \
APXS="$(php-config --configure-options| sed 's/.*=\(.*apxs[^ ]*\) .*/\1/')"

Gist にパッチを公開しましたので、以下のようにして適用できます。

$ cd ~/.anyenv/envs/phpenv/libexec
$ curl https://gist.githubusercontent.com/y-uti/69e0b17f916fb5a25df4/raw/191dbfae6428ca55e311fb094991c4aa9295ab36/phpenv-global.patch | patch -

anyenv-update プラグインのインストール

anyenv, phpenv, php-build の更新 (git pull) を一括して実行できるように、anyenv-update プラグインを導入します。作者の方による紹介記事と GitHubリポジトリは、それぞれ以下にあります。

GitHubリポジトリを clone してインストールします。

git clone https://github.com/znz/anyenv-update.git ~/.anyenv/plugins/anyenv-update

このプラグインを利用すると、次のようにして anyenv 配下の環境を一括して更新できます。

$ anyenv update
Updating 'anyenv'...
Already up-to-date.

Updating 'anyenv-update'...
Already up-to-date.

Updating 'phpenv'...
Already up-to-date.

Updating 'php-build'...
Already up-to-date.

(2014/10/18 追記)
この記事の手順でソースコードの修正やパッチの適用を行うと、git pull に失敗することがあります。これは、修正が commit されていないことが原因です。修正を commit すると、git pull の際にマージが行われて正常に環境を更新できます*6

*1:phpenv/phpenv の dev branch を取得するようになっています。

*2:CHH/phpenv では、git clone した後に bin/phpenv-install.sh を実行し、rbenv のコードを取得して phpenv 用にコードの一部を変更するという導入方式になります。また、CHH/phpenv は PHP の切り替えのみに対応しており、PHP のインストールには別途 CHH/php-build を導入する必要があります。

*3:phpenv 本体のコマンド群は libexec サブディレクトリにあります。phpenv が設定する PATH の順番として、plugins 配下よりも libexec が優先されるようになっているため、同名のコマンドが存在する場合は libexec 側が優先されます。詳細は libexec/phpenv で bin_path を設定している箇所を参照してください。

*4:普通は一般ユーザの書き込み権限はないはずなので、sudo しない限り実際に上書きされてしまうことはないと思いますが。

*5:phpenv global では、php-config --configure-options で apxs の指定の有無を調べているのですが、yum でインストールされた PHP では --with-apxs2 オプションが指定されていないため、シンボリックリンクが更新されません。

*6:もちろん、修正箇所が conflict してしまった場合には解消する必要がありますが、私が今まで使っているなかでは、conflict の解消が必要になったことはありません。