使用 Phar 归档:简介

Phar 归档在概念上类似于 Java JAR 归档,但它是为 PHP 应用程序的需求和灵活性量身定制的。Phar 归档用于在一个文件中分发完整的 PHP 应用程序或库。Phar 归档应用程序的使用方式与任何其他 PHP 应用程序完全相同。

php coolapplication.phar
  

使用 Phar 归档库与使用任何其他 PHP 库相同。

<?php
include 'coollibrary.phar';
?>

phar 流封装器提供了 phar 扩展的核心功能,并在此处进行了详细说明 这里。phar 流封装器允许使用 PHP 的标准文件函数 fopen()opendir() 以及其他适用于常规文件的函数访问 phar 归档中的文件。 phar 流封装器支持对文件和目录的所有读写操作。

<?php
include 'phar://coollibrary.phar/internal/file.php';
header('Content-type: image/jpeg');
// phar 可以通过完整路径或别名访问
echo file_get_contents('phar:///fullpath/to/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');
// 将此设置为基于 tar 的 phar 归档,使用 gzip 压缩(.tar.gz)
$p = $p->convertToExecutable(Phar::TAR, Phar::GZ);

// 创建事务 - 在调用 stopBuffering() 之前,不会将任何内容写入 newphar.phar
// 尽管需要临时存储
$p->startBuffering();
// 将 /path/to/project 中的所有文件添加到 phar 中,并在 phar 中保存前缀为“project”
$p->buildFromIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator('/path/to/project')), '/path/to/');

// 通过数组访问 API 添加新文件
$p['file1.txt'] = 'Information';
$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
'Could not open Phar: ', $e;
}
?>

此外,可以使用任何支持的对称哈希算法(如果启用了 ext/hash,则为 MD5、SHA1、SHA256 和 SHA512)以及使用 OpenSSL 进行非对称公钥/私钥签名来验证 phar 文件内容。为了利用 OpenSSL 签名,您需要生成一对公钥/私钥,并使用私钥使用 Phar::setSignatureAlgorithm() 设置签名。此外,使用此代码提取的公钥

<?php
$public
= openssl_get_publickey(file_get_contents('private.pem'));
$pkey = '';
openssl_pkey_export($public, $pkey);
?>
必须保存在它验证的 phar 存档旁边。如果 phar 存档保存为 /path/to/my.phar,则公钥必须保存为 /path/to/my.phar.pubkey,否则 phar 将无法验证 OpenSSL 签名。

Phar 类还提供 3 个静态方法,Phar::webPhar()Phar::mungServer()Phar::interceptFileFuncs(),这些方法对于打包设计用于在常规文件系统和基于 Web 的应用程序上使用的 PHP 应用程序至关重要。 Phar::webPhar() 实现一个前端控制器,它将 HTTP 调用路由到 phar 存档中的正确位置。 Phar::mungServer() 用于修改 $_SERVER 数组的值,以欺骗处理这些值的应用程序。 Phar::interceptFileFuncs() 指示 Phar 拦截对 fopen()file_get_contents()opendir() 和所有基于 stat 的函数(file_exists()is_readable() 等)的调用,并将所有相对路径路由到 phar 存档中的位置。

例如,将流行的 phpMyAdmin 应用程序的版本打包为 phar 存档,只需要这个简单的脚本,然后修改用户/密码后,就可以像常规文件一样从 Web 服务器访问 phpMyAdmin.phar.tar.php

<?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
/* Servers configuration */
$i = 0;

/* Server 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\'] = \'\';


/* End of servers configuration */
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 is intended to be executed from a web browser\n";
exit -1;
__HALT_COMPILER();
'
);
$a->stopBuffering();
?>

添加注释

用户贡献的注释 3 个注释

shaun at shaunfreeman dot co dot uk
13 年前
如果您尝试将 Phar 用于 Web 应用程序并且只得到一个空白屏幕,如果您也启用了 suhosin,则必须添加

suhosin.executor.include.whitelist="phar"

到 "/etc/php5/conf.d/suhosin.ini" 文件或您的 "php.ini" 文件中。

完成之后,一切正常运行。
ch1902
10 年前
如果您要从浏览器运行 webPhar,例如 http://localhost/myphar.phar,那么您可能需要在 Web 服务器中将 .phar 扩展名与 PHP 关联以解释 PHP 代码。在 Apache 中,修改 httpd.conf 以包含

AddType application/x-httpd-php .php .phar
frame86 at live dot com
11 年前
openssl 示例完全错误。公钥必须从证书中提取,而 openssl_pkey_export() 仅适用于私钥。

工作示例
<?php
$publicKey
= openssl_get_publickey(file_get_contents('certificate.pem'));
$details = openssl_pkey_get_details($publicKey);
file_put_contents('my.phar.pubkey', $details['key']);
?>

不用说,如果消费者不针对公钥的有效指纹或证书进行检查,那么 my.phar/.phar/signature.bin 的最佳和最强的加密是无用的,因为任何人都可以打开、读取、重新创建并使用新密钥签署新的存档。你会吗?想想吧。
To Top