Как поместить phar-файл в phar-файл?

Я хотел бы поместить файл phar в файл phar. Я попробовал это самым прямым образом:

$p = new Phar('test.phar', null, 'self.phar');
$p->setStub('<?php Phar::mapPhar();
include \'phar://self.phar/index.php\'; __HALT_COMPILER(); ?>');
$p['index.php'] = '<?php
echo "hello world\n";';

$p = new Phar('test2.phar', null, 'self.phar');
$p->setStub('<?php Phar::mapPhar();
include \'phar://self.phar/index.php\'; __HALT_COMPILER(); ?>');
$p['index.php'] = '<?php
echo "hello phar world\n";';
$p['test.phar'] = file_get_contents('test.phar');

Однако PHP просто не хочет его открывать. Он не принимает ничего из следующего, включая:

// Warning: Phar::mapPhar(phar://path/to/test2.phar/test.phar): failed to open
// stream: Invalid argument in phar://path/to/test2.phar/test.phar
include('phar://test2.phar/test.phar');

// Warning: include(phar://test2.phar/test.phar/index.php): failed to open
// stream: phar error: "test.phar/index.php" is not a file in phar "test2.phar"
include('phar://test2.phar/test.phar/index.php');

// Warning: include(phar://test2.phar/phar://test.phar/index.php): failed to
// open stream: phar error: "phar:/test.phar/index.php" is not a file in phar
// "test2.phar"
include('phar://test2.phar/phar://test.phar/index.php');

Я знаю, что конструктивность этого вопроса ограничена, потому что он может просто не работать с phar-in-phar, однако, вероятно, я просто упустил способ, как это сделать, и я просто не вижу леса за деревьями.


person hakre    schedule 01.11.2012    source источник
comment
Это сложный вопрос.   -  person wesside    schedule 01.11.2012
comment
Не могли бы вы сделать что-нибудь нелепое и включить базовый файл phar, а затем попытаться получить доступ к файлу sub phar через переменную?   -  person wesside    schedule 01.11.2012
comment
этот вопрос +1 просто потому, что иначе Хакре не задал бы этот вопрос. смешной.   -  person goat    schedule 01.11.2012
comment
@bigman: Нет, это не сработает, по крайней мере, через оболочку phar://, которую я хотел бы использовать здесь. Создание экземпляра Phar и считывание содержимого файла должно работать. Затем включение через data:// может сработать, но для этого необходимо включить удаленное включение файлов.   -  person hakre    schedule 01.11.2012
comment
@hakre ya, я тебя слышу. Позвольте мне спросить, есть ли там другие их субфары?   -  person wesside    schedule 01.11.2012
comment
Код точно такой, как указано. Включения не будут работать в строке, потому что первое выдает исключение, поэтому останавливается. Таким образом, включения задокументированы (но это фактический код). Первый пример кода — это то, как я создаю phar-файлы.   -  person hakre    schedule 01.11.2012
comment
Так что о чем-то вроде создания phar на основе zip, извлечения для получения sub phars не может быть и речи?   -  person wesside    schedule 01.11.2012
comment
Правильно, потому что я хотел бы включить файл из phar в файл phar. Но это может быть просто невозможно. Может быть, что-то с вызовом Phar::mapPhar(); в первой заглушке.   -  person hakre    schedule 01.11.2012
comment
Да, я не уверен, что это возможно. Это все равно, что попросить zip-файл разархивировать zip-файл внутри, не распаковывая его предварительно. Возможно, придется использовать Phar::extractTo   -  person wesside    schedule 01.11.2012
comment
Оболочка phar::// может обрабатывать phar-файлы. Но сейчас нужно прояснить, что внутри файла phar есть файл phar.   -  person hakre    schedule 01.11.2012
comment
Phar::loadPhar('/test2.phar/test.phar', 'sub.phar'); может быть? include('phar://sub.phar');   -  person wesside    schedule 01.11.2012
comment
@bigman: Нет, я ни к чему не приближаюсь. Также псевдоним не работает таким образом. Я даже удалил свои собственные псевдонимы, однако псевдонимы, похоже, работают только внутри файла или что-то в этом роде.   -  person hakre    schedule 01.11.2012


Ответы (1)


Для загрузки phar-файла в PHP следует использовать функцию Phar::loadPhar напр.

Phar::loadPhar("test2.phar", "test2");

Сделает файл phar test2.phar загружаемым и доступным через псевдоним test2, чтобы вы могли включать файлы из него, выполнив:

include ('phar://test2/index.php');

Однако похоже, что это не работает, если этот файл находится внутри самого phar. Код PHP для loadPhar:

fp = php_stream_open_wrapper(fname, "rb", IGNORE_URL|STREAM_MUST_SEEK, &actual);

и, по-видимому, флаг IGNORE_URL делает невозможным открытие файла.

Есть обходной путь — извлеките файл phar, который содержится внутри другого файла phar, во временный файл, и тогда его, по-видимому, можно будет загрузить без каких-либо проблем. Следующий код извлечет файл phar (phar1.phar), который содержится во втором файле phar, а затем вызовет loadPhar.

function extractAndLoadPhar(){

    $tempFilename =  tempnam( sys_get_temp_dir() , "phar");

    $readHandle = fopen("phar://phar2/phar1.phar", "r");
    $writeHandle =  fopen($tempFilename, "w");

    while (!feof($readHandle)) {
        $result = fread($readHandle, 512);
        fwrite($writeHandle, $result);
    }

    fclose($readHandle);
    fclose($writeHandle);

    $result = Phar::loadPhar($tempFilename, "phar1");
}

extractAndLoadPhar(); //Extract and load the phar
include ('phar://phar1/src1.php'); //It can now be referenced by 'phar1'

Я разместил рабочую копию этого кода здесь https://github.com/Danack/pharphar, который создает phar, встраивает его во 2-й phar, а затем загружает и вызывает функцию из 1-го phar внутри 2-го phar.

Чтобы отметить - я не убежден, что этот метод является хорошей идеей. Кажется, есть некоторая двусмысленность (иначе я не понял), что происходит с файлами-заглушками для каждого из файлов phar. то есть загружаются ли они оба, или это только самый внешний файл phar, заглушка которого загружена и запущена.

person Danack    schedule 24.11.2012