Oihana PHP

tar

Table of Contents

Functions

assertTar()  : bool
Validates that a file is a tar archive (compressed or uncompressed).
hasTarExtension()  : bool
Checks if a file has a tar-related extension.
hasTarMimeType()  : bool
Checks if a file has a tar-related extension.
tar()  : string
Creates a tar archive from one or more files and/or directories.
tarBinary()  : string|null
The system `tar` this library is willing to use, or null.
tarBinaryIsUsable()  : bool
Whether a candidate is an executable GNU tar.
tarDirectory()  : string
Creates a tar archive from a directory with specified compression.
tarEntries()  : array<int, array{base: string, name: string, directory: bool, path: string}>
Works out what an archive is to contain, and under which names.
tarEntriesByBase()  : array<string, array<int, string>>
Groups entries by the directory their names are relative to.
tarFileInfo()  : array{is_valid?: bool, extension?: string, mime_type?: string|null, compression?: string|null, file_count?: int|null, total_size?: int|null}
Retrieves detailed information about a tar archive file.
tarIsCompressed()  : bool
Checks if a given tar file is compressed.
tarWithBinary()  : void
Builds an archive with the system `tar`.
tarCompressionFlag()  : string|null
Whether the system tar can produce this compression, and with which flag.
tarCompressorExists()  : bool
Whether the compressor `tar` would shell out to is installed.
tarBinaryHandles()  : bool
Whether the binary engine can take this archive on.
untar()  : true|array<string|int, string>
Extracts a tar archive file into a specified output directory.
validateTarStructure()  : bool
Validates the internal structure of a tar file.

Functions

assertTar()

Validates that a file is a tar archive (compressed or uncompressed).

assertTar(string $filePath[, bool $strictMode = false ]) : bool
Parameters
$filePath : string

Path to the file to validate.

$strictMode : bool = false

If true, performs deep validation using file contents. If false, only checks extension and basic MIME type.

Tags
throws
FileException

If the file does not exist or cannot be read.

example

Basic validation using file extension and MIME type:

$isValid = isTarFile('/path/to/archive.tar');

Strict validation with file content inspection:

$isValid = isTarFile('/path/to/archive.tar.gz', true);

Validation failure for non-tar file:

$isValid = isTarFile('/path/to/image.jpg');
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

True if the file is a valid tar archive, false otherwise.

hasTarExtension()

Checks if a file has a tar-related extension.

hasTarExtension(string $filePath[, array<string|int, string> $tarExtensions = [FileExtension::TAR, FileExtension::TGZ, FileExtension::GZ, FileExtension::TAR_GZ, FileExtension::TAR_BZ2, FileExtension::BZ2] ]) : bool
Parameters
$filePath : string

Path to the file.

$tarExtensions : array<string|int, string> = [FileExtension::TAR, FileExtension::TGZ, FileExtension::GZ, FileExtension::TAR_GZ, FileExtension::TAR_BZ2, FileExtension::BZ2]

Optional list of valid tar-related extensions. Defaults to common tar and compressed tar extensions:

  • .tar
  • .tgz
  • .gz
  • .tar.gz
  • .tar.bz2
  • .bz2
Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0
example

Check a simple tar file:

var_dump(hasTarExtension('/path/to/archive.tar')); // bool(true)

Check a gzipped tar file:

var_dump(hasTarExtension('/path/to/archive.tar.gz')); // bool(true)

Check a file with .tgz extension:

var_dump(hasTarExtension('/path/to/archive.tgz')); // bool(true)

Check a file with unsupported extension:

var_dump(hasTarExtension('/path/to/archive.zip')); // bool(false)

Check a file with double extension .tar.bz2:

var_dump(hasTarExtension('/path/to/archive.tar.bz2')); // bool(true)
Return values
bool

True if the file has a recognized tar extension.

hasTarMimeType()

Checks if a file has a tar-related extension.

hasTarMimeType(string $filePath[, array<string|int, string> $mimeTypes = ['application/x-tar', 'application/tar', 'application/gzip', 'application/x-gzip', 'application/x-bzip2', 'application/bzip2', 'application/x-compressed-tar'] ]) : bool

This function inspects the MIME type of the given file against a list of valid tar-related MIME types to determine if the file is a tar archive.

It is a thin wrapper around hasMimeType() pre-configured with the common tar MIME types.

Parameters
$filePath : string

Path to the file.

