phpizeによるPHP拡張機能のインストール

phpizeによるPHP拡張機能のインストール方法を記す。

3種類のPHPの拡張機能のインストール方法

PHP本体に拡張機能 (モジュール) を追加する方法が3種類ある。

それぞれの方法とその利点・欠点を以下の表に整理した。

PHPの拡張機能の有効化方法
方法 説明 利点 欠点
組み込み PHPのビルド時に–with-xxxで拡張機能を指定。
  • php.iniでextension指令での設定が不要。
  • ビルド時にしか指定できない。
  • 拡張機能の無効化不可能。
pecl pecl installで拡張機能をインストール。
  • 拡張機能の追加有効化が可能。
  • コマンド一発で簡単。
  • php.iniのextension指令により有効化が必要。
  • peclでインストールできない拡張機能が存在。
phpize 拡張機能をビルド・インストール。
  • 拡張機能の追加有効化が可能。
  • PHP標準の全拡張機能に対応。
  • php.iniのextension指令により有効化が必要。
  • コマンドがやや手間。

組み込みはPHPのソースコードビルド時のconfigureのオプションで–enable-xxxや–with-xxで拡張機能を有効化する方法だ。この方法は,PHPのビルド時にしか機能を有効化できないため,後で機能追加する場合に,わざわざPHP本体の再ビルドが必要になるので手間だ。PHPの拡張機能は74個もあるため,ビルド時に全機能を有効化するのは現実的ではない。

peclはパッケージマネージャーのAPTやyumと似ている。コマンドを実行することで,自動的にPECLリポジトリーからパッケージをダウンロード・ビルドしてPHPに拡張機能を追加してくれる。ただし,以下2点の欠点がある。

  1. 使用しているphpのextension_dir (例: lib/php/extensions/debug-zts-YYYYMMDD/) にインストールするため,場合によっては管理者権限が必要。
  2. 拡張機能がpeclのリポジトリーに登録されていないとダメ。

1点目は設定でインストール場所を変更できそうなので問題ないかもしれない。しかし,2点目が大きい。例えば,拡張機能のzlibとmbstringはPECLリポジトリーに存在しないため,peclからインストールできない。そのため,PHPの拡張機能はpeclで全てを有効化できない。ここが非常に惜しい。

phpizeは役割としては組み込みとpeclの中間に位置しており,低レベルで柔軟な方法だ。PECLリポジトリーPHPのソースコード内のext/ディレクトリー配下に存在する拡張機能のソースコードを自分でビルドする。


ルド時にphpizeを実行することで,使用するphp用の拡張機能のライブラリー (.so)
をビルドし,インストールする。インストールせずに,ビルドの段階で止めることもできる。ビルド時にphp-configコマンドを参照し,phpの設定に応じたビルドを行うため,php-configが存在しないと使えない。ただし,それ以外の場合であれば,peclと異なりPHPの全拡張機能に対応できる。そのため,phpizeはPHPの拡張機能を追加で有効化する場合の最善の方法だろう。

そこで,phpizeによるPHPの拡張機能の有効化方法を解説する。

phpizeによる手順概要

まず,phpizeによるビルド・拡張機能の有効化手順を解説する。PHPの拡張機能は共有ライブラリー (.so) 形式であるため,PHPのバージョンが違うと適用できないことに注意する。

phpizeによるビルド・拡張機能の有効化手順
  1. PHPのソースコードをダウンロードする。このとき,ソースコードのバージョンを使用するPHPのバージョンと一致させておく (VER=$(php -v | grep -o '[0-9.]*' | head -n 1))。
  2. 拡張モジュールのディレクトリー (php/ext/<extension>) に移動。
  3. phpizeコマンドを実行。
  4. ビルド・インストールを実行 (./configure; make; make test; make install)。
  5. PHPの拡張機能ディレクトリー (extension_dir, 標準はlib/php/extensions/debug-zts-YYYYMMDD/) に拡張機能がインストールされる。
  6. php.iniか.user.ini (CGI版PHPのみ) にextension = <extension>を記入し,拡張機能を有効化。
  7. モジュール版PHPの場合,サーバーを再起動 (例: apachectl restart) して設定を反映。

