What's new in PHP V5.3, Part 4: Creating and using Phar archives

PHP V5.3 is scheduled to release soon. This "What's new in PHP V5.3" series covers new and exciting features in this release. Part 1 looks at the changes made to the object-oriented programming and object handling in PHP V5.3, Part 2 looks at lambda functions and closures. And in Part 3, we look at namespaces, which is one of the most anticipated and the most debated feature in this release of PHP. Here in Part 4, we take a close look at Phar, which is an archive format that can be used within PHP. It can be used to not only archive files but also to deliver and run an entire PHP application from a single file. It can be used with PHP as an extension from the PECL repository, but will be an official extension of PHP in the upcoming V5.3 version.

Share:

John Mertic, Software Engineer, SugarCRM

John Mertic graduated with a degree in computer science from Kent State University and is currently a software engineer at SugarCRM. He has contributed to many open source projects, most notably PHP projects; he is the creator and maintainer of the PHP Windows Installer.



27 January 2009

Also available in Russian Japanese Vietnamese

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

The 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
$p->setStub($p-> createDefaultStub('index.php'));

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 setStub() command.


Adding files to the archive

The 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::setCompressedGZ() or 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 Phar::buildFromDirectory()
$p->buildFromDirectory('/path/to/files','./\.php$/');

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 Phar::buildFromIterator()
$p->buildFromIterator(new RecursiveIteratorIterator
(new RecursiveDirectoryIterator('/path/to/files')),'/path/to/files');

The 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:

  1. 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.
  2. 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.
  3. 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.


Summary

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.

Resources

Learn

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®.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source
ArticleID=365876
ArticleTitle=What's new in PHP V5.3, Part 4: Creating and using Phar archives
publish-date=01272009