$mimeTypes : array<string|int, string> = ['application/x-tar', 'application/tar', 'application/gzip', 'application/x-gzip', 'application/x-bzip2', 'application/bzip2', 'application/x-compressed-tar']

Optional list of valid tar MIME types. Defaults to common tar and compressed tar types:

  • 'application/x-tar'
  • 'application/tar'
  • 'application/gzip'
  • 'application/x-gzip'
  • 'application/x-bzip2'
  • 'application/bzip2'
  • 'application/x-compressed-tar'
Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0
example

Check if a .tar.gz file is a tar archive:

$result = hasTarMimeType('/path/to/archive.tar.gz');
var_dump($result); // bool(true) or bool(false)

Check a file with a custom list of MIME types:

$customTypes = ['application/x-tar', 'application/x-custom-tar'];
$result = hasTarMimeType('/path/to/custom.tar', $customTypes);

Check a non-existent file (returns false):

$result = hasTarMimeType('/path/to/missing.tar');
var_dump($result); // bool(false)
Return values
bool

True if the file exists and its MIME type matches one of the given tar MIME types.

tar()

Creates a tar archive from one or more files and/or directories.

tar(string|array<string|int, string> $paths[, string|null $outputPath = null ][, string|null $compression = CompressionType::GZIP ][, string|null $preserveRoot = null ]) : string

This function supports adding multiple paths (files or directories) to a tar archive, with optional compression (gzip, bzip2, or none). It can preserve the root directory structure inside the archive, and generates a unique temporary archive if no output path is specified.

Empty directories are preserved in the archive.

Parameters
$paths : string|array<string|int, string>

Absolute path(s) to file(s) or directory(ies) to include in the archive.

$outputPath : string|null = null

Optional full path to the final archive file to create. If null, an automatic unique filename with timestamp is generated in the system temp directory.

$compression : string|null = CompressionType::GZIP

Compression type to use on the tar archive. Supported values are defined in CompressionType, defaults to CompressionType::GZIP.

$preserveRoot : string|null = null

If set, paths inside the archive will be stored relative to this directory, allowing to preserve directory structure when extracting. Must be an absolute path.

Tags
throws
FileException

If any of the provided paths does not exist or is invalid.

UnsupportedCompressionException

If the requested compression type is not supported by the system.

DirectoryException

If the temporary directory cannot be created or accessed.

RuntimeException

If no files are added to the archive or if an error occurs during creation, including inability to rename temporary files.

see
CompressionType
example

Archive a single file, auto-named, gzip compressed (default):

$tarPath = tar('/var/www/html/index.php');

Archive a directory with bzip2 compression:

$tarPath = tar('/var/www/html', '/tmp/site.tar.bz2', CompressionType::BZIP2);

Archive multiple files with no compression:

$tarPath = tar
(
   ['/etc/hosts', '/etc/hostname'],
   '/tmp/config.tar',
   CompressionType::NONE
);

Archive directory with root preserved (relative paths):

$tarPath = tar
(
    '/var/www/html/project',
    '/tmp/project.tar.gz',
    CompressionType::GZIP,
    '/var/www/html'
);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

Returns the full path to the created tar archive file.

tarBinary()

The system `tar` this library is willing to use, or null.

tarBinary([bool $refresh = false ]) : string|null

PharData writes tar archives in pure PHP, and on anything but a toy tree it is not viable: measured against GNU tar on the same 96 MB / 7 554-file directory, producing the same 17 MB archive, it took 317 seconds against 1.63 — and the gap widens with size, because it writes the tar and then reads the whole thing back to compress it. It also refuses any path component longer than 100 bytes, the ustar limit, which a single file of a stock WordPress plugin set is enough to hit.

So the work is handed to the system binary when one is there. Which one matters:

  • GNU tar stores names as raw bytes, exactly as PharData does. Verified on a tree of accented, CJK, quoted and spaced names, plus a symlink and an empty directory: the entry lists are identical.
  • bsdtar, which is what macOS ships as /usr/bin/tar, converts filenames to Unicode NFD. été.txt becomes e´te´.txt inside the archive. An archive written on a Mac and restored on a server would carry different names than the originals — for a site with accented media, different URLs. Speed is not worth that, and a Mac is a development machine rather than a backup target.
  • BusyBox tar is a reduced implementation whose fidelity has not been measured here.

Hence the rule: the binary is used when it identifies itself as GNU tar, and PharData carries the rest. Slower and identical beats faster and subtly different.

