👌

phpenvで最新版のPHPをインストールしてWebサイトで使用する

2021/02/22に公開

はじめに

唐突にPHPを使って簡易的なWebサイトを作りたくなったのでPHPの環境構築をすることにしました。そしてせっかくなので最新版のPHPをインストールすることにしました。公式サイトからソースをダウンロードしてビルドしてもよかったのですが、バージョン管理とか更新がめんどうなので、PHPのバージョン管理ができるphpenvを使ってインストールしたのですが、その作業が結構大変だったので、今回は自分が成功した手順を紹介したいと思います。

ちなみにPHPのバージョン管理にはphpenvとphpbrewがあって、phpbrewのほうがGitHubリポジトリのスターの数が多いですが、Rubyはrbenv, Pythonはpyenvを使用していてコマンド類がとても良く似ていて使いやすいのでphpenvを使用することにしました。

もう一つの理由としてはphpbrewはどうやら PHP 7 系をインストールするときに発生するバグがあるらしく、自分も試した結果、phpbrewのインストールまではうまくいったけど、その後PHPをビルドする際にエラーが発生して全くインストールできなかったです。またGitHubのIssueを確認すると、多くの人が同じエラーが出ると言っていますが、解決法を試してもダメだったので、諦めました。

今回の環境構築では「phpenvで複数のPHPのバージョンを管理する」の記事を大変参考にさせていただきました:pray:
ほとんどこちらのサイト通りで問題ないのですが、一部追加で必要なパッケージがあったり、自分の環境では壮絶なOpenSSL問題が発生したりしたので、そのへんも詳しく紹介していきます。

TL;DR

読むのがめんどうな人向けです。

$ git clone https://github.com/CHH/phpenv.git
$ cd phpenv/bin
$ ./phpenv-install.sh
~/.bashrc
export PATH="$HOME/.phpenv/bin:$PATH"
eval "$(phpenv init -)"
$ source ~/.bashrc
$ git clone https://github.com/CHH/php-build.git ~/.phpenv/plugins/php-build
$ sudo yum -y install epel-release
$ sudo yum -y install gcc libxml2 libxml2-devel libcurl libcurl-devel libpng libpng-devel libmcrypt libmcrypt-devel libtidy libtidy-devel libxslt libxslt-devel openssl-devel bison libjpeg-turbo-devel readline-devel autoconf
$ phpenv install --list
$ phpenv install x.x.x

phpenv install で OpenSSL に関するエラーが発生したら「OpenSSLとの壮絶な闘い」を参照

$ phpenv global x.x.x
$ php -v
$ cp ~/.phpenv/versions/x.x.x/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/x.x.x/etc/php-fpm.d/www.conf
$ cp ~/.phpenv/versions/x.x.x/etc/php-fpm.conf.default ~/.phpenv/versions/x.x.x/etc/php-fpm.conf
$ sudo ~/.phpenv/versions/x.x.x/sbin/php-fpm
$ ps -ef | grep php-fpm | grep -v grep

Webサーバを起動してPHPが使用できるか確認する
CentOS7 + Nginx + PHP-FPM でPHPを実行する環境を整える」参照

# composerのインストール(任意)
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('SHA384', 'composer-setup.php') === '55d6ead61b29c7bdee5cccfb50076874187bd9f21f65d8991d46ec5cc90518f447387fb9f76ebae1fbbacf329e583e30') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"
$ sudo mv composer.phar /usr/local/bin/composer
$ composer --version

環境

  • CentOS 7

phpenvのインストール

まずはphpenvをGitHubのリポジトリからダウンロードしてインストールします。

phpenvのリポジトリは、phpenv/phpenvCHH/phpenvの2種類あって、phpenv/phpenvのほうが如何にも公式って感じでこちらでインストールしようとしたのですが、こちらはバグが多すぎる上に、Issueに載っている解決法もバラバラで、さらにすべて試してもうまくいかないことがあったので、諦めました。そしてCHH/phpenvをインストールしたら何の問題もなくあっさり出来たので、こちらをインストールします。

$ git clone https://github.com/CHH/phpenv.git
$ cd phpenv/bin
$ ./phpenv-install.sh

インストールが終わったら、以下の設定を.bashrcに追加します。

~/.bashrc
export PATH="$HOME/.phpenv/bin:$PATH"
eval "$(phpenv init -)"

追加したら、.bashrcを再読み込みします。

$ source ~/.bashrc

