A library for simplifying the PHAR build process.

Overview

Box

Build Status

Box is a library built on the Phar class. It is designed to make it easier to create new phars and modifying existing ones. Features include compacting source files, better custom stub generation, and better OpenSSL signing handling.

Example

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

Installation

Add it to your list of Composer dependencies:

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

Usage

The Box library includes many features and some are designed so that they can be used independently of each other. This is done to allow the phar builder better control of the phar building process.

Compacting Source Files

Box makes uses of source file "compactors". A compactor is simply a class that checks if the given file is supported, then manipulates its contents to make it smaller. I will later cover how to actually use them in Finally, Building Phars.

There are two ways of creating a compactor class: implement the CompactorInterface interface, or extend the Compactor abstract class.

Implementing CompactorInterface

The CompactorInterface interface only requires that you implement two methods in your class: compact($contents) and support($file). The $contents argument is the contents of the source file, and the $file argument is the full path to the file. How you determine which file types are supported is entirely up to you.

In this example, this custom compactor will only modify files that end in .php, and remove whitespace from the end of each line:

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

Extending Compactor

An abstract compactor class is included that handles file type checking for you. You simply need to provide the default list of file extensions supported. These extension can be overwritten later if necessary, by the developer using them.

This example is a variation of the previous example 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);
    }
}

Developers can later change the supported file extensions by calling the Compactor->setExtensions() method:

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

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

Bundled Compactors

The library has two compactors bundled for your convenience.

Compacting JavaScript

The JavaScript compactor will minify JavaScript files, but requires the tedivm/jshrink packages to work. This is included when you install the Box library.

use Herrera\Box\Compactor\Javascript;

$compactor = new Javascript();
Compacting JSON

The JSON compactor is very simple to use as there are no options to configure. However, the json extension is required to use it. All extra whitespace is removed from .json files.

use Herrera\Box\Compactor\Json;

$compactor = new Json();
Compacting PHP

The PHP compactor will strip all comments whitespace from .php files. Comments that are removed will be removed with an the same number of line breaks as the original comment. This is done in order to preserve the line number that is reported when errors occur in the phar.

use Herrera\Box\Compactor\Php;

$compactor = new Php();

If you make use of Doctrine formatted annotations, you can also make use of a special feature within the Php compactor. To compact comments and preserve annotations, you will need to install the herrera-io/annotations library and create an instance of Tokenizer.

use Herrera\Annotations\Tokenizer;

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

Both line count and annotation data is preserved.

Managing Signatures

The Phar class provides an easy way of extracting and verifying a phar's signature. Simply instantiating the class will verify the phar in question. However, the phar extension is required to do either task. The Box library includes a way to extract and verify signatures without the use of the extension.

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
}

The Signature::create() method is an alias to Signature::__construct() which allows for a shorthand version of the above example:

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

The purpose of being able to verify a phar without having the extension available is more prudent in nature. In sensitive environments without the extension available, a dev or sys admin may want to verify the integrity of a phar they are using before making it available on the system.

Extracting Phars

In addition to being able to verify a phar's signature without the extension, you can also extract its contents. This feature is primarily designed to be embedded as part of a custom stub, but it can also be used to extract any phar.

use Herrera\Box\Extract;

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

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

The first argument for the constructor is the path to the existing phar. The second being the length of the stub. This second argument is required in order for the Extract class to know where the phar's manifest begins. Usually, this value is generated by the Phar class when the default stub is used.

If the value is unknown, the Extract class can be used to make a best guess effort by calling the Extract::findStubLength() method. If the stub length is incorrectly guessed, the Extract class will thrown an exception at some point during the extraction process.

By default, the Extract->go() method will create a temporary directory path and extract the contents of the phar there. The directory path specified in the example is optional.

In order to reduce overhead, the Extract class will not re-extract the phar if a special file exists in the target directory. This is used to speed up the execution process for phars that were executed without the phar extension.

Note that if any of the files within the phar were compressed using either gzip or bzip2, their respective extensions will be required for decompression. If the required extension is not installed, the Extract class will throw an exception.

Generating Stubs

