此包已被废弃,不再维护。作者建议使用 humbug/box 包。

一个简化PHAR构建过程的库。

1.6.1 2014-12-03 23:26 UTC

This package is auto-updated.

Last update: 2020-11-09 01:43:24 UTC


README

Build Status

Box 是基于 Phar 类的库。它旨在简化创建新 phar 和修改现有 phar 的过程。功能包括压缩源文件、更好的自定义存根生成和更好的 OpenSSL 签名处理。

示例

use Herrera\Box\Box;
use Herrera\Box\StubGenerator;

$box = Box::create('test.phar');

$box->buildFromDirectory('/path/to/dir');

$box->getPhar()->setStub(
    StubGenerator::create()
        ->index('path/to/script.php')
        ->generate()
);

安装

将其添加到您的 Composer 依赖项列表中

$ composer require herrera-io/box=1.*

使用

Box 库包含许多功能,其中一些设计为可以独立使用。这样做是为了使 phar 构建器更好地控制 phar 构建过程。

压缩源文件

Box 使用源文件 "压缩器"。压缩器简单来说就是一个类,它会检查给定的文件是否受支持,然后操纵其内容以使其变小。我将在 最后构建 Phars 中介绍如何实际使用它们。

创建压缩器类有两种方式:实现 CompactorInterface 接口或扩展 Compactor 抽象类。

实现 CompactorInterface

CompactorInterface 接口只需要你在你的类中实现两个方法:compact($contents)support($file)。参数 $contents 是源文件的内容,参数 $file 是文件的完整路径。你如何确定哪些文件类型受支持完全取决于你自己。

在这个例子中,这个自定义压缩器将只修改以 .php 结尾的文件,并从每一行的末尾删除空白字符

namespace Example\Compactor;

use Herrera\Box\Compactor\CompactorInterface;

/**
 * My example compactor.
 */
class RemoveWhitespace implements CompactorInterface
{
    /**
     * Seek and destroy (whitespaces).
     *
     * @param string $source The source code.
     *
     * @return string The compacted source code.
     */
    public function compact($source)
    {
        return preg_replace('/[ \t]+$/m', '', $source);
    }

    /**
     * Make sure we support it.
     *
     * @param string $file The file path.
     *
     * @return boolean Returns TRUE if supported, FALSE if not.
     */
    public function supports($file)
    {
        return ('php' === pathinfo($file, PATHINFO_EXTENSION));
    }
}

扩展 Compactor

包含了一个处理文件类型检查的抽象压缩器类。你只需要提供受支持的默认文件扩展列表。这些扩展可以在必要时由使用它们的开发者覆盖。

这个例子是之前示例压缩器的一个变体

namespace Example\Compactor;

use Herrera\Box\Compactor\Compactor;

/**
 * My example compactor.
 */
class RemoveWhitespace extends Compactor
{
    /**
     * The default supported file extensions.
     *
     * @var array
     */
     protected $extensions = array('php');

    /**
     * Seek and destroy (whitespaces).
     *
     * @param string $source The source code.
     *
     * @return string The compacted source code.
     */
    public function compact($source)
    {
        return preg_replace('/[ \t]+$/m', '', $source);
    }
}

开发者可以通过调用 Compactor->setExtensions() 方法来修改支持的文件扩展名

$example = new Example\Compactor\RemoveWhitespace();

$example->setExtensions(
    array(
        'inc',
        'php'
    )
);

捆绑压缩器

该库捆绑了两个压缩器以方便使用。

压缩 JavaScript

JavaScript 压缩器会压缩 JavaScript 文件,但需要 tedivm/jshrink 包才能工作。当你安装 Box 库时,它会包括这个包。

use Herrera\Box\Compactor\Javascript;

$compactor = new Javascript();
压缩JSON

JSON压缩器非常易于使用,因为没有配置选项。但是,需要安装json扩展才能使用它。所有额外的空格都将从.json文件中删除。

use Herrera\Box\Compactor\Json;

$compactor = new Json();
压缩PHP

