Phar

Введение

Модуль phar предоставляет возможность поместить целое PHP-приложение в один-единственный файл c именем phar (PHP Archive) для простого распространения и установки. Помимо этого, модуль phar предоставляет метод абстракции формата файла для создания и обработки архивов tar и zip через класс PharData, примерно как PDO обеспечивает единый интерфейс для доступа к различным базам данных. В отличие от PDO, который не может конвертировать между различными базами данных, Phar может конвертировать данные между форматами tar, zip и phar всего одной строкой кода. Смотрите Phar::convertToExecutable() для примера.

Что же такое phar? Phar-архивы лучше всего можно охарактеризовать как удобный способ группировки нескольких файлов в один. Также phar архив предоставляет возможность распространять целое PHP-приложение в одном единственном файле и запускать его прямо из этого файла без необходимости распаковывать его на диск. Кроме того, phar-архивы могут выполняться PHP с той же лёгкостью, что и любые другие файлы, как из командной строки, так и через веб-сервер. Phar - это как флеш-накопитель для PHP-приложений.

Phar реализует эту функциональность через потоки. Обычно, чтобы использовать в PHP-скрипте внешний файл, вы бы воспользовались, например, include:

Пример #1 Использование внешнего файла

<?php
include '/path/to/external/file.php';
?>

PHP может рассматривать это как преобразование /path/to/external/file.php в обёртку потока file:///path/to/external/file.php, а в действительности он использует потоковые функции обёртки простого файлового потока для доступа ко всем локальным файлам.

Чтобы использовать файл file.php, находящийся внутри phar-архива /path/to/myphar.phar, используется синтаксис очень похожий на синтаксис file:// выше.

Пример #2 Использование файла внутри phar-архива

<?php
include 'phar:///path/to/myphar.phar/file.php';
?>

На самом деле, можно рассматривать phar-архив как если бы это был внешний диск, используя любые fopen()-подобные функции, opendir() и mkdir()-подобные функции для чтения, изменения, или создания новых файлов и директорий внутри phar-архива. Это позволяет целому PHP-приложению распространяться в одном файле и запускаться прямо из этого файла.

Наиболее часто используемое применение для phar-архива - это распространение целого приложения в одном файле. Например, установщик PEAR, который поставляется вместе с PHP, является phar-архивом. Для использования phar-архива распространяемого таким способом, архив может быть выполнен через консоль или через веб-сервер.

Phar-архивы могут распространяться как архивы tar и zip, или как пользовательский формат файла phar, предназначенный специально для модуля phar. Каждый формат файла имеет как преимущества, так и недостатки. Форматы tar и zip могут быть прочитаны или извлечены любой сторонней утилитой которая может работать с этими форматами. Но чтобы PHP мог их запускать, ему будет необходим модуль phar. Файлы в phar-формате настраиваются и уникальны для модуля phar, и могут быть созданы только им или PEAR-пакетом » PHP_Archive. Но их преимущество в том, что приложения, созданные в этом формате, будут работать, даже если модуль phar не включён.

Другими словами, даже если модуль phar отключён, phar-архив всё равно может быть выполнен или подключён. Доступ к отдельным файлам в архиве возможен только с модулем phar, если только архив не был создан с помощью PHP_Archive.

Модуль phar также способно конвертировать phar-архив из tar в zip или в phar-формат одной командой:

Пример #3 Конвертирование phar-архива из формата phar в формат tar

<?php
$phar
= new Phar('myphar.phar');
$pgz = $phar->convertToExecutable(Phar::TAR, Phar::GZ); // создаст myphar.phar.tar.gz
?>

Phar может сжимать отдельные файлы или архив целиком с использованием gzip-компрессии или bzip2-компрессии, а также автоматически проверять целостность архива, используя сигнатуры MD5, SHA-1, SHA-256 или SHA-512.

Наконец, модуль Phar заботится о вашей безопасности и отключает доступ на запись для исполняемых phar-архивов по умолчанию, а также требует отключения на системном уровне настройки phar.readonly в php.ini для создания или изменения phar-архивов. Обычные неисполняемые архивы tar и zip, всегда могут быть созданы или изменены с помощью класса PharData.

Если вы создаёте приложение с целью распространения, вы, возможно, захотите прочитать раздел Как создавать Phar-архивы. Если вам нужно больше информации об отличиях между тремя поддерживаемыми phar форматами файлов, вам следует прочитать раздел Phar, Tar и Zip.

Если вы используете phar-приложение, то полезные советы находятся в разделе Как использовать phar-архивы.

Слово phar - это сокращение от PHP и Archive, и оно частично основано на jar (Java Archive), знакомом Java-разработчикам.

Реализация Phar-архивов основана на PEAR-пакете » PHP_Archive, и детали реализации схожи, хотя модуль Phar гораздо мощнее. Кроме того, модуль Phar позволяет большинству PHP-приложений запускаться без изменений, тогда как phar-архивы, основанные на PHP_Archive, часто требуют существенных изменений для работы.

Добавить

Примечания пользователей 6 notes

up
35
dava
12 years ago
Here is an apache2 htaccess example that prevents the downloading of phar-Archives by the user:

RewriteEngine on
RewriteRule ^(.*)\.phar$ - [F]

It triggers a "403 - Forbidden" message instead of delivering the archive.
up
17
bohwaz
14 years ago
If you get blank pages when trying to access a phar web-page, then you probably have Suhosin on your PHP (like in Debian and Ubuntu), and you need to ad this to your php.ini to allow execution of PHAR archives :

suhosin.executor.include.whitelist="phar"
up
6
v-mafick at microsoft dot com
12 years ago
Users should set the `sys_temp_dir` directive.

