打包 PHP 个应用程序

Packaging a PHP application

我正在尝试从我的 Web 应用程序创建一个 .phar 文件。在 php documentation's example 之后,我为此尝试了以下操作。

<?php
$srcRoot = __DIR__ . "/../app";
$buildRoot = __DIR__ . "/../build";
$p = new Phar("$buildRoot/build.phar", 0, 'build.phar');
$p->buildFromIterator(
    new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($srcRoot)
    ),
    $srcRoot
);

但是我得到了以下错误。我不知道这个错误。代码有什么问题?

PHP Fatal error:  Uncaught exception 'UnexpectedValueException' with message
'Iterator RecursiveIteratorIterator returned a path "D:\site\app" that is
 not in the base directory "D:\site\app"'
in D:\site\tools\create-phar.php:7

Box 使从您的源文件创建 PHAR 档案变得非常容易。基本上你首先添加一个配置文件,然后你可以通过简单地在命令行上调用 box build 来创建你的 PHAR 文件。

Matthieu Moquet 在 great blog post 中描述了他如何使用 Box 来简化 PHP Cli 应用程序的分发。就个人而言,我也一直在使用 Box 作为 CLI 应用程序,但是官方的项目描述并不局限于 CLI 应用程序,而是将 Box 项目总结为:

An application for building and managing Phars.

Box 项目提供 PHAR 构建脚本并负责正确设置所有路径,因此这可能会解决您的问题。

查看 php.ini 文件以检查 phar.readonly 字段的值。 必须为 0 才能创建 phar 存档。

参考:http://php.net/manual/en/phar.configuration.php#ini.phar.readonly

问题的根源在于 RecursiveDirectoryIterator 还列出了点文件 - ...。 当遍历 /path/to/foo 时,它还会列出 /path/to/foo/./path/to/foo/..,它们转到父目录 - 在基本目录之外。

因此您必须防止包含“..”文件,这最容易通过 FilesystemIterator::SKIP_DOTS 作为 DirectoryIterator 的第二个参数来实现:

new RecursiveDirectoryIterator($srcRoot, FilesystemIterator::SKIP_DOTS)

(@cweiske -- 我刚刚意识到你抢先了我,下次我一定会刷新页面,我最诚挚的歉意!)

您只需稍加编辑即可跳过 unix 路径 /。和/..:[=​​11=]

<?php
$srcRoot = __DIR__ . "/../app";
$buildRoot = __DIR__ . "/../build";
$p = new Phar("$buildRoot/build.phar", 0, 'build.phar');
$p->buildFromIterator(
    new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($srcRoot, FilesystemIterator::SKIP_DOTS)
    ),
    $srcRoot
);

@cweiske提出的解决方案非常棒。但是,在某些情况下,您可能需要能够添加更多目录路径排除项。查看此示例,使用 FilterIterator:

排除对 .git 目录的任何引用
// create phar
$p = new Phar($pharFile, 0, $pharFile);

// produce iteration which excludes any references to values assigned to $excludes
$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)
);
$filter = new class($iterator) extends FilterIterator {
    public static $excludes = [];
    public function accept()
    {
        $item = $this->current();
        $actual   = 0;
        foreach (self::$excludes as $exclude) {
            $actual += (int) boolval(strpos($item->getPath(), $exclude));
        }
        return ($actual === 0);
    }
};
$filter::$excludes = ['.git'];

$p->buildFromIterator($filter, $path);