OIHANA_TAR_BINARY overrides the search: a path to use one in particular, or an empty value to force the PharData path — which is how the test suite exercises both engines on the same fixtures.

Parameters
$refresh : bool = false

Whether to look again instead of reusing the previous answer.

Tags
example
$binary = tarBinary() ;

echo $binary === null
    ? 'archives are built in PHP, which is slow on large trees'
    : sprintf( 'archives are built by %s' , $binary ) ;
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
string|null

The binary to run, or null when the archive is to be built in PHP.

tarBinaryIsUsable()

Whether a candidate is an executable GNU tar.

tarBinaryIsUsable(string $candidate) : bool

Asked by running it rather than by trusting its name: /usr/bin/tar is GNU tar on Linux and bsdtar on macOS, and the two do not treat filenames the same way.

Parameters
$candidate : string

The path to test.

Tags
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
bool

True when the binary runs and identifies itself as GNU tar.

tarDirectory()

Creates a tar archive from a directory with specified compression.

tarDirectory(string $directory[, string|null $compression = CompressionType::GZIP ][, string|null $outputPath = null ][, array<string|int, mixed> $options = [] ]) : string

This function creates a compressed (or uncompressed) tar archive from the given directory. It supports filtering files by exclude patterns, by a callback filter function, and adding optional metadata saved as .metadata.json inside the archive.

If no filters or metadata are provided, it simply creates the archive directly from the directory. Otherwise, it copies filtered files to a temporary directory and archives from there.

Parameters
$directory : string

The source directory to archive.

$compression : string|null = CompressionType::GZIP

Compression type (e.g. gzip, bzip2, none). Default is gzip compression.

$outputPath : string|null = null

Optional output archive path. If null, defaults to directory name plus extension based on compression.

$options : array<string|int, mixed> = []

Additional options:

  • exclude => string[] list of glob patterns or file names to exclude
  • filter => callable|null a function (string $filepath): bool
  • metadata => array<string, string> extra metadata to embed in .metadata.json
Tags
throws
DirectoryException

If the source directory does not exist or is inaccessible.

FileException

If there are issues writing files or archives.

UnsupportedCompressionException

If an unsupported compression type is specified.

RuntimeException

If no files match filtering criteria.

example
// Create a gzip compressed tar archive from directory /var/www/html
$archive = tarDirectory('/var/www/html');
echo $archive; // /var/www/html.tar.gz

// Create a bz2 compressed archive, excluding .git and node_modules folders
$archive = tarDirectory(
    '/var/www/html',
    CompressionType::BZIP2,
    null,
    [
        TarOption::EXCLUDE => ['.git', 'node_modules'],
    ]
);

// Create an archive with a custom filter callback and add metadata
$archive = tarDirectory(
    '/var/www/html',
    CompressionType::NONE,
    '/backups/html_backup.tar',
    [
        TarOption::FILTER => function(string $filePath): bool {
            // Only include PHP files
            return str_ends_with($filePath, '.php');
        },
        TarOption::METADATA => [
            'createdBy' => 'admin',
            'description' => 'Backup of PHP source files',
        ],
    ]
);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

Returns the full path to the created archive file.

tarEntries()

Works out what an archive is to contain, and under which names.

tarEntries(array<string|int, string> $paths[, string|null $preserveRoot = null ]) : array<int, array{base: string, name: string, directory: bool, path: string}>

Written once and used by both engines, because the naming is the whole compatibility contract: an archive is only interchangeable with the ones written before it if the entries are called the same thing. Two copies of these rules would drift, and the drift would only show up the day someone tried to restore an old backup.

Each entry carries the directory it is named relative to, so the caller can either add it to a PharData or hand the list to tar -C <base>.

Parameters
$paths : array<string|int, string>

The real paths to archive, each proven to exist.

$preserveRoot : string|null = null

The directory names are taken relative to, when given.

Tags
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
array<int, array{base: string, name: string, directory: bool, path: string}>

base is what name is relative to, path is where the content really is.

tarEntriesByBase()

Groups entries by the directory their names are relative to.

tarEntriesByBase(array<int, array{base: string, name: string, directory: bool, path: string}> $entries) : array<string, array<int, string>>

tar is told a base with -C and reads the names from standard input, so one invocation covers one base. Archiving several unrelated paths at once therefore takes several.

Parameters
$entries : array<int, array{base: string, name: string, directory: bool, path: string}>
Tags
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
array<string, array<int, string>>

