make is.dev make it simple. development.
2024年9月11日

PHPでZip圧縮(exec編)

exec() とzipコマンドを使ってZipファイルを作成してみる。

使用環境

・ Amazon Linux 2
・ PHP 8.2.9
・ Zip 3.0

事前準備

zipが入っていない場合はインストールする。

yum install zip

基本サンプル

指定フォルダとその配下をまるっと圧縮する際のサンプル。
フォルダ sample を sample.zip に圧縮している。

<?php

// フォルダまるごと圧縮
$result = exec( 'cd ./; zip -r sample.zip sample', $output, $resultCode );

// $resultCode はzipコマンドの分の結果しか取得出来ないので注意
if ( $resultCode !== 0 ) {
	// error
}
PHP

zipコマンドの -r オプションをつけて再帰的に処理させつつ、圧縮対象のフォルダを指定する。

zipコマンドで圧縮する際はパスの指定に注意が必要。
というのも、圧縮対象のパス指定がそのまま階層として含まれてしまうため。

それを避けるには、カレントパスを動かした上でZipコマンドを実行する必要がある。

それを調整するためにコマンドの頭でカレントディレクトリを変更しているが、ここで指定するパスは圧縮するファイルのパス(Zipファイルの出力先ではない)を意識して指定する必要がある。

上記例ではフォルダ sample がZipファイルに含まれるが、中のファイルだけ圧縮したい場合は以下のようにする必要がある。

<?php

// フォルダまるごと圧縮
$result = exec( 'cd ./sample; zip -r ../sample.zip ./', $output, $resultCode );
PHP

パスワードを設定する

パスワードを設定する場合、 -P オプションを使う。

<?php

// フォルダまるごと圧縮(パスワード付き)
$result = exec( 'cd ./; zip -rP password sample.zip sample', $output, $resultCode );
PHP

複数フォルダをまとめて圧縮する

複数フォルダをまとめて圧縮する場合は、圧縮対象を列挙すればOK。

<?php

// 2つのフォルダをまるごと圧縮
$result = exec( 'cd ./; zip -r sample.zip sample sample2', $output, $resultCode );
PHP

ただし、この方法は圧縮対象のフォルダのパスに注意。
列挙するとパスが合わなくなる場合は、複数回に分けて圧縮する。

複数回に分けて圧縮する

<?php

// 2つのフォルダをまるごと圧縮
$result = exec( 'cd ./; zip -r sample.zip sample', $output, $resultCode );
$result = exec( 'cd ./; zip -r sample.zip sample2', $output, $resultCode );
PHP

既に存在しているzipファイルが指定された場合、そこにファイルを追加する動きになる。
そのため、複数回に分けてコマンドを実行することが出来る。

指定したファイルを圧縮する

ここまでフォルダをまるごと圧縮する例を挙げてきたが、個別のファイルを圧縮する場合もやり方はほぼ同じ。

<?php

// 指定したファイル1つを圧縮
$result = exec( 'cd ./; zip sample.zip sample/sample.txt', $output, $resultCode );
PHP

違いは -r オプションがいらない事くらい。

パスを意識しないといけないことや、複数ファイルを圧縮する場合も同様。

ワイルドカードも使える

ワイルドカードを使って圧縮対象を指定することも出来る。

<?php

// .txtファイルを圧縮
$result = exec( 'cd ./; zip sample.zip sample/*.txt', $output, $resultCode );
PHP

指定は出来るが、圧縮されるファイルが不明瞭になるので、なるべく明示的に指定した方が安全とは思われる。

補足

exec() を使った圧縮方法をまとめたが、そもそも exec() 自体なるべくなら避けた方が良い。
サーバによっては使えないケースが出て来るなど、環境に依存するので。

ZipArchive で事足りるなら、そちらを使った方が良いかなと。
(パスワード設定が必要だとダメですが)