The concept of Phar archives come from Java™ technology's JAR archives, which allow you to package an application within a single file containing everything needed to run the application. It differs from the concept of a single executable, which is produced normally by languages, such as C, since the file is truly an archive and not a complied application. So the JAR file actually contains the files making up the application, although they can be obfuscated for security reasons. The Phar extension is based on a similar concept, but it is designed more for the Web environment of PHP. Also, unlike JAR archives, Phar archives can be processed by PHP itself and don't require an external tool to create or use them.
The Phar extension is not entirely new to PHP. It was initially written in PHP and known as PHP_Archive, and it was added to the PEAR repository in 2005. However, a pure PHP solution to this problem is quite slow in the real world, so it was rewritten as a pure C extension in 2007, at the same time support was added for using SPL's
ArrayAccess object for iterating through a Phar archive. Since then, quite a bit of work has been done to improve the performance of Phar archives.
Creating a Phar
There are several steps needed to create a Phar file. All the steps require PHP commands in some form to do this, since there exists no stand-alone tools for creating these archives. In addition, in order to create and modify Phar files, the php.ini setting phar.readonly must be set to 0. This setting is not required to open or reference files within a Phar archive within PHP.
Let's look at the steps needed to create a Phar archive that can be used to drive an application. This application will be designed to load directly from the Web browser or the command prompt. The first step is to create the Phar file, so we'll do this by creating the
Phar object we'll be working with for this example in Listing 1. The object reference will allow you to control all aspects of the Phar archive.
Listing 1. Creating the
$p = new Phar('/path/to/my.phar', CURRENT_AS_FILEINFO | KEY_AS_FILENAME, 'my.phar'); $p->startBuffering();
The first parameter to the constructor is the path to where the Phar file should be saved. The second parameter passes any parameters to the
RecursiveDirectoryIterator parent class. The third parameter is the alias for how this Phar archive is referred to in the streams context. So for Listing 1, you can refer to a file within this Phar as phar://my.phar. You can also issue the
Phar::startBuffering() method call to buffer changes made to the archive until you issue the
Phar::stopBuffering() command. Although it is unnecessary to do this, it does improve the performance of creating or modifying an archive since it avoids the need to save changes to the archive every time it's altered in your script.
By default, the Phar created will use the native Phar-based archive format. You can also use the ZIP or TAR format for the Phar file by converting it to that format, shown in Listing 2, by changing the format to ZIP.
Listing 2. Changing the storage format to ZIP
$p = $p->convertToExecutable(Phar::ZIP);
There are advantages and disadvantages to changing the archive format. The main advantage is the ability to inspect the contents of the archive with any of the tools for dealing with ZIP or TAR files. However, using a Phar archive that is not using the native Phar-based archive format does not require the use of the Phar extension for loading the archive, while ZIP- or TAR-formatted Phar archives do.
Next, you'll need to define the file stub, which is the first code called when the Phar file is loaded.
Phar file stub
The file stub is merely a small segment of code that gets run initially when the Phar file is loaded, and it always ends with a
__HALT_COMPILER() token. Listing 3 has what a typical file stub would look like.
Listing 3. Phar file stub
<?php Phar::mapPhar(); include 'phar://myphar.phar/index.php'; __HALT_COMPILER();
Phar::mapPhar() method call shown above initializes the Phar archive by reading the manifest. You need to do this before referencing files within the archive using the phar:// stream wrapper. The file to load initially would be what the file your application would normally load first; for this example: index.php.
How to add this stub to your Phar archive depends upon what archive format you are using. For Phar-based archives, use the
Phar::setStub() method, which accepts the sole parameter of the PHP code to put in the stub as a string. Listing 4 illustrates this approach.
Listing 4. Using
Phar::setStub() to create the file stub
$p->setStub('<?php Phar::mapPhar(); include 'phar://myphar.phar/index.php'; __HALT_COMPILER(); ?>');
If you aren't planning on doing much with the stub other than redirecting to a index.php page, you can use the helper method
Phar::createDefaultStub() to build the file stub for you. For this, you'll just need to pass the filename you wish to include in the file stub. In Listing 5, you'll rewrite the
Phar::setStub() method call to use this helper method.
Listing 5. Using
Phar::createDefaultStub() to create the file stub
A second optional argument to the
Phar::createDefaultStub() method allows you to include a different file if the Phar is loaded from a Web server. This is handy in case your application is designed to be used in a command line and a Web browser context.
For ZIP- and TAR-based implementations, you store the contents of the above stub inside the .phar/stub.php file, instead of using the
Adding files to the archive
Phar object uses the
ArrayAccess SPL object to allow accessing the contents of the archive as an array, so it opens up many ways of adding files to the archive. The easiest way is to use the
ArrayAccess interface directly.
Listing 6. Add files to an archive
$p['file.txt'] = 'This is a text file'; $p['index.php'] = file_get_contents('index.php');
Listing 6 shows that the file name is specified as the array key and the contents as the value. You can use the
file_get_contents() function to get the contents of an existing file to set as the value. This provides a bit of flexibility on how to add a file to an archive, by either referencing an existing file or building a file on the fly. The latter is useful as a part of an application build script.
If the file you are storing in the Phar archive is large, you can optionally compress the file in the archive using the gzip or bzip2 compression via the
PharFileInfo::setCompressedBZIP2() methods, respectively. In Listing 7, you'll compress a file using bzip2.
Listing 7. Compress a file in a Phar archive using bzip2
$p['big.txt'] = 'This is a big text file'; $p['big.txt']->setCompressedBZIP2();
To compress the file or use an archive with the compressed file in it, the bzip2 or zlib (for gz compressed files) extension must be enabled in the PHP install.
Let's say you have lots of files to add to an archive. Adding them one by one using the
ArrayAccess interface can get tedious, so there are a few shortcuts for this. One way is by using the
Phar::buildFromDirectory() method, which will walk through a specified directory and add the files within it. It also supports filtering of the files to add by passing a second parameter with the regular-expression pattern of files to match and add to the archive. Listing 8 shows how to use this.
Listing 8. Adding files to an archive using
Listing 8 adds all of the PHP files in the stated directory to the Phar archive. You can then go back using the
ArrayAccess interface if you need to make any changes to the added files, such as setting them to be compressed.
You can also use the
Phar::buildFromIterator() method to add files using an iterator. Two styles of iterators are supported: iterators that map the filename within the Phar to the name of a file on disk and iterators that return
SplFileInfo objects. One such compatible iterator is the
RecursiveDirectoryIterator, which is used below to add the files in a directory to the archive.
Listing 9. Adding files to an archive using
$p->buildFromIterator(new RecursiveIteratorIterator (new RecursiveDirectoryIterator('/path/to/files')),'/path/to/files');
Phar::buildFromIterator() method accepts the iterator object itself as the sole argument. In the above example, you've wrapped the
RecursiveDirectoryIterator object with the
RecursiveIteratorIterator object, the latter of which provides the compatible type of iterator that the
Phar::buildFromIterator() method needs.
We have now created a Phar archive, which can be used by any PHP application. Let's see how you can use this archive easily.
Dealing with Phar archives
The nice part about Phar archives is how easy they are to integrate within any application. This is especially true if you have used the native Phar-based archive format. In this case, you don't even need the Phar extension installed, since PHP can natively load the file and extract its contents. ZIP- and TAR-based archives require the Phar extension to be loaded.
Phar archives are designed to be included within an application just like any normal PHP file is, which makes using Phar archives very easy for application developers already familiar with including other third-party code. Let's see how easy it is to integrate a Phar into your application.
Integrating Phar archive code in your application
The easiest way to integrate code in a Phar archive is simply by including the Phar archive, then including the file within the Phar file you wish to use. The phar:// stream wrapper can be used to access a file inside a loaded Phar archive, shown below.
Listing 10. Loading code in a Phar archive
include 'myphar.phar'; include 'phar://myphar.phar/file.php';
The first include will load the myphar.phar archive, including the code specified in the file stub. The second include uses the stream wrapper to open the Phar archive and only includes the specified file inside the archive. Note that you don't need to include the Phar archive itself before including a file inside the archive, as shown in Listing 10.
Running a PHP application from a Phar archive
One neat thing you can do with Phar archives is package an entire application with a Phar archive and distribute it that way. The advantage to this approach is that it makes it easy to deploy the application and with no performance penalty, thanks to several of the enhancements made to Phar in PHP V5.3. However, when designing a application to run inside a Phar, here are a few considerations with the design of the application you should be aware of:
- Any files that may need to be created that are specific to an instance of the application, such as config files, cannot be part of the archive, so you'll need to write them to a separate but accessible location. The same goes if your application creates any cache file as a part of the execution.
- You should stick to the Phar-based archive format with no compression of the files in the archive for maximum portability. ZIP- and TAR-based archives require the Phar extension to be installed in PHP, while Phar-based ones can be used even when the Phar extension is not installed.
- Any references to files in the application need to be changed to use the phar:// stream wrapper with the name of the archive, as shown in the previous section.
PHPMyAdmin is one popular PHP application that has been packaged in Phar to use as an example of how easy using Phar archives can be (see Resources). It has been entirely designed to run from the Phar archive file, yet still provides the ability to store its configuration file outside the Phar archive.
Phar archives are a rather handy addition to PHP V5.3. They provide the ability to package PHP code in an archive, which can be useful for distributing an application or library in just one file. The Phar archive can loaded easily from a PHP file using the require or include function, or can be executed directly from the browser or command line by specifying the Phar archive by name.
- Read "A PHP V5 migration guide" to learn how to migrate code developed in PHP V4 to V5.
- "Connecting PHP Applications to Apache Derby" shows you how to install and configure PHP on Windows (some steps are applicable to Linux®).
- For a series of developerWorks tutorials about learning to program with PHP, see "Learning PHP, Part 1," Part 2, and Part 3.
- PHP.net is the central resource for PHP developers.
- Check out the "Recommended PHP reading list."
- Browse all the PHP content on developerWorks.
- Expand your PHP skills by checking out IBM developerWorks' PHP project resources.
- To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
- Using a database with PHP? Check out the Zend Core for IBM, a seamless, out-of-the-box, easy-to-install PHP development and production environment that supports IBM DB2 V9.
- Stay current with developerWorks' Technical events and webcasts.
- Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
- Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
- Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.
Get products and technologies
- PHPMyAdmin is a popular PHP application that has been packaged in Phar to use as an example of how easy using Phar archives are.
- Get PHP V5.2.6.
- Innovate your next open source development project with IBM trial software, available for download or on DVD.
- Download IBM product evaluation versions, and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
- Participate in developerWorks blogs and get involved in the developerWorks community.
- Participate in the developerWorks PHP Forum: Developing PHP applications with IBM Information Management products (DB2, IDS).