digitaledgeit/filesystem
A filesystem utility package for PHP that provides helpers for working with files, directories, and paths. Designed to simplify common filesystem operations in Laravel and standalone PHP projects.
Verdict first: digitaledgeit/filesystem is a tiny, unmaintained local-filesystem helper (last release March 2016, 4 stars, 0 dependents). In a modern Laravel app it adds very little over Illuminate\Filesystem\Filesystem, the File facade, or Storage. Use it only when you inherit code that already depends on it, or for a narrowly scoped local scratch-file task where adding Flysystem would be overkill.
Install and verify immediately. The package predates PHP 7.1+, so its composer.json platform constraint may block installation on PHP 8:
composer require digitaledgeit/filesystem
If Composer refuses on platform grounds, do not blindly use --ignore-platform-reqs in a production app. First inspect:
composer show digitaledgeit/filesystem
cat vendor/digitaledgeit/filesystem/composer.json
find vendor/digitaledgeit/filesystem/src -type f -name '*.php'
Look first at:
composer.json — PHP constraint, autoload namespace, dependencies.src/ — the package is small; read the whole surface in a few minutes.DigitalEdgeIT\Filesystem usages before adding new ones.First use case: a local ingestion command. A realistic day-to-day use is a one-off Artisan command that reads CSVs from storage/app/imports, moves processed files, and writes a manifest. Start with a smoke test that exercises exactly the operations you need in a temp directory, because the package’s method names and error behavior matter more than any README:
use DigitalEdgeIT\Filesystem\Filesystem as LegacyFilesystem; // confirm class name in src/
$fs = new LegacyFilesystem();
$tmp = sys_get_temp_dir().'/fs-smoke-'.uniqid('', true);
$fs->makeDirectory($tmp, 0775, true);
$fs->put($tmp.'/a.txt', 'hello');
if ($fs->get($tmp.'/a.txt') !== 'hello') {
throw new RuntimeException('filesystem smoke test failed');
}
$fs->deleteDirectory($tmp);
Adjust method names to match the actual class in vendor/digitaledgeit/filesystem/src. Do not assume Laravel-like behavior until the smoke test proves it.
1. Wrap it behind your own interface. Never let package classes leak into controllers, jobs, or domain services. The package is abandoned; an adapter gives you a migration path to Laravel’s Filesystem or Symfony’s Filesystem later.
interface LocalScratchStore
{
public function write(string $relativePath, string $contents): string;
public function read(string $relativePath): string;
public function delete(string $relativePath): void;
}
final class LegacyScratchStore implements LocalScratchStore
{
public function __construct(
private LegacyFilesystem $fs,
private string $root,
) {}
public function write(string $relativePath, string $contents): string
{
$path = $this->path($relativePath);
$this->fs->makeDirectory(dirname($path), 0775, true);
if ($this->fs->put($path, $contents) === false) {
throw new RuntimeException("Unable to write [{$path}]");
}
return $path;
}
public function read(string $relativePath): string
{
$path = $this->path($relativePath);
$contents = $this->fs->get($path);
if ($contents === false) {
throw new RuntimeException("Unable to read [{$path}]");
}
return $contents;
}
public function delete(string $relativePath): void
{
$this->fs->delete($this->path($relativePath));
}
private function path(string $relative): string
{
$relative = ltrim(str_replace('\\', '/', $relative), '/');
if (str_contains($relative, '..')) {
throw new InvalidArgumentException('Path traversal rejected.');
}
return rtrim($this->root, '/').'/'.$relative;
}
}
Bind it once in a service provider:
$this->app->singleton(LocalScratchStore::class, function () {
return new LegacyScratchStore(
new LegacyFilesystem(),
storage_path('app/scratch'),
);
});
2. Use it in commands and queued jobs, not request paths. Local filesystem work in a web request is a latency and permissions liability. Put imports/exports in app/Console/Commands or jobs, inject LocalScratchStore, and keep the package out of HTTP controllers.
3. Root every operation under a configured base path. Take the root from config/filesystems.php or a dedicated config key. Never concatenate user input directly into package calls; normalize separators and reject ...
4. Treat it as a primitive, not a storage abstraction. It does not know about disks, S3, visibility, or URLs. For anything that needs those, use Storage. For local-only operations, consider Illuminate\Filesystem\Filesystem, which is already installed, maintained, and tested with Laravel.
5. Make writes atomic where it matters. Old filesystem helpers often write directly to the destination. For manifests or exports, write to a temp file, then rename:
$tmp = $final.'.tmp.'.bin2hex(random_bytes(4));
$store->write($tmp, $contents);
rename($tmp, $final); // same filesystem
6. Normalize and log absolute paths. When a job fails, the most useful log context is the absolute path, the operation name, and is_writable() / is_dir() state. Log those before rethrowing.
7. Test with real temp directories. Do not mock the filesystem package. Its behavior — return values, warnings, permissions — is the thing you are testing. Create a unique directory in setUp(), remove it in tearDown(), and assert both content and side effects.
each(), create_function(), curly-brace string offsets ($str{0}), and old mcrypt-era assumptions. Run your smoke test on the same PHP version as production.--ignore-platform-reqs, you are installing code the maintainer never tested on your runtime. Confine that to a legacy branch.false and null explicitly; do not rely on exceptions. Use error_get_last() when a warning is suppressed, and translate failures into your own exceptions at the adapter boundary.\ to /, strip trailing slashes, and be careful with DIRECTORY_SEPARATOR. Windows paths and symlinks are common failure points.0775 versus 0777, shared hosting, and open_basedir restrictions can all cause silent failures. Verify is_writable(dirname($path)) before writing.is_dir() followed by mkdir() is not atomic. Use @mkdir($path, 0775, true) and then verify is_dir($path), or accept the package’s behavior knowingly.realpath(). If your base path or target contains symlinks, realpath() can escape your intended root. Resolve and compare against the real base path.php artisan tinker with an absolute path, then run strace -e trace=file php artisan ... on Linux if the failure is environment-specific.Storage for disk abstractions and Illuminate\Filesystem\Filesystem for local primitives. Use Symfony’s Filesystem if you need atomic dumps. Keep digitaledgeit/filesystem isolated behind an adapter so replacing it is a one-class change, not a codebase-wide rewrite.How can I help you explore Laravel packages today?