Oihana PHP

zip

Table of Contents

Functions

assertZip()  : bool
Validates that a file is a zip archive.
hasZipExtension()  : bool
Checks if a file has a zip-related extension.
hasZipMimeType()  : bool
Checks if a file has a zip-related MIME type.
unzip()  : true|array<string|int, string>
Extracts a zip archive into a destination directory.
validateZipStructure()  : bool
Validates the internal structure of a zip file.
zip()  : string
Creates a zip archive from one or more files and/or directories.
zipDirectory()  : string
Creates a zip archive from a directory.
zipFileInfo()  : array{isValid?: bool, extension?: string, mimeType?: string|null, compression?: string|null, fileCount?: int|null, totalSize?: int|null}
Retrieves detailed information about a zip archive file.

Functions

assertZip()

Validates that a file is a zip archive.

assertZip(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 (see validateZipStructure()). If false, only checks the extension and the basic MIME type.

Tags
throws
FileException

If the file does not exist or cannot be read.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example

Basic validation using file extension and MIME type:

$isValid = assertZip('/path/to/archive.zip');

Strict validation with file content inspection:

$isValid = assertZip('/path/to/archive.zip', true);
Return values
bool —

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

hasZipExtension()

Checks if a file has a zip-related extension.

hasZipExtension(string $filePath[, array<string|int, string> $zipExtensions = [FileExtension::ZIP] ]) : bool
Parameters
$filePath : string

Path to the file.

$zipExtensions : array<string|int, string> = [FileExtension::ZIP]

Optional list of valid zip-related extensions. Defaults to the single .zip extension.

Tags
author

Marc Alcaraz (ekameleon)

since
1.2.0
example

Check a simple zip file:

var_dump( hasZipExtension('/path/to/archive.zip') ); // bool(true)

Check is case-insensitive:

var_dump( hasZipExtension('/path/to/ARCHIVE.ZIP') ); // bool(true)

Check a file with an unsupported extension:

var_dump( hasZipExtension('/path/to/archive.tar') ); // bool(false)
Return values
bool —

True if the file has a recognized zip extension.

hasZipMimeType()

Checks if a file has a zip-related MIME type.

hasZipMimeType(string $filePath[, array<string|int, string> $mimeTypes = ['application/zip', 'application/x-zip', 'application/x-zip-compressed', 'application/zip-compressed', 'multipart/x-zip'] ]) : bool

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

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

Parameters
$filePath : string

Path to the file.

$mimeTypes : array<string|int, string> = ['application/zip', 'application/x-zip', 'application/x-zip-compressed', 'application/zip-compressed', 'multipart/x-zip']

Optional list of valid zip MIME types. Defaults to common zip types:

  • 'application/zip'
  • 'application/x-zip'
  • 'application/x-zip-compressed'
  • 'application/zip-compressed'
  • 'multipart/x-zip'
Tags
author

Marc Alcaraz (ekameleon)

since
1.2.0
example

Check if a .zip file is a zip archive:

$result = hasZipMimeType('/path/to/archive.zip');
var_dump($result); // bool(true) or bool(false)

Check a non-existent file (returns false):

$result = hasZipMimeType('/path/to/missing.zip');
var_dump($result); // bool(false)
Return values
bool —

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

unzip()

Extracts a zip archive into a destination directory.

unzip(string $zipFile, string $outputPath[, array{dryRun?: bool, overwrite?: bool, maxEntries?: int|null, maxSize?: int|null, keepPermissions?: bool, allowUnsafeLinks?: bool} $options = [] ]) : true|array<string|int, string>

This function mirrors untar(). It guards against path traversal (Zip Slip) and decompression bombs, can preview the contents without writing anything (dry run), and can refuse to overwrite existing files.

Symbolic links are restored as links. An entry whose stored Unix mode carries the link type bits — what zip() writes for every link it meets — is recreated with symlink() and its content read as the target. Such a target is refused when it is absolute or when it escapes the destination directory, since a link is the one entry whose content is itself a path and the Zip Slip guard on entry names does not cover it. The allowUnsafeLinks option lifts that refusal for an archive the caller answers for — a backup of a tree whose links were absolute on the disk it was taken from, which zip() stores faithfully and which could otherwise not be restored.

Parameters
$zipFile : string

Path to the zip archive to extract.

$outputPath : string

Directory where the archive is extracted. Created if missing.

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

Optional flags, keyed by ZipOption:

  • dryRun: If true, no file is written; returns the list of file entries that would be extracted (directory entries excluded). Default: false.
  • overwrite: If false, extraction fails when a target file already exists. Default: true.
  • maxEntries: If a positive integer, the archive is rejected when it declares more entries than this limit (decompression-bomb guard). Default: null (no limit).
  • maxSize: If a positive integer, the archive is pre-scanned and rejected before any file is written when the sum of the entries' uncompressed sizes exceeds this limit (decompression-bomb guard). Default: null (no limit).
  • allowUnsafeLinks: If true, recreates a symbolic link whose target is absolute or escapes the destination directory, which is refused by default. Only for an archive the caller answers for: once such a link stands in the destination, the entries written after it can reach through it, outside. Default: false.
  • keepPermissions: If true, restores the Unix file mode stored in each entry's external attributes (OPSYS_UNIX) via chmod(). Entries without Unix permissions are left with the default mode, and a symbolic link is left alone, since chmod() would follow it and change the permissions of its target. Best-effort: a failing chmod() is ignored. Default: false.
Tags
throws
FileException

If the archive does not exist, cannot be opened, an entry escapes the destination (Zip Slip), an entry is a symbolic link whose target is absolute or escapes the destination while allowUnsafeLinks is off, an entry is a symbolic link without a target, a link cannot be created, a bomb guard trips, a target already exists while overwrite is disabled, an entry cannot be read or does not match its recorded checksum, or an extracted file cannot be written.

DirectoryException

If the destination directory (or an entry's parent) cannot be created.

example
// Basic extraction
unzip( '/path/to/archive.zip' , '/output/dir' );

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

// Refuse to overwrite, and guard against decompression bombs
unzip( '/path/to/archive.zip' , '/output/dir' , [
    'overwrite'  => false,
    'maxEntries' => 10_000,
    'maxSize'    => 500 * 1024 * 1024,
]);
author

Marc Alcaraz (ekameleon)

since
1.2.0
Return values
true|array<string|int, string> —

Returns true on successful extraction, or the list of file entries (relative to the archive root) when dryRun is enabled.

validateZipStructure()

Validates the internal structure of a zip file.

validateZipStructure(string $filePath) : bool

This function checks whether the given file is a valid, readable zip archive. It uses the ZipArchive class to attempt opening the archive and inspects a few entries to confirm structural integrity.

Parameters
$filePath : string

Path to the zip file.

Tags
author

Marc Alcaraz (ekameleon)

since
1.2.0
example
var_dump( validateZipStructure( '/path/to/archive.zip'  ) ); // true or false
var_dump( validateZipStructure( '/path/to/invalid.zip'  ) ); // false
var_dump( validateZipStructure( '/path/to/not_a_zip.txt') ); // false
var_dump( validateZipStructure( '/nonexistent/file.zip' ) ); // false
Return values
bool —

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

zip()

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

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

This function supports adding multiple paths (files or directories) to a zip archive, with a per-entry compression method. 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.

Symbolic links met inside a directory are stored as links, with the target they were written with, and never read: the archive holds the link, not a copy of what it points at, and nothing outside the archived tree is read. unzip() reads them back as links. A path passed directly in $paths is resolved instead, as it always was, so archiving a link on its own archives what it points at.

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

Per-entry compression method. Supported values are CompressionType::ZIP (DEFLATE, the default) and CompressionType::NONE (stored, no compression).

$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 if the archive file cannot be created.

UnsupportedCompressionException

If the requested compression method is not supported for zip archives.

DirectoryException

If the temporary directory cannot be created or accessed.

RuntimeException

If no files are added to the archive.

see
CompressionType
example

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

$zipPath = zip('/var/www/html/index.php');

Archive a directory without compression (stored):

$zipPath = zip('/var/www/html', '/tmp/site.zip', CompressionType::NONE);

Archive multiple files:

$zipPath = zip(['/etc/hosts', '/etc/hostname'], '/tmp/config.zip');

Archive directory with root preserved (relative paths):

$zipPath = zip('/var/www/html/project', '/tmp/project.zip', CompressionType::ZIP, '/var/www/html/project');
author

Marc Alcaraz (ekameleon)

since
1.2.0
Return values
string —

Returns the full path to the created zip archive file.

zipDirectory()

Creates a zip archive from a directory.

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

This function creates a zip 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 (preserving its root). Otherwise, it copies the filtered files to a temporary directory and archives from there.

Parameters
$directory : string

The source directory to archive.

$compression : string|null = CompressionType::ZIP

Per-entry compression method (CompressionType::ZIP — DEFLATE, default — or CompressionType::NONE — stored).

$outputPath : string|null = null

Optional output archive path. If null, defaults to the directory name plus the .zip extension.

$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 method is specified.

RuntimeException

If no files match the filtering criteria.

example
// Create a zip archive from directory /var/www/html
$archive = zipDirectory('/var/www/html');
echo $archive; // /var/www/html.zip

// Create a stored (uncompressed) archive, excluding .git and node_modules
$archive = zipDirectory(
    '/var/www/html',
    CompressionType::NONE,
    null,
    [ ZipOption::EXCLUDE => ['.git', 'node_modules'] ]
);

// Create an archive with a custom filter callback and embedded metadata
$archive = zipDirectory(
    '/var/www/html',
    CompressionType::ZIP,
    '/backups/html_backup.zip',
    [
        ZipOption::FILTER   => fn( string $filePath ): bool => str_ends_with( $filePath , '.php' ),
        ZipOption::METADATA => [ 'createdBy' => 'admin' , 'description' => 'PHP source backup' ],
    ]
);
author

Marc Alcaraz (ekameleon)

since
1.2.0
Return values
string —

Returns the full path to the created archive file.

zipFileInfo()

Retrieves detailed information about a zip archive file.

zipFileInfo(string $filePath[, bool $strictMode = false ]) : array{isValid?: bool, extension?: string, mimeType?: string|null, compression?: string|null, fileCount?: int|null, totalSize?: int|null}

This function inspects the given zip file to determine its validity, MIME type, compression family, number of contained entries, and total uncompressed size.

It uses the ZipArchive class to count entries and sum their uncompressed sizes when the archive is valid.

Parameters
$filePath : string

Absolute path to the zip archive file to inspect.

$strictMode : bool = false

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

Tags
throws
FileException

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

see
assertZip()
author

Marc Alcaraz (ekameleon)

since
1.2.0
example
$info = zipFileInfo( '/archives/sample.zip' );
print_r( $info );

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

// Strict mode
$info = zipFileInfo( '/archives/sample.zip' , true );
Return values
array{isValid?: bool, extension?: string, mimeType?: string|null, compression?: string|null, fileCount?: int|null, totalSize?: int|null} —

Returns an associative array keyed by ZipInfo with:

  • isValid: Whether the file is a valid zip according to assertZip().
  • extension: File extension (lowercase) extracted from the path.
  • mimeType: MIME type detected via finfo.
  • compression: CompressionType::ZIP when the MIME type is zip-like, otherwise CompressionType::NONE.
  • fileCount: Number of entries inside the archive (if valid), otherwise null.
  • totalSize: Sum of the uncompressed sizes (in bytes) of all entries (if valid), otherwise null.
On this page

Search results