Oihana PHP

files

Table of Contents

Namespaces

archive
enums
exceptions
openssl
options
path
phar
toml

Functions

assertDirectory()  : void
Asserts that a directory exists and is accessible, optionally checking readability and writability.
assertFile()  : void
Asserts that a file exists and meets specified accessibility and MIME type requirements.
assertWritableDirectory()  : void
Asserts that a directory exists and is readable and writable.
bunzip2File()  : string
Decompresses a single bzip2 file, streaming it in chunks.
bzip2File()  : string
Compresses a single file with bzip2, streaming it in chunks.
clearFile()  : bool
Clears the content of a file while keeping the file itself.
copyFile()  : bool
Copies a single file to a destination path.
copyFilteredFiles()  : bool
Recursively copies files and directories from a source to a destination with filtering.
copyFilteredFilesWithMetadata()  : void
Copies the filtered files of a directory into a destination directory and, optionally, embeds a `.metadata.json` file describing the archive.
countFileLines()  : int
Counts the number of lines in a file.
createSymlink()  : bool
Creates a symbolic link pointing to a target.
deleteDirectory()  : bool
Deletes a directory recursively.
deleteFile()  : bool
Deletes a file from the filesystem.
deleteTemporaryDirectory()  : bool
Deletes a directory located in the system temporary folder (recursively).
fileChecksum()  : string
Computes the checksum (hash) of a file's contents.
filesAreEqual()  : bool
Tells whether two files have identical contents.
findFiles()  : array<string|int, SplFileInfo>
Lists files in a directory with advanced filtering, sorting, and recursive options.
formatFileSize()  : string
Formats a byte count as a human-readable string.
getBaseFileName()  : string
Returns the base file name without its extension from a given file path.
getDirectory()  : string
Normalises (and optionally validates) a directory path.
getDiskUsage()  : float
Returns the number of used bytes on the filesystem hosting a directory.
getFileContent()  : string
Reads the entire contents of a file into a string.
getFileExtension()  : string|null
Retrieves the file extension (including multipart extensions) from a given file path.
getFileLines()  : array<string|int, mixed>|null
Retrieves all lines from a file as an array, optionally transforming each line with a callback.
getFileLinesGenerator()  : Generator
Reads a file line by line and yields each line as a generator.
getFileSize()  : int
Returns the size of a file, in bytes.
getFreeDiskSpace()  : float
Returns the number of free bytes on the filesystem hosting a directory.
getHomeDirectory()  : string
Returns the current user’s home directory as a **canonical** path.
getMimeType()  : string|null
Detects the MIME type of a file using the `finfo` extension.
getOwnershipInfos()  : OwnershipInfos
Retrieves the current ownership information of a given file or directory.
getRoot()  : string
Extracts the root directory component of a given path.
getSchemeAndHierarchy()  : array{0: ?string, 1: string}
Split a filename or URI into its scheme (if any) and hierarchical part.
getTemporaryDirectory()  : string
Builds a path inside the system temporary directory.
getTimestampedDirectory()  : string
Get a timestamped file path using a formatted date and optional prefix/suffix.
getTimestampedFile()  : string|null
Get a timestamped file path using a formatted date and optional prefix/suffix.
getTotalDiskSpace()  : float
Returns the total size, in bytes, of the filesystem hosting a directory.
gunzipFile()  : string
Decompresses a single gzip file, streaming it in chunks.
gzipFile()  : string
Compresses a single file with gzip (DEFLATE), streaming it in chunks.
hasDirectories()  : bool
Checks if a directory contains at least one subdirectory, or only subdirectories if strict mode is enabled.
hasFiles()  : bool
Checks if a directory contains at least one file, or only files if strict mode is enabled.
hasMimeType()  : bool
Checks whether a file's MIME type matches one of the given MIME types.
isLinux()  : bool
Indicates if the OS system is Linux.
isMac()  : bool
Indicates if the OS system is Mac.
isOtherOS()  : bool
Indicates if the OS system is not Windows, Mac or Linux.
isSymlink()  : bool
Tells whether a path is a symbolic link.
isWindows()  : bool
Indicates if the OS system is Windows.
makeDirectory()  : string|null
Creates a directory if it does not exist and returns the path of the directory.
makeFile()  : string
Creates or updates a file with the given content and options.
makeTemporaryDirectory()  : string
Creates (or returns if already present) a directory inside the system temporary folder.
makeTimestampedDirectory()  : string|null
Creates a directory named with a formatted timestamp.
makeTimestampedFile()  : string|null
Generates a timestamped file path if not exist. Using a formatted date and optional prefix/suffix.
moveFile()  : bool
Moves (or renames) a single file to a destination path.
readSymlink()  : string
Returns the target a symbolic link points to.
recursiveFilePaths()  : array<string|int, mixed>
Recursively retrieves all .php files in a folder (and its subfolders).
renameFile()  : bool
Renames a single file.
requireAndMergeArrays()  : array<string|int, mixed>
Requires multiple PHP files (each returning an array) and merges the results.
shouldExcludeFile()  : bool
Checks if a file path should be excluded based on an array of patterns.
sortFiles()  : void
Sorts an array of SplFileInfo objects.
touchFile()  : string
Creates a file if it does not exist, or updates its modification and access times.
validateMimeType()  : void
Validate the MIME type of a file against a list of allowed types.
writeFileAtomic()  : string
Writes content to a file **atomically**.

Functions

assertDirectory()

Asserts that a directory exists and is accessible, optionally checking readability and writability.

assertDirectory(string|null $path[, bool $isReadable = true ][, bool $isWritable = false ][, int|null $expectedPermissions = null ]) : void
Parameters
$path : string|null

The path of the directory to check.

$isReadable : bool = true

Whether to assert that the directory is readable. Default: true.

$isWritable : bool = false

Whether to assert that the directory is writable. Default: false.

$expectedPermissions : int|null = null

Optional permission mask (e.g., 0755).

Tags
throws
DirectoryException

If the path is null, empty, not a directory, or fails accessibility checks.

example
try
{
    $directoryPath = '/chemin/vers/le/repertoire' ;

    assertDirectory( $directoryPath , true , true , 0755 ) ;

    echo "The directory is accessible with the good permissions.\n";
}
catch ( DirectoryException $e )
{
    echo "Error: " . $e->getMessage() . PHP_EOL ;
}
author

Marc Alcaraz (ekameleon)

since
1.0.0

assertFile()

Asserts that a file exists and meets specified accessibility and MIME type requirements.

assertFile(string|null $file[, array<string|int, mixed>|null $expectedMimeTypes = null ][, bool $isReadable = true ][, bool $isWritable = false ]) : void

This function performs a series of checks on a given file:

  1. Ensures the file path is not null or empty.
  2. Confirms that the path points to a valid file.
  3. Optionally checks if the file is readable.
  4. Optionally checks if the file is writable.
  5. Optionally validates the file's MIME type against a provided list.
Parameters
$file : string|null

The path of the file to check. Cannot be null or empty.

$expectedMimeTypes : array<string|int, mixed>|null = null

Optional array of allowed MIME types. If provided, the file's MIME type must match one of these.

$isReadable : bool = true

Whether to assert that the file is readable. Default: true.

$isWritable : bool = false

Whether to assert that the file is writable. Default: false.

Tags
throws
FileException

If the file path is null, empty, or if the file does not exist or is not accessible.

example

Basic usage: check if a file exists and is readable.

$file = 'test.txt';
file_put_contents($file, 'data');
try
{
   assertFile($file);
    // Continue ...
}
catch (FileException $e)
{
    // Handle error...
}
unlink($file);

Check for specific MIME types.

$file = 'document.txt';
file_put_contents($file, 'some text');
try
{
     // Will pass because a .txt file is typically 'text/plain'.
     assertFile( $file , ['text/plain', 'application/pdf'] );
}
catch ( FileException $e )
{
    // Throws an exception if MIME type is not in the allowed list.
}
unlink($file);

Check if a file is writable.

$file = 'config.ini';
file_put_contents($file, '[settings]');
try
{
    // Asserts the file exists, is readable, and is writable.
    assertFile($file, null, true, true);
}
catch (FileException $e)
{
    // Throws an exception if file is not writable.
}
unlink($file);
author

Marc Alcaraz (ekameleon)

since
1.0.0

assertWritableDirectory()

Asserts that a directory exists and is readable and writable.

assertWritableDirectory(string|null $directory) : void
Parameters
$directory : string|null

The path of the directory to check.

Tags
throws
DirectoryException

If the directory path is null, empty, or if the directory does not exist or is not accessible.

example

Success case: Check a writable directory. The system's temporary directory is a good candidate.

$tempDir = sys_get_temp_dir();
try
{
    assertWritableDirectory($tempDir);
   // Script continues if the directory is indeed writable.
   echo "Directory $tempDir is writable.";
}
catch (DirectoryException $e)
{
    // Handle the error if the directory is not accessible.
}

Failure case: The directory does not exist.

$fakeDir = '/a/path/that/does/not/exist';
try
{
    assertWritableDirectory($fakeDir);
}
catch (DirectoryException $e)
{
     // An exception is thrown because the directory is not valid.
     echo "Caught expected exception: " . $e->getMessage();
}
author

Marc Alcaraz (ekameleon)

since
1.0.0

bunzip2File()

Decompresses a single bzip2 file, streaming it in chunks.

bunzip2File(string $source[, string|null $destination = null ][, bool $overwrite = true ]) : string

Counterpart of bzip2File(), using the bz2 extension — no subprocess, and the file is never fully loaded into memory.

Parameters
$source : string

Path to the bzip2 file to decompress.

$destination : string|null = null

Output path. Defaults to $source without its .bz2 suffix, or $source + .out when the source has no .bz2 suffix.

$overwrite : bool = true

Whether to overwrite an existing destination (default: true).

Tags
throws
FileException

If the source is invalid, bz2 is unavailable, the destination exists and $overwrite is false, or decompression fails.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\bunzip2File;

bunzip2File( '/data/dump.sql.bz2' ) ; // -> /data/dump.sql
Return values
string

The destination path.

bzip2File()

Compresses a single file with bzip2, streaming it in chunks.

bzip2File(string $source[, string|null $destination = null ][, bool $overwrite = true ]) : string

Standalone bzip2 compression outside of tar archives, using the bz2 extension — no subprocess, and the file is never fully loaded into memory.

