PHP アーカイバ「BOX v2」と Git で自作 Phar アプリのバージョン番号更新

## Pharアプリのバージョン情報やビルド日付を簡単に更新したい

PHP ファイルを [Phar にアーカイブ](https://qiita.com/search?q=PHP+Phar)してアプリを配布する際に、**アプリのバージョンの更新が面倒**な方は、「[Box2](https://box-project.github.io/box2/)」（Phar アーカイバー）と Git のコミットやタグ機能を使って管理してはいかがでしょう。

## TL;DR

> `BOX` の本体である `box.phar` には PHP ファイルをアーカイブするとき、つまり **Phar のビルド時に Git の情報をソース内の任意の文字列に置き換える機能がある**。

この機能を利用して、`BOX` の設定ファイルである `box.json` の「キー」に置換対象の指定と、「値」に置換する文字列を指定すると、`.phar` 作成時に置き換えをしてくれます。

```php:ビルド前のソース
$version_build = '@build_version@';
$date_build    = '@build_date@';
```
```php:ビルド後のアーカイブ内のソース
$version_build = '1b1973c';
$date_build    = '2018-02-01 18:02:22';
```

- [指定できる主なキー](#%E4%BB%96%E3%81%AB%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AA%E3%81%84%E3%81%AE)


### box設定ファイル

```box.json
{
    "chmod": "0755",
    "directories": [
        "src"
    ],
    "main": "src/index.php",
    "output": "./HelloWorld.phar",
    "stub": true,
    "git-version": "build_version", ←注目
    "datetime": "build_date" ←注目
}
```

### アーカイブする（Pharに含める）ファイル

```src/index.php
<?php

$version_app = '@build_version@'; //この値がアーカイブ時に自動置換される
$build_date  = '@build_date@';    //この値がアーカイブ時に自動置換される

echo "Hello world! (Build:${version_app} at ${build_date})" . PHP_EOL;
```

### 確認とビルド（アーカイブの作成）

```bash
$ # Git のコミット ID 確認 （最初の7桁が使われる）
$ git show -s --format=%H
1b1973c6453b505e7f6ca7344bfd159765b739aa
$
$ # 登録済みの Git タグの確認
$ git tag
$ # 通常のビルド
$ ./box.phar build -c ./box.json
$ (略)
$ # アプリの実行
$ ./HelloWorld.phar
Hello world! (Build:1b1973c at 2018-02-01 21:22:12)
$
$ # Gitにタグをつけて再ビルド
$ git tag 1.0.0
$ ./box.phar build -c ./box.json
$ (略)
$ # アプリの実行
$ ./HelloWorld.phar
Hello world! (Build:1.0.0 at 2018-02-01 21:26:15)
```

## TS;DR

### Phar とは

> Phar って何? Phar アーカイブは、複数のファイルをひとつにまとめるための便利な仕組みです。 Phar アーカイブを使用すれば、PHP のアプリケーションをひとつのファイルとして配布できるようになります。 また、それをディスク上に展開しなくてもそのまま実行できるのです。 さらに、他のファイルと同様に PHP から phar アーカイブを実行することができます。 コマンドラインとウェブサーバー経由のどちらでも実行可能です。 phar は、いわば PHP アプリケーションにおける thumb drive のようなものです。 （[PHP マニュアル](http://php.net/manual/ja/intro.phar.php)より）

つまり Phar ファイルは、複数ファイルやディレクトリを１つの実行ファイルにアーカイブした（まとめた）ファイルを指します。これにより Python で言えば ZIP アーカイブを `include` して利用できるようなアーカイブ・ファイルを作成したり、単体で実行できる **Java で言う「[JAR](https://ja.wikipedia.org/wiki/JAR_(%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88))」の PHP 版のようなもの**です。

「[Box](https://box-project.github.io/box2/)」とは、この PHP のアーカイブ・ファイルである [Phar ファイル](https://qiita.com/search?q=PHP+Phar+%E3%82%A2%E3%83%BC%E3%82%AB%E3%82%A4%E3%83%96)を作ったり、既存の Phar ファイルを操作するのに便利な PHP コマンドライン・アプリケーションです。`Phar` クラスを使ってアーカイブに苦労された方は、「Box」を一度[試してみる価値はある](https://qiita.com/atijust/items/6edd523e4b56450a8bda)と思います。

2018/10/04 追記：本記事は `BOX v2` の記事ですが、しばらく開発が滞っていた `BOX` ですが、[メンテナが代わり 2018年9月 に `BOX v3` としてリニューアルされました](https://qiita.com/KEINOS/items/62653805b554a538d970)。

### 「Box」のダウンロードとインストール

`box.phar` がない場合は下記のいずれかの方法でインストーラーをダウンロード＆インストールして `box.phar` を作成してください。

1. cURLを使ってダウンロード＆インストール

    ```
    curl -LSs https://box-project.github.io/box2/installer.php | php
    ```
2. `https://box-project.github.io/box2/installer.php` のファイルを別途ダウンロードし `$php ./installer.php` でインストール

インストールが行われると、Phar が作成可能かのチェックを行い、あなたの環境にあった `box.phar`（Pharアーカイバ） をカレント・ディレクトリに作成してくれます。

### サンプルファイルの作成（'Hello World' アプリ）

まずは "Hello World" アプリから始め、次に include/require 、クラスのオートロードと徐々に拡張して行くことをおすすめします。

以下のサンプルは、"Hello World!" を表示したのち、アプリのバージョンや Git のコミット情報を `echo` するサンプルです。

[GitHub にもサンプルを公開しています](https://github.com/KEINOS/Practice_Phar_with_Box)ので、そちらの方がピンとくるかもしれません。クローンして適当に編集＆コミットしたのち、`$git tag vXXXX` で適当なバージョン（vXXXX）番号を付けて、ビルドしてみてください。

#### ディレクトリ構成

```bash
━ ./
 ┣━ src/
 ┃  ┗━ index.php
 ┣━ box.json
 ┗━ box.phar
```


#### ./src/index.php

```src/index.php
<?php

// 'box.json' で置き換え指定する文字列（@〜@）
$git_version      = '@git_version@';
$git_commit_long  = '@git_commit_long@';
$git_commit_short = '@git_commit_short@';
$git_tag          = '@git_tag@';
$date_build       = '@date_build@';

echo 'Hello world!' . PHP_EOL;

echo 'Git version       : ' . $git_version      . PHP_EOL;
echo 'Git commit(long)  : ' . $git_commit_long  . PHP_EOL;
echo 'Git commit(short) : ' . $git_commit_short . PHP_EOL;
echo 'Git tag           : ' . $git_tag          . PHP_EOL;
echo 'Date build        : ' . $date_build       . PHP_EOL;
```

#### ./box.json

```box.json
{
    "chmod": "0755",
    "directories": [
        "./src"
    ],
    "main": "src/index.php",
    "output": "./HelloWorld.phar",
    "stub": true,
    "git-version": "git_version",
    "git-commit": "git_commit_long",
    "git-commit-short": "git_commit_short",
    "git-tag": "git_tag",
    "datetime": "date_build"
}
```
#### ビルド（アーカイブの作成）の仕方

> 基本コマンド
> `$ ./box.phar build -c [設定JSONファイルのパス]`

```bash
$ ls -la
drwxr-xr-x   13 admin  staff    442  1 31 12:25 .
drwxr-xr-x   24 admin  staff    816  1 25 15:42 ..
drwxr-xr-x   16 admin  staff    544  1 30 22:07 .git
-rw-r--r--@   1 admin  staff    191  1 27 12:59 box.json
-rwxr-xr-x    1 admin  staff 961620  1 27 11:43 box.phar
drwxr-xr-x    6 admin  staff    204  1 31 20:00 src
$ # Pharのビルド
$ ./box.phar build -c ./box.json
```

#### Git 情報

- 基本コマンド
    - タグの確認：　`$ git tag`
    - タグの追加：　`$ git tag [任意のタグ]`
    - タグの削除：　`$ git tag -d [削除したいタグ]`
    - GitのコミットID確認：　`$ git show -s --format=%H`

##### Gitのコミットにタグを付けて再ビルドする例

```bash
$ ls -la
drwxr-xr-x   13 admin  staff    442  1 31 12:25 .
drwxr-xr-x   24 admin  staff    816  1 25 15:42 ..
drwxr-xr-x   16 admin  staff    544  1 30 22:07 .git
-rwxr-xr-x    1 admin  staff   3466  1 31 23:40 HelloWorld.phar
-rw-r--r--@   1 admin  staff    191  1 27 12:59 box.json
-rwxr-xr-x    1 admin  staff 961620  1 27 11:43 box.phar
drwxr-xr-x    6 admin  staff    204  1 31 20:00 src
$ # Gitのタグ確認
$ git tag

$ # タグが付いていないのでタグを付けてみる
$ git tag 1.0.0
$ # Pharの再ビルド
$ ./box.phar build -c ./box.json
$ # アプリの実行
$ ./HelloWorld.phar
Hello world! (Build:1.0.0)
```


## 他にできることないの？

色々できます。`box.json`に以下のキーを使うと、`git-version`キーと同様に、用途ごとに文字列を置き換えてくれます。

|キー|値|用途|
|:--:|:--:|:---|
|datetime|任意の置換文字列|ビルドした日付に置き換えます|
|datetime_format|Y-m-d H:i:s|上記`datetime`の日付フォーマットをPHP日付フォーマットで指定できます|
|git-commit|任意の置換文字列|完全長のコミットIDに置き換えます|
|git-commit-short|任意の置換文字列|コミットIDのショートハッシュ（最初の７桁）に置き換えます|
|git-tag|任意の置換文字列|Gitのタグに置き換えます|

## 参考文献

- `$ ./box.phar help build`

> The `git-version` (string) setting is the name of a placeholder value that
 will be replaced in all non-binary files by the one of the following (in
 order): 
   - The git repository's most recent tag.
   - The git repository's current short commit hash.
> 
> The short commit hash will only be used if no tag is available.

- 「[`Box`を使って`Phar`作成時`The tag or commit hash could not be retrieved from “.”`エラー](https://blog.keinos.com/20180201_3220)」 @ blog.keinos.com

## 動作検証環境

```bash
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.12.6
BuildVersion:	16G1114
$ php -v
PHP 7.1.8 (cli) (built: Aug  7 2017 15:02:45) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
$ ./box.phar -V
Box version 2.7.5 build 8ce371cdc1f0005e087e9ca5c265b52b5f560fd4
```