If appropriate for the project, a custom stub can be generated by the Box library. You will have control over the following functions in the stub:

  • Setting an alias.
  • Setting a "banner" comment (such as a copyright statement).
  • Embed the Extract class to support self-extraction.
  • Setting the CLI index script.
  • Enabling the use of Phar::interceptFileFuncs().
  • Setting the file mimetypes.
  • Setting the list of server variables to "mung".
  • Setting the 404 script.
  • Setting the "shebang" line.
  • Opting the user of Phar::webPhar() over Phar::mapPhar().

The following is an example of a stub generated with all of the settings used:

use Herrera\Box\StubGenerator;

$generator = new StubGenerator();

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

Some license text here.
BANNER;

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

$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();

And the resulting stub:

\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();">

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

For the sake of brevity, the embedded Extract class was replaced with "... snip ...".

The example stub is likely overkill for what you need. By not using the extract() method, you can easily shave a few hundred lines of code from your stub, reducing its size, but you will lose the ability to execute the phar in an environment without the phar extension.

Finally, Building Phars

All these features are great, but they're even better when used together in the Box class. The Box class is designed to automatically integrate all of these features in a (hopefully) simple to use interface.

There are two ways of instantiating the class:

user Herrera\Box\Box;

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

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

Note that the Box::create() method accepts the same arguments as the Phar::__construct() method.

Registering Compactors

Whether you are using the bundled compactors or your own, you will need to call the Box->addCompactor() method to register your class with Box. All files added to the phar using Box will be automatically run through the supported compactors.

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

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

Using Placeholder Values

The Box class offers the ability to search and replace placeholder values in added files. Keep in mind that only scalar values are supported for any replacements.

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

With the above value to match, the following code:

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

will be added to the phar as:

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

Adding Files

To actually make use of the registered compactors and set placeholder value replacements, you will need to use the Box class's methods for adding files. The methods are identical to that of the Phar class, but automatically apply the appropriate compactors and replacements:

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

Note that if you need you need to add a file without any alterations (such as a binary file), you may need to add the file directly using the Phar instance:

$phar = $box->getPhar();

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

Setting the Stub

The Box class offers a simple way of adding a stub sourced from a file, and also applying the placeholder replacements at the same time:

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

The second argument indicates that replacements should be performed on the stub. If you leave it out, it will default to false which means that no replacements will be performed and the stub will be used as is.

Private Key Signing

The Box class offers two simple ways of signing the phar using a private key. Either method will, however, require the availability of the openssl extension.

With a String

If you have already loaded the private key as a string variable, you can use the Box->sign() method.

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

The password is only required if the key was generated with a password.

With a File

You can also sign the phar using a private key contained with a file.

