Packaging Your Apps with Phar

Tweet

Deployment of web applications can be difficult and cumbersome if you don’t have the right tools. If you’ve ever deployed a Java application before, I’m sure you’ve heard of JAR files (which stands for “Java ARchive”). Everything executable/accessible that makes up the application can be bundled in a single JAR file, which is a blessing when it comes time to deploy.

PHAR (“Php ARchive”) is analogous to the JAR file concept but for PHP. If you have PHP 5.3 or greater, the Phar extension is built-in and enabled; you can start using it without any additional requirements.

This article is intended to shed some light on this important feature for those who haven’t used it before. Hopefully you’ll find it a very helpful tool and have a better and faster deployment experience.

PHAR files are treated as read-only by default, and you can use any PHAR file without any special configuration. This is great for deployment. But as you’ll be creating your own PHARs you’ll need to allow write-access which is done through the php.ini file.

Open php.ini, find the phar.readonly directive, and modify it accordingly:

phar.readonly = 0

Now you’re ready to package your libraries and applications as PHARs.

Your First PHAR

Begin by creating the application’s directory structure; somewhere on your system, create the following:

application directory structure

The build directory will hold the PHAR package when it’s created to avoid polluting the source tree with generated artifacts. The src directory holds the source files that make up the application.

index.php will serve as the application’s entry point, common.php will be a pseudo-library of common classes used by the application, and config.ini will be the configuration file for the application.

The contents of index.php looks like:

<?php
require_once "phar://myapp.phar/common.php";
$config = parse_ini_file("config.ini");
AppManager::run($config);

The contents of common.php looks like:

<?php
class AppManager
{
    public static function run($config) {
         echo "Application is now running with the following configuration... ";
         var_dump($config);
     }
}

And the contents of config.ini looks like:

[database]
host=localhost
db=dbname
user=myuser
pass=dbpass

Creating the PHAR

Besides the application structure, you also need a script to generate the PHAR archive. Create a new PHP file named create-phar.php in your myapp root with the following code:

<?php
$srcRoot = "~/myapp/src";
$buildRoot = "~/myapp/build";
 
$phar = new Phar($buildRoot . "/myapp.phar", 
	FilesystemIterator::CURRENT_AS_FILEINFO |     	FilesystemIterator::KEY_AS_FILENAME, "myapp.phar");
$phar["index.php"] = file_get_contents($srcRoot . "/index.php");
$phar["common.php"] = file_get_contents($srcRoot . "/common.php");
$phar->setStub($phar->createDefaultStub("index.php"));

copy($srcRoot . "/config.ini", $buildRoot . "/config.ini");

Then open a terminal window, navigate to the myapp directory and run it:

aabouzekry@platinum:~/myapp$ php create-phar.php

After running the script, you should find the myapp.phar archive in the build directory along with a copy of config.ini file. Copy these two files to your web server’s document root directory (e.g. htdocs).

To access the Phar packaged application you could call the archive directly, but this is not recommended and may require additional configuration of your web server to forward PHAR files to the correct PHP handler. Another approach is to create a run script which includes the archive.

Create a run script called run.php in your web server’s document root with the following:

<?php
require "myapp.phar";

The code does nothing but bypass the hassle of reconfiguring your server to handle PHAR files directly. If you’re hosting your application in a shared hosting environment and don’t have access to your server’s configuration, then this is a perfect solution as well!

After creating the runner, your web root should look like this:

files in document root

Point your browser to the run.php script and you should see the following output:

browser output

Behind the Curtains

Let’s take a closer look at the create-phar.php code to see what it all means. Jave a look at the following line from it:

<?php
$phar = new Phar($buildRoot . "/myapp.phar", 
        FilesystemIterator::CURRENT_AS_FILEINFO |
        FilesystemIterator::KEY_AS_FILENAME, "myapp.phar");

A new Phar object is created which typically takes three arguments. The first argument is the path of the archive file to manipulate. Not only can you create new archives, but you can also manipulate existing ones.

The second argument is a flag to set how the object will handle files. The Phar object subclasses the PHP RecursiveDirectoryIterator class and this argument is simply passed to the parent class. The argument I provided is the default for RecursiveDirectoryIterator anyway, which is fine for now.

