はじまり
ZipArchiveで以下の様なコードを実行していたが、yum update
でPHP等のアップデートを行ってから急にZipArchive::addFromString(): Invalid or uninitialized Zip object
が出て正常に動作しないようになった。
<?php
$zip = new ZipArchive;
$zip->open(tempnam(sys_get_temp_dir(), 'foo-'), ZipArchive::CREATE);
$zip->addFromString('bar.txt', 'hogehoge');
$zip->close();
調べてみると $zip->open()
の部分で失敗している様子。
原因の調査
PHPの確認
アップデート前のサーバがたまたまあったので、適当なコードを書いて比較してみることにした。
CentOS 7でPHPはremi-php72でインストール。
<?php
$zip = new ZipArchive;
var_dump($zip->open(tempnam(sys_get_temp_dir(), 'foo-'), ZipArchive::CREATE));
var_dump($zip->open(sys_get_temp_dir().'foo.zip', ZipArchive::CREATE));
PHP 7.2.26
$ php test.php
bool(true)
bool(true)
どちらも通る。
PHP 7.2.27
$ php test.php
int(19)
bool(true)
tempnam()を使っている方が通らなくなった。
int(19) はzip archiveでは無いファイルを開こうとした場合に返ってくるエラーコードの模様。しかし、そもそも空のファイルのはず…
PHPのソースコードでzip関連のコミットログを追いかけて見るも怪しい箇所は見つからず。PHPでは無くlibzipに原因があるのかもと思い確認してみる。
libzipの確認
PHP 7.2.26
# yum list installed php libzip5
libzip5.x86_64 1.5.2-1.el7.remi @remi-safe
php.x86_64 7.2.26-1.el7.remi @remi-php72
PHP 7.2.27
# yum list installed php libzip5
libzip5.x86_64 1.6.0-1.el7.remi @remi
php.x86_64 7.2.27-1.el7.remi @remi-php72
GitHubのリポジトリで変更内容を確認する。
1.6.0 [2020-01-24]
Avoid using umask() since it's not thread-safe.
Set close-on-exec flag when opening files.
Do not accept empty files as valid zip archives any longer.
Add support for XZ compressed files (using liblzma).
Add support for cancelling while closing zip archives.
Add support for setting the time in the on-disk format.
ん…?
Do not accept empty files as valid zip archives any longer.
Do not accept empty files as valid zip archives any longer.
Do not accept empty files as valid zip archives any longer.
該当部分の変更内容を確認するかぎり、libzipの仕様が変更になったとわかる。
まとめ
ZipArchiveの使い方によっては不具合が出る場合がある。ただしバグではなく仕様変更なので元に戻ることは期待できない。
…と思っていたらPHP 7.4.5で対応されたようだ。PHP 7.2系には現時点でバックポートされていないが、そのうち対応されるのかも。
ダメでした。PHP 8より後で正式に非対応となることが決まったようです。https://www.php.net/manual/ja/migration80.deprecated.php#migration80.deprecated.zip