$box->signUsingFile($file, $pass);
Comments
  • Running (extracting) phar archives without ext-phar fails

    Running (extracting) phar archives without ext-phar fails

    Tried bundling several projects as phar archives using StubGenerator::extract(true), but always get the same results in an environment with no phar extension:

    root@embedded:/var/www# php phar-composer.phar 
    PHP Warning:  fread(): Length parameter must be greater than 0 in /var/www/phar-composer.phar on line 265
    PHP Fatal error:  Uncaught exception 'RuntimeException' with message 'Could not read 0 bytes from "/var/www/phar-composer.phar".' in /var/www/phar-composer.phar:266
    Stack trace:
    #0 /var/www/phar-composer.phar(204): Extract->read(0)
    #1 /var/www/phar-composer.phar(136): Extract->extractFile(Array)
    #2 /var/www/phar-composer.phar(14): Extract->go()
    #3 {main}
      thrown in /var/www/phar-composer.phar on line 266
    

    Any thoughts? Generated phar archive works locally with enabled phar extension, but not on our embedded platform with no phar extension.

    Refs #4

    opened by clue 5
  • Consider removing Compactor / moving to (optional) dependency

    Consider removing Compactor / moving to (optional) dependency

    Compacting the source code before bundling is a very useful feature, imho. We should consider whether it's perhaps even as useful as to warrant its own package. Afaikt it's a bit of scope of the boxing process and might be better suited for an external dependency. Ideally, we'd only use its public interface to support adding custom compacting logic.

    Any thoughts?

    enhancement bc break 
    opened by clue 4
  • Add a feature to even use Extractor when ext-phar is available

    Add a feature to even use Extractor when ext-phar is available

    Some packages are very difficult to bundle as a phar, most often because they work with their paths in a way that does not work within phars (most notably using realpath() etc.)

    As such, it would be nice to add an option to the StubGenerator to always enforce extracting the archive to a temporary directory - regardless of whether ext-phar is available or not.

    Adjusting the logic should be fairly trivial, given that the Extractor already works out of the box. It's mostly a matter of how we should define the interface to the StubGenerator.

    enhancement 
    opened by clue 3
  • Support executing archives without Phar extension

    Support executing archives without Phar extension

    Phar archives can be executed without the Phar extension [1]: For this to work, it needs a special stub file that extract the phar archive and runs its contents from a temporary directory if no phar extension is found.

    Phar::createDefaultStub() creates one such special stub (around 7KiB code). I've created a gist that shows its usage and indented(!) output: https://gist.github.com/clue/5642099

    As such, it would be nice if such a loader stub would could be provided by the StubGenerator. Instead of rewriting the phar parser (see Extract_Phar class in the above gist), one can probably re-use the result from createDefaultStub() similar to this. Special care needs to be taken with regards to the other settings on StubGenerator.

    Any input welcome!

    enhancement 
    opened by clue 3
  • Added Javascript Compactor using JShrink

    Added Javascript Compactor using JShrink

    This Pull Request adds Javascript compaction to this library using the JShrink javascript minifier. It minifies javascript files that have not already been minified (skipping over those that have), and in the event of any type of error it automatically falls back to the original javascript.

    opened by tedivm 2
  • Current

    Current "master" failing tests, potential issue with output buffering

    I can't get the test suite to run out of the box- downloading and running it (even using the phpunit version pulled down by composer) results in two failures:

    1. Herrera\Box\Tests\ExtractTest::testFindStubLengthOpenError Failed asserting that '' matches PCRE pattern "/No such file or directory/".

    2. Herrera\Box\Tests\Signature\OpenSslTest::testVerifyErrorHandlingBug Failed asserting that exception of type "Herrera\Box\Exception\OpenSslException" is thrown.

    For the first one I believe there may be something going on with the output buffering that PHPUnit uses to read what's displayed- I can see the warning that there is "No such file or directory", but PHPUnit apparently can not. The assertion that this depends on- expectOutputRegex- relies on output buffering to read what's echo'd out.

    I think the second error is also related to output buffering. The code is showing the warning, which in theory it shouldn't be because you're running output buffering around it. It also seems like it's not properly populating $error with the output buffer, which may be why the exception isn't getting thrown properly.

    This is on a clean pull down of this library with no changes made at all.

    opened by tedivm 2
  • Extracting files larger than 8KiB may fail

    Extracting files larger than 8KiB may fail

    While preparing a fix for #7 I noticed that Extract::read() only ever issues a single fread() call. Because of PHP's stream buffers, it will likely return only partial results for files that do not fit into the default buffer and will thus lead to a RuntimeException.

    opened by clue 2
  • Preserve annotations in PHP docblocks

    Preserve annotations in PHP docblocks

    It has been requested that a PHP compactor support the preservation of docblock annotations.

    My idea was to

    1. Find annotated docblocks.
    2. Parse annotations from docblocks.
    3. Replace parsed docblocks with compacted annotations.

    I was hoping to use the Doctrine Annotations library to handle the parsing, but it appears that the annotation classes must be loaded in order for the parsing to happen. If I am correct, this will not work since it

    • may conflict with classes used by Box
    • will complicate the configuration process

    As far as I can tell, I may depend on the Annotations library, but will need to create my own DocParser class. I am unable to modify the existing DocParser class since it is "highly discouraged" and made final.

    I am also mulling around an idea to just write a simple library to handle only annotations.

    I am open to suggestions!

    enhancement 
    opened by ghost 2
  • Add option to set shebang line to StubGenerator

    Add option to set shebang line to StubGenerator

    This patch adds an optional setShebang($shebang) method to the StubGenerator in order to overwrite the default shebang.

    In particular, this is useful for custom setups where /usr/bin/env is not available or if it's required to pass additional arguments to the php interpreter (like #!/usr/bin/php -q).

    opened by clue 2
  • Add LSB init standard support

    Add LSB init standard support

    This pull request adds (optional) LSB init standard support to the generated PHAR file. It basically enables the PHAR to be used directly as a service script in Linux, e.g.: # sudo service my.phar start

    This is particularly useful when a PHAR is compiled for use as a (background) daemon, which I frequently do with box2. Up until this PR, I had to work around this issue as editing this information manually in the PHAR results in an invalid signature. Unfortunately, the necessary fields cannot be set in the "banner" property, as the LSB subsystem is very strict in its syntax (asterisks are not allowed as a line prefix).

    Corresponding unit test is added as well.

    If this PR is approved, I have a corresponding PR for box-project/box2 that enables setting the parameters in box.js for easy generation.

    opened by baspeters 1
  • Always call Phar::mapPhar() even when no alias has been set

    Always call Phar::mapPhar() even when no alias has been set

    This simple PR makes sure to always include a call to Phar::mapPhar(). This call is needed if you rename your resulting phar file and remove its file extension. Removing the file extension is often used when moving local phars to systems wide installations, e.g. when renaming ~/demo.phar to /usr/bin/demo.

    opened by clue 1
  • Optimize build speed by 97% or more

    Optimize build speed by 97% or more

    Hi there!

    My colleague informed me that building the phar file takes about 4 minutes. I couldn't believe this so I quickly looked into what the issue was. Blackfire told me 97% of all the time is needed at Phar::addFromString(). So I thought why not just write it all to a temporary directory, make it "lazy" and then add all of the files to the phar file at once using Phar::buildFromDirectory(). Turns out this works just fine for me and build time went down from 4 min 5 s to 7.05 s 😎

    I couldn't add tests because the supported php versions and the used phpunit is so old that I sort of cannot get it to work without some serious changes. Do you plan to update the tests on master and update to a decent phpunit version? If so, I'll be happy to add tests for this stuff here.

    Hope to help :-)

    PS: Blackfire comparison: https://blackfire.io/profiles/compare/2d79d513-2460-4010-a797-914ba7237a7f/graph

    opened by Toflar 0
  • Unexpected behaviour when using webPhar

    Unexpected behaviour when using webPhar

    I can't pass a custom rewrite function, because it gets escaped and inserted in as a string. It's not passed to Phar::webPhar as a callable.

    The PHP docs seem to suggest that if I pass an empty array of mimetypes, then it will use the default. If I pass an empty array, then I get the default, but my custom rewrite is not added.

    This might work?

    https://github.com/box-project/box2-lib/blob/master/src/lib/Herrera/Box/StubGenerator.php#L416

    if ($this->mimetypes) {
        $stub .= ', ' . var_export(
            $this->mimetypes,
            true
        );
    
        if ($this->rewrite) {
            $stub .= ', ' . $this->rewrite;
        }
    }
    else {
        if ($this->rewrite) {
            $stub .= ', array(), ' . $this->rewrite;
        }
    }
    
    opened by darrenmothersele 0
  • Faster-builds

    Faster-builds

    Faster build times by being able to exclude certain paths from variable replacement:

    Issue: https://github.com/box-project/box2/issues/97

    These changes are required for the other PR I am making for box2

    opened by webdevvie 0
  • it would be nice if there was a specific define set to detect if your script is running within a phar

    it would be nice if there was a specific define set to detect if your script is running within a phar

    Aloha,

    basically it would be nice to have some sort of define ("BOX_PHAR".. something like that), which explicitely allows to detect if a script is run from within a phar file.

    right now I'm abusing the BOX_EXTRACT_PATTERN_DEFAULT one for that, and that feels like a cheat.

    enhancement 
    opened by ppetermann 1