CGI版のphpの拡張機能のビルド時など,システム標準以外のphp向けに拡張機能をビルドする時は,./configure--with-php-configオプションで対象のphp向けのphp-configをフルパスで指定する (参考: PHP: Compiling shared PECL extensions with phpize – Manual)。

インストールしたくない場合,make installを実行しなければ拡張機能はインストールはされない。その場合,modulesディレクトリーに拡張機能のライブラリーが格納されているので,必要に応じてこのファイルを参照する。

設定ファイルのextension指令は拡張機能1個につき,1回ずつ記入する。複数個の拡張機能を有効化する場合,その数だけextension = を記入する。サンプルのphp.iniに記載がある通り,カンマ区切りで複数個指定できないので注意する。

拡張機能を標準のextension_dir (php -i grep | ^extension_dirで確認可能) 以外に格納している場合,絶対パスで指定することもできる。

ネット上の事例では,拡張子.soや.dllを記入している例が多い。しかし,末尾の拡張子は将来の廃止事項となっているので,拡張子は省略しよう。

拡張機能の依存情報

拡張機能のビルドに外部ライブラリーが必要なことがある。必要なライブラリーは拡張機能のRequirementsのページに明記されている (例: https://www.php.net/manual/en/zip.requirements.php)。

確認できた拡張機能ごとの依存関係を以下の表に示す。

PHPの拡張機能の依存情報
拡張機能 依存先
cURL libcurl 7.10.5+
GD PHPに付属しているので,libgd自体は不要。ただし,実際の画像処理には対応する画像のライブラリー (gif, jpeg, png, xpm, freetype) が必要。
intl ICU 50.1+
mbstring なし
MYSQL Improved Extension (mysqli) なし
MySQL Native Driver (mysqlnd) OpenSSL (SHA-256認証対応)
openssl OpenSSL 1.0.1+
pdo なし
pdo_mysql なし
zend_test
zip libzip
zlib zlib

確認できたものがあれば,随時追記していく。

インストール手順

具体的なインストールコマンドを記す。

インストール情報
項目 説明
配布元
リポジトリー
手順 PHP: Compiling shared PECL extensions with phpize – Manual
依存先 (必須)
依存元 Nextcloud, Tiny Tiny RSS, GNU Social, Kanboard
インストールコマンド
sh -eux <<-"EOT"
LOCAL=~/.local J=$(grep -cs '^processor' /proc/cpuinfo || echo 2)
PKG=php VER=$(php -v | grep -o '[0-9.]*' | head -n 1) TAG=$PKG-$VER
mkdir -p "$LOCAL/src"
cd "$LOCAL/src"

if command -v git >/dev/null; then
  [ -e $PKG ] || git clone --depth 1 git://git.php.net/php-src.git $PKG
  cd $PKG
  git fetch --depth 1 origin tag $TAG
  git checkout -f $TAG
else
  [ -e $PKG-$VER ] || wget http://jp2.php.net/distributions/$PKG-$VER.tar.xz
  tar -xf $PKG-$VER.*
  cd $PKG-$VER
fi

MOD="bcmath bz2 calendar com_dotnet ctype curl date dba dom enchant exif
fileinfo filter ftp gd gettext gmp hash iconv imap interbase intl
json ldap libxml mbstring mysqli mysqlnd oci8 odbc opcache openssl
pcntl pcre pdo pdo_dblib pdo_firebird pdo_mysql pdo_oci pdo_odbc pdo_pgsql
pdo_sqlite pgsql phar posix pspell readline recode reflection session
shmop simplexml skeleton snmp soap sockets sodium spl sqlite3 standard
sysvmsg sysvsem sysvshm tidy tokenizer wddx xml xmlreader xmlrpc xmlwriter
xsl zend_test zip zlib"
#MOD="intl"
for mod in $MOD; do
  cd ext/$MOD
  make -kj $J distclean clean || :
  [ ! -e config.m4 ] && [ -e config?.m4 ] && ln -fs config?.m4 config.m4
  phpize
  case $mod in
    mysqlnd) PHP_OPENSSL_DIR="$LOCAL" ./configure;;
    *)       ./configure;;
  esac
  make -j $J
  make -j $J NO_INTERACTION=1 test
  make -j $J install
  cd ..