phpenvがインストールできたら、クローンしたリポジトリ(phpenvディレクトリ)は必要ないので削除して大丈夫です。間違って.phpenvを削除しないように注意してください。

php-buildのインストール

次にphp-buildをインストールします。

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

依存関係のあるパッケージのインストール

インストールの前にEPELリポジトリを追加しないとインストールできないパッケージがあるので、以下のコマンドでEPELリポジトリをインストールします。

$ sudo yum -y install epel-release

参考: CentOS7.1 64bitのyumリポジトリにEPELを追加

PHPでは非常に多くのパッケージをインストールしないといけなくて、パッケージが存在しないぞというエラーが、毎回インストールで時間が経ったあとに出てくるので大変でした。なので、無駄な時間を消費しないために、先に必要なパッケージを一気にインストールします。

$ sudo yum -y install gcc libxml2 libxml2-devel libcurl libcurl-devel libpng libpng-devel libmcrypt libmcrypt-devel libtidy libtidy-devel libxslt libxslt-devel openssl-devel bison libjpeg-turbo-devel readline-devel autoconf

develのついているほうとついていないほうはどちらかがインストールできれば良いと思いますが、あとでインストールし損じてエラーになるのが厄介なので、両方まとめて指定します(どちらか一方のみがインストールされることが多いです)

PHPのインストール

以下のコマンドでインストール可能なPHPのバージョンを確認します。

$ phpenv install --list

現在の安定版のバージョンは、公式のダウンロードページで確認できます。

確認したら、インストールしたいバージョンを指定してインストールします。

$ phpenv install x.x.x

x.x.xの箇所にインストールしたいバージョンを指定してください。形式は必ずしもこうとは限らないので、phpenv install --list で表示された通りに指定してください。

なお、インストールにはかなり時間がかかります。自分の環境では20分ちょっとかかりました。時間に余裕があるときにゆっくりと作業してください:coffee:

最後にsuccessfullyと表示されればインストール完了です。

もしここでOpenSSLに関するエラーが発生した場合は後述するOpenSSLとの壮絶な闘いを参考にしてください。

この状態でPHPのバージョンを確認しようとすると以下のように表示されます。

$ php -v
phpenv: php: command not found