Unlike gzipFile(), no compression level is exposed: bzopen() does not accept one in streaming mode.

Parameters
$source : string

Path to the file to compress.

$destination : string|null = null

Output path. Defaults to $source + .bz2.

$overwrite : bool = true

Whether to overwrite an existing destination (default: true).

Tags
throws
FileException

If the source is invalid, bz2 is unavailable, the destination exists and $overwrite is false, or compression fails.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\bzip2File;

bzip2File( '/data/dump.sql' ) ; // -> /data/dump.sql.bz2
Return values
string

The destination path.

clearFile()

Clears the content of a file while keeping the file itself.

clearFile(string|null $file[, bool $assertable = true ]) : bool

This function empties the given file. Returns true if the file was successfully cleared, false otherwise.

The behavior on failure depends on the $assertable parameter:

  • If $assertable is true (default), a FileException is thrown if the file does not exist or is not writable.
  • If $assertable is false, no exception is thrown; the function simply returns false on failure.
Parameters
$file : string|null

The full path to the file to clear.

$assertable : bool = true

Whether to throw exceptions on failure (default: true).

Tags
throws
FileException

If $assertable is true and the file does not exist or is not writable.

example
use function oihana\files\clearFile;

$file = '/path/to/file.txt';

// Clear the file, throwing exception on failure
$success = clearFile($file);

// Clear the file, returning false instead of throwing an exception
$success = clearFile($file, assertable: false);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

True if the file was cleared successfully, false otherwise.

copyFile()

Copies a single file to a destination path.

copyFile(string $source, string $destination[, bool $overwrite = true ][, bool $createDirectory = true ]) : bool

Unlike copyFilteredFiles() (which mirrors a whole directory tree), this helper copies one file with explicit, typed error handling:

  • the source is validated with assertFile() (must exist and be readable);
  • if $destination is an existing directory, the file is copied inside it, keeping the source basename (the cp source dir/ convention);
  • copying a file onto itself is refused (it would truncate the source);
  • when $overwrite is false, an existing destination raises a FileException;
  • the destination's parent directory is created on demand when $createDirectory is true.
Parameters
$source : string

Path to the source file to copy.

$destination : string

Destination file path, or an existing directory to copy into.

$overwrite : bool = true

Whether to overwrite an existing destination file (default: true).

$createDirectory : bool = true

Whether to create the destination directory if missing (default: true).

Tags
throws
FileException

If the source is invalid, source and destination are the same file, the destination exists and $overwrite is false, or the copy fails.

DirectoryException

If the destination directory is missing and $createDirectory is false, or cannot be created.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\copyFile;

copyFile( '/data/report.pdf' , '/backup/report.pdf' ) ;          // explicit target
copyFile( '/data/report.pdf' , '/backup' ) ;                     // into a directory
copyFile( '/data/report.pdf' , '/backup/report.pdf' , false ) ;  // throws if it already exists
Return values
bool

Returns true on success.

copyFilteredFiles()

Recursively copies files and directories from a source to a destination with filtering.

copyFilteredFiles(string $sourceDir, string $destDir[, array<string|int, string> $excludePatterns = [] ][, callable|null $filterCallback = null ]) : bool

This function iterates through a source directory and copies its contents to a destination directory, preserving the folder structure. It provides two methods for filtering which files and directories get copied:

  1. $excludePatterns: An array of glob/regex patterns. Any file or directory matching a pattern in this array will be skipped. See shouldExcludeFile().
  2. $filterCallback: An optional user-defined function. This callback receives the full path of each item and must return true for the item to be copied.

Destination directories are created as needed.

Parameters
$sourceDir : string

The path to the source directory to copy from.

$destDir : string

The path to the destination directory.

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

An array of patterns to exclude from the copy.

$filterCallback : callable|null = null

Optional callback for custom filtering. It receives the file path and should return true to include it.

Tags
throws
DirectoryException

If a directory cannot be created in the destination path.

security

$excludePatterns is forwarded to shouldExcludeFile() which uses fnmatch() (glob) or preg_match() (regex). Patterns must come from a trusted source — a malicious regex can cause CPU exhaustion (ReDoS) since PHP's regex engine has no execution timeout. See the security guide.

example

Source directory structure:

/tmp/source/
├── .git/
│   └── config
├── images/
│   └── logo.png  (size: 5KB)
├── index.php     (size: 1KB)
└── error.log
$source = '/tmp/source';
$destination = '/tmp/destination';

// Exclude .git directories and all .log files.
$exclude = ['.git', '*.log'];

// Only include files smaller than 2KB (2048 bytes).
$filter = function(string $filePath)
{
   return is_dir($filePath) || filesize($filePath) < 2048;
};

copyFilteredFiles($source, $destination, $exclude, $filter);

Resulting destination directory:

/tmp/destination/
├── images/
└── index.php

Explanation:

  • .git/ was skipped by the exclude pattern.
  • error.log was skipped by the exclude pattern.
  • images/logo.png was skipped by the filter callback (size > 2KB).
  • index.php was copied as it passed both filters.
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

Returns true if at least one file or directory was copied, false otherwise.

copyFilteredFilesWithMetadata()

Copies the filtered files of a directory into a destination directory and, optionally, embeds a `.metadata.json` file describing the archive.

copyFilteredFilesWithMetadata(string $sourceDir, string $destDir[, array<string|int, string> $excludePatterns = [] ][, callable|null $filterCallback = null ][, array<string, mixed> $metadata = [] ]) : void

This is the staging step shared by the directory-archiving helpers (tarDirectory() and zipDirectory()): it delegates the copy to copyFilteredFiles(), writes the metadata when provided, and guarantees the destination is non-empty.

Embedding metadata always makes the destination non-empty, even when no source file matched the filters (the archive then contains only .metadata.json).

Parameters
$sourceDir : string

The source directory to copy from.

$destDir : string

The destination (staging) directory to copy into.

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

Glob patterns or file names to exclude.

$filterCallback : callable|null = null

Optional function (string $filepath): bool returning true to include the item.

$metadata : array<string, mixed> = []

Optional metadata embedded as .metadata.json.

Tags
throws
DirectoryException
author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\copyFilteredFilesWithMetadata;

copyFilteredFilesWithMetadata(
    '/var/www/html',
    '/tmp/staging',
    ['.git', 'node_modules'],
    fn( string $path ): bool => str_ends_with( $path , '.php' ),
    [ 'createdBy' => 'admin' ]
);

countFileLines()

Counts the number of lines in a file.

countFileLines(string|null $file) : int

This function efficiently counts lines by reading the file in chunks, making it suitable even for very large files.

Example usage:

use function oihana\files\countFileLines;

$count = countFileLines('/path/to/file.log');
Parameters
$file : string|null

The full path to the file.

Tags
throws
FileException

If the file does not exist, is not readable, or cannot be opened.

author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
int

The total number of lines in the file.

Creates a symbolic link pointing to a target.

createSymlink(string $target, string $link[, bool $overwrite = false ]) : bool

The target is not required to exist — dangling symlinks are valid and supported (standard POSIX behaviour). When an entry already exists at $link, it is replaced only if $overwrite is true.

Parameters
$target : string

The path the symlink points to.

$link : string

The symlink path to create.

$overwrite : bool = false

Whether to replace an existing file/symlink at $link (default: false).

throws
FileException

If an entry already exists at $link and $overwrite is false, or if the symlink cannot be created.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\createSymlink;

createSymlink( '/var/www/releases/42' , '/var/www/current' , overwrite: true ) ;
Return values
bool

Returns true on success.

deleteDirectory()

Deletes a directory recursively.

deleteDirectory(string|array<string|int, mixed>|null $path[, bool $assertable = true ][, bool $isReadable = true ][, bool $isWritable = true ]) : bool
Parameters
$path : string|array<string|int, mixed>|null

Directory or segments to remove.

$assertable : bool = true

Whether to validate the resulting path. Defaults to true.

$isReadable : bool = true

Check if the directory is readable (Default true).

$isWritable : bool = true

Check if the directory is writable (Default false).

Tags
throws
DirectoryException

If the directory path is null, empty, or if the directory cannot be deleted.

example

Create a temporary directory structure and then delete it.

$baseDir = sys_get_temp_dir() . '/temp_dir_to_delete';
$subDir = $baseDir . '/nested_dir';
mkdir($subDir, 0777, true); // Create nested directories
file_put_contents($baseDir . '/file.txt', 'content');

try
{
    if ( deleteDirectory( $baseDir ) )
    {
          // The directory and all its contents are now removed.
          // is_dir($baseDir) will return false.
    }
}
catch (DirectoryException $e)
{
    // Handle potential permission errors or other issues.
    echo "Error: " . $e->getMessage();
}

Using an array to specify the path to delete.

$parentDir = sys_get_temp_dir();
$dirName = 'another_temp_dir';
mkdir($parentDir . '/' . $dirName);
try
{
    // The path will be resolved to '/path/to/temp/another_temp_dir' and deleted.
    if (deleteDirectory([$parentDir, $dirName]))
    {
        // The directory is now removed.
    }
}
catch (DirectoryException $e)
{
    // Handle error.
}
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

Returns true if the directory is removed.

deleteFile()

Deletes a file from the filesystem.

deleteFile(string $filePath[, bool $assertable = true ][, bool $isReadable = true ][, bool $isWritable = true ]) : bool

This function optionally asserts that the file exists and meets the specified readability and writability requirements before attempting deletion. If the deletion fails, a FileException is thrown.

Parameters
$filePath : string

The path to the file to delete.

$assertable : bool = true

Whether to perform assertions on the file before deletion (default: true).

$isReadable : bool = true

Whether to assert that the file is readable (default: true).

$isWritable : bool = true

Whether to assert that the file is writable (default: true).

Tags
throws
FileException

If the file does not meet the assertions or cannot be deleted.

example
$file = 'example.txt';
file_put_contents($file, 'Sample content');

try
{
    deleteFile($file);
    echo "File deleted successfully.";
}
catch (FileException $e)
{
    echo "Error deleting file: " . $e->getMessage();
}
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

Returns true on successful deletion.

deleteTemporaryDirectory()

Deletes a directory located in the system temporary folder (recursively).

deleteTemporaryDirectory(string|array<string|int, string>|null $path[, bool $assertable = true ][, bool $isReadable = true ][, bool $isWritable = true ]) : bool