Releases(1.6.0)
  • 1.6.0(Dec 3, 2014)

    The project has been moved to the box-project organization since it appears that it will be living for a while longer until the new version of Box has a stable release.

    In the meantime, a new (and long overdue) feature is being added: JavaScript minification!

    use Herrera\Box\Compactor\Javascript;
    
    $compactor = new Javascript();
    
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Aug 12, 2013)

    • Improved documentation.
    • Fixed Extract buffering issues.
    • Fixed Extract when a phar contains an empty file.
    • Supporting the renaming of example.phar to just example in StubGenerator.
    • Added support for compacting PHP source while also preserving Doctrine annotations in docblocks.

    Annotations

    Previously, if you needed Doctrine annotations in your phar, you would be required to add each file with annotations as-is. This was not ideal since it meant that no compacting would be done. After having completed my Annotations library, I was able to add better annotations support to this library.

    use Herrera\Annotations\Tokenizer;
    use Herrera\Box\Box;
    use Herrera\Box\Compactor\Php;
    
    $compactor = new Php();
    $compactor->setTokenizer(new Tokenizer());
    
    $box = Box::create('my.phar');
    $box->addCompactor($compactor);
    

    With the Php compactor set with the Tokenizer instance, the following class:

    /**
     * This is a test entity.
     *
     * @ORM\Entity()
     * @ORM\Table(name="Test")
     */
    class Test
    {
        /**
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         * @ORM\Id()
         */
        private $id;
    
        /**
         * @ORM\JoinTable(
         *     name="exampleJoin",
         *     joinColumns={
         *          @ORM\JoinColumn(name="joinA", referencedColumnName="colA")
         *     },
         *     inverseJoinColumns={
         *          @ORM\JoinColumn(name="joinB", referencedColumnName="colB")
         *     }
         * )
         */
    }
    

    would be compacted like so:

    <?php
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
    @ORM\Entity()
    @ORM\Table(name="Test")
    
    
    */
    class Test
    {
    /**
    @ORM\Column(type="integer")
    @ORM\GeneratedValue(strategy="AUTO")
    @ORM\Id()
    */
    private $id;
    
    /**
    @ORM\JoinTable(name="exampleJoin",joinColumns={@ORM\JoinColumn(name="joinA",referencedColumnName="colA")},inverseJoinColumns={@ORM\JoinColumn(name="joinB",referencedColumnName="colB")})
    
    
    
    
    
    
    
    
    */
    }
    

    Mentions

    I would also like to thank @clue for his help with the Extract class!

    Source code(tar.gz)
    Source code(zip)
  • 1.4.0(Jul 23, 2013)

    To piggy back off the work done for extracting a phar's signature without the phar extension, you can now validate a phar without the extension as well. A new class called Signature has been added to handle phar signatures.

    use Herrera\Box\Signature;
    
    $signature = new Signature('my.phar');
    
    print_r($signature->get());
    /*
    Array
    (
        [hash_type] => OpenSSL
        [hash] => 54AF1D4E5459D3A77B692E46FDB9C965D1C7579BD1F2AD2BECF4973677575444FE21E104B7655BA3D088090C28DF63D14876B277C423C8BFBCDB9E3E63F9D61A
    )
    */
    
    echo 'Verified?', $signature->verify() ? 'yes' : 'no', "\n";
    // Verified? yes
    

    The class also supports verifying signatures, signed using a private key, without the openssl extension. However, you will need to have the phpseclib library installed.

    Notes

    • The Box::getSignature() method is now an alias for Signature::create('my.phar')->get().
    Source code(tar.gz)
    Source code(zip)
  • 1.3.0(Jul 22, 2013)

    With this release comes two new features:

    • Extract an existing phar without the extension.
    • Retrieve a phar's signature without the extension.

    To extract a phar:

    $extract = new Herrera\Box\Extract('my.phar', $stubSize);
    $extract->go(__DIR__ . '/my/out/dir');
    

    This feature is also integrated into StubGenerator, so that you may be able to execute a phar without the phar extension as well.

    StubGenerator::create()
        ->extract(true)
        ->index('hello.php')
        ->generate();
    

    Being able to execute the phar largely depends on how you designed your application.

    To get a phar's signature:

    $signature = Herrera\Box\Box::getSignature('my.phar');
    

    The value returned is identical to the result of Phar->getSignature().

    Source code(tar.gz)
    Source code(zip)
