Boxing up your Apps as Phars Quickly and Easily with Box

Share this article

In this tutorial, we’ll use Box to package a PHP application into a Phar, in order to make it easily distributable and globally installable via Composer.

Box

On what?

We need a project for this, and packaging up yet another “Hello World” script would be pointless. We’ll use Webiny’s FolderBuilder, a tool which you can use to plan out the folder structure for your project, interactively drag and drop files and folders, and even export and share these structures with others.

Webiny FolderBuilder Screenshot

But that’s almost entirely a JavaScript tool, why would we be using Phars for it? Yes, that GUI is JS, but if you look at the repo you’ll notice a PHP script inside which you can run on any folder and get the required JSON generated. This means you can easily generate FolderBuilder compatible structures from existing projects, too, which is super handy for planning a project’s restructuring.

While it’s very simple to just download and run the script from any folder you’d like to parse into JSON, why not make the whole project Phar-distributable and allow for something like:

composer global require webiny/folderbuilder
folderbuilder . > structure.json

Boxstrapping

Let’s bootstrap a Box project. First, we need to install Box if it’s not already present on our system. I am, of course, using Homestead Improved as usual to keep things isolated from my host OS.

composer global require kherge/box

We could download the phar of Box and use that, but we’re a Composer crowd here, we don’t use those outdated platform-specific methods ;)

Now that’s done, the box command is accessible from anywhere on our machine:

Box 01 Gif

To package an app with Box, one needs to include a box.json file in the project’s folder. The simplest of these can be seen in the example application:

{
    "files": ["src/Put.php"],
    "main": "bin/main",
    "output": "example.phar",
    "stub": true
}

The project we’ll be packaging has a lot of files, but only one we actually need for the Phar to be useful, so to keep it light, we’ll only package that one (and another, but more on that later). In that regard, our json file won’t be all that different (though if you’d like to see a more complex one, see the from Box itself here). Let’s begin!

Box.json

Note for Vagrant users: when using Vagrant boxes such as Homestead Improved the Phar extension won’t be able to write files for some reason. The solution is to either change the “output” property to a folder outside the shared one, or to do everything outside a shared folder altogether. We’ll take the latter approach in this case and just do everything inside the Vagrant user’s “home” folder.

The first thing we do is, of course, clone the repo:

cd ~
git clone https://github.com/webiny/folderbuilder
cd folderbuilder
git checkout 74b234fa33bd69690a2c26df38ef7d188c4e69eb

The last command is necessary so that you end up in a state of the project before I applied the fixes outlined in this post.

Then, we create the file box.json and populate it with:

{
	"files": ["structure.php"],
	"output": "bin/wfb.phar",
	"stub": true,
	"main": "structure.php"
}

So what does this mean?

The “files” property lists all the files we want to include in the Phar. “output” is the product of our build, and “main” indicates the entry file. “stub” is required when using CLI apps. The help file says:

“The stub (string, boolean) setting is used to specify the location of a stub file, or if one should be generated. If a path is provided, the stub file will be used as is inside the Phar. If true is provided, a new stub will be generated. If false (or nothing) is provided, the default stub used by the Phar class will be used.” and further explanation can be found here.

We make a bin folder because it’s a common place to put built/compiled resources.

Then, we run:

box build -v

Box will automatically detect the box.json file in the folder and produce output not unlike this one:

? Output path: /home/vagrant/folderbuilder/bin/wfb.phar
? Adding files...
  + /home/vagrant/folderbuilder/structure.php
? Adding main file: /home/vagrant/folderbuilder/structure.php
? Generating new stub...
* Done.

If we now execute the command:

php bin/wfb.phar

The current directory’s structure will be printed on screen in JSON format, just like if we ran php structure.php directly.

Executable

But how can we make it run without needing to specify either php or .phar? If you look inside the contents of wfb.phar, the first two lines will read:

#!/usr/bin/env php
<?php

This means “When this file is executed, use the PHP environment to chew it through”. To be able to do this, though, we need to make the file executable, and we do this by adding a “chmod” flag to our box.json file. While we’re at it, we can also make sure the files we include in the phar are compacted by using the two default compressors included with Box:

{
	"files": ["structure.php", "bin/stub.php"],
	"output": "bin/wfb.phar",
	"stub": true,
	"main": "bin/stub.php",
	"chmod": "0755",
	"compactors": [
        "Herrera\\Box\\Compactor\\Json",
        "Herrera\\Box\\Compactor\\Php"
    ]
}

Now, rerun box build and after it’s done, try running:

bin/wfb.phar

It should work. We still have to specify the extension though, and just removing it from box.json will cause Box to throw errors at us. What if we just removed .phar from the filename and hoped for the best?

mv bin/wfb.phar bin/wfb
bin/wfb

Lo and behold, it works! Okay, now how do we distribute this?

Distribution

If your project already has a composer.json file, then all you need to do is add a bin field for vendor binaries:

"bin": ["bin/wfb"]

In the case of FolderBuilder, there was no composer.json file at all, so I created one from scratch with composer init. The final version is here.

The project also needed to be put onto Packagist. Following the instructions in this post, that’s a 5-minute endeavor.

Trying it out