The given $path is appended to sys_get_temp_dir() in the same way as getTemporaryDirectory():

  • null → sys temp dir itself,
  • 'logs' → "/tmp/logs",
  • ['my', 'app'] → "/tmp/my/app".
Parameters
$path : string|array<string|int, string>|null

Optional sub‑path(s) inside sys_get_temp_dir().

$assertable : bool = true

Whether to validate the composed directory before deletion. Defaults to true.

$isReadable : bool = true

Check readability (passed to assertDirectory()). Defaults to true.

$isWritable : bool = true

Check writability (passed to assertDirectory()). Defaults to true.

Tags
throws
DirectoryException

If validation/deletion fails.

example
use function oihana\files\deleteTemporaryDirectory;

// Remove /tmp/old_reports (et son contenu)
deleteTemporaryDirectory('old_reports');

// Remove /tmp/tmp123/cache/images
deleteTemporaryDirectory(['tmp123', 'cache', 'images']);

// Force failure if folder is not writable
deleteTemporaryDirectory('protected_dir', isWritable: true);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

True if the directory was deleted or did not exist.

fileChecksum()

Computes the checksum (hash) of a file's contents.

fileChecksum(string $file[, string $algorithm = 'sha256' ]) : string

Reads the file through hash_file(), so the whole file does not need to be loaded into memory. Useful for integrity checks, deduplication, and verifying extracted archives.

Parameters
$file : string

Path to the file to hash.

$algorithm : string = 'sha256'

A hashing algorithm supported by hash_algos() (default: 'sha256').

Tags
throws
FileException

If the file is missing or unreadable, the algorithm is unsupported, or the hash computation fails.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\fileChecksum;

$sha256 = fileChecksum( '/data/report.pdf' ) ;            // default sha256
$md5    = fileChecksum( '/data/report.pdf' , 'md5' ) ;    // explicit algorithm
Return values
string

The computed hash, lowercase hexadecimal.

filesAreEqual()

Tells whether two files have identical contents.

filesAreEqual(string $a, string $b[, string $algorithm = 'sha256' ]) : bool

The comparison is short-circuited for speed:

  1. if both paths resolve to the same file on disk, returns true without reading;
  2. if the file sizes differ, returns false without hashing;
  3. otherwise the files are compared by fileChecksum().
Parameters
$a : string

Path to the first file.

$b : string

Path to the second file.

$algorithm : string = 'sha256'

A hashing algorithm supported by hash_algos() (default: 'sha256').

Tags
throws
FileException

If either file is missing or unreadable, or the algorithm is unsupported.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\filesAreEqual;

if ( filesAreEqual( '/data/a.bin' , '/backup/a.bin' ) )
{
    // contents match — safe to deduplicate
}
Return values
bool

true if both files have identical contents, false otherwise.

findFiles()

Lists files in a directory with advanced filtering, sorting, and recursive options.

findFiles(string|null $directory[, array{filter?: callable|null, followLinks?: bool|null, includeDots?: bool|null, mode?: string|null, order?: string|null, pattern?: string|array|null, recursive?: bool|null, sort?: callable|string|array|null} $options = [] ]) : array<string|int, SplFileInfo>

This function provides flexible options for retrieving files and directories from a given path. It supports recursive search, glob and regex pattern matching, sorting, symbolic link following, and custom filters.

Parameters
$directory : string|null

The target directory path. If null or invalid, a DirectoryException is thrown.

$options : array{filter?: callable|null, followLinks?: bool|null, includeDots?: bool|null, mode?: string|null, order?: string|null, pattern?: string|array|null, recursive?: bool|null, sort?: callable|string|array|null} = []

Optional settings to customize the file listing.

  • filter : A function to map or transform each SplFileInfo result.
  • followLinks : Whether to follow symbolic links (default: false).
  • includeDots : Whether to include dot files (default: false).
  • mode : Filter by type: 'files', 'dirs', or 'both' (default: 'files').
  • order : Sort order: 'asc' (default) or 'desc'.
  • pattern : A glob pattern, regex, or list of patterns to match file names.
  • recursive : Whether to search recursively (default: false).
  • sort : A sort option, eg: callback, predefined string, or array of keys.
Tags
security

The pattern option is evaluated with fnmatch() (glob) or preg_match() (regex). PHP's regex engine has no execution timeout, so a maliciously crafted regex such as /^(a+)+$/ can cause catastrophic backtracking and effectively a CPU DoS. Patterns must come from a trusted source (configuration, internal code) — never from direct user input. See the security guide.

throws
DirectoryException
example
  1. Basic usage: list files in directory
use function oihana\files\findFiles;
use SplFileInfo;

$files = findFiles('/var/www');
  1. Recursive search
$files = findFiles('/var/www', [
'recursive' => true,
]);
  1. Include dotfiles
$files = findFiles('/var/www', [
'includeDots' => true,
]);
  1. Follow symbolic links (only affects recursive mode)
$files = findFiles('/var/www', [
'recursive'   => true,
'followLinks' => true,
]);
  1. Filter by file name pattern (glob or regex)
$files = findFiles('/var/www', [
'pattern' => '*.php',
]);
  1. Filter by multiple patterns (mixed glob + regex)
$files = findFiles('/var/www', [
'pattern' => ['*.php', '/^config\..+$/'],
]);
  1. List directories only
$dirs = findFiles('/var/www', [ 'mode' => 'dirs', ]);
  1. List both files and directories
$all = findFiles('/var/www', [ 'mode' => 'both' ]);
  1. Custom sort: by real path
$files = findFiles('/var/www', [
'sort' => fn(SplFileInfo $a, SplFileInfo $b) => strcmp($a->getRealPath(), $b->getRealPath()),
]);
  1. Predefined sort (e.g., name), descending order
$files = findFiles('/var/www', [
'sort'  => 'name',
'order' => 'desc',
]);
  1. Combined sort: type then name (directories first)
$files = findFiles('/var/www', [
'sort' => ['type', 'name'],
]);
  1. Map output to base names only
$names = findFiles('/var/www', [
'filter' => fn(SplFileInfo $file) => $file->getBasename(),
]);
  1. Get only file sizes
$sizes = findFiles('/var/www', [
'filter' => fn(SplFileInfo $file) => $file->getSize(),
]);
  1. List recursively with all options combined
$files = findFiles('/var/www',
[
    'recursive'    => true,
    'followLinks'  => true,
    'includeDots'  => true,
    'mode'         => 'files',
    'pattern'      => ['*.log', '*.txt'],
    'sort'         => 'ci_name',
    'order'        => 'asc',
    'filter'       => fn(SplFileInfo $file) => $file->getFilename(),
]);
see
sortFiles()
FindFindOption
FindMode
Order::asc
author

Marc Alcaraz (ekameleon)

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

formatFileSize()

Formats a byte count as a human-readable string.

formatFileSize(int $bytes[, int $precision = 2 ]) : string

Uses binary multiples (base 1024) with the FileSizeUnit symbols B, KB, MB, GB, TB, PB. Byte values are rendered without decimals; larger units use $precision decimals. Zero or negative values yield "0 B". Values beyond PB are clamped to PB.

Parameters
$bytes : int

The size in bytes (e.g. from getFileSize()).

$precision : int = 2

Number of decimals for non-byte units (default: 2).

Tags
author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\formatFileSize;

formatFileSize( 0 ) ;        // "0 B"
formatFileSize( 512 ) ;      // "512 B"
formatFileSize( 1536 ) ;     // "1.5 KB"
formatFileSize( 1240518 ) ;  // "1.18 MB"
Return values
string

A human-readable size, e.g. "1.18 MB".

getBaseFileName()

Returns the base file name without its extension from a given file path.

getBaseFileName(string $file[, array<string|int, mixed>|null $multiplePartExtensions = null ]) : string

This function extracts the file name from a full path and removes its extension. It supports both single and multi-part extensions (e.g. .tar.gz, .blade.php).

Parameters
$file : string

The full path to the file (e.g. '/path/to/archive.tar.gz').

$multiplePartExtensions : array<string|int, mixed>|null = null

Optional list of multi-part extensions to consider (e.g. ['.tar.gz', '.blade.php']). If null, the method defaults to FileExtension::getMultiplePartExtensions().

Tags
throws
InvalidArgumentException

If the file path is empty or invalid.

example
use function oihana\files\getBaseFileName;

// Basic example with simple extension
echo getBaseFileName('/path/to/image.png'); // 'image'

// With nested path and multi-part extension
echo getBaseFileName('/backups/2025-07-18.tar.gz'); // '2025-07-18'

// File with multiple dots, using default multi-part extensions
echo getBaseFileName('/views/template.blade.php'); // 'template'

// File with unknown multi-dot extension, fallback to last dot
echo getBaseFileName('/logs/system.debug.txt'); // 'system.debug'

// File without extension
echo getBaseFileName('/opt/bin/mybinary'); // 'mybinary'

// Windows-style path (backslashes will be normalized)
echo getBaseFileName('C:\\Users\\me\\file.tar.gz'); // 'file'

// Override default multi-part extensions
echo getBaseFileName('/path/to/file.custom.ext', ['.custom.ext']); // 'file'

// Edge case: dot file (no extension)
echo getBaseFileName('/path/.env'); // '.env'

// Throws exception: empty string
getBaseFileName('');

// Throws exception: path is a directory
getBaseFileName('/path/to/folder/');
see
FileExtension
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

The file name without its extension (e.g. 'archive' for 'archive.tar.gz').

getDirectory()

Normalises (and optionally validates) a directory path.

getDirectory(string|array<string|int, mixed>|null $path[, bool $assertable = true ][, bool $isReadable = true ][, bool $isWritable = false ]) : string
  • If $path is an array, empty segments and Char::EMPTY are removed, then the remaining parts are joined with DIRECTORY_SEPARATOR.
  • If $assertable is true (default), assertDirectory() ensures the resulting path exists and is readable.
  • Trailing separators are always stripped before return.
Parameters
$path : string|array<string|int, mixed>|null

Directory or segments to normalise.
Examples: '/tmp' or ['tmp','logs'].

$assertable : bool = true

Whether to validate the resulting path. Default: true.

$isReadable : bool = true

Whether to assert that the directory is readable. Default: true.

$isWritable : bool = false

Whether to assert that the directory is writable. Default: false.

Tags
throws
DirectoryException

If validation is enabled and the directory is invalid.

example

Basic use with a character string Validates that the system temporary directory exists and deletes the final separator.

