Search by

tereta / storage

tereta

Tereta/Storage is a package for working with file resources.You work with them the same way regardless of where the storage is located. The `local` and `sftp` drivers are supported out of the box.

0.0.12 2026-10-11 13:47 UTC

This package is not auto-updated.

Last update: 2026-10-11 10:47:49 UTC


README

🌐 English | Русский | Π£ΠΊΡ€Π°Ρ—Π½ΡΡŒΠΊΠ°

Introduction

Tereta/Storage is a package for working with file resources. You work with them the same way regardless of where the storage is located. The local and sftp drivers are supported out of the box.

Requirements

  • PHP version 8.2 or newer.
  • The ext-ssh2 extension - required only for the sftp driver. It is not needed for local storage (local).

Installation

composer require tereta/storage

Git Repository

https://gitlab.com/tereta/library/storage

Usage

All work is done through the Tereta\Storage\Filesystem facade. It is created by the Tereta\Storage\Factories\Filesystem factory: pass the strategy name (local or sftp) and its settings.

Available methods:

  • exists(string $path) - check whether a file exists. Returns true or false.
  • read(string $path) - read the file contents. Returns a string.
  • write(string $path, string $contents, ?int $mode = null) - save (or create) a file.
  • copy(string $source, string $destination, ?int $mode = null) - copy a file.
  • move(string $source, string $destination, ?int $mode = null) - move or rename a file.
  • remove(string $path, bool $recursively = false) - delete a file. To recursively delete a folder with all its contents, pass true as the second argument.
  • list(string $path) - get the list of files in a folder. Returns an array of names.
  • glob(string $pattern) - find files by a pattern, for example **/*.md. See Search files.
  • resolve(string $path) - get the full path of a file inside the storage.

In write(), copy() and move() the $mode sets the file permissions, for example 0644. By default it is null and the permissions are not changed: an existing file keeps its permissions, a moved file or folder keeps them too, and a new file gets the permissions the server gives by default. Keep null where permissions can not be changed, for example on some SFTP servers.

Local filesystem

Use the local strategy for the local filesystem

use Tereta\Storage\Factories\Filesystem as FilesystemFactory;

$storage = (new FilesystemFactory())->create('local', '/var/www/files');

All paths stay inside the root folder: a path where .. goes above it, and a symbolic link that leads outside the root, throw Tereta\Storage\Exceptions\Runtime. A link that points inside the root works as usual, and remove() deletes a link itself without touching its target.

The root folder itself can not be deleted or moved: remove('/'), remove('a/..', true) and move('/', ...) throw Tereta\Storage\Exceptions\Runtime. To clear the storage, delete the entries from list('/') one by one.

For files on an SFTP server - the sftp strategy

use Tereta\Storage\Strategies\Sftp;

$storage = new Filesystem(new Sftp(
    host: 'example.com',
    username: 'user',
    password: 'secret',
    root: '/home/user/files',
    fingerprint: '5A:1B:...:9F',
));

The fingerprint of the server key is required: it protects the password from a fake server in the middle. Take it once from a trusted place, for example ssh-keygen -l -E sha1 -f /etc/ssh/ssh_host_ed25519_key.pub on the server, and keep it in the config. SHA1 (40 hex digits) and MD5 (32 hex digits) are accepted. Without a fingerprint the first operation throws Tereta\Storage\Exceptions\Runtime. Only for a local test server you can turn the check off with verifyHost: false.

A symbolic link on the server that leads outside the root folder throws Tereta\Storage\Exceptions\Runtime, the same as for local files.

The connection to the SFTP server opens on the first operation, not when the storage is created. So a wrong host or password shows up as an error on the first read(), write() or other call.

You can also create the strategy yourself. Then the editor and static analysis check every parameter:

use Tereta\Storage\Filesystem;
use Tereta\Storage\Strategies\Local;

$storage = new Filesystem(new Local('/var/www/files'));

Examples

Below are the available methods and examples for working with the filesystem:

// Write a file
$storage->write('notes/hello.txt', 'Hello!');

// Read
$text = $storage->read('notes/hello.txt');

// Check whether a file exists
if ($storage->exists('notes/hello.txt')) {
    // ...
}

// Copy and move
$storage->copy('notes/hello.txt', 'notes/backup.txt');
$storage->move('notes/hello.txt', 'archive/hello.txt');

// View the list of files in a folder
$files = $storage->list('notes');

// Delete a file (or an entire folder - pass true as the second argument)
$storage->remove('archive/hello.txt');

Search files - glob()

glob() finds files by a pattern and returns their paths one by one:

foreach ($storage->glob('notes/*.txt') as $file) {
    echo $file; // notes/hello.txt
}
  • * - any part of a name inside one folder.
  • ** - any number of nested folders, including none.
  • ** at the end, for example notes/**, returns everything inside the folder at any depth: files and folders.
  • The pattern is counted from the storage root. A leading / is allowed and does not change anything.
  • Paths are returned from the storage root, without a leading /, for example notes/hello.txt.
  • .. in a pattern is not allowed, you can not search outside the storage.
// All .md files in all folders
foreach ($storage->glob('**/*.md') as $file) {
    $text = $storage->read($file);
}

Errors

  • Tereta\Storage\Exceptions\Runtime - an operation failed: the file is not found, there is no access, the connection failed and so on. The message contains the reason, for example Unable to read file: notes/a.txt: ... No such file or directory.
  • Tereta\Storage\Exceptions\InvalidArgument - the factory got an unknown strategy name, wrong strategy settings, or a class that is not a strategy.