Owner
Box Project
An application for building and managing Phars.
Box Project
PPM is a process manager, supercharger and load balancer for modern PHP applications.

PPM - PHP Process Manager PHP-PM is a process manager, supercharger and load balancer for PHP applications. It's based on ReactPHP and works best with

PPM - PHP Process Manager 6.5k Jan 3, 2023
A visual process builder

DataStory ⚡ visual programming DataStory provides a workbench for designing data flow diagrams. ⚠️ We have moved to an organisation ?? Live Demo data-

Anders Jürisoo 120 Dec 12, 2022
This extension facilitates the cms editing process in your store.

Magenerds_PageDesigner This extension facilitates the cms editing process in your store. Instead of just a wysiwyg editor you now have a drag and drop

Magenerds 92 Nov 23, 2022
This composer plugin is a temporary implementation of using symbolic links to local packages as dependencies to allow a parallel work process

Composer symlinker A Composer plugin to install packages as local symbolic links. This plugin is a temporary implementation of using symbolic links to

Pierre Cassat 18 Nov 9, 2021
A sampling profiler for PHP written in PHP, which reads information about running PHP VM from outside of the process.

Reli Reli is a sampling profiler (or a VM state inspector) written in PHP. It can read information about running PHP script from outside of the proces

null 272 Dec 22, 2022
An async process dispatcher for Amp.

