【業務向け】PHPでzip圧縮する

PHPでファイルをzip圧縮するサンプルプログラムです。
業務向けに、適宜リネームやディレクトリ移動も行っています。

## 環境
* OS: Amazon Linux2
* PHP: 7.4.11

## ディレクトリ構成と処理概要

```:ディレクトリ構成
/product/share
     |
    aaa
     |----zipCompress.php → 処理プログラム
     |
     |----files
     |      |----share.csv → 圧縮対象のファイル
     | 
     |----zips                    
            |----share.zip → zip圧縮してできたファイル                    
            |----backup → バックアップ用のディレクトリ
                    |----share_yyyymmdd.zip → 前日以前のzipファイルのバックアップ
                                :
                                :
```
処理概要は、以下の通り。
処理プログラムzipCompress.phpにより、files配下のファイルをzip圧縮し、zips配下に配置します。
zips配下に既にファイルが存在する場合は、既存のファイルのタイムスタンプの日付をファイル名につけ、バックアップ用のディレクトリに配置してからzip圧縮を実施します。

## プログラム

### 設定ファイル
ファイルの格納先のような将来的に変更される可能性の高いものは外出ししておきます。

```config:config.ini
[path]
;圧縮対象のファイル格納先
file = "/product/share/aaa/files/";
;zipファイル格納先
zip = "/product/share/aaa/zips/";
```
先頭に「;」をつけると、その行はコメントになります。

### プログラム本体
```php:zipCompress.php

<?php
	// 設定ファイルの読み込み
	$conf = parse_ini_file("config.ini", true);
	$file_path = $conf["path"]["file"];
	$zip_path = $conf["path"]["zip"];
	$backup_path = $zip_path."backup/";
	$file_name = "share.csv";
	$file_origin = $file_path.$file_name;
	$zip_file = $zip_path."share.zip";
	
	// ファイルが存在しない場合、処理終了
	if(!file_exists($file_origin)){
		echo "対象ファイルが存在しません\n";
		exit();
	}
	// バックアップ
	if(file_exists($zip_file)){
		rename($zip_file, $backup_path."share_".date("Ymd",filemtime($zip_file)).".zip");
	}
	// zip圧縮
	$zip = new ZipArchive;
	if($zip->open($zip_file,ZipArchive::CREATE)=== TRUE){
		$zip->addFile($file_origin, $file_name);
		$zip->close();
	}else{
		echo "zip圧縮に失敗しました";
	}
?>
```

本プログラムのポイントとなる、PHPの関数、クラスは、以下の通り。

#### (1) [parse_ini_file](https://www.php.net/manual/ja/function.parse-ini-file)
設定ファイルをパースします。
第1引数に読み込む設定ファイルを、第2引数をtrueにすることで、セクション名と設定が含まれた多次元の配列を取得することができます。

#### (2) [file_exists](https://www.php.net/manual/ja/function.file-exists.php)
ファイルまたはディレクトリの存在有無を確認します。
存在する場合はtrueを、存在しない場合はfalseを返却します。

#### (3) [rename](https://www.php.net/manual/ja/function.rename)
ファイルをリネームします。
第1引数に元のファイル名を、第2引数に変更後のファイル名を入れます。
第2引数をパス記入することで、ディレクトリの移動も可能。
本プログラムでも、バックアップディレクトリへのパスをリネーム後のファイル名の前につけることで、ディレクトリ移動しています。

#### (4) [filemtime](https://www.php.net/manual/ja/function.filemtime)
ファイルの更新時刻を取得します。
本プログラムでは、もともとあったzipファイルを、そのファイルの更新時刻をつけてリネームしています。

#### (5) [ZipArchive](https://www.php.net/manual/ja/class.ziparchive)
Zip で圧縮されたファイルアーカイブ。

① [open](https://www.php.net/manual/ja/ziparchive.open.php)
ZIP ファイルアーカイブをオープンします。
第1引数に、命名したいzipファイル名を、第2引数にモードを記入します。
本プログラムの、ZipArchive::CREATEは、zipアーカイブが存在しない場合に新規作成するモードです。
その他のモードについては、「open」上のリンク先でご覧ください。

② [addFile](https://www.php.net/manual/ja/ziparchive.addfile.php)
第1引数で指定したファイルパスのファイルをzipアーカイブへ追加します。
注意点として、そのままだと、指定したパスごとzip圧縮されてしまうため、第2引数以降で、パスを含め、zipアーカイブ内での名前に変更してあげる必要があります。

③ [close](https://www.php.net/manual/ja/ziparchive.close.php)
オープンされた、あるいは作成されたアーカイブを閉じ、 変更内容を保存します。

### ＋α
もっと業務に即した内容にするなら、上記プログラムをfunction化し、失敗した場合は、エラーメールを飛ばすなどするとよいです。
基本的にこういった処理はクーロン登録などして、定期的に実行することになると思います。
aaaディレクトリ直下にlogsディレクトリを作成し、以下のように記述して、ログ出力もできるようにしておくとよいですね（毎週月曜10:00に実行する場合）。

```
00 10 * * 1 php /product/share/aaa/fileCompress.php >> /product/share/aaa/log/file_compress_`date +\%Y\%m\%d`.log 2>&1
```

### 終わりに
業務だと、ただその処理ができればOKではなく、いろいろ考慮が必要。
全体感を考慮して、最適なプログラムを作成できるようにしていきたいところです。

## 参考
* [cronの日時指定を、基礎から学ぶ（分,時,日,月,曜日の指定、◯分ごと、月末起動、など） | YoheiM.Net](https://www.yoheim.net/blog.php?q=20190902)