PEAR is archived and read-only

This mirror preserves historical PEAR package releases and metadata so existing references remain available.

Home » File Formats » File_Archive » Manual

This package will let you manipulate easily tar, gz, bz2, tgz, tbz, zip, ar and deb files.

Examples

Examples – Some simple usage examples

Extract a tar archive to a sub directory

Here we simply take a tar archive called archive.tar and extract its contents to the folder

<?php
require_once "File/Archive.php";

File_Archive::extract('archive.tar/', 'output');
?>

Send a zip archive containing the content of a tar file to the standard output

<?php
require_once "File/Archive.php";

File_Archive::extract(
    //The content of archive.tar appears in the root folder (default argument)
    'archive.tar/',

    //And is written to ...
    File_Archive::toArchive(       // ... a zip archive
        'archive.zip',             // called archive.zip
        File_Archive::toOutput()   // that will be sent to the standard output
    )
);
?>

Extracting a file from an archive

Use extract() to get files out of an archive. When specifying the file to extract, make sure to use the archive name as first folder.

<?php
require_once "File/Archive.php";

File_Archive::extract(
    'archive.tar/inner.tgz/file.txt',
    File_Archive::toOutput()
);
?>

Readers

Readers – Getting files into an archive

Introduction

A reader is an object that represents a list of files and directories. Those files can be generated dynamically or exist physically. For example, there is a reader class for a directory, or for each archive format handled by File_Archive, and they all have the same interface.

To create a reader, you will have to use the File_Archive factory. The important function is the read() function:

read ( string $url , string $symbolic = null , integer $uncompression = 0 , integer $directoryDepth = -0 )

In this function the URL will represent what you want to read.

Generation of sources

<?php
require_once "File/Archive.php";

/*
To read a directory, just give the directory name
By default, the directory and all the subdirectories
will be parsed (see $directoryDepth to change this)
*/
$source = File_Archive::read("Path/to/dir");

/*
To read from one single file,
simply provide the name of the file
*/
$source = File_Archive::read("Path/to/dir/file.txt");

/*
An archive will be considered as a directory if a slash follows
This example reads the directory and all the subdirectories of inner/dir
contained in archive Path/to/dir/archive.tar
This reads all the .txt files in the inner directory of the archive.tar
*/
$source = File_Archive::read("Path/to/dir/archive.tar/inner/*.txt");

/*
If you want to uncompress the archive (read all its content)
Note: if you ommit the trailing /, the archive will be treated as a single file
*/
$source = File_Archive::read("Path/to/dir/archive.tar/");
?>

The symbolic attribute says how the files read will be displayed for future use. If $URL is a directory, $URL will be replaced by $symbolic (or '' if $symbolic is null). So, in our first example, the files will be displayed as if the current directory was 'Path/to/dir': Since by default $symbolic is empty, Path/to/dir will be simply removed from the file. You may want to put Path/to/dir as $symbolic to keep the full path Path/to/dir.

If $URL is a file, then only the filename will be kept, and $symbolic will be added to it. So, in our second example, the source contains a file with symbolic name file.txt. If a symbolic name foo had been specified, the source would contain foo/file.txt.

The $uncompression parameter indicate how many files will be uncompressed while parsing the tree to files. By default the files are not uncompressed. So, if you do File_Archive::read('archive.tar/inner/dir', 'inner/dir'), and if archive.tar contains a file called archive.tar/inner/dir/file.tgz, this second archive will appear as a file and not as a directory. It won't be uncompressed because $uncompression is 0. If $uncompression is set to 1, file.tgz would appear as a directory, but the files inside this archive would not be uncompressed. If $uncompression is set to -1, all the files would be uncompressed, regardless of the depth.

The compressed files that may appear in $URL are not taken into account by $uncompression variable.

The $directoryDepth parameter gives a limit to the number of directory read by the reader.

Multi readers

Using a multi reader, you can make several sources appear as one. You can create a multi reader using the File_Archive::readMulti() function.

Multi reader

<?php
//This reader contains the content of directory and archive.tar
$source = File_Archive::readMulti(
    array(
        File_Archive::read('directory'),
        File_Archive::read('archive.tar/')
    )
);
?>

Reading the content of a data reader

Any reader provides the following interface:

Listing the content of a data reader

<?php
$source->close(); //Move back to the begining of the source

while($source->next()) {
    echo $source->getFilename() . "<br/>\n";
}
?>

Functions that use readers

All File_Archive functions that take a reader as an argument also accept strings and arrays. The strings will be automatically interpreted as a reader using File_Archive::read function. The arrays will be interpreted as a multi reader.

