久しぶりにやってくれたPHP。
気づかず同じところに引っかかる人が出ると思ったので書いておきます。
今回PHPで.tar.gz圧縮/解凍を実装することになりまして、
phar拡張モジュールが対応しているということなので、素直にこれで実装したところ動作確認中にエラーが発生しました。
1 2 3 4 5 |
PHP Fatal error: Uncaught BadMethodCallException: Unable to add newly converted phar "/path/to/hogehoge.tar.gz" to the list of phars, a phar with that name already exists in C:\Users\Kurosawa\Desktop\phar.php:18 Stack trace: #0 /path/to/phar.php(18): PharData->compress() #1 {main} thrown in /path/to/phar.php on line 18 |
再現のための最小コードがこちらになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php // 適当に.tar.gzに入れるファイル file_put_contents('hogehoge.txt', 'このままでは俺の寿命がストレスでマッハなんだが・・'); // .tarと.tar.gzファイルを作成 $phar = new \PharData('hogehoge.tar'); $phar->addFile('hogehoge.txt', 'hogehoge.txt'); $phar->compress(\Phar::GZ); // .tarと.tar.gzファイルを削除 unlink('hogehoge.tar'); unlink('hogehoge.tar.gz'); // 同じ名前の.tarと.tar.gzファイルを作成したい $phar = new \PharData('hogehoge.tar'); $phar->addFile('hogehoge.txt', 'hogehoge.txt'); $phar->compress(\Phar::GZ); |
PharDataは内部でファイルパスをキーとして静的な領域にデータをキャッシュする実装になっているようで、上記のように同じファイルパスだと、複数PharDataを作成しても同じデータを指すことになり、2回目のcompressを実行しようとしたタイミングで「それはもう有るよエラー」ということです。
逆に以下のようなコードで1つのファイルを複数のPharDataで操作出来ます(意味は無い)
1 2 3 4 5 |
$phar1 = new \PharData('hogehoge.tar'); $phar2 = new \PharData('hogehoge.tar'); $phar1->addFile('hogehoge.txt', 'hogehoge1.txt'); $phar2->addFile('hogehoge.txt', 'hogehoge2.txt'); $phar1->compress(\Phar::GZ, '.tar.gz'); |
この現象については報告されていたのですが、ソースとかディスカッションを見るに
意図して実装されており、良い悪いは別として仕様な気がします。
https://bugs.php.net/bug.php?id=75101
1処理中に同じファイルパスで複数回ファイルを作り直すみたいなのはレアケースだと思うので遭遇する確率は低いと思いますが、記憶の片隅に留めておくとよいと思います。