Self-hosted service
box-project/box avatar
box-project/box

Box puts PHP code isolation, a requirements checker and PHAR signing in one bundler

📦🚀 Fast, zero config application bundler with PHARs.

1,325 stars114 forksPHPMIT

At a glance

What is it?
Box is the PHP application bundler that builds PHAR archives, and its configuration surface is much larger than the build step: code isolation, a bundled requirements checker, compactors, signing keys and a set of git-derived placeholders. Its full documentation lives in doc/ rather than in the README.
Who is it for?
Adopt Box when you ship a PHP command line tool as a PHAR and want isolation, a requirements check, signing and reproducible versioning handled by one tool rather than assembled by hand. Do not adopt it if you only need an archive without the isolation step, since scoping changes how your classes and namespaces are rewritten and that is a decision to make deliberately.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 116 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One JSON file is the whole interface

Box's stated goal is to simplify the PHAR building process, and the claim is zero configuration by default alongside fast application bundling. The configuration itself is a single JSON file, and the repository ships it as box.json.dist, which is the distribution copy of a config a project would start from.

The table of contents in the README is the best available map of that surface, because the README itself links out to doc/configuration.md for every key. The structure is worth reading as a design rather than a list. There is a base path setting, a main setting for the entry point, an output setting, and permissions under chmod. There are settings for which files and directories are included, with files and files-bin, directories and directories-bin, a finder and finder-bin, a blacklist, and two switches that are really shortcuts: exclude-composer-files and exclude-dev-files.

Two of those deserve attention before the rest. exclude-dev-files is the difference between a development archive and a distributable one, and forgetting it ships your test tooling to users. force-autodiscovery overrides the automatic detection of what belongs in the archive, which is the setting you reach for when Box guesses wrong and you would rather state the answer than keep editing the rest.

There is also a timestamp setting for forcing the timestamp, and dump-autoload for the Composer autoloader, so the archive's contents are deliberate rather than a side effect of the working directory.

Five subcommands, and only one of them builds

The feature list names the commands directly, and the ratio matters. There is `box info` and `box diff` to retrieve information about the PHAR extension, about a PHAR file and about its contents. There is `box verify` to verify the signature of an existing PHAR. There is `box validate` to get recommendations and warnings about your configuration. There is `box docker` for Docker support, which has its own document.

So the build itself is the smallest part of the tool. Information retrieval, diffing, signature verification, configuration validation and Docker support extend Box beyond its build step.

`box diff` is the one that changes how you work rather than what you can do. Comparing two archives is how you find out whether a rebuild changed anything beyond the version string, which is the question a release engineer asks and cannot answer by reading a changelog.

`box validate` addresses the failure mode of a configuration-driven tool, which is a typo in a key. The documentation also describes a friendly error logging experience as a feature, and those two are the same concern seen from two ends: telling you the configuration is wrong before you ship, and telling you what went wrong when something fails anyway.

The requirements checker has the same shape and is worth its own treatment, because it is the one part of Box that other projects depend on.

Code isolation rewrites your namespaces, and that is the decision to make deliberately

PHAR code isolation is documented separately, in doc/code-isolation.md, with subsections for why and how it works, for isolating the PHAR and for debugging the scoping.

The mechanism is prefixing. Two libraries can collide when they declare the same fully qualified class name, and isolation rewrites symbols into a private namespace. Box does that as part of the build, and the repository shows the tool it uses: scoper.inc.php at the root is a PHP-Scoper configuration, and the compactors list includes a php-scoper entry.

This is the feature with the widest blast radius, and the documentation naming a section on debugging the scoping is the tell. A build that succeeds can still produce an archive where a class is not found at runtime, because scoping renames things and reflection, string class names and service definitions in configuration files are the usual casualties. The compactors section also lists annotations, which suggests the same problem in the other direction, stripping annotations that are not needed in a distributable.

So the honest position is that isolation is optional in intent and invasive in effect. Turning it on fixes collisions between dependencies; turning it on also means your own code is being rewritten, and any behaviour that depends on a class name at runtime has to be checked. A project with a service container configured by class name strings is where this decision gets made.

The requirements checker ships inside the archive

The requirements checker has its own document, its own configuration section, and its own directory in the repository, which tells you it is a component rather than a build step.

Its job is to check that the environment running the PHAR has what the application needs. The configuration documentation covers three areas: PHP version requirements, extension configuration requirements, and polyfills. There is also a documented section on integration with a custom stub, which is the part that explains how the check actually runs.

The mechanism is visible in the Makefile. A variable extracts the checker into res/requirement-checker, and the phpunit target includes that path among the files the test suite exercises. In other words, the checker is a library that gets bundled into the archive and invoked by the stub at startup, rather than something that runs once on your machine at build time.

That design is the point. A PHAR is distributed to machines you do not control, and the failure mode without a checker is a fatal error partway through a command with a message about a missing extension. With it, the application checks its own environment at startup and reports what is missing, which is the difference between a support ticket and a usable error.

The stub is the other half of that mechanism. There is a stub setting, an alias, a shebang and a banner, plus a banner-file setting, and the Makefile's DEFAULT_STUB points at dist/default_stub.php, so the stub is a real artefact in the build rather than a constant inside the tool.