Since the readers are passed by reference, you will have to pass a variable and not the raw string or array.

It is thus possible to rewrite the previous example like that:

Multi reader

<?php
//This reader contains the content of directory and archive.tar
File_Archive::extract(
    array(
        'directory',
        'archive.tar/'
    ),
    File_Archive::toArchive('test.zip')
);
?>

Writers

Writers – Saving archives

Introduction

A writer is an object that deals with data. Some writers transform data (this is the case of the archive writers), some save them to disk (for files writers), or to memory (for the memory writer)... They all implement the same interface.

You can transfer data from a reader to a writer using the File_Archive::extract function.

All the writers can be created thanks to the File_Archive factory, and more particularly the File_Archive::to* functions.

Write archives

To create a writer that will generate an archive, use the toArchive() function:

toArchive ( string $filename , &$innerWriter , $type = null , $stat = array() , $autoClose = true )

Generation of archive writers

<?php
require_once "File/Archive.php";

/* Writer to a tar file */
File_Archive::toArchive("archive.tar", $innerWriter);

/* Writer to a tar.gz file */
File_Archive::toArchive("archive.tgz", $innerWriter);

/* Writer to a zip file */
File_Archive::toArchive("archive.zip", $innerWriter);
?>

Write to files

A writer can write the files to physical files. To create such a writer, call File_Archive::toFiles();. If a directory does not exist, it will be automatically created.

Use files writer

<?php
require_once "File/Archive.php";

/* Copy a whole directory to another location */
File_Archive::extract(
    File_Archive::read('Path/to/dir', 'new/directory');
    File_Archive::toFiles()
);

/* Convert an archive to another format: tgz to zip */
File_Archive::extract(
    File_Archive::read('archive.tgz/'),

    File_Archive::toArchive(
        'archive.zip',
        File_Archive::toFiles()
    )
);
?>

Send emails

You can send emails as attachment using a mail writer available thanks to File_Archive::toMail function.

toMail ( array $to , array $headers , string $message , &$mail = null )

This function relies on the PEAR Mail and Mail_Mime libraries, and the parameters are the same as the one of these classes:

<?php
require_once "File/Archive.php";

/* Send the files in the current directory (no recursion) as attachment */
File_Archive::extract(
    File_Archive::read('Path/to/dir', '', 0, 0),
    File_Archive::toMail(
        $to, // recipients
        array(
            'Subject' => 'Path/to/dir directory',
            'From'    => 'address@of.expeditor'
        ),
        'Find all the files attached' // body
    )
);
?>

Send files to the user

To send files to the remote user (i.e. write data to the standard output), you need a special writer. You can build one calling function File_Archive::toOutput().

This writer will automatically send a header forcing the download of the file.

If you don't want that, call File_Archive::toOutput(false).

Multi writers

Using a multi writer, you can write the data to two or more different locations in parallel.

A typical use is to send the file to the user at the same time as you write it to a file.

It can also be used to generate archives in different formats.

You can create a multi writer using File_Archive::toMulti($dest1, $dest2).

Multi writer

<?php
//Send a directory to the user and to a file

File_Archive::extract(
    File_Archive::read('directory'),
    File_Archive::toArchive(
        'multi.zip',
        File_Archive::toMulti(
            File_Archive::toOutput(),
            File_Archive::toFiles()
        )
    )
);
?>

Writing to a writer

It is also possible to write data directly to a writer, without using a reader. To do so, you can use the following interface implemented by any writer:

Dynamic creation of a zip file

<?php
require_once "File/Archive.php";

$dest = File_Archive::toArchive("foo.zip", File_Archive::toFiles());
$dest->newFile("even.txt");
for($i=0; $i<100; $i++)
    $dest->writeData((2*$i)."\n");
$dest->newFile("odd.txt");
for($i=0; $i<100; $i++)
    $dest->writeData((2*$i+1)."\n");
$dest->close();

?>

If you do not specify the stat array in the newFile() function, the majority of the archives will have to buffer the data until the end of the file is reached (this is because the size of the file is usually needed to be able to write the header).

This may be a memory problem if you want to generate really large files.

Functions that use writers

All File_Archive functions that take a writer as an argument also accept strings and arrays. The strings will be automatically interpreted as a writer using File_Archive::appender() function. The arrays will be interpreted as a multi writer.

Since the writers are passed by reference, you will have to pass a variable and not the raw string or array.

It is thus possible to rewrite the previous example like that:

Multi writer

<?php
//Send a directory to the user and to a file

File_Archive::extract(
    $src = 'directory',
    File_Archive::toArchive(
        'multi.zip',
        array(
            File_Archive::toOutput(),
            File_Archive::toFiles()
        )
    )
);
?>

