Самоисполняемый phar как способ распространения веб-приложений

  • Tutorial
Как уже, наверное, всем известно, в PHP 5.3 появилась поддержка специального типа архивов с расширением .phar. Те, кто не в курсе — могут почитать отличную статью .phar — исполняемые PHP-архивы
Область применения, которая сразу приходит на ум — это библиотеки/фреймворки в виде подключаемых *.phar архивов и установщики веб-приложений, например, CMS. О последних я и собираюсь рассказать подробнее и с примерами.

Постановка задачи


Цель — получить на выходе один файл, который будет сам по себе исполняемым, и будет содержать в себе все нужные файлы. Если провести аналогию c обычными приложениями — это приложение, которое запаковано в SFX (self-extracting archive).

Требования


Примеры в статье написаны для PHP 5.4 (но их легко подправить под 5.3), а так же используется PEAR библиотека Archive_Tar для создания нативных *.tar архивов.

Возьмем для примера простейшую структуру:
    build.php
    index.php
    install.php
    readme.txt

Естественно, файл install.php нужен только на этапе установки, а build.php только на этапе сборки. Файл readme.txt будем создавать на этапе сборки.

Создание tar


Сначала мы соберем нужные файлы в tar, это дает возможность обойти некоторые ограничения *.phar формата, например, недопустимость кириллицы в названии файла. Если использовать для этого Phar или PharData — придется переименовывать файлы в допустимый вид при запаковке, и обратно в исходный вид при распаковке.

Создаем tar архив:
//Подключаем PEAR библиотеку
require_once	'Archive/Tar.php';
//Создаем файл
$tar		= new Archive_Tar(__DIR__.'/system.phar.tar');

Расширение файла указано .phar.tar для того, чтобы php мог с ним работать.
Добавляем файлы в архив:
//Добавляем существующие файлы
$tar->createModify(
    [
        'index.php',
        'install.php'
    ],
    null,
    __DIR__
);
//Третий параметр для того, чтобы получить внутри архива пути относительно текущей директории, а не корня файловой системы.

//Создаем readme.txt, в котором сохраним дату и время сборки проекта
$tar->addString(
    'readme.txt',
    "This is demo project\nBuilt ".date('d-m-Y').' at '.date('H:i')
);


Превращаем tar в phar


Создадим из полученного архива так называемый tar-based phar.
//Открываем существующий архив
$phar		= new Phar(__DIR__.'/system.phar.tar');
//Конвертируем с bz2 сжатием, назначаем расширение .phar
$phar->convertToExecutable(Phar::TAR, Phar::BZ2, '.phar');


Делаем архив само исполняемым


Для этого нужно задать файл, который будет открываться при попытке прямого доступа к файлу веб-сервером. По-умолчанию это index.php, но у нас установка, поэтому нужно открыть install.php
//Открываем конвертированный архив
$phar		= new Phar(__DIR__.'/system.phar');
//Меняем открываемый по умолчанию файл
$phar->setStub("<?php Phar::webPhar(null, 'install.php'); __HALT_COMPILER();");
//Переименовываем
rename(__DIR__.'/system.phar', __DIR__.'/system.phar.php');

Странный формат .phar.php играет очень важную роль. Расширение .php заставляет передавать файл интерпретатору PHP, а .phar дает понять, что это архив, а не файл с исходным кодом. По-сути, архив превращается в директорию, например, можно ввести в адресной строке браузера /system.phar.php/index.php — и это будет работать.

Установка


Листинг install.php, который производит установку
//Определяем путь к корню, где лежит архив, находясь внутри него
$root		= substr(pathinfo(__DIR__, PATHINFO_DIRNAME), 7);
//Открываем и распаковываем 2 файла из архива в корень
(new Phar($root.'/'.pathinfo(__DIR__, PATHINFO_BASENAME)))->extractTo(
    $root,
    [
        'index.php',
        'readme.txt'
    ]
);
//Удаляем архив (не обязательно)
unlink($root.'/'.pathinfo(__DIR__, PATHINFO_BASENAME));

И герой, ради которого затевалась вся кухня — index.php
echo 'I was inside the phar archive';

Надеюсь, кому-то эта информация будет полезна, и всё больше продуктов будет поставляться не в виде zip/rar/tar/gz/bz2 архивов, а нативного phar, для чего он и был создан.

Исходные файлы system.phar.php
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 13

    0
    apc и всякие eaccelerator-ы кэшируют в байт-код содержимое phar-ов?
      0
      Да, проверял с APC.
        0
        Насколько я помню, APC раньше кешировал только содержимое stub phar-архива, но не содержание.
          0
          Phar is APC-compatible, the latest APC will cache files within a phar archive, resulting in
          a 6x speedup measured running phpMyAdmin as a phar archive.

          http://pecl.php.net/package/phar
            0
            Интерестно, с какой версии APC стал корректно работать с phar? Просто это прошло как-то мимо меня, а changelog APC об этом не пишет.
        0
        http://silex.sensiolabs.org/doc/phar.html тут пишут что с phar еще не всё гладко.
          0
          А ещё не извлекаются директории, несмотря на заявленную поддержку, только отдельные файлы (разработчики уже в курсе).
          Не гладко, но в умелых руках всё равно полезный инструмент.
          0
          А что насчёт сжатия?
            0
            Мой движок 1.2 МБ запаковался в 271.8 КБ
              0
              Значит там не просто tar, а скорее tgz.
                0
                Из статьи:

                //Конвертируем с bz2 сжатием, назначаем расширение .phar
                $phar->convertToExecutable(Phar::TAR, Phar::BZ2, '.phar');
                

                Поддерживается так же конвертация без сжатия, и с gz сжатием. Просто bz2 показал наилучший результат. Хотя он и самый медленный в работе (разница небольшая, но всё же) — для установщика как раз то, что нужно.
                0
                Тут на сайте IBM есть инфа, о том, что тип содержимого phar может быть родным или tar и zip.

                By default, the Phar created will use the native Phar-based archive format. You can also use the ZIP or TAR format for the Phar file by converting it to that format, shown in Listing 2, by changing the format to ZIP.

                Listing 2. Changing the storage format to ZIP
                $p = $p->convertToExecutable(Phar::ZIP);

          Only users with full accounts can post comments. Log in, please.