The `php' command exists in these PHP versions:
  x.x.x

これはPHPはインストールされているけど、phpコマンドとしてのパスが通っていないことを示します。
以下のコマンドでパスを通します。

$ phpenv global x.x.x

phpコマンドを打ったときに実行されるPHPのバージョンを選んで指定してください。複数バージョンをインストールしても、特に指定しない場合に実行されるバージョンが上記で指定したバージョンになります。

そしてもう一度バージョンを確認します。

$ php -v

バージョンなどが表示されればOKです。

PHP-FPMのインストール

ここまでの設定だと、phpコマンドを実行した際には、今回インストールしたPHPが使えますが、Webアプリケーションとしては使用できません(.phpのファイルをWebサーバで配信することができません。仮に実行できたとしたらそれは以前にyumでインストールしたPHPを使用している可能性があります。)

そのため、今回インストールしたPHPをWebアプリケーションとして実行できるようにするために、PHP-FPMを使えるようにします。

$ cp ~/.phpenv/versions/x.x.x/etc/php-fpm.d/www.conf.default ~/.phpenv/versions/x.x.x/etc/php-fpm.d/www.conf
$ cp ~/.phpenv/versions/x.x.x/etc/php-fpm.conf.default ~/.phpenv/versions/x.x.x/etc/php-fpm.conf

x.x.xにはインストールしたPHPのバージョンを指定してください。

次にPHP-FPMのプロセスを起動します。

$ sudo ~/.phpenv/versions/x.x.x/sbin/php-fpm

起動できたか確認するには以下のコマンドを実行します。

$ ps -ef | grep php-fpm | grep -v grep

PHP-FPMにプロセス(画面に何か)が表示されればOKです。

参考: Mac OS X El CapitanにNginx + phpenv + php-build + php-fpmの環境を構築する手順

Webサーバで確認

今回インストールされたPHPがWebアプリケーションとして実行できるか確認します。これに関しては「CentOS7 + Nginx + PHP-FPM でPHPを実行する環境を整える」を参考にしてください。最後の確認(phpinfo()の内容)で、今回インストールしたPHPのバージョンが表示されればOKです。

Composerのインストール(おまけ)

PHPがインストールできてしまえば、Composerのインストールはとても簡単なのでついでに紹介します。

ComposerとはPHPのパッケージ管理ツールです。RubyでいうGem, NodeでいうNPMに相当します。結構便利なので、PHPで開発する際はインストールしておいて損はないと思います。

インストールするには以下のコマンドを実行します。

$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('SHA384', 'composer-setup.php') === '55d6ead61b29c7bdee5cccfb50076874187bd9f21f65d8991d46ec5cc90518f447387fb9f76ebae1fbbacf329e583e30') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"

:warning: 2つめの長いコマンドに関してですが、これはインストーラのSHAの検証を行っています。ここで指定している値が今後将来的に同じかどうかはよくわからないので、上記のコマンドでうまくいかない場合は公式サイトのダウンロードページに行ってダウンロードスクリプトをコピペして実行してください。

インストールされたら以下のコマンドでバージョンを確認してください。

$ ./composer.phar --version

バージョンが表示されればOKです。

このままでも使えますが、一般的なコマンドではなくて少し使いづらいので、composer.pharを移動させて、汎用的なコマンドとして実行できるようにします。

$ sudo mv composer.phar /usr/local/bin/composer

composerコマンドで同じ結果が表示されたら成功です。

$ composer --version

参考: Composer を CentOS にインストールする手順

:warning: コマンドが見つからないと表示された場合は/usr/local/binのパスを通してください。

~/.bashrc
export PATH="/usr/local/bin:$PATH"

.bashrcを再読み込みします。

$ source ~/.bashrc

OpenSSLとの壮絶な闘い

こちらは、OpenSSLでエラーが発生する場合についてです。上記の手順で問題なくインストールできた場合は気にする必要はありません。

少し前に、「OpenSSLをソースからビルドしてNginxで使用する」という記事を投稿しました。これにある通り、自分はOpenSSLをソースからビルドして、OpenSSL 1.0.2 系の環境にしました。実はこれが、自分の環境でのインストールを厄介にさせた一番の理由でした。この問題に悩まされなかったVM上の環境では上記の手順ですんなりいけたのに、1.0.2系をインストールしたマシン上では相当苦労しました…

このようなエラーが発生しました。

/tmp/php-build/source/x.x.x/ext/ftp/php_ftp.c:313: undefined reference to `OPENSSL_init_ssl'
/tmp/php-build/source/x.x.x/ext/ftp/php_ftp.c:314: undefined reference to `OPENSSL_init_crypto'
/tmp/php-build/source/x.x.x/ext/ftp/php_ftp.c:315: undefined reference to `OPENSSL_init_crypto'
/tmp/php-build/source/x.x.x/ext/ftp/php_ftp.c:316: undefined reference to `OPENSSL_init_crypto'
/tmp/php-build/source/x.x.x/ext/ftp/php_ftp.c:318: undefined reference to `OPENSSL_init_ssl'
ext/ftp/.libs/ftp.o: In function `ftp_login':
/tmp/php-build/source/x.x.x/ext/ftp/ftp.c:283: undefined reference to `TLS_client_method'
/tmp/php-build/source/x.x.x/ext/ftp/ftp.c:292: undefined reference to `SSL_CTX_set_options'
ext/phar/.libs/util.o: In function `phar_verify_signature':
/tmp/php-build/source/x.x.x/ext/phar/util.c:1563: undefined reference to `EVP_MD_CTX_new'
/tmp/php-build/source/x.x.x/ext/phar/util.c:1595: undefined reference to `EVP_MD_CTX_free'
/tmp/php-build/source/x.x.x/ext/phar/util.c:1586: undefined reference to `EVP_MD_CTX_free'
ext/phar/.libs/util.o: In function `phar_create_signature':
/tmp/php-build/source/x.x.x/ext/phar/util.c:1860: undefined reference to `EVP_MD_CTX_new'
/tmp/php-build/source/x.x.x/ext/phar/util.c:1892: undefined reference to `EVP_MD_CTX_free'
collect2: error: ld returned 1 exit status

その原因についてですが、いろいろ調べていたら PHPのビルドではOpenSSLのSSLv2に関する関数を実行しているのですが、OpenSSL 1.0.2f 以降のバージョンでは、実はこの関数はセキュリティ上の理由から削除されてしまいました。

参考: php-5.3.3のビルドでエラーが出てしまう
参考: OpenSSL 1.0.2 Series Release Notes

ビルドの際に使用する関数が使えなくなってしまったので、当然エラーが発生します。ここで一番困るのが、エラーが発生するタイミングです。コマンドを実行して即座にエラーが発生するならまだしも、この関数を使用するのはインストールの最後のほうなので、ただでさえ20分以上かかるPHPのビルドで散々待たされた結果、OpenSSLでエラーが発生するので、非常に酷でした。後述しますが、何度も失敗しているので、この20分近く待たされる状態を数回繰り返しました。