Predicates

Predicates – Filters

Introduction

File_Archive introduces the concept of filters to be able to select the files from a source. A filter is a particular reader that you can create with the File_Archive::filter() function. This function requires you to give a predicate. You can build this predicate using the File_Archive::pred* functions.

The standard logic predicates are:

Some other predicats will help you filtering the files:

Filter examples

<?php
//Extract all the files that contain an 'a' in their path
// or filename from a tar archive
File_Archive::extract(
    File_Archive::filter(
        File_Archive::predEreg('a'),
        File_Archive::read(
            'archive.tar/',
            'folder'
        )
    ),
    File_Archive::toFiles()
);

//Compress a directory to a zip file, including only the files
//smaller than 1MB that have changed since last hour
File_Archive::extract(
    File_Archive::filter(
        File_Archive::predAnd(
            File_Archive::predNot(
                File_Archive::predMinSize(1024 * 1024)
            ),
            File_Archive::predMinTime(time()-3600)
        ),
        File_Archive::read('directory')
    ),
    File_Archive::toArchive(
        'directory.zip',
        File_Archive::toFiles()
    )
);
?>

Archive modification

Archive modification – Remove and append files

Introduction

File_Archive version 1.3 introduces some new functions to edit existing archives. These functions will allow you to remove or append files to an existing archive.

Since for File_Archive, the file system is just another reader / writer, those modifications can be done on "real" archives (real files), or on nested archives (an archive inside another archive).

Remove files from an existing archive

To remove files from an archive, you'll use one of the following functions from File_Archive class:

Note that those functions will not recursively uncompress archives.

Remove Jpg, gif and Bmp from a zip archive

<?php
require_once "File/Archive.php";

File_Archive::remove(
    File_Archive::predExtension(
        array('jpg', 'jpeg', 'bmp', 'gif')
    ),
    'archive.zip'
);
?>

Remove image files from a nested archive

<?php
require_once 'File/Archive.php';

File_Archive::remove(
    File_Archive::predMIME(
        array('image/*')
    ),
    'archive.zip/data.tgz'
);
?>

Appending files to an archive

To append files to an archive, you'll use one of the following functions from File_Archive class:

Both of these functions return a writer that you can use as in the previous examples, using the extract function

Add a folder to an archive

<?php
require_once "File/Archive.php";

File_Archive::extract(
    File_Archive::read('folder'),
    File_Archive::appender('archive.zip')
);
?>

Note that if you use a string instead of a writer in a function, the string will be converted using File_Archive::appender(). Thus the previous example could be rewritten to:

Add a folder to an archive

<?php
require_once "File/Archive.php";

File_Archive::extract(
    $src = 'folder',
    $dest= 'archive.zip'
);
?>

Cache

Cache – Caching compressed files

Introduction

File_Archive 1.4 introduce the possibility to use a cache to store intermediate result of a zip compression. It uses the Cache_Lite PEAR package to do so.

A zip file is made of compressed files, one after the others. So if you generate an archive that contains files A, B and C and then another archive that contains A and C, you will compress twice the files A and C. The use of the cache will allow to save the compressed version of files A, B and C on the first compression, to use them again in the second compression.

Usage examples

The cache can be (and should be) used if you dynamically create some zip archive that contains frequently the same files. For example, you may want to allow the user to select some images, videos or other files from your gallery and allow them to download a compressed zip archive that contains these files.

If you do so without cache, your server will answer very slowly if a lot of users ask the files. With the cache, the files will be compressed only once.

On my machine (a thinkpad T42P with default factory equipment), generating a 200MB zip archive takes around 30s of CPU without the cache, 32s of CPU with an empty cache and 2s of CPU if all the files to compress are already in cache.

How to use the cache

The cache is a Cache_Lite object. So you must have installed the package. Then all you have to do is use the File_Archive::setOption() function with the cache parameter.

Set up the cache

<?php
require_once "File/Archive.php";
require_once "Cache/Lite.php";

//Create the cache object
$cache = new Cache_Lite(
    array(
        //See the doc of Cache_Lite for its constructor parameters
    )
);

//Ask File_Archive to use the cache object we just created
File_Archive::setOption('cache', $cache);

//And then create your archives as usual
//Generate a file called archive.zip in the working folder
File_Archive::extract(
    'folderToCompress',
    'archive.zip'
);

//Send an archive to the user
File_Archive::extract(
    'folderToCompress',
    File_Archive::toArchive(
        'archive.zip',
        File_Archive::toOutput()
    )
);
?>