The third argument is the alias for the archive which will be used internally when referring to itself using the phar stream wrapper. In other words, all files inside the archive which require including other files from the archive should refer to it explicitly using the stream wrapper and the alias. For example, the code from index.php earlier references common.php file in this manner.

<?php
require_once "phar://myapp.phar/common.php";

After the object is created, index.php and common.php are added to the archive. The code treats the Phar object now as an associative array to specify the contents of the files keyed by their filenames, and file_get_contents() is used to read the file from disk. You can add as many files as you like similarly, but if you need to add a lot of files or an entire directory then you may want to consider using the more convenient buildFromDirectory() method.

<?php
$phar->buildFromDirectory("/path/to/dir",'/.php$/');

The first argument to buildFromDirectory() is the path to the desired directory and the second is an optional regular expression specifying which files to include. To include all of the files within the directory, just skip the second argument.

The setStub() method is called to create the stub file. A stub file tells the archive what to do when its loaded by the compiler.

Finally, the config.ini is copied from the src directory to the build directory alongside the archive.

The Stub File

When you run a PHAR archive, the stub inside is treated as a meta file to initialize the archive and tell it what to do when its called without referring to a particular file. In the example, I left the creation of the stub file up to the Phar object with the createDefaultStub() method which created a default stub containing the following code:

<?php
Phar::mapPhar();
include "phar://myapp.phar/index.php";
__HALT_COMPILER();

The default stub generated with createDefaultStub() illustrates little more than the minimum requirements. Phar::mapPhar() populates the meta-data of the archive and initializes it, and your stub file should end with a call to __HALT_COMPILER() with no trailing white space. This function halts further execution by the PHP interpreter at this point, allowing the possibility of including data after it without the risk of it being executed. This is a requirement by the Phar wrapper, without which the archive won’t work at all.

Alternatively, you can create your own stub file to perform custom initializations of your PHAR archive and read it in like so:

<?php
$phar->setStub(file_get_contents("stub.php"));

Taking Phar Seriously

If you’re developing a class library or other includable code, putting it in a PHAR archive is a neat and tidy solution to distribute it to multiple projects. The Phar extension has been highly optimized to give the same performance if not better than normal file access, so it’s likely you will not compromise the performance of your own application by using it.

To use Phar effectively though you should be aware it does have some limitations. Here are a few tips to help you better understand Phar and get the most out of it:

  • You can package a whole application in a PHAR, but it is not an auto-deploy solution. It’s a single-file access method for the application.
  • You can perform auto-deployment functionality manually inside the archive allowing for more robust deployments, like creating cache and upload directories on the sever, generating common configuration files, etc.
  • You should avoid back-writing to Phars in a real-world deployment. Instead, put all writeable files outside the archive. Writing to the PHAR is disabled in a standard PHP installation because it’s insecure for your application to do so.

Summary

Phar can save you a lot of hassle in packaging and deploying your applications and I recommend you consider using it. This article was intended to introduce you to the main concepts of Phar. You saw how to create the archive and include files, learned a bit about the importance of the stub file, and how PHP can access files within the archive. Unfortunately the resources for working with Phar in the PHP manual are incomplete and the limited amount of resources elsewhere on the Internet aren’t helpful enough. Hopefully in future articles I’ll be able to show you more about leveraging Phar.

