ZTS 版の PHP に PECL 拡張モジュールをインストールする

公開日

PHP に PECL 拡張モジュールをインストールしようとしてハマったのでメモ。

PHP で ImageMagick を使うためのラッパーであるimagick(pecl.php.net)のインストールを例にします。

`pecl install` でインストール

まずは普通にインストールしてみます。 ImageMagick については、 yum install ImageMagick だと古いバージョン6系がインストールされてしまうので、公式サイトのダウンロードページ(imagemagick.org)から7系最新バージョンの RPM ファイルを直接指定してインストール。

yum install https://imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-libs-7.0.10-29.x86_64.rpm

yum install https://imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-7.0.10-29.x86_64.rpm

yum install https://imagemagick.org/download/linux/CentOS/x86_64/ImageMagick-devel-7.0.10-29.x86_64.rpm

続いて PECL で imagick をインストールします。

これは ZTS 版の PHP ではダメな例であり、後でアンインストールする羽目になります。失敗の経験も含めて書き残しておく次第です。

pecl install imagick

インストールが完了するとこうなります。

Build process completed successfully

Installing '/usr/lib64/php/modules/imagick.so'

Installing '/usr/include/php/ext/imagick/php_imagick_shared.h'

install ok: channel://pecl.php.net/imagick-3.4.4

configuration option "php_ini" is not set to php.ini location

You should add "extension=imagick.so" to php.ini

オリジナル画像
図1:pecl install imagick が終わった時のコンソール画面

このメッセージでとくに重要なのは以下の2点です。

  • モジュールディレクトリ(/usr/lib64/php/modules/)に imagick.so がインストールされた
  • php.ini に "extension=imagick.so" の記述を手動で追加せよ

メッセージどおり php.ini に追記してもいいのですが、他のモジュールと同じように個別の .ini ファイルを作って .so を読み込むようにします。

vi /etc/php.d/20-imagick.ini

ファイルの中身はこれだけ。

extension=imagick

インストールのメッセージでは前述のとおり "extension=imagick.so" と書くように指示されていますが、これは古い書き方です。公式マニュアルにはPHP 7.2.0 以降では、拡張機能の名前が、拡張機能のファイル名の代わりに使えるようになりました。 これは OS に依存せず、特に初心者に簡単な仕組みです。 これは、読み込む拡張機能を指定する推奨できるやり方になっています。とあるので、拡張子なしの記述の方が良いでしょう。こうすることで開発機は Windows 、本番環境は Linux といった場合でも記述を統一できるメリットがあります。

php -m してみると、ちゃんと imagick も追加されています。

オリジナル画像
図2:php -m した結果

Web 画面の phpinfo() で認識されない

ところが、 Web 画面で phpinfo() を見ると imagick は追加されていません。よく見ると「Scan this dir for additional .ini files」のディレクトリが「/etc/php-zts.d」となっています。また extension_dir も「/usr/lib64/php-zts/modules」です。

オリジナル画像
図3:phpinfo() 画面の最上部のシステム情報部分

この zts とは何なのかいろいろ調べてみたところ、以前サイトを HTTP/2 対応した際、 Apache の動作を prefork → event に変更したことが原因だと分かりました。 Apache + PHP の組み合わせでは、 Apache が prefork モードでない場合、 Zend Thread Safety(ZTS)版の PHP が読み込まれるようになるようです。これは Apache の設定ファイル(私の環境だと /etc/httpd/conf.modules.d/15-php.conf )に書かれています。

#
# PHP is an HTML-embedded scripting language which attempts to make it
# easy for developers to write dynamically generated webpages.
#

# Cannot load both php5 and php7 modules
<IfModule !mod_php5.c>
  <IfModule prefork.c>
    LoadModule php7_module modules/libphp7.so
  </IfModule>
</IfModule>


<IfModule !mod_php5.c>
  <IfModule !prefork.c>
    LoadModule php7_module modules/libphp7-zts.so
  </IfModule>
</IfModule>

つまり、先ほど実施した pecl install では非 ZTS 版の方にインストールされてしまったので、 php コマンドを叩くと認識されるものの、 Web の PHP にはインストールされていないということだったのです。 ZTS 版の PHP の実態は /usr/bin/zts-php にあるので、 php -m でなく zts-php -m をすると、やはり imagick は追加されていませんでした。

ZTS 版の PHP に PECL 拡張モジュールをインストール

で本題ですが、 pecl install に ZTS 版へインストールするオプションがあれば一発解決なのですが、どうやらそのようなものはなさそうです(この辺あまり詳しくないので、もしあったら教えてください)。

なので手動ビルドすることにします。 PECL のimagick のページ(pecl.php.net)へ行き、最新バージョン(2020年9月9日現在は 3.4.4)の URL を調べて落とします。

wget https://pecl.php.net/get/imagick-3.4.4.tgz

gunzip imagick-3.4.4.tgz

tar -xvf imagick-3.4.4.tar

あとは公式マニュアルのphpize で共有 PECL 拡張モジュールをコンパイルする方法(www.php.net)を参考にしますが、下記2点に注意です。

  • phpize の代わりに zts-phpize を使う
  • ./configure のオプションで ZTS 版の php-config を指定する

cd imagick-3.4.4

zts-phpize

./configure --with-php-config=/usr/bin/zts-php-config

make

sudo make install

あとは先ほどと同じ要領で設定ファイルに "extension=imagick" を記述します。

vi /etc/php-zts.d/20-imagick.ini

サーバーを再起動すると、 Web 版の phpinfo() にも imagick が追加されました。

オリジナル画像
図4:phpinfo() 画面の imagick 部分

最後に、非 ZTS 環境にインストールしてしまった imagick をアンインストールします。

pecl uninstall imagick

rm /etc/php.d/20-imagick.ini