結局問題がわかったので、少し前のバージョン(SSLv2に関する関数が用意されているバージョン)を使えば良いというのが解決策なのですが、いろんなサイトを調べると、全く同じエラーに関する解決策を示すサイトが山ほどあるのに、どれを試しても一切解決しませんでした。

以下のように、ヘッダーファイルが見つからないとか、ライブラリが不足している(不足していないのに)と言われてしまいます。

configure: error: Cannot find OpenSSL's <evp.h>
configure: error: Cannot find OpenSSL's libraries

そして、唯一PHPのビルドに成功したのが、以下のサイトの手順です。

PHP+OpenSSLバージョンアップ

上記サイトのOpenSSLバージョンアップの作業に従ってOpenSSLをインストールして、phpenvでインストールするときに--with-opensslオプションをつけると、ようやくビルドが通るようになりました。結局、エラーが直らなかった原因は、OpenSSLのインストール先が違っていたことなんですが、他のサイトでは/usr/local/opensslとかにインストールすることが多くて、これだとうまくいきませんでした。/usr/localにインストールしたときに限っては/usr/local/bin/usr/local/includeにそれぞれOpenSSLのバイナリファイルとライブラリ等のファイルがインストールされ、php-buildが正しくOpenSSLを認識してくれるようになりました。でもこれはどこを調べても解決しなかったので、解決するまで非常に時間がかかりました。

これで問題は解決かというと実はそうではなくて、今度はComposerをインストールするときに同様にOpenSSLでエラーが発生してインストールできませんでした。Composerのインストールのときにも同様に特定のOpenSSLを指定する方法がわからないし、ここまで来るともはやPHPに関する何かしらをインストールする度にエラーが発生するので、ついにここで心が折れて、yumでインストールできるoepnssl-develに戻すことにしました。せっかく最新版のOpenSSLをソースからビルドしたので、正直すごく嫌でしたが、これからのことも考えて仕方なく決めました。

ただ、yumのopenssl-develがインストールされていて、opensslコマンドを実行するときにもちゃんとそちらが実行されるようになっていたのですが、なぜかビルドするときには、最新版のOpenSSLが使用されてしまってエラーが発生するので、ソースからビルドしたOpenSSLをすべてアンインストールすることにしました。

$ sudo rm -rf /usr/local/ssl
$ sudo rm -rf /usr/local/openssl
$ sudo rm -rf /usr/local/bin/openssl
$ sudo rm -rf /usr/local/include/openssl

そして念のためopensslをアンインストールしopenssl-develを再インストールしました。

$ sudo yum -y remove openssl
$ sudo yum -y remove openssl-devel
$ sudo yum -y install openssl-devel

openssl-develだけだとopensslコマンドは使えませんが、バイナリ自体はどこかに存在するので、今回ビルドを通す分には問題ありませんでした。

さらに念には念を入れて、サーバを再起動しました。そしてもう一度Composerをインストールしようとしましたが、同じエラーでした。そこで一旦インストールしたPHPを削除してもう一度インストールし直してみました。

$ rm -rf ~/.phpenv/versions/x.x.x

x.x.xにはPHPのバージョンが入ります。

そして、もう一度インストールしました。

$ phpenv install x.x.x

今度はyumでインストールしたopenssl-develを使用してビルドしたので、--with-opensslオプションをつけなくても、エラーなくインストールすることができました。

そして、もう一度Composerをインストールしたら、ちゃんとインストールすることができました…!

というわけで結論ですが、phpenvに限らずPHPをソースからビルドする際に、OpenSSLの最新版(1.0.2系など)をソースからビルドした環境で行うと、果てしなくエラーに悩まされるのでおすすめしません。素直にopenssl-develをyumでインストールすればこれらの問題は起こりません。実際、多くのサイトではそのように解決されているので、今回のケースでの解決がなかなかできませんでした。

結局ソースからビルドしたOpenSSLではComposerのインストールまでできなかったし、解決したか、と言われると微妙なのですが、PHPのビルドとComposerのインストールに関しては「一応解決した」ということにしておきます。

解決方法というより、ほとんど愚痴っぽい感じになってしまいましたが、OpenSSL問題で同じく苦労された人に役立てば幸いです。

GitHubで編集を提案

Discussion