$path = getDirectory( sys_get_temp_dir() . DIRECTORY_SEPARATOR );
// $path contient maintenant quelque chose comme '/tmp' ou 'C:\Users\...\Temp'.

Builds and validates a path from an array. Empty or null elements are ignored (assumes ‘/tmp/logs’ exists and is readable).

$parts = [sys_get_temp_dir(), '', 'logs', null];
$path = getDirectory($parts);
// $path contient maintenant quelque chose comme '/tmp/logs'.

Normalizes a path without validating it Ne lève pas d'exception si le chemin n'existe pas.

$path = getDirectory('/path/not/exist/', assertable: false);
// $path contains '/path/not/exist/'.

Validates that a directory is also writable.

try
{
    $path = getDirectory(sys_get_temp_dir(), isWritable: true);
    // The script continue if the directory is writable
}
catch ( DirectoryException $e )
{
    // Thrown an error
}
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

Normalized directory path.

getDiskUsage()

Returns the number of used bytes on the filesystem hosting a directory.

getDiskUsage([string $directory = '.' ]) : float

Computed as getTotalDiskSpace()getFreeDiskSpace(), so the result shares the same unit (bytes) as the two helpers it builds on. Pair it with formatFileSize() for a human-readable value, or divide by getTotalDiskSpace() for a usage ratio.

Parameters
$directory : string = '.'

A directory (or path) on the filesystem to inspect (default: '.').

Tags
throws
FileException

If the disk space cannot be determined (e.g. invalid path).

author

Marc Alcaraz (ekameleon)

since
1.2.0
see
getFreeDiskSpace()
getTotalDiskSpace()
example
use function oihana\files\{ getDiskUsage , formatFileSize };

echo formatFileSize( (int) getDiskUsage( '/' ) ) ; // e.g. "187.4 GB"
Return values
float

The number of used bytes.

getFileContent()

Reads the entire contents of a file into a string.

getFileContent(string|null $file[, int|null $maxBytes = null ]) : string

Symmetric counterpart of makeFile() (which writes a file): where getFileLines() reads a file line by line, this helper returns the whole content as a single string.

Parameters
$file : string|null

The full path to the file to read.

$maxBytes : int|null = null

Optional cap on the file size (in bytes). When set, the file is rejected before* being read if its size exceeds this value, throwing RuntimeException. Default null (no limit). Useful as a defensive guard against OOM when the caller does not fully trust the input size.

Tags
throws
FileException

If the file does not exist, is not readable, or cannot be read.

RuntimeException

If the file size exceeds $maxBytes.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\getFileContent;

$content = getFileContent( '/path/to/config.json' ) ;

// Refusing files larger than 10 MiB (defensive cap on untrusted sources).
$content = getFileContent( '/path/to/upload.bin' , 10 * 1024 * 1024 ) ;
Return values
string

The full file contents. An empty string for an empty file.

getFileExtension()

Retrieves the file extension (including multipart extensions) from a given file path.

getFileExtension(string $file[, array<string|int, mixed>|null $multiplePartExtensions = null ][, bool $lowercase = true ]) : string|null

This function extracts the file extension from the filename portion of the path, supporting both simple extensions (e.g. .txt) and multipart extensions (e.g. .tar.gz, .blade.php). It relies on the getBaseFileName() function to determine the filename without its extension, then returns the remainder as the extension.

The function normalizes Windows-style backslashes (\) to forward slashes (/) before processing.

Parameters
$file : string

The full path or filename from which to extract the extension.

$multiplePartExtensions : array<string|int, mixed>|null = null

Optional array of multipart extensions to consider. If null, the default set from FileExtension::getMultiplePartExtensions() is used.

$lowercase : bool = true

Enforce the extension to be lowercase (default true).

Tags
example

Basic usage: extract extension from a file path.

use function oihana\files\getFileExtension;

echo getFileExtension('/path/to/archive.tar.gz');    // .tar.gz
echo getFileExtension('photo.JPG');                  // .jpg (lowercased by default)
echo getFileExtension('/some/file.txt');             // .txt
echo getFileExtension('/templates/home.blade.php');  // .blade.php
echo getFileExtension('script.min.js');              // .js

Using custom multipart extensions:

$custom = ['.custom.ext', '.tpl.php'];

echo getFileExtension('file.custom.ext', $custom);   // .custom.ext
echo getFileExtension('file.tpl.php', $custom);      // .tpl.php

Preserving original case:

echo getFileExtension('README.MD', null, false);     // .MD

Files with no extension:

echo getFileExtension('Makefile');                   // null
echo getFileExtension('.env');                       // null

Windows-style path normalization:

echo getFileExtension('C:\\projects\\demo.tar.bz2'); // .tar.bz2

Edge case: file with multiple dots and unknown multipart extension:

echo getFileExtension('data.backup.final.bak');      // .bak
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string|null

The file extension including the leading dot (e.g. .tar.gz), or null if the file has no extension.

getFileLines()

Retrieves all lines from a file as an array, optionally transforming each line with a callback.

getFileLines(string|null $file[, callable|null $map = null ][, int|null $maxBytes = null ]) : array<string|int, mixed>|null

This function uses a generator internally (getFileLinesGenerator) to read the file line by line, which allows efficient processing of large files. Each line can optionally be mapped using the provided callable.

Example usage:

use function oihana\files\getFileLines;

$lines = getFileLines('/path/to/file.log');

// Using a mapping function to parse CSV lines
$csvLines = getFileLines('/path/to/data.csv', fn($line) => str_getcsv($line));

// Refusing files larger than 10 MiB (defensive cap on untrusted sources).
$lines = getFileLines('/path/to/upload.log', null, 10 * 1024 * 1024);
Parameters
$file : string|null

The full path to the file to read.

$map : callable|null = null

Optional mapping function applied to each line. Signature: fn(string $line): mixed

$maxBytes : int|null = null

Optional cap on the file size (in bytes). When set, getFileLines() rejects any file whose size exceeds this value before opening it, throwing RuntimeException. Default null (no limit — historical behaviour). Useful as a defensive guard against OOM when the caller does not fully trust the size of the input.

Tags
throws
FileException

If the file does not exist, is not readable, or cannot be opened.

RuntimeException

If the file size exceeds $maxBytes.

author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
array<string|int, mixed>|null

Returns an array of lines (or mapped values). Returns an empty array if the file is empty.

getFileLinesGenerator()

Reads a file line by line and yields each line as a generator.

getFileLinesGenerator(string|null $file[, callable|null $map = null ]) : Generator

Each line can optionally be transformed using a callback function. This is particularly useful for processing large files efficiently without loading the entire file into memory at once.

Example usage:

use function oihana\files\getFileLinesGenerator;

// Simply iterate over each line
foreach (getFileLinesGenerator('/path/to/file.log') as $line)
{
    echo $line, PHP_EOL;
}

// Using a mapping function to parse CSV lines
foreach (getFileLinesGenerator('/path/to/data.csv', fn($line) => str_getcsv($line)) as $csvRow)
{
    print_r($csvRow);
}
Parameters
$file : string|null

Full path to the file to read.

$map : callable|null = null

Optional mapping function applied to each line. Signature: fn(string $line): mixed

Tags
throws
FileException

If the file does not exist, is not readable, or cannot be opened.

author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
Generator

Yields each line of the file, optionally transformed by the mapping function.

getFileSize()

Returns the size of a file, in bytes.

getFileSize(string $file) : int

A thin, exception-throwing wrapper around filesize(): the file is first validated with assertFile() (must exist and be readable), so a missing file raises a typed FileException rather than a warning + false.

Parameters
$file : string

Path to the file to measure.

Tags
throws
FileException

If the file is missing, unreadable, or its size cannot be read.

author

Marc Alcaraz (ekameleon)

since
1.2.0
see
formatFileSize()

To render the returned byte count as a human-readable string.

example
use function oihana\files\getFileSize;

$bytes = getFileSize( '/data/report.pdf' ) ; // e.g. 1240518
Return values
int

The file size in bytes.

getFreeDiskSpace()

Returns the number of free bytes on the filesystem hosting a directory.

getFreeDiskSpace([string $directory = '.' ]) : float

Typed wrapper around disk_free_space(): an invalid path raises a FileException instead of returning false. Useful as a pre-flight guard before extracting an archive or writing large files.

Parameters
$directory : string = '.'

A directory (or path) on the filesystem to inspect (default: '.').

Tags
throws
FileException

If the free space cannot be determined (e.g. invalid path).

author

Marc Alcaraz (ekameleon)

since
1.2.0
see
getTotalDiskSpace()
getDiskUsage()
example
use function oihana\files\getFreeDiskSpace;

if ( getFreeDiskSpace( '/var/www' ) < $estimatedSize )
{
    throw new RuntimeException( 'Not enough free disk space.' ) ;
}
Return values
float

The number of available bytes.

getHomeDirectory()

Returns the current user’s home directory as a **canonical** path.

getHomeDirectory() : string

Resolution strategy – in order :

  1. Unix / macOS / Linux Uses the HOME environment variable if it is set and non‑empty.
  2. Windows (≥ XP) Combines HOMEDRIVE + HOMEPATH (e.g. C: + \Users\John) if both are available.
  3. Failure Throws a RuntimeException when no recognised combination is found.

The resulting string is passed through canonicalizePath() so that path separators are normalized (backslashes → slashes) and redundant slashes are removed.

Tags
throws
RuntimeException

When the home directory cannot be determined.

example
$home = getHomeDirectory(); // "/home/alice" or "C:/Users/Alice"
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

Canonical absolute path to the user’s home directory.

getMimeType()

Detects the MIME type of a file using the `finfo` extension.

getMimeType(string $file) : string|null

This is the low-level primitive shared by the higher-level MIME helpers (hasMimeType(), getImageMimeType(), tarFileInfo(), zipFileInfo()). It returns the raw type reported by finfo (e.g. text/plain, application/zip) without any normalization.

The function never throws: it returns null when the path is not a file or when detection fails (including an empty result), so callers can decide how to react (a boolean check, a fallback label such as 'unknown', etc.).

Parameters
$file : string

Path to the file to inspect.

Tags
author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\getMimeType;

var_dump( getMimeType('/path/to/notes.txt'  ) ); // string(10) "text/plain"
var_dump( getMimeType('/path/to/archive.zip') ); // string(15) "application/zip"
var_dump( getMimeType('/path/to/missing'    ) ); // NULL
Return values
string|null