done
EOT
インストール例
日付 拡張機能 OS 依存関係
2019-04-28 cURL, GD, mbstring, OpenSSL, zip, zlib Ubuntu 18.04 PHP 7.3.4, GNU Make 4.2.1, GCC 7.4.0, cURL 7.64.0, OpenSSL 1.1.1a, libzip 1.5.2, zlib 1.2.11
2019-05-04 zend_test Ubuntu 18.04 PHP 7.3.4, GNU Make 4.2.1, GCC 7.4.0

MOD変数にインストール対象の拡張機能名を指定して,1個ずつインストールしている。必要に応じてMOD変数を書き換えてインストールすればよいだろう。

config.m4の欠如

zlibをビルドしようとphpizeコマンドを実行すると,以下のエラーが表示された。

phpize
Cannot find config.m4.
Make sure that you run '/home/senooken/.local/bin/phpize' in the top level source directory of the module

zlibや一部の拡張機能でconfig.m4が存在しないのが問題のようだ。代わりに,config.m4の代わりにはconfig0.m4がある。

他にもconfig.m4が存在しない拡張機能が存在するか以下のコマンドで確認してみた。

find . -name "config?.m4" | sort
./date/config0.m4
./libxml/config0.m4
./mysqlnd/config9.m4
./openssl/config0.m4
./pcre/config0.m4
./recode/config9.m4
./sqlite3/config0.m4
./zlib/config0.m4

config0.m4の他にconfig9.m4が存在するケースがあることがわかった。また,recode拡張機能のようにconfig9.m4とconfig.m4が両方共存在するケースもあった。

ひとまず,phpize実行前に以下のコマンドでconfig.m4が存在しない場合にconfig.m4へのシンボリックリンクを貼ることで対応した。

[ -e config.m4 ] || [ -e config?.m4 ] && ln -fs config?.m4 config.m4

なぜconfig.m4が一部の拡張機能に存在しないのか調べてみた。しかし,以下で同じ質問がある程度で,はっきりとした理由はわからなかった。

PHP Install — Why does ext/zlib have config0.m4 instead of config.m4

ひとまずシンボリックリンクを貼ることで対応できたのでよしとする。

拡張機能ごとの対応

cURLのmake test失敗

PHP 7.3.4のcurl 7.64.0 (OpenSSL 1.1.1a, zlib 1.2.11) のmake testが失敗している。

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
Bug #76675 (Segfault with H2 server push write/writeheader handlers) [tests/bug76675.phpt]
=====================================================================

サーバー関係のテストで失敗しているようだが,原因がわからなかった。

ローカル環境で検証したいだけなので,遺憾だがそのままmake installした。

OpenSSLのmake test失敗