PHP压缩器将从.php文件中删除所有注释和空白。被删除的注释将与原始注释相同的行数一起删除。这样做是为了在phar中发生错误时保留报告的行号。

use Herrera\Box\Compactor\Php;

$compactor = new Php();

如果您使用Doctrine格式的注释,还可以在PHP压缩器中利用一个特殊功能。为了压缩注释并保留注释,您需要安装herrera-io/annotations库并创建一个Tokenizer实例。

use Herrera\Annotations\Tokenizer;

$compactor->setTokenizer(new Tokenizer());

行数和注释数据都将保留。

管理签名

Phar类提供了一种简单的方法来提取和验证phar的签名。只需实例化该类即可验证指定的phar。然而,执行这些任务需要phar扩展。Box库包括了一种在不使用扩展的情况下提取和验证签名的方法。

use Herrera\Box\Exception\SignatureException;
use Herrera\Box\Signature;

$sig = new Signature('/path/to/my.phar');


// same output as Phar->getSignature()
$signature = $sig->get();

try {
    // TRUE if passed, FALSE if failed
    $result = $sig->verify();
} catch (SignatureException $exception) {
    // the signature could not be verified
}

Signature::create()方法是对Signature::__construct()的别名,允许使用上述示例的简写版本。

if (Signature::create('/path/to/my.phar')->verify()) {
    // do the do
}

在没有扩展可用的情况下验证phar的能力,在本质上更为谨慎。在没有扩展的敏感环境中,开发人员或系统管理员在将phar部署到系统之前,可能想要验证其完整性。

提取Phar

除了能够在没有扩展的情况下验证phar的签名之外,您还可以提取其内容。此功能主要设计为作为自定义stub的一部分嵌入,但它也可以用于提取任何phar。

use Herrera\Box\Extract;

$extract = new Extract('/path/to/my.phar', 65538);

$extract->go('/path/to/extract/dir');

构造函数的第一个参数是现有phar的路径。第二个是stub的长度。第二个参数是必需的,以便Extract类知道phar的清单开始的位置。通常,当使用默认stub时,该值由Phar类生成。

如果该值未知,可以使用Extract::findStubLength()方法调用Extract类来做出最佳猜测。如果stub长度被错误地猜测,Extract类将在提取过程中抛出异常。

默认情况下,Extract->go()方法将创建一个临时目录路径,并将phar的内容提取到该目录。示例中指定的目录路径是可选的。

为了减少开销,如果目标目录中存在特殊文件,则Extract类不会重新提取phar。这用于加快没有使用phar扩展执行的phar的执行过程。

请注意,如果phar中的任何文件使用gzip或bzip2进行了压缩,则需要相应的扩展进行解压缩。如果未安装所需的扩展,则Extract类将抛出异常。

生成stub

如果项目适用,可以使用 Box 库生成自定义的桩。您将控制桩中的以下功能

  • 设置别名。
  • 设置“横幅”注释(例如版权声明)。
  • 嵌入 Extract 类以支持自提取。
  • 设置 CLI 索引脚本。
  • 启用使用 Phar::interceptFileFuncs()
  • 设置文件 MIME 类型。
  • 将服务器变量列表设置为“mung”。
  • 设置 404 脚本。
  • 设置“shebang”行。
  • 选择使用 Phar::webPhar() 而不是 Phar::mapPhar()

以下是一个使用所有设置的桩生成示例

use Herrera\Box\StubGenerator;

$generator = new StubGenerator();

$banner = <<<BANNER
Copyright (c) 2013 Some Dude

Some license text here.
BANNER;

$mimetypes = array(
    'phps' => Phar::PHP
);

$rewrite = <<<REWRITE
function rewrite_url(\$uri)
{
    return \$rewritten;
}
REWRITE;

$stub = $generator
            ->alias('test.phar')
            ->banner($banner)
            ->extract(true)
            ->index('bin/cli.php')
            ->intercept(true)
            ->mimetypes($mimetypes)
            ->mung(array('REQUEST_URI'))
            ->notFound('lib/404.php')
            ->rewrite($rewrite)
            ->shebang('/home/dude/.local/php/bin/php')
            ->web(true)
            ->generate();

