Skip to content

omnidrive/local

Omnidrive Local: a directory of this machine as an omnidrive drive, through league/flysystem-local - its root, its Unix modes, its public address, the file's local path.

Floor
Provider · Omnidrive
Version
1.x
Conformance suite
runs, CI green
Verified for real
Verified in part
Licence
MIT
composer require omnidrive/local:1.x-dev

A directory of this machine as an omnisense/omnidrive drive, through league/flysystem-local (League\Flysystem\Local\LocalFilesystemAdapter). No server, no network: the drive's paths are files under its root, and localPath() gives them.

Installation

composer require omnisense/omnidrive omnidrive/local

Requires PHP 8.2, omnisense/omnidrive (1.x) and league/flysystem-local (^3.0). Under Symfony or Laravel, a local storage of the framework is already a drive through omnibridge (Hosts); this factory is for plain PHP and for drives the framework does not configure.

Credentials

None: the PHP process's own Unix user and its permissions on root.

Options

new LocalDriveFactory(); factory name local.

Option Type Default Required
root string - yes the directory behind the drive's paths (a trailing / removed; '' is /)
lazy_root bool false no the root made on the first write, not when the drive is built
lock bool true no an exclusive lock (LOCK_EX) while a file is written
links disallow, skip disallow no a symbolic link met in a listing is an error, or left out
permissions map {file: {public: 0644, private: 0600}, dir: {public: 0755, private: 0700}} no the Unix mode of each visibility; octal strings accepted, a mode left out keeps its default
public_url string or list none no the prefix files are served from, or several (sharded)
visibility public/private public (the adapter's) no a write's visibility when it does not say
directory_visibility public/private private no the same for directories
retain_visibility bool true no whether a copy keeps its source's visibility

Capabilities

Capability
local (localPath()) yes: root + the path
publicUrls with public_url
temporaryUrls no
visibility per file yes: the file's Unix mode, by permissions
checksum any algorithm hash() knows (the adapter hashes the file)

Behaviour

Every operation is the adapter's: PHP's file functions on root. The root is made when the drive is built, with the directory_visibility mode, unless lazy_root. A write makes the missing directories with the directory_visibility mode - private (0700) unless that option says public, whatever the file's own visibility. visibility() reads the file's mode back against permissions. A listing follows no symbolic link: disallow makes the listing fail on one, skip leaves it out. Paths climbing out of root (..) are refused before any file function runs.

Example

<?php

require __DIR__.'/vendor/autoload.php';

use Omnidrive\Local\LocalDriveFactory;
use Omnidrive\Registry;
use Omnidrive\Visibility;

$drives = new Registry([new LocalDriveFactory()], [
    'uploads' => ['factory' => 'local', 'options' => [
        'root' => sys_get_temp_dir().'/site/public/uploads',
        'public_url' => '/uploads',
        'permissions' => ['file' => ['public' => '0664'], 'dir' => ['public' => '0775']],
        'links' => 'skip',
    ]],
]);
$uploads = $drives->get('uploads');

$uploads->write('avatars/1.png', "\x89PNG...", ['visibility' => Visibility::Public]);
$uploads->write('drafts/notes.txt', 'private notes', ['visibility' => 'private']);
symlink('/etc/hostname', sys_get_temp_dir().'/site/public/uploads/link');      // left out of listings

echo json_encode($uploads->capabilities()->toArray()), "\n";
echo $uploads->publicUrl('avatars/1.png'), ' ', $uploads->localPath('avatars/1.png'), "\n";
printf("%o %o %o\n", fileperms($uploads->localPath('avatars/1.png')) & 0777, fileperms($uploads->localPath('drafts/notes.txt')) & 0777, fileperms(dirname($uploads->localPath('avatars/1.png'))) & 0777);
echo implode(' ', array_map(static fn ($e) => $e->path, [...$uploads->list('')])), "\n";

unlink(sys_get_temp_dir().'/site/public/uploads/link');
$uploads->deleteDirectory('avatars');
$uploads->deleteDirectory('drafts');
{"local":true,"publicUrls":true,"temporaryUrls":false}
/uploads/avatars/1.png /tmp/site/public/uploads/avatars/1.png
664 600 700
avatars drafts

(run on 2026-10-25 in omnidrive's harness, PHP 8.4: the file 0664 as permissions asked, the private one 0600, the directory 0700 - the default directory_visibility is private; the link left out of the listing)

Errors

What PHP's file functions refuse (a permission, a full disk, a link with links: disallow) is a DriveException whose message ends with PHP's own warning; a missing file read is a FileNotFoundException; temporaryUrl() and publicUrl() without public_url are NotSupportedExceptions. A missing root is an InvalidConfigException (The "local" drive needs: root.).

Verified, and not

Verified (2026-10-23 and 2026-10-25, omnidrive's harness, PHP 8.4): the contract's tests on a temporary directory; the modes of each visibility as permissions gives them (octal strings too); a link refused, then skipped; the root made at once or lazily; the drive in plain PHP (bare). Not verified: Windows paths and permissions.

Responsibility

An independent, unofficial client, not affiliated with The PHP League. Whoever runs it is responsible for the data it stores and the access it gives (a public or temporary address serves the file to whoever holds it); see the core's Responsibility section (omnisense/omnidrive).

Propose a change docs/index.md