Использование Phar-архивов: Введение
Концептуально Phar-архивы аналогичны JAR-архивам Java, но учитывают нужды и гибкость PHP-приложений. Phar-архив используется для распространения законченного PHP-приложения или библиотеки в виде одного файла. Приложение, имеющее вид Phar-архива, используется в точности так же, как и любое другое PHP-приложение:
php coolapplication.phar
Использование библиотеки, имеющей вид Phar-архива, идентично использованию любой другой PHP-библиотеки:
<?php
include 'coollibrary.phar';
?>
Обертка потока phar
представляет собой основу расширения phar,
про ее использование подробно написано здесь.
Обертка потока phar
предоставляет доступ к файлам внутри phar-архива
с использованием стандартных файловых функции PHP: fopen(), opendir()
и других, которые работают с обычными файлами.
Обертка потока phar
поддерживает все операции чтения/записи
как над файлами, так и над каталогами.
<?php
include 'phar://coollibrary.phar/internal/file.php';
header('Content-type: image/jpeg');
// доступ к phar-архивам может осуществляться по полному пути или с помощью псевдонима
echo file_get_contents('phar:///полный/путь/к/coollibrary.phar/images/wow.jpg');
?>
Класс Phar реализует расширенные возможности по доступу к файлам и по созданию phar-архивов. Использование класса Phar подробно описано здесь.
<?php
try {
// открыть существующий phar-архив
$p = new Phar('coollibrary.phar', 0);
// Phar наследует SPL-класс DirectoryIterator
foreach (new RecursiveIteratorIterator($p) as $file) {
// $file является объектом класса PharFileInfo, который наследует SplFileInfo
echo $file->getFileName() . "\n";
echo file_get_contents($file->getPathName()) . "\n"; // отображает содержимое;
}
if (isset($p['internal/file.php'])) {
var_dump($p['internal/file.php']->getMetadata());
}
// создать новый phar-архив - параметр phar.readonly в php.ini должен быть 0
// phar.readonly включен по умолчанию из соображений безопасности.
// На работающих серверах phar-архивы никогда не должны создаваться,
// а только выполняться.
if (Phar::canWrite()) {
$p = new Phar('newphar.tar.phar', 0, 'newphar.tar.phar');
// создать phar-архив, основанный на tar, сжатый gzip-сжатием (.tar.gz)
$p = $p->convertToExecutable(Phar::TAR, Phar::GZ);
// создать транзакцию - в newphar.phar ничего не будет записано
// до тех пор, пока не будет вызван stopBuffering(), однако для этого требуется временное хранилище
$p->startBuffering();
// добавить все файлы в каталоге /путь/к/проекту/project, сохранение в phar-архив с префиксом "project"
$p->buildFromIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator('/путь/к/проекту/project')), '/путь/к/проекту/');
// добавить новый файл используя ArrayAccess
$p['file1.txt'] = 'Информация';
$fp = fopen('hugefile.dat', 'rb');
// скопировать все данные из потока
$p['data/hugefile.dat'] = $fp;
if (Phar::canCompress(Phar::GZ)) {
$p['data/hugefile.dat']->compress(Phar::GZ);
}
$p['images/wow.jpg'] = file_get_contents('images/wow.jpg');
// любое значение может быть сохранено в качестве метаданных файла
$p['images/wow.jpg']->setMetadata(array('mime-type' => 'image/jpeg'));
$p['index.php'] = file_get_contents('index.php');
$p->setMetadata(array('bootstrap' => 'index.php'));
// сохранить phar-архив на диск
$p->stopBuffering();
}
} catch (Exception $e) {
echo 'Невозможно открыть Phar: ', $e;
}
?>
Кроме того, проверка содержимого phar-файла может быть осуществлена с помощью любого из поддерживаемых симметричных алгоритмов хеширования (MD5, SHA1, SHA256 и SHA512, если ext/hash включен), а также с помощью подписывания асимметричными открытым/закрытым ключами, используя OpenSSL. Для того чтобы использовать подписывание OpenSSL, вам необходимо сгенерировать пару из открытого и закрытого ключей и установить закрытый ключ для подписывания, используя Phar::setSignatureAlgorithm(). Кроме того, открытый ключ, извлеченный при помощи этого кода:
<?php
$public = openssl_get_publickey(file_get_contents('private.pem'));
$pkey = '';
openssl_pkey_export($public, $pkey);
?>
/путь/к/моему/архиву/my.phar
,
то открытый ключ должен быть сохранен как /путь/к/моему/архиву/my.phar.pubkey
,
иначе phar не сможет проверить подлинность подписи OpenSSL.
Класс Phar также предоставляет 3 статических метода: Phar::webPhar(), Phar::mungServer() и Phar::interceptFileFuncs(), которые имеют решающее значение для упаковки PHP-приложений, предназначенных для использования на обычных файловых системах и для веб-приложений. Phar::webPhar() реализует фронтальный контроллер, который направляет HTTP-вызовы в правильное место внутри phar-архива. Phar::mungServer() используется для изменения значений массива $_SERVER, что позволяет обмануть приложения, обрабатывающие эти значения. Phar::interceptFileFuncs() инструктирует Phar о необходимости перехвата вызовов fopen(), file_get_contents(), opendir() и прочих функций, основанных на stat (file_exists(), is_readable() и так далее) и перенаправления всех относительных путей внутрь phar-архива.
Например, для упаковки выпуска популярного приложения phpMyAdmin
для его использования в качестве phar-архива, требуется только этот простой скрипт,
а phpMyAdmin.phar.tar.php
будет доступен как обычный файл
на вашем веб-сервере после изменения значений user/password:
<?php
@unlink('phpMyAdmin.phar.tar.php');
copy('phpMyAdmin-2.11.3-english.tar.gz', 'phpMyAdmin.phar.tar.php');
$a = new Phar('phpMyAdmin.phar.tar.php');
$a->startBuffering();
$a["phpMyAdmin-2.11.3-english/config.inc.php"] = '<?php
/* Конфигурация сервера */
$i = 0;
/* Сервер localhost (config:root) [1] */
$i++;
$cfg[\'Servers\'][$i][\'host\'] = \'localhost\';
$cfg[\'Servers\'][$i][\'extension\'] = \'mysqli\';
$cfg[\'Servers\'][$i][\'connect_type\'] = \'tcp\';
$cfg[\'Servers\'][$i][\'compress\'] = false;
$cfg[\'Servers\'][$i][\'auth_type\'] = \'config\';
$cfg[\'Servers\'][$i][\'user\'] = \'root\';
$cfg[\'Servers\'][$i][\'password\'] = \'\';
/* Конец конфигурации сервера */
if (strpos(PHP_OS, \'WIN\') !== false) {
$cfg[\'UploadDir\'] = getcwd();
} else {
$cfg[\'UploadDir\'] = \'/tmp/pharphpmyadmin\';
@mkdir(\'/tmp/pharphpmyadmin\');
@chmod(\'/tmp/pharphpmyadmin\', 0777);
}';
$a->setStub('<?php
Phar::interceptFileFuncs();
Phar::webPhar("phpMyAdmin.phar", "phpMyAdmin-2.11.3-english/index.php");
echo "phpMyAdmin предназначен для выполнения в веб-браузере\n";
exit -1;
__HALT_COMPILER();
');
$a->stopBuffering();
?>