Signing keys and the placeholders that build a version string

The security section of the configuration covers three keys: the signing algorithm, the private key, and the private key password. That is the whole signing surface, and it pairs with the `box verify` subcommand, which verifies the signature of an existing PHAR.

Build and verify being separate commands is what makes signing useful rather than decorative. A release pipeline signs, and a consumer, or a distribution, checks, without needing the signing key to inspect an archive.

The metadata and placeholder sections are the other half of the configuration and they solve a problem that every PHAR author hits: a distributable needs a version, and a version has to come from somewhere reproducible rather than from a constant someone edits and forgets. The replaceable placeholders are configured with a replacement sigil setting, and the named placeholders are git, which is the pretty git commit placeholder, git-commit, git-commit-short, git-tag and git-version, plus a datetime placeholder with its own datetime-format setting.

The feature list states the intent directly: use Git tags and short commit hashes for versioning. A build from a tagged commit then produces an archive whose version matches the tag, and a build from an untagged commit produces one whose version identifies the commit, without anyone editing a file.

There is also a compression algorithm setting, and the optimisations document covers reviewing your files, compressing your PHAR and optimising your code, so the size question has its own guidance rather than being an afterthought.

Six ways to install it, and an upgrade guide for people arriving from Box 2

Installation has six documented channels, and the list itself tells you who the project expects to serve. There is Phive, Composer, Homebrew, GitHub releases, Docker, and a GitHub Actions route through shivammathur/setup-php.

The Docker option is part of the tool rather than a community package: `box docker` is a subcommand with its own document, so you can build inside a known container instead of discovering a version mismatch on your own machine.

The README opens with an upgrade guide for people arriving from Box2, linking UPGRADE.md and its section on going from 2.7 to 3.0. That is a real signal about the compatibility surface, and the repository's own file list shows the toolchain around it: a Makefile alongside Makefile.e2e, a fixtures/ directory, phpunit.xml.dist, infection.json.dist, phpbench.json, rector.php, a.php-cs-fixer configuration and a.markdownlint.jsonc.

Those files describe how the project is tested rather than how you should test your application, and they are worth a look before you trust a bundler with a build. Mutation testing with infection configured at a minimum MSI of 100 is a demanding setting, phpbench is there for performance work, rector and php-cs-fixer keep the code current, and Makefile.e2e means the end to end behaviour of building real archives is exercised, not only the unit level.

The Symfony support document, with sections on project files, the project directory and cache, is a separate document again, and its presence is the signal that a large PHP application has specific needs here that a small command line tool does not.

Maintenance, licence and the question a bundler always raises

The licence is MIT with a LICENSE file at the root, and the README links a Scrutinizer code quality badge and a Slack badge alongside the Packagist version. The package is humbug/box on Packagist, which is a name from the project's earlier identity and is still what composer requires.

Releases show a 4.x line in active use: 4.6.9 and 4.6.10 both on 2025-10-31, and 4.7.0 on 2026-03-18. The repository is not archived and the last push was on 2026-06-29.

The question a bundler always raises is what a PHAR costs you, and this project is unusually explicit about the answers. Scoping rewrites your symbols. Excluding dev files and Composer files changes what ships. The requirements checker changes what runs at startup. Signing adds a key to your release process. Compressing changes startup time. Each of those is a decision with a cost, and the documentation has a page for each one rather than a single best practice.

That is the argument for reading the configuration documentation before the first build rather than after, since the defaults are described as requiring zero configuration, which means the defaults are the ones you will be living with until you change them.

Editorial conclusion

Adopt Box when you ship a PHP command line tool as a PHAR and want isolation, a requirements check, signing and reproducible versioning handled by one tool rather than assembled by hand. Do not adopt it if you only need an archive without the isolation step, since scoping changes how your classes and namespaces are rewritten and that is a decision to make deliberately. Verify first the box.json.dist in the repository against the configuration documentation, because the key names such as check-requirements, exclude-dev-files, compression, algorithm, key and key-pass are the actual interface, and confirm the output and base-path settings before your first compile.

Frequently asked questions

What is Box used for?

Box is a PHP application bundler that builds PHAR archives, and the README describes it as simplifying the PHAR building process with fast bundling, zero configuration by default, code isolation and a requirements checker. Configuration is a single JSON file, distributed as box.json.dist in the repository.

Which Box subcommands exist besides building?

The feature list names `box info` and `box diff` for information about the PHAR extension, a PHAR file and its contents, `box verify` to verify the signature of an existing PHAR, `box validate` for recommendations and warnings about your configuration, and `box docker` for Docker support.

How do I install Box?

The installation documentation covers six routes: Phive, Composer, Homebrew, GitHub releases, Docker, and the shivammathur/setup-php GitHub Action. The Composer package is humbug/box on Packagist, and a full documentation site is linked from the README.

What does Box code isolation do?

It rewrites the symbols in your archive into a private namespace so libraries with colliding class names do not clash when bundled. The documentation has separate sections for why it works, for isolating the PHAR and for debugging the scoping, and the repository carries a PHP-Scoper configuration in scoper.inc.php.

Official sources

  1. box-project/box on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/box-project-box.svg)](https://hysenlabs.com/projects/box-project-box)

Was this useful?