Phar 内で一緒にアーカイブされているファイルを参照したい
自作した PHP アプリを Box3 などで Phar (PHPアーカイブ)形式で配布する際、アーカイブ前の動作確認含め Phar として呼び出されているか確認したい。
例えば、一緒にアーカイブされているファイル( JSON ファイルなど)を file_get_contents()
で取得したい場合です。直接実行とアーカイブ経由での実行で、ファイルのパス(表記)が変わるので、条件で分岐させたい場合などです。
TL;DR
Phar::running()
メソッドを使って、自身のphar
ファイルのパスを取得できるか否かで判断する
function isPhar()
{
return strlen(\Phar::running()) > 0 ? true : false;
}
サンプル
<?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 の呼び出し結果サンプル
$ 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 ファイル)内のファイルにアクセスする際の違い
下記のようなディレクトリ構成を考えます。
━┳━ src/
┃ ┣━ index.php
┃ ┗━ sample.json
┃
┣━ HelloWorld.phar // 'src/' をアーカイブしたもの
┣━ box.phar // アーカイブ・アプリ(Pharアーカイバ)
┗━ box.json // アーカイブ設定情報
一般的に、index.php
が sample.json
を読み込みたい場合はシンプルに file_get_contents()
が使えます。
$file_json = file_get_contents('sample.json');
しかし file_get_contents('sample.json');
のままだと、これらの(2 つの)ファイルを HelloWorld.phar
にアーカイブした場合に読み込めなくなります。なぜならアーカイブ内ではなく 'HelloWorld.phar' と同じ階層にある sample.json
を探しに行ってしまうからです。
そのため、パスを次のように変更しないといけません。
$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 のどちらでも使える汎用的なファイル指定ができます。
HelloWorld.phar/
┣━ index.php
┗━ sample.json
<?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」@ StackOverflow - 「Calling files inside PHAR」@ StackOverflow
- 「PHP: Phar::running | Manual」@ PHP.net