PHPackages                             ricwein/filesystem - 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. ricwein/filesystem

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

ricwein/filesystem
==================

Filesystem abstraction layer

4.4.4(4y ago)82.9k[1 PRs](https://github.com/ricwein/FileSystem/pulls)3MITPHPPHP &gt;=8.0.2

Since Jul 19Pushed 2y ago2 watchersCompare

[ Source](https://github.com/ricwein/FileSystem)[ Packagist](https://packagist.org/packages/ricwein/filesystem)[ RSS](/packages/ricwein-filesystem/feed)WikiDiscussions master Synced 6d ago

READMEChangelog (10)Dependencies (4)Versions (73)Used By (3)

FileSystem
==========

[](#filesystem)

This Library provides a Filesystem abstraction layer.

```
use ricwein\FileSystem\Exceptions\FilesystemException;
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

try {

    $file = new File(new Storage\Disk(__DIR__, '/test', '/dir2', 'test.json'));
    $alt = new File(new Storage\Memory('{"some": "content"}'));

    // read file into output-buffer
    if ($file->isReadable()) {
        header('Content-Type: ' . $file->getType(true));
        echo $file->read();
    } else {
        header('Content-Type: ' . $alt->getType(true));
        echo $alt->read();
    }

} catch (FileSystemException $e) {
    http_response_code(500);
    echo json_encode(['errors' => [
        'status' => $e->getCode(),
        'title' => 'something went wrong',
        'detail' => $e->getMessage(),
    ]]);
}
```

Installation
------------

[](#installation)

```
composer require ricwein/filesystem
```

Overview
--------

[](#overview)

Let's begin with a short overview over the supported Filesystem classes and abstractions.

All classes uses the root-namespace `ricwein\FileSystem`.

### Object-Types

[](#object-types)

A File is represented as a `File` Object and a Directory as a `Directory` Object.

### Storage

[](#storage)

Accessing the Objects (File/Directory) Content is abstracted as `Storage`s. A File can be either:

- a `Disk` file/directory at your local filesystem (`Storage\Disk`)
- a `Memory` file, which only temporary exists in-memory (`Storage\Memory`)
- a `Stream` a stream which points to a file or resource (`Storage\Stream`)
- an abstract `Flysystem` file (`Storage\Flysystem`)

All Storage-Types must extend the abstract base class `Filesystem\Storage`.

> WARNING: since storage-objects are mutable and php automatically handles class-objects as references when passed into a function (constructor), it's highly recommended using the `clone` keyword when storages are recycled between to FileSystem-Objects. DO NOT:

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Storage;

$originalDir = new Directory(new Storage\Disk(__DIR__));
$copyDir = new Directory($originalDir->storage());

$copyDir->cd('test'); // will also change $originalDir path!
```

> DO:

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Storage;

$originalDir = new Directory(new Storage\Disk(__DIR__));
$copyDir = new Directory(clone $originalDir->storage());

$copyDir->cd('test'); // $originalDir will stay in __DIR__
```

### Exceptions

[](#exceptions)

Accessing File/Directory Attributes can result in throwing Exceptions. All Exceptions implement the `Exceptions\FileSystemException` Interface.

Usage: Files
------------

[](#usage-files)

All *FileSystem*-base-classes must be initialized using a Storage.

### Methods

[](#methods)

methoddescription`read(?$offset, ?$length, $mode)`read and return file-content, allows partial read with `$offset` and `$length` parameters, file is locked while reading with `$mode``stream(?$offset, ?$length, $mode)`stream file into output-buffer, file is locked while reading with `$mode``write($content, $append, $mode)`write `$content` to file, creates new file if it doesn't already exists, allows appended writing if `$append` isset, locks file with `$mode``copyTo($destination [,Constraint $constraints])`copy file to new `$destination` Storage-adapter`moveTo($destination [,Constraint $constraints])`like `copyTo()`, but moves files instead`touch([bool $ifNewOnly])`create file if it doesn't exists, updates last-modified timestamp`remove()`try to remove file`getType([bool $withEncoding])`guess files mime-type`getTime([Time $type])`get last-modified unix-timestamp`getDate([Time $type])`same as `getTime()`, but returns a DateTime object instead`getSize()`calculate size`getHash([Hash $mode [,string $algo [,bool $raw]]])`calculates a hash over `$mode` with `$algo` algorithm`isReadable()`is file readable?`isWriteable()`is file writeable?`isSymlink()`is file a symlink?`isFile()`is selected path an actual file?`isDir()`is selected path a directory? =&gt; always `false` for File instance`isDotfile()`is file a hidden dot-file?`isValid()`run constraints validation`getHandle([string $mode])`gets new file-Handle for binary file-access`storage()`access internal storage adapter`getPath()`fetch filesystem-path`getStream()`returns `Stream` wrapper around internal resource pointing to actual file`dir([,int $constraints [,string $as [,...$arguments]]])`get parent `Directory` of file### Open and read a file from the local filesystem

[](#open-and-read-a-file-from-the-local-filesystem)

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$file = new File(new Storage\Disk(__DIR__, 'test.txt'));
$content = $file->read();
```

### or from in-memory-file

[](#or-from-in-memory-file)

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$file = new File(new Storage\Memory('some content'));
$content = $file->read();
```

### or from stream

[](#or-from-stream)

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$file = new File(new Storage\Stream(fopen('php://output', 'wb')));
$content = $file->write('content');
```

### or from a Flysystem object

[](#or-from-a-flysystem-object)

```
use League\Flysystem\Local\LocalFilesystemAdapter;
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$file = new File(new Storage\Flysystem(new LocalFilesystemAdapter(__DIR__), 'test.txt'));
$content = $file->read();
```

Usage: Directories
------------------

[](#usage-directories)

Like Files, Directories must be initialized using a Storage.

### Methods

[](#methods-1)

methoddescription`list($recursive)`returns DirectoryIterator-Object to list directory-content as new `File`/`Directory` objects`mkdir()`try to create directory`remove()`try to remove directory`copyTo($destination [,Constraint $constraints])`copy directory recursively to new `$destination` Storage-adapter`getTime([Time $type])`get last-modified unix-timestamp`getDate([Time $type])`same as `getTime()`, but returns a DateTime object instead`getSize([bool $recursive])`calculate size`getHash([Hash $mode [,string $algo [,bool $raw]]])`calculates a hash over `$mode` with `$algo` algorithm`isReadable()`is directory readable?`isWriteable()`is directory writeable?`isSymlink()`is directory a symlink?`isFile()`is selected path a file? =&gt; always `false` for Directory instance`isDir()`is selected path an actual directory?`isDotfile()`is directory a hidden dot-file?`isValid()`run constraints validation`storage()`access internal storage adapter`getPath()`fetch filesystem-path`file(string $filename [,int $constraints [,string $as [,...$arguments]]])`get `File` in current directory by name`dir(string $dirname [,int $constraints [,string $as [,...$arguments]]])`get `Directory` in current directory by name (`clone`s storage!)### check if directory is readable

[](#check-if-directory-is-readable)

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Storage;

$dir = new Directory(new Storage\Disk(__DIR__));
var_dump($dir->isReadable());
```

### list all files inside a directory

[](#list-all-files-inside-a-directory)

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Storage;

$hashes = [];
$dir = new Directory(new Storage\Disk(__DIR__));

foreach($dir->list(true)->files() as $file) {
    $hashes[$file->getPath()->getFilename()] = $file->getHash();
}
```

Security
--------

[](#security)

Using this filesystem-layer also provides some kind of security for usage with user-defined file-paths. Accessing file attributes or content is only done after checking against so called ***Constraints***.

### Constraints

[](#constraints)

Constraints are defined on initialization of `File` or `Directory` objects and are stored inside the internal `Storage` object. This allows Constraints-inheritance, if new FileSystem-objects are accessed from existing ones. Example:

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Helper\Constraint;
use ricwein\FileSystem\Storage;

$dir = new Directory(new Storage\Disk(__DIR__), Constraint::STRICT);
$file = $dir->file($_GET['filename']);
```

In this example, the `$file` object shares the ***Constraints*** (inherited) and ***safepath*** with `$dir` - allowing safely accessing a file in `$dir` from user defined parameters. Path traversal is therefore prevented.

The following constraints are set as default (as part of `Constraint::STRICT`), but can be overwritten with the second argument of the `File($storage, $constraints)` or `Directory($storage, $constraints)` constructor:

- `Constraint::IN_OPEN_BASEDIR` =&gt; the path must be within the `open_basedir` php-ini paths, this allows throwing exceptions before running into php core errors
- `Constraint::DISALLOW_LINK` =&gt; the path must not be a (symbolic-) link
- `Constraint::IN_SAFEPATH` =&gt; if a file/directory path is build out of multiple components (parameters), the resulting file/directory destination must be inside the first path-component (called ***safepath***)

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Helper\Constraint;
use ricwein\FileSystem\Storage;

// let's assume $_GET['file'] == '/../file.txt'

// path concatenated as a single string
// this runs fine but is HIGHLY UNRECOMMENDED
$file = new File(new Storage\Disk(__DIR__ . $_GET['file']));

// path is passed as single parameters (comma instead of dot!)
// this throws an error since the resulting path is not within the safepath (__DIR__)
$file = new File(new Storage\Disk(__DIR__, $_GET['file']));

// however: disabling the safepath-constraint would also allow path traversal attacks:
$file = new File(new Storage\Disk(__DIR__, $_GET['file']), Constraint::STRICT & ~Constraint::IN_SAFEPATH);
```

Extensions
----------

[](#extensions)

### Directory Extensions

[](#directory-extensions)

- `Directory\Command`: Allows running shell-commands inside the given directory.

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Helper\Constraint;
use ricwein\FileSystem\Storage;

$git = new Directory\Command(new Storage\Disk(__DIR__), Constraint::STRICT, ['/usr/local/bin/git', '/usr/bin/git']);
$ref = $git->execSafe('rev-parse HEAD');
```

### File Extensions

[](#file-extensions)

- `File\Image`: Allows image-manipulations based on `imagemagick` or `gd` (later one is default). Requires the `Intervention\Image` package.

> Be aware: all image-file manipulations are directly mutating the original file!

```
use Intervention\Image\Image;
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$image = new File\Image(new Storage\Disk('test.png'));
$image->resizeToFit(1024, 1024);
$image->compress(1048576); // iterative process to reduce filesize to be less than given filesize (1MB) by reducing the jpg-quality
// $image->encode('jpg');
$image->edit(function (Image $image): Image {
    // add advanced image-manipulation here
    [...]
    return $image;
});
```

- `File\Zip`: Allows basic zip-operations, like creating a new archive or extracting an existing one.

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$zip = new File\Zip(new Storage\Disk('archive.zip'));

// create zip file
$zip->add(new File(new Storage\Disk('file.json'))); // or $zip->addFile(...)
$zip->add(new File(new Storage\Memory('some file-content')), 'anotherfile.txt'); // or $zip->addFile(...)
$zip->add(new Directory(new Storage\Disk(__DIR__, 'data-dir'))); // or $zip->addDirectory(...)
$zip->commit();

// extract zip file
$extractDir = $zip->extractTo(new Storage\Disk\Temp);
```

- `File\SSLCertificate`: Access some basic x509 SSL Certificate information, either from:
    - a certificate-file (usually `.crt`)
    - a Server (by URL) if it's serving a ssl based protocol like `HTTPS`

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$cert = new File\SSLCertificate(new Storage\File('certs/domain.crt'));
// OR
$cert = new File\SSLCertificate(new Storage\Memory('ssl://domain.com:443')); // or for HTTPS simply: 'domain.com'

// check if cert it currently valid (by timestamps)
$isValid = $cert->isValid();
// check if cert is also valid for a given host
$isValidForHost = $cert->isValidFor('subdomain.domain.com');

// show some certificate details
print_r([
    'issuer' => $cert->getIssuer(),
    'subject' =>  $cert->getValidDomains(),
    'validFrom' => $cert->validFrom()->format('d.m.Y H:i:s'),
    'validTo' => $cert->validTo()->format('d.m.Y H:i:s'),
]);
```

### Storage Extensions

[](#storage-extensions)

- `Disk\Current`: Uses current-working-directory (`getcwd()`) as safepath. Useful for cli-scripts in combination with `Directory\Command`.

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Helper\Constraint;
use ricwein\FileSystem\Storage;

$current = new File(new Storage\Disk(getcwd(), 'file.json'), Constraint::STRICT & ~Constraint::IN_SAFEPATH);
// is the same as:
$current = new File(new Storage\Disk\Current('file.json'));
```

```
use ricwein\FileSystem\Directory;
use ricwein\FileSystem\Helper\Constraint;
use ricwein\FileSystem\Storage;

$git = new Directory\Command(new Storage\Disk\Current, Constraint::STRICT, ['/usr/local/bin/git', '/usr/bin/git']);

if (!$git->execSafe('pull $branch', ['branch' => 'develop'])) {
    echo 'failed to execute: ' . $git->getLastCommand() . PHP_EOL;
}

exit($git->lastExitCode());
```

- `Disk\Temp`: Uses the system-temp directory to create a temporary file/directory. The file is automatically removed after freeing the object instance!

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$temp = new File(new Storage\Disk\Temp);
$temp->write('test');
$temp->read();
$temp = null; // will delete the temp-file again!
```

- `Disk\Uploaded`: Provides safe and easy *uploaded-files* access through php's native `is_uploaded_file()` and `move_uploaded_file()` functions.

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$uploaded = new File(new Storage\Disk\Uploaded($_FILES['file']));
$file = $uploaded->moveTo(new Storage\Disk(__DIR__, 'uploads'));
```

- `Memory\Resource`: Reads resource content into **MEMORY** on construction. The resource can be closed afterward.

> ATTENTION: Usually it's a better idea to just use `Storage\Stream` instead!

```
use ricwein\FileSystem\File;
use ricwein\FileSystem\Storage;

$resource = fopen('test.json', 'rb');
$file = new File(new Storage\Memory\Resource($resource));
fclose($resource);
$content = $file->read();
```

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity25

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity82

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 98.9% 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 ~27 days

Recently: every ~175 days

Total

71

Last Release

934d ago

Major Versions

1.4.8 → 2.02018-11-09

2.2.1 → 3.02020-12-10

3.2.0 → 4.02021-01-28

4.4.4 → 5.0-beta12023-10-27

PHP version history (5 changes)1.0PHP &gt;= 7.2.0

2.1.0PHP &gt;= 7.4.0

4.1.0PHP &gt;=8.0

4.4.4PHP &gt;=8.0.2

5.0-beta1PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/1e4c46b9e849423ff1355ff0a8dc5046c29e636308378f44ed0a55933f749e83?d=identicon)[ricwein](/maintainers/ricwein)

---

Top Contributors

[![ricwein](https://avatars.githubusercontent.com/u/870354?v=4)](https://github.com/ricwein "ricwein (177 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")

---

Tags

filesystemfilesystem-libraryphp

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ricwein-filesystem/health.svg)

```
[![Health](https://phpackages.com/badges/ricwein-filesystem/health.svg)](https://phpackages.com/packages/ricwein-filesystem)
```

###  Alternatives

[knplabs/gaufrette

PHP library that provides a filesystem abstraction layer

2.5k39.8M123](/packages/knplabs-gaufrette)[google/cloud-storage

Cloud Storage Client for PHP

34390.8M125](/packages/google-cloud-storage)[illuminate/filesystem

The Illuminate Filesystem package.

15261.6M2.6k](/packages/illuminate-filesystem)[superbalist/flysystem-google-storage

Flysystem adapter for Google Cloud Storage

26320.6M30](/packages/superbalist-flysystem-google-storage)[creocoder/yii2-flysystem

The flysystem extension for the Yii framework

2931.7M62](/packages/creocoder-yii2-flysystem)[flowjs/flow-php-server

PHP library for handling chunk uploads. Works with flow.js html5 file uploads.

2451.6M15](/packages/flowjs-flow-php-server)

PHPackages © 2026

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