8/25/2016

Getting Started with PHP Archives: PHAR

You can think of PHAR Archive as tar Archive or JAVA Archive (jar), but PHAR Archive serve specific purpose and more flexible.
  1. You can convert your PHP App into single Phar archive, So it saves space and easy to distribute
  2. If you want, you can compress it either using gz, bzip2 or zip compression Algorithms
  3. You can create executable Phar Archive which can have multiple endpoints, Endpoints server very different purpose, because, When you execute this Phar Archive from Command line, it will call, shell endpoint, But when you try to run that same archive using Browser, After putting it into web document Directory, it will look for (if Exists), web endpoint. That way you can create a single Phar archive which can we used as either command line utility, or when serve through web, it behaves like web app.
If You are facing any Error about, phar.readonly setting in php.ini file Then You need to Edit Your PHP Configuration File (In My case, php.ini) search for string phar.readonly and remove any Semi-colon before that line And set it to Off Example:- phar.readonly = Off

Example - Just create a simple Phar Archive for Given Directory

cd /tmp
mkdir first
cd first
# Create 10,000 Files for Testing purpose
php -r 'foreach(range(0,10000) as $i){ echo "$i\n"; $d=sprintf("%07d.txt", $i); file_put_contents($d, "Hello from $d\n"); }'


cd ..
# Now create a Phar Archive for all those generated Files
php -r "(new Phar('archive.phar', 0, 'archive.phar'))->buildFromDirectory('first');"
ls
# archive.phar


# Check Time taken by PHP Script to access individual File inside Phar Archive
time php -r 'echo file_get_contents("phar://archive.phar/0000693.txt");'
# Hello from 0000693.txt
#
# real  0m0.056s
# user  0m0.048s
# sys   0m0.000s


# Lets create a ZIP Archive for same Directory
zip -r first.zip first/

# Check out, How much size each archive is taking
du -h archive.phar first.zip first/
# 616K  archive.phar
# 1.8M  first.zip
# 40M   first/


# Lets read the same file inside ZIP File
time php -r 'echo file_get_contents("phar://first.zip/first/0000693.txt");'
# Hello from 0000693.txt
#
# real  0m0.198s
# user  0m0.120s
# sys   0m0.068s


Although phar:// wrapper supports reading zip, tar.gz, tar.bz2, phar Archives, i have checked all supported formats, and phar is taking less time to read individual file from archive.

Example - Lets me tell you structure of my app

/app
    /web
        assets/
            jquery
            bootstrap
        index.php
    /cli
        functions.php
        index.php
    /libs
    /vendors
    index.php

Example - Lets create Executable Phar Archive

<?php

# Case 1: When You want to include all Files from GIVEN Directory
// create with alias "project.phar"
$phar = new Phar('project.phar', 0, 'project.phar');
// add all files in the project
$phar->buildFromDirectory(dirname(__FILE__) . '/project');

# You can execute it from Command line or Just run it Using Your web Browser
# final public static string Phar::createDefaultStub ([ string $indexfile [, string $webindexfile ]] )
$phar->setStub($phar->createDefaultStub('cli/index.php', 'www/index.php'));

Example - Using Regex Filter to add matched files into Phar Archive

<?php
# Case 2: When You want to include all PHP (*.php) Files from GIVEN Directory
$phar2 = new Phar('project2.phar', 0, 'project2.phar');
// add all files in the project, only include php files
$phar2->buildFromDirectory(dirname(__FILE__) . '/project', '/\.php$/');
$phar2->setStub($phar->createDefaultStub('cli/index.php', 'www/index.php'));

Example - Create NEW Phar Archive for Given Directory

# Using Phar::buildFromDirectory API
php -r '(new Phar("users_arc.phar", 0, "users_arc.phar"))->buildFromDirectory("/home/ssp/www/app/users");'
# Using Phar::buildFromIterator API
php -r '(new Phar("app_arc.phar", 0, "app_arc.phar"))->buildFromIterator( new RecursiveIteratorIterator( new RecursiveDirectoryIterator("/home/ssp/www/app")), "/home/ssp/www/app");'

Example - How to convert TAR to Phar Archive

We will use PharData class to convert tar to phar Archive
<?php
try {
    $tarphar = new PharData('myphar.tar');
    // convert it to the phar file format
    $phar = $tarphar->convertToExecutable(Phar::PHAR); // creates myphar.phar
    $phar->setStub($phar->createDefaultStub('cli/index.php', 'web/index.php'));
    // Lets Create compressed Phar Archive
    $compressed = $tarphar->convertToExecutable(Phar::TAR, Phar::GZ, '.phar.tgz');
} catch (Exception $e) {
    // handle the error here
}

Example - Convert Phar to ZIP/Tar/TAR.GZ/TAR.BZ2 Archive

php -r '(new Phar("archive.phar"))->convertToData(Phar::ZIP);'
ls
// archive.phar  archive.zip
# To create tar.bz2 Archive
php -r '(new Phar("archive.phar"))->convertToData(Phar::TAR, Phar::BZ2, ".tbz");'