The detected MIME type, or null if $file is not a file or detection failed.

getOwnershipInfos()

Retrieves the current ownership information of a given file or directory.

getOwnershipInfos(string $path) : OwnershipInfos

Returns an OwnershipInfo object containing both numeric UID/GID and their corresponding human-readable owner and group names (if resolvable).

Requires the posix extension to resolve usernames and group names; otherwise, owner and group may be null.

Parameters
$path : string

Absolute or relative path to the file or directory.

Tags
throws
RuntimeException

If the given path does not exist.

example
use oihana\files\getOwnershipInfo;

$info = getOwnershipInfo('/var/www/html');

echo $info->owner; // 'www-data'
echo $info->uid;   // 33
echo $info;        // www-data:www-data (33:33)
Return values
OwnershipInfos

Object containing UID, GID, and optionally owner and group names.

getRoot()

Extracts the root directory component of a given path.

getRoot(string $path) : string

This function identifies the root portion of a file system path, including handling of protocol schemes. ( e.g., "file://", "s3://" )

UNIX root ("/"), and Windows root ( e.g., "C:/" ).

It returns the canonical root as a string, or an empty string if the path is relative or empty.

Behavior:

  • "file:///usr/bin""file:///"
  • "/usr/bin""/"
  • "C:\\Windows\\System32""C:/"
  • "relative/path""" (empty string)
Parameters
$path : string

The input path, optionally with a scheme.

Tags
example
use function oihana\files\getRoot;

echo getRoot("file:///var/log");        // "file:///"
echo getRoot("/usr/local/bin");         // "/"
echo getRoot("C:\\Windows\\System32");  // "C:/"
echo getRoot("D:");                     // "D:/"
echo getRoot("some/relative/path");     // ""
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

The root component of the path, or an empty string if no root can be determined.

getSchemeAndHierarchy()

Split a filename or URI into its scheme (if any) and hierarchical part.

getSchemeAndHierarchy(string $filename) : array{0: ?string, 1: string}

Logic

  • Detect the first “://” only once – no array allocation if not present.
  • Accept schemes that match RFC‑3986 [A‑Za‑z][A‑Za‑z0‑9+\-.]*.
  • Return [$scheme, $hierarchy], where $scheme is null when absent.
Parameters
$filename : string

A path or URI such as file:///tmp/app.log or /etc/hosts.

Tags
throws
InvalidArgumentException

if the scheme is malformed (e.g. '1http://')

example
getSchemeAndHierarchy('s3://bucket/folder/img');    // ['s3',   'bucket/folder/img']
getSchemeAndHierarchy('/home/user/report.pdf');     // [null,  '/home/user/report.pdf']
getSchemeAndHierarchy('C:\\Windows\\notepad.exe');  // [null,  'C:\\Windows\\notepad.exe']
getSchemeAndHierarchy('file:///tmp/cache.db');      // ['file', '/tmp/cache.db']
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
array{0: ?string, 1: string}

getTemporaryDirectory()

Builds a path inside the system temporary directory.

getTemporaryDirectory([string|array<string|int, string>|null $path = null ][, bool $assertable = false ][, bool $isReadable = true ][, bool $isWritable = false ]) : string
Parameters
$path : string|array<string|int, string>|null = null

Optional sub‑path(s) to append inside sys_get_temp_dir().

$assertable : bool = false

Whether to validate the final directory path. Defaults to false because the directory may not exist yet.

$isReadable : bool = true

Check if the directory is readable (Default true).

$isWritable : bool = false

Check if the directory is writable (Default false).

Tags
throws
DirectoryException

If validation is enabled and the path is invalid.

example

Basic usage: get the system temp directory.

use function oihana\files\getTemporaryDirectory;

echo getTemporaryDirectory();
// e.g. "/tmp" on Unix, "C:\Windows\Temp" on Windows

Append a subdirectory path:

echo getTemporaryDirectory('myapp/cache'); // e.g. "/tmp/myapp/cache"
echo getTemporaryDirectory(['myapp', 'logs']); // e.g. "/tmp/myapp/logs"

Validate that the directory exists and is readable:

try
{
    $dir = getTemporaryDirectory('myapp/logs', true); // assertable = true
    echo $dir;
}
catch ( DirectoryException $e )
{
    // Handle error if directory does not exist or is not readable
}

Validate that the directory is writable:

try
{
   // assertable + readable + writable
   $dir = getTemporaryDirectory('myapp/uploads', true, true, true);
   echo $dir;
}
catch (DirectoryException $e)
{
   // Handle permission error
}

Using an absolute path (bypasses sys_get_temp_dir):

echo getTemporaryDirectory('/var/tmp/myapp'); // stays as is on Unix
echo getTemporaryDirectory('C:\\Temp\\custom'); // stays as is on Windows

Edge case: skip path argument to return system temp dir directly:

echo getTemporaryDirectory(null); // same as sys_get_temp_dir()
echo getTemporaryDirectory('');   // same as sys_get_temp_dir()
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

Normalised temporary directory path.

getTimestampedDirectory()

Get a timestamped file path using a formatted date and optional prefix/suffix.

getTimestampedDirectory([string|null $date = null ][, string $basePath = Char::EMPTY ][, string $prefix = Char::EMPTY ][, string $suffix = Char::EMPTY ][, string|null $timezone = 'Europe/Paris' ][, string|null $format = 'Y-m-d\TH:i:s' ][, bool $assertable = true ]) : string

Combines a date/time string (or the current time) with optional *extension, prefix, suffix, and base path to generate a unique file name. The file is not created on disk.

Asserts by default if the file exist, you can disabled the behavior with the boolean assertable argument.

Parameters
$date : string|null = null

Optional date/time string to use. If null or invalid, the current date/time is used ("now").

$basePath : string = Char::EMPTY

Optional base path in which to place the directory. Defaults to the current directory.

$prefix : string = Char::EMPTY