PHP 7.3.4のOpenSSL (OpenSSL 1.1.a) の拡張機能のmake testが失敗する。

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
#46127 php_openssl_tcp_sockop_accept forgets to set context on accepted stream [tests/bug46127.phpt]
Bug #48182: ssl handshake fails during asynchronous socket connection [tests/bug48182.phpt]
Bug #54992: Stream not closed and error not returned when SSL CN_match fails [tests/bug54992.phpt]
Bug #65538: SSL context "cafile" supports stream wrappers [tests/bug65538_001.phpt]
Bug #65538: SSL context "cafile" supports phar wrapper [tests/bug65538_003.phpt]
Bug #65729: CN_match gives false positive when wildcard is used [tests/bug65729.phpt]
Bug #68265: SAN match fails with trailing DNS dot [tests/bug68265.phpt]
Bug #68879: Match IP address fields in subjectAltName checks [tests/bug68879.phpt]
Bug #68920: peer_fingerprint input checks should be strict [tests/bug68920.phpt]
Bug #69215: Crypto servers should send client CA list [tests/bug69215.phpt]
Bug #72333: fwrite() on non-blocking SSL sockets doesn't work [tests/bug72333.phpt]
Bug #74159: Writing a large buffer to non-blocking encrypted streams fails [tests/bug74159.phpt]
Bug #76705: unusable ssl => peer_fingerprint in stream_context_create() [tests/bug76705.phpt]
Bug #76705: feof might hang on TLS streams in case of fragmented TLS records [tests/bug77390.phpt]
capture_peer_cert context captures on verify failure [tests/capture_peer_cert_001.phpt]
openssl_get_cert_locations() tests [tests/openssl_get_cert_locations_basic.phpt]
Testing peer fingerprint on connection [tests/openssl_peer_fingerprint_basic.phpt]
Peer verification enabled for client streams [tests/peer_verification.phpt]
Peer verification matches SAN names [tests/san_peer_matching.phpt]
Capture SSL session meta array in stream context [tests/session_meta_capture.phpt]
sni_server [testsっっs/sni_server.phpt]
sni_server with separate pk and cert [tests/sni_server_key_cert.phpt]
Basic bitwise stream crypto context flag assignment [tests/stream_crypto_flags_001.phpt]
TLSv1.1 and TLSv1.2 bitwise stream crypto flag assignment [tests/stream_crypto_flags_002.phpt]
Server bitwise stream crypto flag assignment [tests/stream_crypto_flags_003.phpt]
Specific protocol method specification [tests/stream_crypto_flags_004.phpt]
security_level setting to prohibit cert [tests/stream_security_level.phpt]
Verify host name by default in client transfers [tests/stream_verify_peer_name_001.phpt]
Allow host name mismatch when "verify_host" disabled [tests/stream_verify_peer_name_002.phpt]
Host name mismatch triggers error [tests/stream_verify_peer_name_003.phpt]
Specific crypto method for ssl:// transports. [tests/streams_crypto_method.phpt]
tls stream wrapper with min version 1.0 and max version 1.1 [tests/tls_min_v1.0_max_v1.1_wrapper.phpt]
tls stream wrapper [tests/tls_wrapper.phpt]
tlsv1.0 stream wrapper [tests/tlsv1.0_wrapper.phpt]
tlsv1.1 stream wrapper [tests/tlsv1.1_wrapper.phpt]
tlsv1.2 stream wrapper [tests/tlsv1.2_wrapper.phpt]
=====================================================================
./bug46127.sh
Warning: stream_socket_client(): unable to connect to ssl://127.0.0.1:64321 (Connection refused) in /home/senooken/.local/src/php/ext/openssl/tests/ServerClientTestCase.inc(118) : eval()'d code on line 10

Warning: fgets() expects parameter 1 to be resource, bool given in /home/senooken/.local/src/php/ext/openssl/tests/ServerClientTestCase.inc(118) : eval()'d code on line 12

なんか,ssl://で接続できていない。

openssl s_client -connect localhost
139995254880064:error:0200206F:system library:connect:Connection refused:crypto/bio/b_sock2.c:110:
139995254880064:error:2008A067:BIO routines:BIO_connect:connect error:crypto/bio/b_sock2.c:111:
connect:errno=111

ApacheのSSLが有効になっていないのが原因だろう。先にApacheのSSLを有効化する。

Apacheに証明書をインストールして,mod_sslを有効化すると,エラーが減る。

SSLを有効化して実行すると応答がない。

./bug46127.sh

試しに,OSにインストールされているphpで実行すると警告が出る。

