PHPackages                             likeajohny/php-fs - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [File &amp; Storage](/categories/file-storage)
4. /
5. likeajohny/php-fs

ActiveLibrary[File &amp; Storage](/categories/file-storage)

likeajohny/php-fs
=================

Tools to help you get around the filesystem with PHP.

3.0.0(4mo ago)21.2k↓50%[1 PRs](https://github.com/LikeAJohny/php-fs/pulls)MITPHPPHP ^8.0CI passing

Since Mar 2Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/LikeAJohny/php-fs)[ Packagist](https://packagist.org/packages/likeajohny/php-fs)[ RSS](/packages/likeajohny-php-fs/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (1)Versions (10)Used By (0)

PHP FS (Filesystem Helpers)
===========================

[](#php-fs-filesystem-helpers)

A lightweight, production-ready PHP library for filesystem operations with proper validation, error handling, and comprehensive features.

Features
--------

[](#features)

- **Static utility classes** - Clean, simple API with no instantiation required
- **Proper exception hierarchy** - Granular exception types for precise error handling
- **Memory-efficient operations** - Stream-based operations for large files
- **File locking** - Concurrent access protection
- **Atomic writes** - Prevent partial writes on failure
- **Symbolic link support** - Create, read, and manipulate symlinks
- **Path utilities** - Safe path manipulation and traversal prevention
- **Dry-run mode** - Preview destructive operations before executing

Requirements
------------

[](#requirements)

- PHP 8.0+
- ext-fileinfo

Install
-------

[](#install)

```
composer require likeajohny/php-fs
```

Quick Start
-----------

[](#quick-start)

```
use PhpFs\File;
use PhpFs\Directory;
use PhpFs\Path;

// File operations
File::create('/path/to/file.txt');
File::write('/path/to/file.txt', 'Hello World');
$content = File::read('/path/to/file.txt');

// Directory operations
Directory::create('/path/to/dir');
$files = Directory::files('/path/to/dir');
Directory::remove('/path/to/dir');

// Path utilities
$normalized = Path::normalize('/foo/../bar/./baz'); // '/bar/baz'
$joined = Path::join('/foo', 'bar', 'baz.txt');     // '/foo/bar/baz.txt'
```

API Reference
-------------

[](#api-reference)

### File Class

[](#file-class)

#### Constants

[](#constants)

```
File::DEFAULT_FILE_MODE  // 0644 - Default permissions for new files
```

#### Basic Operations

[](#basic-operations)

```
// Create a new file (directory must exist)
File::create(string $file, int $mode = 0644): mixed

// Check if file exists
File::exists(string $file): bool

// Get file information (dirname, basename, extension, permissions, mime_type, mime_encoding)
File::info(string $file): array

// Read file contents
File::read(string $file): string

// Write content to file (overwrites existing content)
File::write(string $file, string $content, bool $lock = false): int

// Append content to file
File::append(string $file, string $content): int

// Prepend content to file
File::prepend(string $file, string $content): int

// Copy file
File::copy(string $file, string $targetFile): bool

// Move/rename file
File::move(string $file, string $targetFile): bool

// Remove file (with optional dry-run)
File::remove(string $file, bool $dryRun = false): bool|string
```

#### Advanced Operations

[](#advanced-operations)

```
// Touch file (create if not exists, update timestamps)
File::touch(string $file, ?int $mtime = null, ?int $atime = null): bool

// Truncate file to specified size
File::truncate(string $file, int $size = 0): bool

// Write with exclusive lock
File::writeWithLock(string $file, string $content, int $lockType = LOCK_EX): int

// Read with shared lock
File::readWithLock(string $file): string

// Atomic write (write to temp, then rename)
File::writeAtomic(string $file, string $content): int

// Swap two files atomically
File::swap(string $file1, string $file2): bool
```

#### Streaming Operations

[](#streaming-operations)

```
// Read file line by line (memory-efficient)
foreach (File::lines($file) as $lineNumber => $line) {
    echo "Line $lineNumber: $line";
}

// Read file in chunks
foreach (File::chunks($file, 8192) as $chunkNumber => $chunk) {
    process($chunk);
}

// Stream copy (for large files)
File::copyStream(string $source, string $target, ?int $length = null): int
```

#### Symbolic Links

[](#symbolic-links)

```
// Check if path is a symlink
File::isLink(string $path): bool

// Read symlink target
File::readLink(string $link): string

// Create symlink
File::link(string $target, string $link): bool
```

### Directory Class

[](#directory-class)

#### Constants

[](#constants-1)

```
Directory::DEFAULT_DIR_MODE  // 0755 - Default permissions for new directories
```

#### Basic Operations

[](#basic-operations-1)

```
// Create directory (recursive by default)
Directory::create(string $dir, int $permissions = 0755, bool $recursive = true): void

// Check if directory exists
Directory::exists(string $dir): bool

// Get directory information
Directory::info(string $dir): array
// Returns: path, basename, permissions, owner, group, mtime, atime

// Get total size of directory contents (recursive)
Directory::size(string $dir): int

// Count files and directories
Directory::count(string $dir, bool $recursive = true): array
// Returns: ['files' => 42, 'directories' => 7]

// Copy directory recursively
Directory::copy(string $dir, string $targetDir): bool

// Move/rename directory
Directory::move(string $dir, string $targetDir): bool

// Empty directory (keep directory, remove contents)
Directory::empty(string $dir, bool $dryRun = false): bool|array

// Remove directory recursively (with optional dry-run)
Directory::remove(string $dir, bool $dryRun = false): bool|array
```

#### Listing Operations

[](#listing-operations)

```
// List directory contents (nested structure)
Directory::list(string $dir, bool $recursive = true, bool $flatten = false): array

// List only files
Directory::files(string $dir, bool $recursive = true): array

// List only subdirectories
Directory::directories(string $dir, bool $recursive = true): array

// Glob pattern matching
Directory::glob(string $pattern, int $flags = 0): array

// Find with custom filter
Directory::find(string $dir, callable $filter, bool $recursive = true): array
```

#### Symbolic Links

[](#symbolic-links-1)

```
// Check if path is a symlink
Directory::isLink(string $path): bool

// Read symlink target
Directory::readLink(string $link): string

// Create symlink to directory
Directory::link(string $target, string $link): bool
```

### Path Class

[](#path-class)

```
use PhpFs\Path;

// Normalize path (resolve . and .., normalize separators)
Path::normalize('/foo/../bar/./baz');  // '/bar/baz'

// Join path segments
Path::join('/foo', 'bar', 'baz.txt');  // '/foo/bar/baz.txt'

// Check if path is absolute
Path::isAbsolute('/foo/bar');  // true
Path::isAbsolute('foo/bar');   // false

// Check if path is relative
Path::isRelative('foo/bar');   // true

// Get directory name
Path::dirname('/foo/bar/baz.txt');  // '/foo/bar'

// Get base name
Path::basename('/foo/bar.txt');         // 'bar.txt'
Path::basename('/foo/bar.txt', '.txt'); // 'bar'

// Get extension
Path::extension('/foo/bar.txt');  // 'txt'

// Compare paths (after normalization)
Path::equals('/foo/./bar', '/foo/bar');  // true

// Check if path is inside directory (prevents traversal)
Path::isInside('/foo/bar/baz', '/foo/bar');  // true
Path::isInside('/foo/baz', '/foo/bar');      // false

// Get relative path
Path::relative('/foo/bar', '/foo/bar/baz');  // 'baz'
Path::relative('/foo/bar', '/foo/baz');      // '../baz'
```

Exception Hierarchy
-------------------

[](#exception-hierarchy)

The library provides a granular exception hierarchy for precise error handling:

```
RuntimeException
├── FileException
│   └── FileNotFoundException
├── DirectoryException
│   └── DirectoryNotFoundException
├── PermissionException
└── LinkException

```

### Exception Factory Methods

[](#exception-factory-methods)

```
// File exceptions
FileException::createError($file, $error)
FileException::noFile($file)                    // Returns FileNotFoundException
FileException::isDirectory($path)
FileException::notReadable($file)               // Returns PermissionException
FileException::notWriteable($file)              // Returns PermissionException
FileException::readError($file, $error)
FileException::writeError($file, $error)
FileException::streamError($file, $operation)
FileException::lockFailed($file)
FileException::touchError($file)
FileException::truncateError($file)

// Directory exceptions
DirectoryException::directoryNotCreated($dir)
DirectoryException::noDirectory($dir)           // Returns DirectoryNotFoundException
DirectoryException::isFile($path)
DirectoryException::globError($pattern)
DirectoryException::scanError($dir)

// Permission exceptions
PermissionException::notReadable($path)
PermissionException::notWriteable($path)
PermissionException::notExecutable($path)

// Link exceptions
LinkException::createFailed($target, $link)
LinkException::notALink($path)
LinkException::targetNotFound($link, $target)
LinkException::readFailed($link)
```

### Catching Specific Exceptions

[](#catching-specific-exceptions)

```
use PhpFs\File;
use PhpFs\Exception\FileNotFoundException;
use PhpFs\Exception\PermissionException;

try {
    $content = File::read('/path/to/file.txt');
} catch (FileNotFoundException $e) {
    // Handle missing file
} catch (PermissionException $e) {
    // Handle permission error
}
```

Dry-Run Mode
------------

[](#dry-run-mode)

Preview destructive operations before executing them:

```
// Preview files that would be deleted
$paths = File::remove('/path/to/file.txt', dryRun: true);
// Returns: '/path/to/file.txt'

// Preview directory contents that would be deleted
$paths = Directory::remove('/path/to/dir', dryRun: true);
// Returns: ['/path/to/dir/file1.txt', '/path/to/dir/subdir', '/path/to/dir']

// Preview what emptying would delete (excludes directory itself)
$paths = Directory::empty('/path/to/dir', dryRun: true);
// Returns: ['/path/to/dir/file1.txt', '/path/to/dir/subdir']
```

Examples
--------

[](#examples)

### Memory-Efficient Large File Processing

[](#memory-efficient-large-file-processing)

```
use PhpFs\File;

// Process large log file line by line
foreach (File::lines('/var/log/large.log') as $lineNum => $line) {
    if (str_contains($line, 'ERROR')) {
        echo "Error on line $lineNum: $line";
    }
}

// Copy large file using streams
File::copyStream('/path/to/large.zip', '/backup/large.zip');
```

### Concurrent File Access

[](#concurrent-file-access)

```
use PhpFs\File;

// Write with exclusive lock (prevents race conditions)
File::writeWithLock('/path/to/config.json', json_encode($config));

// Read with shared lock (allows concurrent reads)
$config = json_decode(File::readWithLock('/path/to/config.json'), true);
```

### Atomic Configuration Updates

[](#atomic-configuration-updates)

```
use PhpFs\File;

// Atomic write - prevents partial writes if interrupted
File::writeAtomic('/path/to/config.json', json_encode($newConfig));
```

### Safe Path Handling

[](#safe-path-handling)

```
use PhpFs\Path;

// Prevent directory traversal attacks
$userPath = $_GET['file'];
$basePath = '/var/www/uploads';

if (Path::isInside(Path::join($basePath, $userPath), $basePath)) {
    // Safe to access
    $content = File::read(Path::join($basePath, $userPath));
}
```

### Finding Files with Filters

[](#finding-files-with-filters)

```
use PhpFs\Directory;

// Find all PHP files
$phpFiles = Directory::find('/src', fn($path) => str_ends_with($path, '.php'));

// Find files modified in last 24 hours
$recentFiles = Directory::find('/logs', fn($path) =>
    is_file($path) && filemtime($path) > time() - 86400
);

// Using glob patterns
$configFiles = Directory::glob('/etc/**/*.conf');
```

Migration Guide
---------------

[](#migration-guide)

### Permission Defaults Change

[](#permission-defaults-change)

Version 3.0 changes default file permissions from `0766` to `0644` and directory permissions from `0766` to `0755`. This is the standard Unix convention.

If you rely on the old defaults, explicitly pass the permissions:

```
// Old behavior (not recommended)
File::create('/path/to/file.txt', 0766);
Directory::create('/path/to/dir', 0766);

// New defaults (recommended)
File::create('/path/to/file.txt');     // 0644
Directory::create('/path/to/dir');     // 0755
```

### Return Types

[](#return-types)

- `Directory::copy()` now returns `bool` (was `void`)
- `Directory::empty()` now returns `bool` (was `void`)
- `File::append()` now returns only bytes written (not total file size)

Testing
-------

[](#testing)

```
# Run tests
composer test

# Run specific test
vendor/bin/phpunit --filter testMethodName
```

Contributing
------------

[](#contributing)

Issues and pull requests are welcome at

License
-------

[](#license)

MIT

###  Health Score

45

—

FairBetter than 93% of packages

Maintenance78

Regular maintenance activity

Popularity21

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~202 days

Recently: every ~196 days

Total

8

Last Release

122d ago

Major Versions

1.2.0 → 2.0.12023-11-22

2.0.5 → 3.0.02026-01-16

PHP version history (2 changes)1.0.0PHP ^7.4 || ^8.0

2.0.1PHP ^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/a1e659e36a7b8c671a172f178ca1cc3cf4200d5307e42ace60ac586db328d35e?d=identicon)[LikeAJohny](/maintainers/LikeAJohny)

---

Top Contributors

[![likeajohny](https://avatars.githubusercontent.com/u/6093736?v=4)](https://github.com/likeajohny "likeajohny (15 commits)")

---

Tags

phpfilesystemhelperdirectoryphp filesystemphp helperphp directory

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/likeajohny-php-fs/health.svg)

```
[![Health](https://phpackages.com/badges/likeajohny-php-fs/health.svg)](https://phpackages.com/packages/likeajohny-php-fs)
```

###  Alternatives

[internal/path

Type-safe, immutable file path library with cross-platform support and automatic normalization.

1137.7k3](/packages/internal-path)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