Optional string to prepend to the directory name (e.g., "/hello-2025-12-01T14:00:00"").

$suffix : string = Char::EMPTY

Optional string to append to the directory name (e.g., "/2025-12-01T14:00:00-hello"").

$timezone : string|null = 'Europe/Paris'

Timezone identifier (e.g., 'Europe/Paris'). Defaults to 'Europe/Paris'.

$format : string|null = 'Y-m-d\TH:i:s'

Date format compatible with DateTime::format(). Defaults to 'Y-m-d\TH:i:s'.

$assertable : bool = true

Whether to validate the path with assertDirectory(). Defaults to true.

Tags
throws
DirectoryException

If the directory path is invalid or assertion fails.

example
use function oihana\files\getTimestampedDirectory;

// Example 1: Generate directory path with current date/time, no prefix/suffix, current directory base
$dirPath = getTimestampedDirectory();
// e.g. "./2025-07-15T14:32:00"

// Example 2: Generate directory path with specific date, custom base path, and extension-like suffix
$dirPath = getTimestampedDirectory(
date: '2025-12-01 14:00:00',
basePath: '/var/backups',
suffix: '_archive'
);
// e.g. "/var/backups/2025-12-01T14:00:00_archive"

// Example 3: Add prefix and suffix, custom timezone and format, without assertion
$dirPath = getTimestampedDirectory
(
    prefix: 'backup_',
    suffix: '_final',
    timezone: 'UTC',
    format: 'Ymd_His',
    assertable: false
);
// e.g. "./backup_20250715_123200_final"
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

The full path of the generated directory.

getTimestampedFile()

Get a timestamped file path using a formatted date and optional prefix/suffix.

getTimestampedFile([string|null $date = null ][, string $basePath = Char::EMPTY ][, string|null $extension = null ][, string $prefix = Char::EMPTY ][, string $suffix = Char::EMPTY ][, string|null $timezone = 'Europe/Paris' ][, string|null $format = 'Y-m-d\TH:i:s' ][, bool $assertable = true ]) : string|null

Combines a date/time string (or the current time) with optional *extension, prefix, suffix, and base path to generate a unique file name. The file is not created on disk.

Asserts by default if the file exist, you can disabled the behavior with the boolean assertable argument.

Parameters
$date : string|null = null

Optional date/time string to use. If null or invalid, the current date/time is used ("now").

$basePath : string = Char::EMPTY

Optional base path in which to place the file. Defaults to the current directory.

$extension : string|null = null

Optional extension to append to the file name (e.g., ".log", ".txt").

$prefix : string = Char::EMPTY

Optional string to prepend to the file name.

$suffix : string = Char::EMPTY

Optional string to append to the file name (e.g., "2025-12-01T14:00:00-hello"").

$timezone : string|null = 'Europe/Paris'

Timezone identifier (e.g., 'Europe/Paris'). Defaults to 'Europe/Paris'.

$format : string|null = 'Y-m-d\TH:i:s'

Date format compatible with DateTime::format(). Defaults to 'Y-m-d\TH:i:s'.

$assertable : bool = true

Whether to validate the path with assertFile(). Defaults to true.

Tags
throws
FileException

If the file path is invalid.

example
use oihana\files\makeTimestampedFile;
use oihana\enums\Char;

// Example 1: file in the current directory using default format
$file = getTimestampedFile();
// e.g. ./2025-07-15T10:45:33

// Example 2: file inside /tmp with prefix and suffix
$file = getTimestampedFile
(
    date:     '2025-12-01 14:00:00',
    basePath: '/tmp',
    prefix:   'backup_',
    suffix:   '.sql'
);
// e.g. /tmp/backup_2025-12-01T14:00:00.sql

// Example 3: use a different timezone and format
$file = getTimestampedFile
(
    basePath : Char::EMPTY,
    prefix   : 'log_',
    suffix   : '.txt',
    timezone : 'UTC',
    format   : 'Ymd_His'
);
// e.g. ./log_20250715_084533.txt
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string|null

The full path of the generated file, or null on failure.

getTotalDiskSpace()

Returns the total size, in bytes, of the filesystem hosting a directory.

getTotalDiskSpace([string $directory = '.' ]) : float

Typed wrapper around disk_total_space(): an invalid path raises a FileException instead of returning false.

Parameters
$directory : string = '.'

A directory (or path) on the filesystem to inspect (default: '.').

Tags
throws
FileException

If the total space cannot be determined (e.g. invalid path).

author

Marc Alcaraz (ekameleon)

since
1.2.0
see
getFreeDiskSpace()
getDiskUsage()
example
use function oihana\files\getTotalDiskSpace;

$total = getTotalDiskSpace( '/' ) ;
Return values
float

The total number of bytes of the filesystem.

gunzipFile()

Decompresses a single gzip file, streaming it in chunks.

gunzipFile(string $source[, string|null $destination = null ][, bool $overwrite = true ]) : string

Counterpart of gzipFile(), using the zlib extension — no subprocess, and the file is never fully loaded into memory.

Parameters
$source : string

Path to the gzip file to decompress.

$destination : string|null = null

Output path. Defaults to $source without its .gz suffix, or $source + .out when the source has no .gz suffix.

$overwrite : bool = true

Whether to overwrite an existing destination (default: true).

Tags
throws
FileException

If the source is invalid, zlib is unavailable, the destination exists and $overwrite is false, or decompression fails.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\gunzipFile;

gunzipFile( '/var/log/app.log.gz' ) ; // -> /var/log/app.log
Return values
string

The destination path.

gzipFile()

Compresses a single file with gzip (DEFLATE), streaming it in chunks.

gzipFile(string $source[, string|null $destination = null ][, int $level = -1 ][, bool $overwrite = true ]) : string

Standalone gzip compression outside of tar archives, using the zlib extension — no subprocess, and the file is never fully loaded into memory.

Parameters
$source : string

Path to the file to compress.

$destination : string|null = null

Output path. Defaults to $source + .gz.

$level : int = -1

Compression level 09, or -1 for zlib's default (default: -1).

$overwrite : bool = true

Whether to overwrite an existing destination (default: true).

Tags
throws
FileException

If the source is invalid, zlib is unavailable, the destination exists and $overwrite is false, or compression fails.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\gzipFile;

gzipFile( '/var/log/app.log' ) ;                 // -> /var/log/app.log.gz
gzipFile( '/data/dump.sql' , '/data/dump.gz' , 9 ) ;
Return values
string

The destination path.

hasDirectories()

Checks if a directory contains at least one subdirectory, or only subdirectories if strict mode is enabled.

hasDirectories(string|null $dir[, bool $strict = false ]) : bool
Parameters
$dir : string|null

The path to the directory to check. Must be a valid readable directory.

$strict : bool = false

If true, the function returns true only if the directory contains only subdirectories (no files or other items). Defaults to false.

Tags
throws
DirectoryException

If the path is null, empty, not a directory, or does not meet the readability/writability requirements as checked by assertDirectory().

example
try
{
    $dir = '/path/to/directory';

    // Check if directory contains at least one subdirectory
    if ( hasDirectories($dir) )
    {
        echo "Directory contains at least one subdirectory.\n";
    }
    else
    {
        echo "No subdirectories found.\n";
    }

    // Check if directory contains only subdirectories (strict mode)
    if ( hasDirectories( $dir , true ) )
    {
        echo "Directory contains only subdirectories.\n";
    }
    else
    {
        echo "Directory contains files or other items besides subdirectories.\n";
    }
}
catch (DirectoryException $e)
{
    echo "Error: " . $e->getMessage() . "\n";
}
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

Returns true if the directory contains at least one subdirectory, or if in strict mode, only subdirectories.

hasFiles()

Checks if a directory contains at least one file, or only files if strict mode is enabled.

hasFiles(string|null $dir[, bool $strict = false ]) : bool
Parameters
$dir : string|null

The path to the directory to check. Must be a valid readable directory.

$strict : bool = false

If true, the function returns true only if the directory contains only files (no directories or other items). Defaults to false.

Tags
throws
DirectoryException

If the path is null, empty, not a directory, or does not meet the readability/writability requirements as checked by assertDirectory().

example
try
{
    $dir = '/path/to/directory';

    // Check if directory contains at least one file
    if ( hasFiles( $dir ) )
    {
        echo "Directory contains at least one file.\n";
    }
    else
    {
        echo "No files found.\n";
    }

    // Check if directory contains only files (strict mode)
    if (hasFiles($dir, true))
    {
        echo "Directory contains only files.\n";
    }
    else
    {
        echo "Directory contains directories or other items besides files.\n";
    }
}
catch (DirectoryException $e)
{
    echo "Error: " . $e->getMessage() . "\n";
}
Return values
bool

Returns true if the directory contains at least one file, or if in strict mode, only files.

hasMimeType()

Checks whether a file's MIME type matches one of the given MIME types.

hasMimeType(string $filePath, string|array<string|int, string> $mimeTypes) : bool

The file's MIME type is detected with finfo and compared to each entry of $mimeTypes using a substring match (via str_contains()), so a partial type such as application/zip matches a detected application/zip; charset=binary.

Parameters
$filePath : string

Path to the file.

$mimeTypes : string|array<string|int, string>

A single MIME type, or a list of MIME types (or fragments) to match against.

Tags
author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\hasMimeType;

var_dump( hasMimeType('/path/to/archive.zip', 'application/zip'   ) ); // bool(true)
var_dump( hasMimeType('/path/to/archive.zip', ['application/zip'] ) ); // bool(true)
var_dump( hasMimeType('/path/to/notes.txt'  , ['application/zip'] ) ); // bool(false)
var_dump( hasMimeType('/path/to/missing'    , ['application/zip'] ) ); // bool(false)
Return values
bool

True if the file exists and its detected MIME type contains one of $mimeTypes.

isLinux()

Indicates if the OS system is Linux.

isLinux() : bool
Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

isMac()

Indicates if the OS system is Mac.

isMac() : bool
Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

isOtherOS()

Indicates if the OS system is not Windows, Mac or Linux.

isOtherOS() : bool
Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

Tells whether a path is a symbolic link.

isSymlink(string $path) : bool

Thin wrapper around is_link(): returns false (never throws) for a regular file, a directory, or a non-existent path.

Parameters
$path : string

The path to test.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\isSymlink;

var_dump( isSymlink( '/var/www/current' ) ) ; // bool(true)
var_dump( isSymlink( '/etc/hosts' ) ) ;        // bool(false)
Return values
bool

true if $path is a symbolic link, false otherwise.

isWindows()

Indicates if the OS system is Windows.

isWindows() : bool
Tags
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

makeDirectory()

Creates a directory if it does not exist and returns the path of the directory.

makeDirectory(null|array<string|int, mixed>|string $pathOrOptions[, int $permissions = 0755 ][, bool $recursive = true ][, string|null $owner = null ][, string|null $group = null ]) : string|null
Parameters
$pathOrOptions : null|array<string|int, mixed>|string

The path of the directory to create.

$permissions : int = 0755

The permissions to set for the directory (default: 0755).

$recursive : bool = true

If true, creates parent directories as needed (default: true).

$owner : string|null = null

User name or ID to set as directory owner (optional).

$group : string|null = null

Group name or ID to set as directory group (optional).

Tags
throws
DirectoryException

If the directory cannot be created.

example

Basic usage: create a directory if it does not exist.

use function oihana\files\makeDirectory;

$dir = 'cache/files';
try
{
    makeDirectory($dir);
    echo "Directory created or already exists: $dir";
}
catch ( DirectoryException $e )
{
    // Handle error
}

Create a directory with custom permissions:

try
{
    makeDirectory('data/output', 0777);
}
catch ( DirectoryException $e )
{
    // Handle permission or creation error
}

Create a nested directory with recursive option:

try
{
    makeDirectory('var/log/myapp/debug', 0755, true); // parent folders created
}
catch ( DirectoryException $e )
{
    // Handle error
}

Handle failure when directory path is invalid or not writable:

try
{
   makeDirectory(''); // Throws exception: empty path
}
catch (DirectoryException $e)
{
    echo $e->getMessage(); // Directory path cannot be null or empty.
}

Check if the returned path is usable:

$path = makeDirectory('tmp/test');
file_put_contents( $path . '/sample.txt', 'content' ) ;

Assign an user/group permissions :

makeDirectory('/var/www/mydir', 0775, true, 'www-data', 'www-data');

Use an associative array to creates the new directory

makeDirectory
([
    'path'        => '/var/www/mydir',
    'permissions' => 0775,
    'recursive'   => true,
    'owner'       => 'www-data',
    'group'       => 'www-data',
]);
author

Marc Alcaraz (ekameleon)

since
1.0.0
see
MakeDirectoryOption
Return values
string|null

Returns the path of the directory.

makeFile()

Creates or updates a file with the given content and options.

makeFile(array{append?: bool, content?: string|null, file?: string|null, force?: bool, group?: null|string, lock?: bool, overwrite?: bool, permissions?: int, owner?: string|null}|string|null $fileOrOptions[, string|null $content = null ][, array{append?: bool, force?: bool, group?: null|string, lock?: bool, overwrite?: bool, permissions?: int, owner?: string|null} $options = [] ]) : string

This function writes content to the specified file path. It supports appending to existing files, overwriting, setting file permissions, changing ownership, and group. It can also create the parent directories if needed.

Usage:

  • Classic signature:
makeFile(string $filePath, string $content = '', array $options = []);
  • Signature with options array as first parameter:
makeFile(array $options);

Required keys in $options:

  • 'filePath' (string): The path of the file to create or modify (mandatory).
  • 'content' (string): The content to write into the file (optional, default ''). Other keys correspond to options (see below).
Parameters
$fileOrOptions : array{append?: bool, content?: string|null, file?: string|null, force?: bool, group?: null|string, lock?: bool, overwrite?: bool, permissions?: int, owner?: string|null}|string|null

Either the file path as a string (classic usage), or an associative array containing at least 'filePath' and optionally 'content' and other options.

$content : string|null = null

The content to write into the file. Defaults to empty string. Ignored if $filePathOrOptions is array.

$options : array{append?: bool, force?: bool, group?: null|string, lock?: bool, overwrite?: bool, permissions?: int, owner?: string|null} = []

An associative array of options:

  • 'append' (bool): If true, appends content instead of overwriting. Default: false.
  • 'force' (bool): If true, creates parent directories if they do not exist. Default: true.
  • 'group' (string|null): Group name or ID to set as file group owner. Default: null.
  • 'lock' (bool): If true, uses an exclusive lock while writing. Default: true.
  • 'overwrite' (bool): If true, overwrites existing files. Default: false.
  • 'permissions' (int): File permissions to set (octal). Default: 0644.
  • 'owner' (string|null): User name or ID to set as file owner. Default: null.
Tags
throws
FileException

If the file path is invalid, writing fails, or permission/ownership changes fail.

DirectoryException

If directory creation fails.

author

Marc Alcaraz (ekameleon)

Marc Alcaraz (ekameleon)

since
1.0.0
1.0.0
example

Create a new file with content, creating directories if needed

makeFile('/path/to/file.txt', "Hello World");

Append content to an existing file, creating directories if needed

makeFile('/path/to/file.txt', "\nAppended line", ['append' => true]);

Overwrite existing file with new content

makeFile('/path/to/file.txt', "Overwrite content", ['overwrite' => true]);

Create a file with custom permissions and without locking

makeFile('/path/to/file.txt', "Content", ['permissions' => 0600, 'lock' => false]);

Create a file and set ownership and group (requires appropriate permissions)

makeFile('/path/to/file.txt', "Content", ['owner' => 'username', 'group' => 'groupname']);

Create a file without forcing directory creation (will fail if directory missing)

makeFile('/path/to/file.txt', "Content", ['force' => false]);

With a unique array definition :

 makeFile([
     'file'        => '/path/to/file.txt',
     'content'     => "Hello World",
     'append'      => true,
     'permissions' => 0600,
 ]);
Return values
string

The path of the created or updated file.

makeTemporaryDirectory()

Creates (or returns if already present) a directory inside the system temporary folder.

makeTemporaryDirectory(string|array<string|int, string>|null $path[, int $permission = 0755 ]) : string

The sub‑path is appended to sys_get_temp_dir() de la même manière que getTemporaryDirectory() :

  • null → the temp dir itself
  • 'cache'/tmp/cache
  • ['my', 'app']/tmp/my/app
Parameters
$path : string|array<string|int, string>|null

Optional sub‑directory path segments.

$permission : int = 0755

Octal mode for mkdir() (default: 0755).

Tags
throws
DirectoryException

If creation fails or the directory is still missing afterwards.

example
// 1) Ensure /tmp/reports exists
$reportsDir = makeTemporaryDirectory('reports');

// 2) Ensure /tmp/my/app/cache exists
$cacheDir = makeTemporaryDirectory(['my','app','cache'], 0700);

// 3) Just return /tmp itself
$tmp = makeTemporaryDirectory(null);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string

Full path to the (existing or newly created) temporary directory.

makeTimestampedDirectory()

Creates a directory named with a formatted timestamp.

makeTimestampedDirectory([string|null $date = null ][, string $basePath = Char::EMPTY ][, string $prefix = Char::EMPTY ][, string $suffix = Char::EMPTY ][, string|null $timezone = 'Europe/Paris' ][, string|null $format = 'Y-m-d\TH:i:s' ]) : string|null

Combines a date/time string (or the current time) with optional prefix, suffix, and base path to generate a unique directory name. The directory is created if it does not already exist.

Parameters
$date : string|null = null

Optional date/time string to use. If null or invalid, the current date/time is used ("now").

$basePath : string = Char::EMPTY

Optional base path in which to create the directory. Defaults to an empty string.

$prefix : string = Char::EMPTY

Optional string to prepend to the directory name.

$suffix : string = Char::EMPTY

Optional string to append to the directory name.

$timezone : string|null = 'Europe/Paris'

Timezone identifier (e.g., 'Europe/Paris'). Defaults to 'Europe/Paris'.

$format : string|null = 'Y-m-d\TH:i:s'

Date format compatible with DateTime::format(). Defaults to 'Y-m-d\TH:i:s'.

Tags
throws
DirectoryException

If directory creation fails due to an error.

example

Example 1: simple directory in current path, using current date‑time

use oihana\\files\\createTimestampedDirectory;
use oihana\\enums\\Char;

$dir = createTimestampedDirectory();
// e.g. ./2025-07-15T10:30:12

Example 2 : directory inside /tmp with custom prefix/suffix and explicit date

$dir = createTimestampedDirectory
(
    date:     '2025-12-01 14:00:00',
    basePath: '/tmp',
    prefix:   'backup_',
    suffix:   '_v1'
);
// e.g. /tmp/backup_2025-12-01T14:00:00_v1

Example 3 : use a different timezone and format

$dir = createTimestampedDirectory
(
    date:     null,              // now
    basePath: Char::EMPTY,       // current directory
    prefix:   'log_',
    suffix:   Char::EMPTY,
    timezone: 'UTC',
    format:   'Ymd_His'          // 20250715_083012
);
// e.g. ./log_20250715_083012
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string|null

The full path of the created directory, or null on failure.

makeTimestampedFile()

Generates a timestamped file path if not exist. Using a formatted date and optional prefix/suffix.

makeTimestampedFile([string|null $date = null ][, string $basePath = Char::EMPTY ][, string|null $extension = null ][, string $prefix = Char::EMPTY ][, string $suffix = Char::EMPTY ][, string|null $timezone = 'Europe/Paris' ][, string|null $format = 'Y-m-d\TH:i:s' ][, bool $mustExist = false ]) : string|null

Combines a date/time string (or the current time) with optional prefix, suffix, and base path to generate a unique file name. The file is not created on disk.

Parameters
$date : string|null = null

Optional date/time string to use. If null or invalid, the current date/time is used ("now").

$basePath : string = Char::EMPTY

Optional base path in which to place the file. Defaults to the current directory.

$extension : string|null = null

Optional extension to append to the file name (e.g., ".log", ".txt").

$prefix : string = Char::EMPTY

Optional string to prepend to the file name.

$suffix : string = Char::EMPTY

Optional string to append to the file name (e.g., "2025-12-01T14:00:00-hello"").

$timezone : string|null = 'Europe/Paris'

Timezone identifier (e.g., 'Europe/Paris'). Defaults to 'Europe/Paris'.

$format : string|null = 'Y-m-d\TH:i:s'

Date format compatible with DateTime::format(). Defaults to 'Y-m-d\TH:i:s'.

$mustExist : bool = false

Whether the generated file must exist. If true, asserts the file exists. Defaults to false.

Tags
throws
FileException

If the file path is invalid, not writable, or must exist but does not.

example
use oihana\files\makeTimestampedFile;

// Example 1: Generate a file path with current datetime in default format, no prefix/suffix
$filePath = makeTimestampedFile();
// e.g. "./2025-07-15T10:45:33"

// Example 2: Generate a file path with a specific date and extension inside /tmp
$filePath = makeTimestampedFile(
    date: '2025-12-01 14:00:00',
    basePath: '/tmp',
    extension: '.log'
);
// e.g. "/tmp/2025-12-01T14:00:00.log"

// Example 3: Add prefix and suffix, use a custom timezone and date format
$filePath = makeTimestampedFile(
    prefix: 'backup_',
    suffix: '_final',
    timezone: 'UTC',
    format: 'Ymd_His'
);
// e.g. "./backup_20250715_084533_final"

// Example 4: Require that the generated file already exists (throws if not)
$filePath = makeTimestampedFile(mustExist: true);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
string|null

The full path of the generated file, or null on failure.

moveFile()

Moves (or renames) a single file to a destination path.

moveFile(string $source, string $destination[, bool $overwrite = true ][, bool $createDirectory = true ]) : bool

Shares the destination semantics of copyFile():

  • the source is validated with assertFile() (must exist and be readable);
  • if $destination is an existing directory, the file is moved inside it, keeping the source basename;
  • when $overwrite is false, an existing destination raises a FileException;
  • the destination's parent directory is created on demand when $createDirectory is true.

The move is performed with rename() (atomic on the same filesystem). When the source and destination live on different filesystems, rename() cannot span devices, so the function transparently falls back to copyFile() + deleteFile().

Parameters
$source : string

Path to the source file to move.

$destination : string

Destination file path, or an existing directory to move into.

$overwrite : bool = true

Whether to overwrite an existing destination file (default: true).

$createDirectory : bool = true

Whether to create the destination directory if missing (default: true).

Tags
throws
FileException

If the source is invalid, or the destination exists and $overwrite is false.

DirectoryException

If the destination directory is missing and $createDirectory is false, or cannot be created.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\moveFile;

moveFile( '/tmp/upload.tmp' , '/data/final.pdf' ) ;  // move + rename
moveFile( '/data/final.pdf' , '/archive' ) ;         // into a directory
Return values
bool

Returns true on success.

Returns the target a symbolic link points to.

readSymlink(string $link) : string
Parameters
$link : string

Path to the symbolic link.

throws
FileException

If $link is not a symbolic link, or its target cannot be read.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\readSymlink;

echo readSymlink( '/var/www/current' ) ; // '/var/www/releases/42'
Return values
string

The target path the symlink points to.

recursiveFilePaths()

Recursively retrieves all .php files in a folder (and its subfolders).

recursiveFilePaths(string $directory[, array{excludes?: array|null, extensions?: array|null, maxDepth?: int, sortable?: bool} $options = [] ]) : array<string|int, mixed>
Parameters
$directory : string

The base path of the file to be scanned.

$options : array{excludes?: array|null, extensions?: array|null, maxDepth?: int, sortable?: bool} = []

The optional parameter to send in the function.

  • excludes (array) : The enumeration of all files to excludes
  • extensions (array) : The optional list of the extensions to use to scan the folder(s).
  • maxDepth (int) : The maximum allowed depth. Default -1 is used
  • sortable (bool) : Indicates if the list of file paths is sorted before returned.
Tags
example

Basic usage: list all PHP files in a directory (and its subdirectories).

use function oihana\files\recursiveFilePaths;

$files = recursiveFilePaths( __DIR__ ) ;
foreach ( $files as $file )
{
   echo $file . PHP_EOL;
}

Include only files with certain extensions:

$files = recursiveFilePaths( __DIR__ ,
[
    RecursiveFilePathsOption::EXTENSIONS => ['php', 'inc'],
]);

Exclude specific filenames from the scan:

$files = recursiveFilePaths(__DIR__,
[
    RecursiveFilePathsOption::EXCLUDES => ['ignore.php', 'test.php'],
]);

Limit maximum depth of traversal:

$files = recursiveFilePaths( __DIR__ ,
[
    RecursiveFilePathsOption::MAX_DEPTH => 1, // Only scan current directory and its direct children
]);

Disable sorting of the resulting file list:

$files = recursiveFilePaths( __DIR__,
[
    RecursiveFilePathsOption::SORTABLE => false,
]);

Error handling when scanning an invalid directory:

try {
$files = recursiveFilePaths('invalid/path');
} catch (RuntimeException $e) {
echo "Error: " . $e->getMessage();
}
author

Marc Alcaraz (ekameleon)

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

The list of the full paths to all files found.

renameFile()

Renames a single file.

renameFile(string $source, string $destination[, bool $overwrite = true ][, bool $createDirectory = true ]) : bool

Semantic alias of moveFile(): renaming a file is the same operation as moving it (the destination may be a new name in the same directory, a path in another directory, or an existing directory to move into). See moveFile() for the full destination, overwrite and cross-filesystem semantics.

Parameters
$source : string

Path to the source file to rename.

$destination : string

New file path, or an existing directory to move into.

$overwrite : bool = true

Whether to overwrite an existing destination file (default: true).

$createDirectory : bool = true

Whether to create the destination directory if missing (default: true).

Tags
throws
FileException

If the source is invalid, or the destination exists and $overwrite is false.

DirectoryException

If the destination directory is missing and $createDirectory is false, or cannot be created.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\renameFile;

renameFile( '/data/old-name.txt' , '/data/new-name.txt' ) ;
Return values
bool

Returns true on success.

requireAndMergeArrays()

Requires multiple PHP files (each returning an array) and merges the results.

requireAndMergeArrays(array<string|int, mixed> $filePaths[, bool $recursive = true ][, string|null $allowedBase = null ][, int|null $maxBytes = null ]) : array<string|int, mixed>

Each path goes through a defensive validation pipeline before require:

  1. The path must be a non-empty string.
  2. It must resolve via realpath() to an existing regular file.
  3. The file extension must be .php (case-insensitive).
  4. If $allowedBase is provided, the resolved file must be located inside that base directory (defense in depth against path-escape attacks).
  5. If $maxBytes is provided, the file size must be ≤ $maxBytes (defensive cap against parser OOM on extremely large config files).

This protects against arbitrary file inclusion when paths come from untrusted or semi-trusted sources. Note that even with $allowedBase, callers must still trust the content of the included files — require executes their PHP code.

Parameters
$filePaths : array<string|int, mixed>

An array of file paths to load.

$recursive : bool = true

Whether to perform a deep (recursive) merge (true) or a simple merge (false).

$allowedBase : string|null = null

Optional absolute directory path. When provided, every file in $filePaths must be located inside this directory after canonicalisation. Strongly recommended when paths are not 100% trusted at the call site.

$maxBytes : int|null = null

Optional per-file size cap (in bytes). When provided, any file whose size exceeds this limit is rejected before being included, throwing RuntimeException. Default null (no limit — historical behaviour).

Tags
throws
InvalidArgumentException

If $allowedBase is provided but does not resolve to a valid directory.

RuntimeException

If a path is not a non-empty string, does not resolve to an existing .php file, escapes $allowedBase, exceeds $maxBytes, or does not return an array.

example
use function oihana\files\requireAndMergeArrays;

$paths = [
    __DIR__ . '/config/default.php',
    __DIR__ . '/config/override.php',
];

// Basic usage — relies on the caller to trust $paths.
$config = requireAndMergeArrays($paths);

// Shallow merge.
$config = requireAndMergeArrays($paths, false);

// Hardened usage — every file must be under __DIR__/config.
$config = requireAndMergeArrays($paths, true, __DIR__ . '/config');

// With a per-file size cap (defensive — 1 MiB max per config file).
$config = requireAndMergeArrays($paths, true, __DIR__ . '/config', 1024 * 1024);

Example of a required file:

// config/default.php
return [
    'app' => [
        'debug'    => false,
        'timezone' => 'UTC',
    ],
];
author

Marc Alcaraz (ekameleon)

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

The merged array.

shouldExcludeFile()

Checks if a file path should be excluded based on an array of patterns.

shouldExcludeFile(string $filePath, array<string|int, string> $excludePatterns) : bool

This function supports two types of patterns:

  1. Glob patterns (e.g., '.log', 'config/.php'). These are matched using fnmatch().
  2. PCRE regular expressions (e.g., '/^temp-\d+.tmp$/i'). The function auto-detects regex patterns by checking if they are enclosed in matching delimiter characters.

For each pattern, the function attempts to match it against both the full file path and the basename of the file. The match is successful if any pattern matches. The glob matching is performed with the FNM_PATHNAME flag, meaning wildcards will not match directory separators (/).

Parameters
$filePath : string

The absolute or relative path to the file to check.

$excludePatterns : array<string|int, string>

An array of glob or PCRE patterns.

Tags
security

Each pattern is evaluated with fnmatch() (glob) or preg_match() (regex, when the pattern is enclosed in matching delimiters). PHP's regex engine has no execution timeout, so a maliciously crafted regex such as /^(a+)+$/ can cause catastrophic backtracking and effectively a CPU DoS. Patterns must come from a trusted source (configuration, internal code) — never from direct user input. See the security guide.

example
$patterns = [
'*.log',          // Exclude all .log files (matches basename)
'/^error_\d+/',   // Exclude files starting with error_... (regex)
'config/db.php'   // Exclude a specific file path (matches path suffix)
];

// Returns true (matches '*.log' on basename)
shouldExcludeFile('/var/www/app/logs/access.log', $patterns);

// Returns true (matches regex on basename)
shouldExcludeFile('/tmp/error_12345.txt', $patterns);

// Returns true (fnmatch matches '*config/db.php' against the full path)
shouldExcludeFile('/var/www/app/config/db.php', $patterns);

// Returns false (no pattern matches)
shouldExcludeFile('/var/www/index.php', $patterns);
author

Marc Alcaraz (ekameleon)

since
1.0.0
Return values
bool

Returns true if the file path matches any of the exclusion patterns, false otherwise.

sortFiles()

Sorts an array of SplFileInfo objects.

sortFiles(array<string|int, SplFileInfo&$files, callable|string|array<string|int, mixed> $sort[, string|null $order = 'asc' ]) : void
Parameters
$files : array<string|int, SplFileInfo>

Array of files to sort (modified in‑place).

$sort : callable|string|array<string|int, mixed>

One of:

  • callable : custom compare function, ex: fn(SplFileInfo $a, SplFileInfo $b): int
  • string : single built‑in key
    'name' | 'ci_name' | 'extension' | 'size' | 'type' | 'atime' | 'ctime' | 'mtime'
  • array : ordered list of such keys for multi‑criteria sorting e.g. ['type', 'name'] or ['extension','size']
$order : string|null = 'asc'

The direction of the sort method 'asc' (default) or 'desc'.

Tags
examples
// 1) Sort by filename ascending
sortFiles($files, 'name');

// 2) Case‑insensitive filename descending
sortFiles($files, 'ci_name', 'desc');

// 3) Sort by extension then by size
sortFiles($files, ['extension', 'size']);

// 4) Custom comparator: modified time descending
sortFiles($files, fn($a, $b) => $a->getMTime() <=> $b->getMTime(), 'desc');

// 5) Type then case‑insensitive name
sortFiles($files, ['type', 'ci_name']);
author

Marc Alcaraz (ekameleon)

since
1.0.0

touchFile()

Creates a file if it does not exist, or updates its modification and access times.

touchFile(string $file[, int|null $mtime = null ][, int|null $atime = null ][, bool $createDirectory = true ]) : string

Thin, exception-throwing wrapper around touch(). When $mtime is null, the current time is used. When $mtime is given but $atime is null, the access time is set to $mtime as well. The parent directory is created on demand.

Parameters
$file : string

Path to the file to touch.

$mtime : int|null = null

Modification timestamp (default: null → current time).

$atime : int|null = null

Access timestamp (default: null → same as $mtime).

$createDirectory : bool = true

Whether to create the parent directory if missing (default: true).

Tags
throws
FileException

If the file cannot be touched.

DirectoryException

If the parent directory is missing and cannot be created.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\touchFile;

touchFile( '/var/run/app.lock' ) ;                 // create or bump to now
touchFile( '/data/marker' , strtotime('-1 day') ) ; // backdate the mtime
Return values
string

The file path.

validateMimeType()

Validate the MIME type of a file against a list of allowed types.

validateMimeType(string $file, array<string|int, mixed> $allowedMimeTypes) : void
Parameters
$file : string

Path to the file to validate.

$allowedMimeTypes : array<string|int, mixed>

List of allowed MIME types. Can include strings or arrays of strings.

Tags
throws
FileException

If the MIME type is not allowed or cannot be determined.

example

Basic usage: validate that an uploaded file is a PDF or plain text file.

use function oihana\files\validateMimeType;
use oihana\files\exceptions\FileException;

$file = __DIR__ . '/example.txt';
file_put_contents($file, 'Some text content');

try
{
    validateMimeType($file, ['text/plain', 'application/pdf']);
    echo "File is valid.";
}
catch ( FileException $e )
{
    echo "Error: " . $e->getMessage();
}

unlink($file);

Accepting multiple MIME types (grouped by type):

$allowedTypes =
[
    ['image/png', 'image/jpeg'],
    ['application/pdf'],
];
validateMimeType('photo.jpg', $allowedTypes);

Error example:

try
{
    validateMimeType('fake.exe', ['image/png', 'image/jpeg']);
}
catch (FileException $e)
{
    echo "Validation failed: " . $e->getMessage();
}

Notes:

  • This function uses mime_content_type(), which relies on the system's file command or magic database.
  • For consistent results across platforms, ensure the PHP fileinfo extension is enabled.
author

Marc Alcaraz (ekameleon)

since
1.0.0

writeFileAtomic()

Writes content to a file **atomically**.

writeFileAtomic(string $file, string $content[, int $permissions = 0644 ]) : string

The content is first written to a temporary file located in the same directory as the target (so the final rename() stays on the same filesystem and is therefore atomic), then renamed over the destination. A concurrent reader always sees either the previous file or the fully-written new one — never a half-written file. This addresses the non-atomicity caveat of plain copy/write helpers (see the copying guide).

The destination's parent directory is created on demand. On failure, the temporary file is removed and a typed exception is thrown.

Parameters
$file : string

Destination file path.

$content : string

The content to write.

$permissions : int = 0644

File permissions to set (octal, default: 0644).

Tags
throws
FileException

If the temporary file cannot be written, permissions cannot be set, or the atomic rename fails.

DirectoryException

If the destination directory cannot be created.

author

Marc Alcaraz (ekameleon)

since
1.2.0
example
use function oihana\files\writeFileAtomic;

writeFileAtomic( '/etc/myapp/config.json' , $json ) ;
// readers never observe a truncated config.json
Return values
string

The destination file path.

On this page

Search results