Real Dreams
Real Dreams

Reputation: 18010

Packaging a PHP application

I am trying to create a .phar file from my web application. Following the php documentation's example I tried the following for this purpose.

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

However I got the following error. I dont have any idea about the error. What is wrong with the code?

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

Upvotes: 4

Views: 1334

Answers (5)

dougB
dougB

Reputation: 509

The solution proposed by @cweiske is brilliant. In some situations, however, you may need the ability to add more directory path exclusions. Have a look at this example that excludes any references to the .git directory, using FilterIterator:

// 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);

Upvotes: 0

cweiske
cweiske

Reputation: 31078

The source of the problem is that RecursiveDirectoryIterator also lists the dot files - . and ... When iterating over /path/to/foo it also lists /path/to/foo/. and /path/to/foo/.. which goes to the parent directory - outside the base directory.

Thus you have to prevent the inclusion of the ".." files, which is most easily achieved with FilesystemIterator::SKIP_DOTS as second parameter to DirectoryIterator:

new RecursiveDirectoryIterator($srcRoot, FilesystemIterator::SKIP_DOTS)

Upvotes: 6

Patrick Webster
Patrick Webster

Reputation: 290

(@cweiske -- I just realized you beat me to it, I'll make sure to refresh the page next time, my sincerest apologies!)

You need just a slight edit to skip over the unix paths /. and /..:

<?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
);

Upvotes: 2

Rashid Azar
Rashid Azar

Reputation: 94

Have a look at php.ini file to check the value of phar.readonly field. It must be 0 to create phar archive.

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

Upvotes: -1

Fabian Kleiser
Fabian Kleiser

Reputation: 3008

Box makes it very easy to create PHAR archives from your source files. Basically you first add a configuration file and then you can create your PHAR file by simply invoking box build on the command line.

There is a great blog post by Matthieu Moquet describing how he used Box to simplify the distribution of a PHP Cli application. Personally, I've also been using Box for a CLI application, however the official project description is not limited to CLI applications, but rather summarizes the Box project as:

An application for building and managing Phars.

The Box project provides the PHAR build script and takes care of setting all paths correctly, so this might solve your problem.

Upvotes: 0

Related Questions