/usr/bin/php bug46127.php
PHP Warning:  stream_socket_server(): unable to connect to ssl://127.0.0.1:64321 (Address already in use) in /home/senooken/.local/src/php/ext/openssl/tests/ServerClientTestCase.inc(107) : eval()'d code on line 7
PHP Warning:  stream_socket_accept() expects parameter 1 to be resource, boolean given in /home/senooken/.local/src/php/ext/openssl/tests/ServerClientTestCase.inc(107) : eval()'d code on line 10
PHP Warning:  fwrite() expects parameter 1 to be resource, boolean given in /home/senooken/.local/src/php/ext/openssl/tests/ServerClientTestCase.inc(107) : eval()'d code on line 11

原因がわからず,どうしてもOpenSSLの拡張機能のmake testが失敗する。

やむを得ないので,make testは成功していないが,そのままmake installした。

intl

PHP 7.3.4, ICU 50.2のmake checkが失敗した。

=====================================================================
FAILED TEST SUMMARY
---------------------------------------------------------------------
spoofchecker with locale settings [tests/spoofchecker_003.phpt]
=====================================================================

対処方法がわからないため,やむを得ずそのままインストールした。

MySQL関係
mysqlnd

./configure実行時に以下のエラーが出た。

checking for pkg-config... /usr/bin/pkg-config
configure: error: Cannot find OpenSSL's <evp.h>

configureを確認したところ,PHP_OPENSSL_DIR変数でOpenSSLの配置場所を検知していた。configureでなぜ自動検知できないか不明だが,configure実行時に以下のように環境変数を指定することでこの問題に対処した。

  case $mod in
mysqlnd) PHP_OPENSSL_DIR="$LOCAL" ./configure;;
*) ./configure;;
esac

テストも失敗せずに成功したのでインストールした。以下のコマンドで拡張機能が有効になっていることを確認すると,エラーが出ていた。

php -m | grep mysql
PHP Warning:  PHP Startup: Unable to load dynamic library 'mysqlnd' (tried: /home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqlnd (/home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqlnd: cannot open shared object file: No such file or directory), /home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqlnd.so (/home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqlnd.so: undefined symbol: _tsrm_ls_cache)) in Unknown on line 0

mysqlndが参照している_tsrm_ls_cache関数が存在しないためエラーが出ている。TSRMはPHPのスレッド管理の機能である。

この問題の対処方法がわからない。mysqlndは依存関係がないこともあり,やむを得ずPHP本体のビルド時に有効化することで暫定的に対応する。

mysqli

インストール後,拡張機能の有効化を確認するとエラーが出ていた。

php -m | grep mysql
PHP Warning:  PHP Startup: Unable to load dynamic library 'mysqli' (tried: /home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqli (/home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqli: cannot open shared object file: No such file or directory), /home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqli.so (/home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/mysqli.so: undefined symbol: mysqlnd_global_stats)) in Unknown on line 0

参照先のmysqlndの関数が見つからないためエラーが出ている。

しかし,肝心のmysqlnd拡張機能のインストールが失敗しており,こちらも有効にできない。そのため,やむを得ずPHP本体のビルド時に有効化して暫定的に対応する。

pdo_mysql

インストール後,拡張機能の有効化を確認するとエラーが出た。

php -m | grep mysql
PHP Warning:  PHP Startup: Unable to load dynamic library 'pdo_mysql' (tried: /home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/pdo_mysql (/home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/pdo_mysql: cannot open shared object file: No such file or directory), /home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/pdo_mysql.so (/home/senooken/.local/stow/php-7.3.4/lib/php/extensions/debug-zts-20180731/pdo_mysql.so: undefined symbol: mysqlnd_debug_std_no_trace_funcs)) in Unknown on line 0

参照先のmysqlndの関数が見つからないためエラーが出ている。

しかし,肝心のmysqlnd拡張機能のインストールが失敗しており,こちらも有効にできない。そのため,やむを得ずPHP本体のビルド時に有効化して暫定的に対応する。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です