PHAR stores temporary files in either `sys_temp_dir` or the current working directory(CWD).

This is especially important if you're CWD is on a remote file system. Often web server clusters will share a common file system between each web server (using NFS, DFS, etc...). In such scenarios, if you don't set `sys_temp_dir` to a local directory, PHAR will be creating temporary files over the network, which will result in performance and functionality problems.
up
3
brunoczim
8 years ago
Here is a very simple program for creating phar files with CLI. Note that it requires phar.readonly in php.ini  set to false (Off).

<?php
$filename = "default";
$dir = "./";
$regex = "/^(?!.*build\\.php)(?:.*)$/";
$main = "main.php";
$shebang = "#!/usr/bin/env php";
$chmod = true;

for ($i = 0; $i < $argc; $i++) {
    switch ($argv[$i]) {
        case "-o":
            $i++;
            if ($i >= $argc) {
                echo "Missing output file name" . PHP_EOL;
                exit(1);
            }
            $filename = $argv[$i];
            break;
        case "-i":
            $i++;
            if ($i >= $argc) {
                echo "Missing input directory name" . PHP_EOL;
                exit(1);
            }
            $dir = $argv[$i];
            break;
        case "-p":
            $i++;
            if ($i >= $argc) {
                echo "Missing regular expression pattern" . PHP_EOL;
                exit(1);
            }
            $regex = $argv[$i];
            break;
        case "-m":
            $i++;
            if ($i >= $argc) {
                echo "Missing main file" . PHP_EOL;
                exit(1);
            }
            $main = $argv[$i];
            break;
        case "-b":
            $i++;
            if ($i >= $argc) {
                echo "Missing shebang of file" . PHP_EOL;
                exit(1);
            }
            $shebang = $argv[$i];
            break;
        case "--no-chmod":
            $chmod = false;
            break;
    }
}
if (file_exists($filename)) unlink($filename);
$phar = new Phar($filename);
$phar->buildFromDirectory($dir, $regex);
$phar->setStub(($shebang ? $shebang . PHP_EOL : "") . $phar->createDefaultStub($main));
if ($chmod) {
    chmod($filename, fileperms($phar) | 0700);
}
up
1
lemonkid from OpenToAll
7 years ago
when read via phar://, stream will unserialize object including phar file

Use this to create phar
<?php
// create new Phar
$phar = new Phar('lemon.phar');
$phar->startBuffering();
$phar->addFromString('test.txt', 'text');
$phar->setStub('<?php __HALT_COMPILER(); ? >');

// add object of any class as meta data
class AnyClass {}
$object = new AnyClass;
$object->data = 'Chanh';
$phar->setMetadata($object);
$phar->stopBuffering();
?>

and read it by:
<?php
class AnyClass {
    function __destruct() {
        echo $this->data;
    }
}
// output: Chanh
file_get_contents('phar://test.phar');
?>
up
1
t dot habenreich at web dot de
12 years ago
Here is a very simple class to build a phar file from a given source directory. You can use this for your own project and simple deployment.

But my main goal was to show how to use PHAR functions in a simple way.

<?php

class BuildPhar
{
  private $_sourceDirectory = null;
  private $_stubFile        = null;
  private $_outputDirectory = null;
  private $_pharFileName    = null;

  /**
   * @param $_sourceDirectory       // This is the directory where your project is stored.
   * @param $stubFile               // Name the entry point for your phar file. This file have to be within the source
   *                                   directory. 
   * @param null $_outputDirectory  // Directory where the phar file will be placed.
   * @param string $pharFileName    // Name of your final *.phar file.
   */
  public function __construct($_sourceDirectory, $stubFile, $_outputDirectory = null, $pharFileName = 'myPhar.phar') {

    if ((file_exists($_sourceDirectory) === false) || (is_dir($_sourceDirectory) === false)) {
      throw new Exception('No valid source directory given.');
    }
    $this->_sourceDirectory = $_sourceDirectory;

    if (file_exists($this->_sourceDirectory.'/'.$stubFile) === false) {
      throw new Exception('Your given stub file doesn\'t exists.');
    }

    $this->_stubFile = $stubFile;

    if(empty($pharFileName) === true) {
      throw new Exception('Your given output name for your phar-file is empty.');
    }
    $this->_pharFileName = $pharFileName;

    if ((empty($_outputDirectory) === true) || (file_exists($_outputDirectory) === false) || (is_dir($_outputDirectory) === false)) {

      if ($_outputDirectory !== null) {
        trigger_error ( 'Your output directory is invalid. We set the fallback to: "'.dirname(__FILE__).'".', E_USER_WARNING);
      }

      $this->_outputDirectory = dirname(__FILE__);
    } else {
      $this->_outputDirectory = $_outputDirectory;
    }

    $this->prepareBuildDirectory();
    $this->buildPhar();
  }

  private function prepareBuildDirectory() {
    if (preg_match('/.phar$/', $this->_pharFileName) == FALSE) {
      $this->_pharFileName .= '.phar';
    }

    if (file_exists($this->_pharFileName) === true) {
      unlink($this->_pharFileName);
    }
  }

  private function buildPhar() {
    $phar = new Phar($this->_outputDirectory.'/'.$this->_pharFileName);
    $phar->buildFromDirectory($this->_sourceDirectory);
    $phar->setDefaultStub($this->_stubFile);
  }
}
//END Class

//Example Usage:
$builder = new BuildPhar(
  dirname(__FILE__).'/_source',
  'my_default_stub.php',
  dirname(__FILE__).'/_output',
  'my-phar-file.phar'
);
To Top