PHP
Phar

Phar で実行(呼び出し)されているかをPHPのスクリプト内から検知(確認)する

自作した PHP アプリを Phar (PHPアーカイブ)形式で配布する際、アーカイブ前の動作確認含め Phar として呼び出されているか確認したい時があります。

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

TL;DR

Phar::running() メソッドを使って、自身のpharファイルのパスを取得できるか否かで判断する

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

サンプル

index.php
<?php

echo 'Hello World!' . PHP_EOL;

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

if (is_phar()) {
    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 の呼び出し結果サンプル
$ php ./src/index.php
Hello World!
Running PHP directly.
Path FILE is: /path/to/your/src/index.php
Path Phar is: 
  • アーカイブの HelloWorld.phar の呼び出し結果サンプル
$ 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 ファイル)内のファイルにアクセスする際の違い

bash
━┳━ src/
 ┃   ┣━ index.php
 ┃   ┗━ sample.json
 ┃
 ┣━ HelloWorld.phar // 'src/'をアーカイブしたもの
 ┣━ box.phar        // アーカイブ・アプリ(Pharアーカイバ) 
 ┗━ box.json        // アーカイブ設定情報 

上記のようなディレクトリ構成の場合で、'index.php' が 'sample.json' を file_get_contents() したい場合はシンプルに file_get_contents('sample.json'); で済みます。

しかし、これらの(2 つの)ファイルを 'HelloWorld.phar' にアーカイブした場合、 file_get_contents('sample.json'); のままだとアーカイブ内ではなく 'HelloWorld.phar' と同階層にある 'sample.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);

参考文献