process This package provides an asynchronous process dispatcher that works on all major platforms (including Windows). As Windows pipes are file hand

AMPHP 204 Jan 8, 2023
A lightweight mulit-process helper base on PHP.

workbunny/process ?? A lightweight multi-process helper base on PHP. ?? 简介 这是一个基于ext-pcntl和ext-posix拓展的PHP多进程助手,用于更方便的调用使用。 快速开始 composer require work

workbunny 10 Dec 14, 2022
A sampling profiler for PHP written in PHP, which reads information about running PHP VM from outside of the process.

Reli Reli is a sampling profiler (or a VM state inspector) written in PHP. It can read information about running PHP script from outside of the proces

null 258 Sep 15, 2022
A framework agnostic PHP library to build chat bots

BotMan If you want to learn how to create reusable PHP packages yourself, take a look at my upcoming PHP Package Development video course. About BotMa

BotMan 5.8k Jan 1, 2023
Library to build PHP extensions with C++

PHP-CPP The PHP-CPP library is a C++ library for developing PHP extensions. It offers a collection of well documented and easy-to-use classes that can

Copernica 1.3k Dec 24, 2022
QuidPHP/Main is a PHP library that provides a set of base objects and collections that can be extended to build something more specific.

QuidPHP/Main is a PHP library that provides a set of base objects and collections that can be extended to build something more specific. It is part of the QuidPHP package and can also be used standalone.

QuidPHP 4 Jul 2, 2022
This tool is used to build and maintain browscap files.

Browser Capabilities Project This tool is used to build and maintain browscap files.

Browser Capabilities Project 400 Dec 29, 2022
Parsica - PHP Parser Combinators - The easiest way to build robust parsers.

Parsica The easiest way to build robust parsers in PHP. composer require parsica-php/parsica Documentation & API: parsica-php.github.io <?php $parser

null 350 Dec 27, 2022
Fly50W is a new language which helps you build simple apps using more than 500k lines of code easily.

Fly50W is a new language which helps you build simple apps using more than 500k lines of code easily. Installation

null 4 Jun 22, 2022
Phalcon Builder - is a packaging system that make it easy and quick to build Phalcon packages such as rpms, debs, etc. Phalcon's distribution that hosted at PackageCloud.

Phalcon Builder - is a packaging system that make it easy and quick to build Phalcon packages such as rpms, debs, etc. Phalcon's distribution that hos

The Phalcon PHP Framework 26 Oct 7, 2022
Time registration tool build with Phalcon

PhalconTime Application PhalconTime is a timekeeping tool that helps you track hours spend on clients and projects. Please write me if you have any fe

null 6 Oct 7, 2022
The light version of NexoPOS 4.x, which is a web-Based Point Of Sale (POS) System build with Laravel, TailwindCSS, and Vue.Js.

About NexoPOS 4.x NexoPOS 4 is a free point of sale system build using Laravel, TailwindCSS, Vue and other open-source resources. This POS System focu

Blair Jersyer 402 Jan 7, 2023
Cookbook-magento - Collection of recipes to build app stack for the Magento deployments with Chef

Magento Cookbook Collection of recipes to build app stack for the Magento deployments with Chef Installation With Berkshelf echo "cookbook 'magento',

Yevhen Viktorov 37 Sep 26, 2020
Magento2 Spanish (Argentina) language pack build from Crowdin community translation tool.

Magento2-language-es_ar Magento2 Spanish (Argentina) language pack build from Crowdin community translation tool. Paquete de idioma de Español (Argent

SemExpert 2 Apr 7, 2021