生成的桩如下

<?php
/**
 * Copyright (c) 2013 Some Dude
 *
 * Some license text here.
 */
define('BOX_EXTRACT_PATTERN_DEFAULT', '__HALT' . '_COMPILER(); ?>');
define('BOX_EXTRACT_PATTERN_OPEN', "__HALT" . "_COMPILER(); ?>\r\n");
if (class_exists('Phar')) {
Phar::webPhar('test.phar', 'bin/cli.php', 'lib/404.php', array (
  'phps' => 0,
), 'function rewrite_url($uri)
{
    return $rewritten;
}');
Phar::interceptFileFuncs();
Phar::mungServer(array (
  0 => 'REQUEST_URI',
));
} else {
$extract = new Extract(__FILE__, Extract::findStubLength(__FILE__));
$dir = $extract->go();
set_include_path($dir . PATH_SEPARATOR . get_include_path());
require "$dir/bin/cli.php";
}
// ... snip ...

__HALT_COMPILER();

为了简洁起见,嵌入的 Extract 类被替换为 "... 省略 ..."。

示例桩可能对你需要的来说有点过头。通过不使用 extract() 方法,你可以轻松地从桩中删除几百行代码,减小其大小,但你将失去在没有 phar 扩展的环境中执行 Phar 的能力。

最后,构建 Phar

所有这些功能都很棒,但它们在 Box 类中使用时更好。设计 Box 类是为了在(希望)简单的用户界面中自动集成所有这些功能。

有两种方式可以实例化该类

user Herrera\Box\Box;

// use an existing Phar instance
$box = new Box($phar);

// or create one
$box = Box::create('/path/to/my.phar');

请注意,Box::create() 方法接受与 Phar::__construct() 方法相同的参数。

注册压缩器

无论您是使用捆绑的压缩器还是您自己的压缩器,您都需要调用 Box->addCompactor() 方法将您的类注册到 Box 中。使用 Box 添加到 Phar 的所有文件都将自动通过支持的压缩器进行处理。

use Herrera\Box\Compactor\Json;
use Herrera\Box\Compactor\Php;

$box->addCompactor(new Json());
$box->addCompactor(new Php());
$box->addCompactor($custom);

使用占位符值

Box 类提供搜索和替换添加文件中占位符值的能力。请记住,任何替换都仅支持标量值。

$box->setValues(
    array(
        '@match@' => 'replace'
    )
);

使用上述值进行匹配,以下代码

$myCode = 'This @match@ is now "replace".';

将作为以下内容添加到 Phar 中

$myCode = 'This replace is now "replace".';

添加文件

要实际使用已注册的压缩器和设置占位符值替换,您需要使用 Box 类的添加文件方法。这些方法与 Phar 类的方法相同,但会自动应用适当的压缩器和替换

  • Box->addFile()
  • Box->addFromString()
  • Box->buildFromDirectory()
  • Box->buildFromIterator()

请注意,如果您需要添加不进行任何更改的文件(例如二进制文件),您可能需要使用 Phar 实例直接添加该文件。

$phar = $box->getPhar();

$phar->addFile('...');

设置桩

Box 类提供了一种简单的方法来添加从文件中获取的桩,并同时在桩上应用占位符替换

$box->setStubUsingFile('/path/to/stub.php', true);

第二个参数表示应该在桩上执行替换。如果您将其省略,它将默认为 false,这意味着不会执行替换,桩将按原样使用。

私钥签名

Box类提供了两种使用私钥签名phar文件的方法。然而,无论使用哪种方法,都需要有openssl扩展可用。

使用字符串

如果您已经将私钥作为字符串变量加载,则可以使用Box->sign()方法。

$box->sign($key, $pass);

如果私钥是用密码生成的,则需要提供密码。

使用文件

您还可以使用文件中包含的私钥来签名phar文件。

$box->signUsingFile($file, $pass);