The names to archive, keyed by base directory.

tarFileInfo()

Retrieves detailed information about a tar archive file.

tarFileInfo(string $filePath[, bool $strictMode = false ]) : array{is_valid?: bool, extension?: string, mime_type?: string|null, compression?: string|null, file_count?: int|null, total_size?: int|null}

This function inspects the given tar file to determine its validity, compression type, MIME type, number of contained files, and total size of the contents.

It uses the PharData class to count files and calculate total size when the tar is valid.

Parameters
$filePath : string

Absolute path to the tar archive file to inspect.

$strictMode : bool = false

When true, enables strict validation of the tar file structure via assertTar(). Default is false for a more lenient check.

Tags
throws
FileException

If the provided file does not exist or is not accessible.

see
assertTar()
example
$info = tarFileInfo( '/archives/sample.tar' );
print_r( $info );

$info = tarFileInfo( '/archives/compressed.tar.gz' );
echo $info['compression']; // 'gzip'

$info = tarFileInfo( '/bad/path.tar' );
var_dump( $info['isValid'] ); // false

// Strict mode
$info = tarFileInfo( '/archives/sample.tar' , true );
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
array{is_valid?: bool, extension?: string, mime_type?: string|null, compression?: string|null, file_count?: int|null, total_size?: int|null}

Returns an associative array with:

  • isValid: Whether the tar file is valid according to assertTar().
  • extension: File extension (lowercase) extracted from the path.
  • mimeType: MIME type detected via finfo.
  • compression: Compression type detected (gzip, bzip2, or none).
  • fileCount: Number of files inside the tar (if valid), otherwise null.
  • totalSize: Sum of sizes (in bytes) of all files inside (if valid), otherwise null.

tarIsCompressed()

Checks if a given tar file is compressed.

tarIsCompressed(string $tarFile) : bool

This function determines whether the file name indicates a compressed tar archive based on common compressed tar extensions such as .tar.gz, .tgz, .tar.bz2, or .tbz2.

Note: This function only inspects the file name extension, not the actual file contents.

Parameters
$tarFile : string

The path or filename of the tar archive.

Tags
example
var_dump( tarIsCompressed( 'archive.tar.gz'   ) ); // true
var_dump( tarIsCompressed( 'archive.tgz'      ) ); // true
var_dump( tarIsCompressed( 'archive.tar.bz2'  ) ); // true
var_dump( tarIsCompressed( 'archive.tbz2'     ) ); // true
var_dump( tarIsCompressed( 'archive.tar'      ) ); // false
var_dump( tarIsCompressed( 'archive.zip'      ) ); // false
var_dump( tarIsCompressed( 'README.md'        ) ); // false
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

True if the file is recognized as a compressed tar archive, false otherwise.

tarWithBinary()

Builds an archive with the system `tar`.

tarWithBinary(string $binary, array<int, array{base: string, name: string, directory: bool, path: string}> $entries, string $finalPath, string $compression) : void

The entry names are computed in PHP by tarEntries() and handed over verbatim, with --no-recursion, so tar walks nothing and decides nothing: it writes exactly the list it is given, under exactly the names PharData would have used. That is what keeps archives written by either engine interchangeable.

The list travels on standard input, NUL-separated. Passed as arguments it would break on any real site — a stock WordPress install is sixteen thousand paths, far past ARG_MAX — and NUL separation is the only form that survives newlines and quotes in filenames.

Parameters
$binary : string

The tar to run.

$entries : array<int, array{base: string, name: string, directory: bool, path: string}>

What to archive.

$finalPath : string

Where the archive goes.

$compression : string

A CompressionType value.

Tags
throws
RuntimeException

If tar cannot be started, or refuses the archive.

author

Marc Alcaraz (ekameleon)

since
1.3.0

tarCompressionFlag()

Whether the system tar can produce this compression, and with which flag.

tarCompressionFlag(string $compression) : string|null
Parameters
$compression : string

A CompressionType value.

Tags
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
string|null

The flag, null for an uncompressed archive.

tarCompressorExists()

Whether the compressor `tar` would shell out to is installed.

tarCompressorExists(string $compression) : bool

tar does not compress: it pipes through gzip, bzip2, xz. PharData does it in PHP, through the bundled extensions — so a machine with ext-bz2 and no bzip2 program used to produce a bzip2 archive and would stop. Asked before the engine is chosen, so that host keeps the engine that works for it instead of receiving an error where it had a file.