Image via Pavel Ignatov / Shutterstock

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://adayinthelifeof.nl Joshua Thijssen

    There is one important issue when creating PHAR files on Debian or Ubuntu systems. They use the suhosin PHP security patches which means you have to enabled PHAR writing by additional adding: “suhosin.executor.include.whitelist = phar” to your php.ini file.

  • http://www.onphp5.com Dennis

    Hello,

    Have you evaluated what is the performance penalty related to unzipping the files, especially under heavy load? Does it play will with bytecode caches?

  • Abdullah Abouzekry

    @Joshua, Thanks for the valuable tip :)
    @Dennis, There’s no zipping and unzipping here, Phar is similar to Tar in that it groups all files into a single file, of course you can add zip compression but I don’t recommend so, as this would add unneeded overhead at the server, did that answer your question?

  • http://PaulANorman.com Paul Norman

    Hi Abdullah,
    Thanks for that I had wanted to check out using PHAR for a while and that is a really helpful overview.

    What happens when you have more than one phar – regarding the “config.ini” can these be named like myApp.config.ini or can you use a direectory structure on your end user server?
    And so…
    $config = parse_ini_file(“myApp.config.ini”);
    Or is “config.ini” mandatory please?
    Paul

  • Pravin Gundawar

    Hey! Abdullah,
    This is a great article, thank you very much. I am using cakephp (MVC) to develop my application. It has app/webroot/files directory. Here we sometimes stores the user uploaded files, in cakephp all files are kept in app directory along with application files like controllers, models or views. So, in the next build of PHAR how can I get or include those uploaded files. If not possible then I have to separate the directory structure of application and additional files.

  • http://keronmaurice.com Keron Maurice

    Is there any way to work with Codeigniter and PHAR? I ask because from what I read here it seems to complex to even attempt it. Am I right?

  • http://about.me/bruno.skvorc Bruno

    Nice overview, thanks. But, if I built my library in a single folder either way which autoincludes everything it requires when it requires it, isn’t using PHAR identical to this situation with the exception that PHAR isn’t browsable in the filesystem?

    Somehow I fail to see the real benefit. Now, if it provided encryption, obfuscation or any security measure, I’d consider it, but as it is, I kind of don’t see a need for it.

    Also, if I want to edit the source code of the PHAR archive, how do I extract the PHP files? Do I have to use PHP’s PHAR object or can I just extract as usual with an archive manager?

  • Abdullah Abouzekry

    Hi, everybody!, thanks all for your comments and sharing your thoughts.

    @Paul Norman Actually there’s no restrictions on how much PHAR(s) you can access from your code, the name of configs file and it’s format is not mandatory by any means, you can have your own structure use array files for configs, multiple files..etc, the only restriction is writing back to the PHAR, since most of PHP configurations online (and all should be in production) treat PHARs as read-only.

    @Pravin Gandawar Thanks! and hope you enjoyed :), as said in my answer to Paul, any behavior that introduces adding files / writing back at runtime to PHAR should be changed to be outside of PHAR, so, yes you should change your structure to do things right.

    @Keroun Maurice Actually I didn’t try packaging a CI application into PHAR, but theoretically you can package any PHP code into PHAR as long as your code is not writing back to the PHAR in anyway, so check your application structure and do it, would like to hear from you about how things went :)

    @Bruno You are welcome!, It’s not identical actually, since the main purpose of PHAR is easy “Packaging” and “Deployment” it’s PHAR’s main benefit, so if you have done multiple changes to your library and repackage it as a PHAR, you have now the luxury of uploading a single file to the server which will work as your folder, so its easier for deployment, distribution,..etc and making your library self contained, however using auto includes is a total different benefit, you will need it whether you use PHAR or not, it’s crucial in any real library.
    Why would you need to edit the source code of the PHAR archive in production?, the recommended way if you are using PHARs all over is to do the changes then “Package” then “Deploy”.
    If you want to extract PHAR archive you should use PHAR object, but PHAR object supports several formats other than PHAR itself, so you can have a zip/tar file accessible by PHAR object and by your favorite archive manager, but I don’t recommend this in production, but you may use it for playing with PHAR.

  • sandro

    hi how to create a file. exe in php?

  • http://donatstudios.com Jesse Donat

    Personally I’d like a download of a basic phar project to get me started.

  • http://www.os-cms.net dennis

    Very nice walk through – just what I needed. I don’t know about the performance but there seems to be bit of a hit when using phars. E.g see this:
    http://bohwaz.net/p/Is-serving-files-from-PHAR-slower-%28PHAR-benchmark%29

  • Ian Simmons

    Old post but just what I wanted. A simple intro to making a phar file. Only problem is it assumes the user is on a unix based system using ‘~’ in the path to srcRoot and buildRoot. I used this on windows and it works. Should work on any system since it’s php specific.

    $srcRoot = __DIR__.'/src';
    $buildRoot = __DIR__.'/build';