Phar で実行されているか PHP のスクリプト内から検知（確認）する

<h2>Phar 内で一緒にアーカイブされているファイルを参照したい</h2>

> 自作した PHP アプリを [Box3](https://qiita.com/KEINOS/items/62653805b554a538d970) などで Phar （PHPアーカイブ）形式で配布する際、アーカイブ前の動作確認含め **Phar として呼び出されているか確認したい**。

例えば、**一緒にアーカイブされているファイル（ JSON ファイルなど）を `file_get_contents()` で取得したい場合**です。直接実行とアーカイブ経由での実行で、ファイルのパス（表記）が変わるので、条件で分岐させたい場合などです。

## TL;DR

> [`Phar::running()` メソッド](http://php.net/manual/ja/phar.running.php)を使って、自身の`phar`ファイルのパスを取得できるか否かで判断する

```php
function isPhar()
{
    return strlen(\Phar::running()) > 0 ? true : false;
}
```

### サンプル

```index.php
<?php

echo 'Hello World!' . PHP_EOL;

function isPhar()
{
    return strlen(\Phar::running()) > 0 ? true : false;
}

if (isPhar()) {
    echo 'Running via phar.', PHP_EOL;
    echo 'Path FILE is: '   , __FILE__        , PHP_EOL;
    echo 'Path Phar is: '   , \Phar::running(), PHP_EOL;
} else {
    echo 'Running PHP directly.', PHP_EOL;
    echo 'Path FILE is: '       , __FILE__       , PHP_EOL;
    echo 'Path Phar is: '       , \Phar::running(), PHP_EOL;
}

```

- アーカイブ**前**の index.php の呼び出し結果サンプル

```bash
$ php ./src/index.php
Hello World!
Running PHP directly.
Path FILE is: /path/to/your/src/index.php
Path Phar is: 
```

- アーカイブ**後**の HelloWorld.phar の呼び出し結果サンプル

```bash
$ php ./HelloWorld.phar
Hello World!
Running via phar.
Path FILE is: phar:///path/to/your/HelloWorld.phar/index.php
Path Phar is: phar:///path/to/your/HelloWorld.phar
```

## TS;DR

### 同じアーカイブ（Phar ファイル）内のファイルにアクセスする際の違い

下記のようなディレクトリ構成を考えます。

```text:ディレクトリ構成
━┳━ src/
 ┃   ┣━ index.php
 ┃   ┗━ sample.json
 ┃
 ┣━ HelloWorld.phar // 'src/' をアーカイブしたもの
 ┣━ box.phar        // アーカイブ・アプリ（Pharアーカイバ） 
 ┗━ box.json        // アーカイブ設定情報 
```

一般的に、`index.php` が `sample.json` を読み込みたい場合はシンプルに `file_get_contents()` が使えます。

```php
$file_json = file_get_contents('sample.json');
```

しかし `file_get_contents('sample.json');` のままだと、これらの（２ つの）ファイルを `HelloWorld.phar` にアーカイブした場合に読み込めなくなります。なぜなら**アーカイブ内ではなく 'HelloWorld.phar' と同じ階層にある `sample.json` を探しに行ってしまう**からです。

そのため、パスを次のように変更しないといけません。

```php
$file_json = file_get_contents('phar://HelloWorld.phar/src/sample.json');
```

この時 `HelloWorld.phar/src/sample.json` のパスはアーカイブ内の `sample.json` を見に行っていることになります。

つまり、**Phar の場合とそうでない場合でファイルのパスを分岐する必要がある**わけです。

### 分岐の例

文頭のサンプルを見てわかるように、`phar`経由で実行している場合 **`Phar::running` メソッドは自身の `.phar` までのパスを返す**ので、以下のような PHP/Phar のどちらでも使える汎用的なファイル指定ができます。

```Phar内のファイル構成.
HelloWorld.phar/
  ┣━ index.php
  ┗━ sample.json
```

```index.php
<?php

function get_path_root()
{
    if (strlen(\Phar::running()) > 0) {
        $path_file_phar = \Phar::running(false);
        return dirname($path_file_phar) . DIRECTORY_SEPARATOR;
    }
    return __DIR__ . DIRECTORY_SEPARATOR;
}

$name_file_include = 'sample.json';
$path_root         = get_path_root();
$data_json         = file_get_contents($path_root . $name_file_include);
```


## 参考文献

- 「[Determine if PHP files is Running as Part of a `phar` archive](https://stackoverflow.com/questions/34597749/determine-if-php-files-is-running-as-part-of-a-phar-archive)」@ StackOverflow
- 「[Calling files inside PHAR](https://stackoverflow.com/questions/28256927/calling-files-inside-phar)」@ StackOverflow
- 「[PHP: Phar::running](http://php.net/manual/ja/phar.running.php) | Manual」@ PHP.net