cmpayments/crate-lib

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

v1.0.1 2020-10-27 10:43 UTC

This package is auto-updated.

Last update: 2024-08-27 19:00:35 UTC


README

Build Status

Crate 是一个从 Box 项目 分支出来的库,并且基于 Phar 类构建。它旨在简化创建新PHAR和修改现有PHAR的过程。功能包括压缩源文件、更好的自定义存根生成和更好的OpenSSL签名处理。

示例

use CmPayments\Crate\Crate;
use CmPayments\Crate\StubGenerator;

$crate = Crate::create('test.phar');

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

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

安装

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

$ composer require cmpayments/crate=1.*

用法

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

压缩源文件

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

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

实现 CompactorInterface

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

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

namespace Example\Compactor;

use CmPayments\Crate\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

包含了一个抽象压缩器类,它可以为你处理文件类型检查。你只需要提供默认支持的文件扩展名列表。如果需要,开发者可以通过调用 Compactor->setExtensions() 方法覆盖这些扩展名。

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

namespace Example\Compactor;

use CmPayments\Crate\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 包才能工作。当你安装Crate库时,它会包含在内。

use CmPayments\Crate\Compactor\Javascript;

$compactor = new Javascript();
压缩JSON

JSON 压缩器非常简单易用,因为它没有配置选项。然而,需要 json 扩展才能使用它。从所有 .json 文件中删除所有额外空白。

use CmPayments\Crate\Compactor\Json;

$compactor = new Json();
压缩PHP

PHP 压缩器将从 .php 文件中删除所有注释空白。删除的注释将使用与原始注释相同数量的换行符删除。这是为了在PHAR中发生错误时保留报告的行号。

use CmPayments\Crate\Compactor\Php;

$compactor = new Php();

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

use Herrera\Annotations\Tokenizer;

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

行数和注释数据都得到了保留。

管理签名

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

use CmPayments\Crate\Exception\SignatureException;
use CmPayments\Crate\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的完整性。

提取Phars

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

use CmPayments\Crate\Extract;

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

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

构造函数的第一个参数是现有phar的路径。第二个参数是存根的长度。这个参数是必须的,因为Extract类需要知道phar的清单从哪里开始。通常,这个值是由使用默认存根时Phar类生成的。

如果这个值未知,可以使用Extract::findStubLength()方法来尝试最佳猜测。如果存根长度猜测错误,Extract类将在提取过程中某个时刻抛出异常。

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

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

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

生成存根

如果项目需要,Crate库可以生成自定义存根。您将能够控制存根中的以下功能

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

以下是使用所有设置生成的存根示例

use CmPayments\Crate\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('CRATE_EXTRACT_PATTERN_DEFAULT', '__HALT' . '_COMPILER(); ?>');
define('CRATE_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的能力。

最后,构建Phars

所有这些功能都非常出色,但将它们在Crate类中一起使用时则更加出色。Crate类旨在通过一个(希望)简单易用的接口自动集成所有这些功能。

有两种方式可以实例化这个类

use CmPayments\Crate\Crate;

// use an existing Phar instance
$crate = new Crate($phar);

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

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

注册压缩器

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

use CmPayments\Crate\Compactor\Json;
use CmPayments\Crate\Compactor\Php;

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

使用占位符值

Crate类提供了在添加的文件中搜索和替换占位符值的功能。请注意,任何替换都只支持标量值。

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

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

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

将被添加到phar中

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

添加文件

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

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

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

$phar = $crate->getPhar();

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

设置Stub

Crate类提供了一个简单的方法来添加来自文件的stub,并同时应用占位符替换。

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

第二个参数表示应在stub上执行替换。如果您省略了它,则默认为false,这意味着不会执行任何替换,并且将直接使用stub。

私钥签名

Crate类提供了两种简单的方法来使用私钥对phar进行签名。然而,任何一种方法都需要openssl扩展可用。

使用字符串

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

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

如果密钥是带密码生成的,则需要密码。

使用文件

您还可以使用包含在文件中的私钥对phar进行签名。

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