Parameters
$compression : string

A CompressionType value.

Tags
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
bool

True when nothing external is needed, or when what is needed is there.

tarBinaryHandles()

Whether the binary engine can take this archive on.

tarBinaryHandles(array<int, array{base: string, name: string, directory: bool, path: string}> $entries, string $compression) : bool

It takes the ones it can reproduce exactly, and leaves the rest to PharData — decided before anything is written, never after something has failed.

Archiving several paths that do not share a parent needs one tar invocation per parent, and an archive cannot be appended to once compressed. That case is rare — it means passing unrelated paths with no preserveRoot — and PharData already handles it correctly, so it stays there rather than justifying a second, less-travelled code path.

Parameters
$entries : array<int, array{base: string, name: string, directory: bool, path: string}>
$compression : string
Tags
author

Marc Alcaraz (ekameleon)

since
1.3.0
Return values
bool

untar()

Extracts a tar archive file into a specified output directory.

untar(string $tarFile, string $outputPath[, array{dryRun?: bool, keepPermissions?: bool, overwrite?: bool, maxExtractedSize?: int|null} $options = [] ]) : true|array<string|int, string>

This function supports regular and compressed tar files (.tar, .tar.gz, .tar.bz2). It can perform a dry run to preview extracted files, optionally preserve file permissions, and control overwriting of existing files.

Parameters
$tarFile : string

Path to the tar archive file to extract.

$outputPath : string

Path to the directory where files will be extracted. The directory will be created if it does not exist.

$options : array{dryRun?: bool, keepPermissions?: bool, overwrite?: bool, maxExtractedSize?: int|null} = []

Optional flags:

  • dryRun: If true, the function does not extract files but returns the list of files that would be extracted. Default: false.
  • keepPermissions: If true, preserves the original file permissions from the archive. Default: false.
  • overwrite: If false, prevents overwriting existing files during extraction. Extraction will fail if a file already exists. Default: true.
  • maxExtractedSize: If set to a positive integer, defines the maximum total uncompressed size (in bytes) accepted during extraction. The archive is pre-scanned and a RuntimeException is thrown before any file is written if the sum of the entries' uncompressed sizes exceeds this limit. Guards against decompression-bomb attacks. Default: null (no limit).
Tags
throws
FileException

If the provided tar file is invalid or inaccessible.

DirectoryException

If the output directory cannot be created or is not writable.

RuntimeException

For extraction errors such as:

  • Path traversal attempts detected inside archive entries.
  • Attempt to overwrite existing files when overwrite is disabled.
  • Total uncompressed size exceeds maxExtractedSize (decompression-bomb protection).
  • Other errors during decompression or extraction.
Exception

Propagates unexpected exceptions during extraction wrapped as RuntimeException.

example
// Basic extraction
untar( '/path/to/archive.tar' , '/output/dir' );

// Extraction with options
untar( '/path/to/archive.tar.gz' , '/output/dir' , [
'overwrite'        => false,
'keepPermissions'  => true
]);

// Dry-run: preview contents without extracting
$files = untar( '/path/to/archive.tar' , '/output/dir' , [ 'dryRun' => true ] );
print_r( $files );

// Prevent overwriting, will throw RuntimeException if file exists
untar( '/path/to/archive.tar' , '/output/dir' , [ 'overwrite' => false ] );
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
true|array<string|int, string>

Returns true on successful extraction, or an array of file paths (relative to archive root) if dryRun is enabled.

validateTarStructure()

Validates the internal structure of a tar file.

validateTarStructure(string $filePath) : bool

This function checks whether the given file is a valid, readable tar archive. It uses the PharData class to attempt parsing the archive and iterates over a few entries to confirm structural integrity.

Note: Compressed tar files (e.g., .tar.gz, .tar.bz2) are not supported directly. Decompress them before using this function.

Parameters
$filePath : string

Path to the tar file.

Tags
example
var_dump( validateTarStructure( '/path/to/archive.tar'     ) ); // true or false
var_dump( validateTarStructure( '/path/to/invalid.tar'     ) ); // false
var_dump( validateTarStructure( '/path/to/archive.tar.gz'  ) ); // false (must decompress first)
var_dump( validateTarStructure( '/path/to/not_a_tar.txt'   ) ); // false
var_dump( validateTarStructure( '/nonexistent/file.tar'    ) ); // false
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

True if the file has a valid tar structure, false otherwise.

On this page

Search results