With everything done, let’s try it out. I’m going to fire up a new Homestead Improved instance for that, just so I’m 100% sure I’m starting with a fresh environment, and so that I don’t have to uninstall anything from the environment we’ve built this tutorial on.

Starting a new HI instance for testing is literally 5 lines of shell commands:

git clone https://github.com/swader/homestead_improved hi_fbtest
cd hi_fbtest
sed -i '' "s@map\: \.@map\: $PWD@g” Homestead.yaml
vagrant up
vagrant ssh

Now inside my new VM, I run:

composer global require webiny/folderbuilder

That should be enough. Let’s see if it works. I want to map out the Code folder (i.e. the root of the Homestead Improved project, should produce the scripts folder, Homestead.yaml, and other files and folders).

wfb ~/Code > out.json

And indeed, the file is there! Pasting its contents into FolderBuilder, we get exactly what we asked for.

FolderBuilder Displays Desired Output

Conclusion

In this tutorial, we looked at boxing up PHP code into Phars with the Box project. We discussed making them executable and we explained how to distribute these Phars during Composer installation, so that they become immediately accessible from everywhere once globally required. We could talk about signing the Phars or building their auto-update scripts, but that was already done better by someone else – check that post out if you’d like to learn more advanced aspects.

As for Webiny’s folder builder, it’s open source and welcoming contributions. Have ideas on how to improve it further? Maybe add tree creation into the mix, reading a JSON file and creating what was developed in the GUI? Go for it, submit a PR!

Did you see any missteps in our process? Do you follow the same workflow or do you package your Phars differently? Let us know in the comments!

Frequently Asked Questions (FAQs) about Boxing Apps and PHARs

What is the main purpose of using PHARs in PHP?

PHARs, or PHP Archives, are a way to package entire PHP applications into a single file for easy distribution and installation. They are similar to Java’s JAR files. PHARs can include a complete PHP application, including any necessary files, images, and scripts. This makes it easier to distribute and run PHP applications, as you only need to distribute a single file rather than an entire directory structure.

How do I create a PHAR file?

Creating a PHAR file involves packaging your PHP application into a single file. This can be done using the Phar class in PHP. You’ll need to create a new instance of the Phar class, add files to it using the addFile method, and then save it using the stopBuffering method. You can also set a stub, which is a small piece of code that runs when the PHAR file is executed.

What are the benefits of using boxing apps like Box-Project?

Boxing apps like Box-Project allow you to easily and quickly package your PHP applications into PHAR files. This simplifies the distribution and installation process, as you only need to distribute a single file. Box-Project also provides features like Git and Composer integration, making it even easier to manage your PHP applications.

How do I use Box-Project to create a PHAR file?

To use Box-Project, you’ll first need to install it. Once installed, you can create a box.json file that specifies how your application should be packaged. Then, you can use the box command to package your application into a PHAR file. Box-Project also provides options for compressing your PHAR file and setting a stub.

Can I use PHARs with web applications?

Yes, PHARs can be used with web applications. When a PHAR file is accessed through a web server, it behaves like a PHP application. This means you can package your entire web application into a single PHAR file and distribute it easily. However, keep in mind that not all web servers are configured to allow PHAR files to be executed.

Are there any security concerns with using PHARs?

Like any file that can be executed, PHARs can potentially be a security risk if they are not handled properly. It’s important to only use PHARs from trusted sources and to keep your PHAR files up to date. PHP also provides several settings that can be used to increase the security of PHAR files, such as phar.readonly and phar.require_hash.

How do I update a PHAR file?

Updating a PHAR file involves creating a new PHAR file with the updated application and replacing the old PHAR file with the new one. This can be done manually or using a tool like Box-Project. Keep in mind that if your PHAR file is being used by other people, you’ll need to provide them with the updated PHAR file.

Can I use PHARs with PHP frameworks?

Yes, PHARs can be used with PHP frameworks. Many frameworks provide support for PHARs, allowing you to package your entire application, including the framework, into a single PHAR file. This can make it easier to distribute and install your application, especially if it relies on a specific version of a framework.

What is the difference between Box-Project and Box-Project 2?

Box-Project 2 is the second version of Box-Project. It provides several improvements and new features over the original Box-Project, such as support for Composer, better error handling, and improved performance. If you’re already using Box-Project, it’s recommended to upgrade to Box-Project 2 to take advantage of these improvements.

How do I troubleshoot issues with PHARs?

Troubleshooting issues with PHARs can involve several steps, depending on the issue. Common issues include problems with file permissions, issues with PHP settings, and errors in the PHAR file itself. If you’re having trouble with a PHAR file, it can be helpful to check the PHP error log, test the PHAR file on a different system, and make sure your PHP settings are configured correctly.

Bruno SkvorcBruno Skvorc
View Author

Bruno is a blockchain developer and technical educator at the Web3 Foundation, the foundation that's building the next generation of the free people's internet. He runs two newsletters you should subscribe to if you're interested in Web3.0: Dot Leap covers ecosystem and tech development of Web3, and NFT Review covers the evolution of the non-fungible token (digital collectibles) ecosystem inside this emerging new web. His current passion project is RMRK.app, the most advanced NFT system in the world, which allows NFTs to own other NFTs, NFTs to react to emotion, NFTs to be governed democratically, and NFTs to be multiple things at once.

boxBrunoScomposerpackagistpharPHPwebiny
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week