Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Php Filesystem Laravel Package

leovie/php-filesystem

A lightweight PHP filesystem library offering an object-oriented API for common file and directory operations such as reading, writing, listing, copying, and deleting. A simple drop-in helper for projects that need clean, dependency-free filesystem handling.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it directly (pin the major you've verified — see below, this is now a 2.x line):

composer require leovie/php-filesystem

Where to look first: the v2.0.0 diff, then src/. The last assessment said the newest release was May 2022; that's now out of date — there is a v2.0.0 followed by v2.0.1, so the package has been revived at least once. The major-version bump is the thing you actually need to read: compare v1.x...v2.0.0 on the repo and confirm the namespace (LeoVie\PhpFilesystem\…), the class name, the method signatures, and the PHP constraint in composer.json. Do that before you write any code against the snippet below, because a 2.0 that nobody has written about is exactly where naming drifts.

After the major-version check, the rest is quick: this is still a single-purpose wrapper ("some small filesystem operations") with no service provider, no facade, no published docs. Open src/ and read every file — you'll be done in a few minutes — and confirm whether a test suite appeared in the 2.x line, because that changes how much you trust edge-case behaviour.

The shape you're likely working with is a plain instantiable class with stateless methods:

use LeoVie\PhpFilesystem\Filesystem;

$fs = new Filesystem();

$fs->createDir('/var/www/app/storage/exports');
$fs->writeFile('/var/www/app/storage/exports/report.txt', $contents);
$content = $fs->readFile('/var/www/app/storage/exports/report.txt');
$fs->deleteFile('/var/www/app/storage/exports/report.txt');

Verify against 2.x before committing. If the signatures moved, adjust; the wrapper's value is unchanged — it collapses the file_exists → mkdir → file_put_contents → chmod dance into one call.

First use case: an Artisan command or scheduled job that manipulates absolute local paths — creating a working directory, dropping a generated file next to a binary, cleaning up temp artifacts. That's the sweet spot: places where reaching for Storage::disk() would force you to define a disk for something that isn't really "storage," and where file_put_contents() with manual mkdir/is_dir checks is getting noisy.

Do a two-minute sanity check before adopting: write one file, read it back, delete it, and confirm the exceptions thrown on failure are ones you can reasonably catch in a catch (Throwable) around a command. Also check it installs alongside your existing composer.lock without conflict — see the roave/security-advisories note below, which is the one genuinely consumer-visible change in this release.

Implementation Patterns

Wrap it, don't scatter it. Zero dependents, one star, and an uneven release history (a 2022 tag, then silence, then a 2.0.x revival). Maintenance is non-zero again, which is better than before — but treat it as vendored utility code anyway. Put it behind your own interface so you can swap the implementation later without touching call sites.

namespace App\Support;

interface LocalFiles
{
    public function put(string $path, string $contents): void;
    public function get(string $path): string;
    public function ensureDir(string $path): void;
}

final class WrappedLocalFiles implements LocalFiles
{
    public function __construct(private \LeoVie\PhpFilesystem\Filesystem $fs) {}

    public function put(string $path, string $contents): void
    {
        $this->fs->writeFile($path, $contents);
    }
    // ...
}

Bind the interface as a singleton in a service provider — the underlying class is stateless, so new per call is harmless, but a singleton keeps your container clean and makes mocking in tests trivial.

Pin the major in composer.json. Given the version history (1.x → long gap → 2.0.0 → 2.0.1), ^2.0 is the constraint you want, not * or an unpinned require. If a 2.1 or 3.0 lands while you're not looking, you don't want a composer update to silently change filesystem semantics in a deploy script.

Use it for the "outside the disk" cases. The natural division of labour in a Laravel app:

Task Use
User uploads, S3, public assets Storage::disk() / File facade
Reading composer.json, .env, package manifests File::get()
Arbitrary absolute paths, temp work dirs, subprocess artifacts This wrapper (or symfony/filesystem)
Copying a directory tree with progress Neither — use symfony/filesystem or shell

Wrapping this package instead of using Illuminate\Support\Facades\File only pays off if you want the class decoupled from the framework (e.g., shared with a CLI tool or a non-Laravel package). If everything is Laravel, File:: already does all of this and has better error messages.

In queued jobs, make it idempotent. Filesystem ops in jobs get retried. Before writing, make sure the directory exists (or that your wrapper's ensureDir is a no-op when present). Before deleting, tolerate "not found" as success — otherwise a retried job dies on the second attempt.

In tests, avoid touching the real disk. There's no virtual-filesystem support here; mock your LocalFiles interface or use Storage::fake() for the Laravel-flavoured parts. Never let a unit test hit /var/....

Compose with Artisan output. For CLI tasks, wrap each call and log the path:

$this->info("Writing {$path}");
$fs->writeFile($path, $json);

When something fails, the exception alone usually won't tell you which of your five writes broke.

Gotchas and Tips

  • Still no Laravel integration whatsoever. No auto-discovery, no facade, no config. You instantiate it yourself or bind it. Any tutorial implying File::-style usage is wrong.
  • roave/security-advisories moved to dev — this is good news, and mildly install-affecting. In v2.0.1 it was relocated from require to require-dev. That package is a meta-package of conflict rules blocking known-vulnerable dependency versions; when it sits in a library's runtime require, every consumer inherits those conflicts, which is a classic cause of "your package blocks my composer update" tickets. If you previously had to work around this package in a resolution conflict, retry on 2.0.1. Note the flip side: it no longer runs in your CI unless you require it in your own require-dev — which you should, if you were relying on it transitively (you shouldn't have been, but it happens).
  • Exception types are the real risk, and the 2.0 bump may have changed them. A thin wrapper often lets \ErrorException, \RuntimeException, or native warnings bubble up inconsistently. A major version is precisely when an author introduces a FilesystemException hierarchy or tightens return types. Re-audit every method's failure mode once on the version you install, then normalise them in your adapter. Verify by triggering a permission-denied write in a scratch container.
  • Check path handling before trusting it. Thin wrappers frequently don't normalise paths, don't expand ~, and resolve relative paths against the process CWD (which in a queue worker is not your project root). Always pass absolute paths built from base_path() or storage_path().
  • Non-atomic writes. A plain file_put_contents()-style write means a reader can observe a partial file, and a crash mid-write leaves a truncated artifact. For anything another process consumes, write to $path . '.tmp' and rename() — check whether the wrapper exposes a move/rename method; if not, use rename() directly.
  • Permissions and umask. Files created by a web request (www-data) and later read by a queue worker (different user) is the classic failure. The wrapper almost certainly doesn't take a mode argument — chmod() afterwards if you need predictable permissions.
  • Light maintenance, not no maintenance — plan for both. v2.0.1 is a one-line dependency-hygiene release, which is not a signal of active feature work; there's no roadmap implied. But it does mean a maintainer is still tagging. The BSD-3-Clause license means you can fork and vendor freely: if you end up modifying it, copy it into app/Support/ rather than patching vendor/.
  • Extension points are minimal or absent. No plugin system, no stream wrapper registration, no driver abstraction as of the 2.0.x notes. If you need those, league/flysystem is the correct tool; this package is deliberately not that. Worth a quick grep of the 2.0.0 diff in case a stream abstraction was added alongside the bump.
  • Debugging tip: when a call fails silently, strace the process (strace -f -e trace=file php artisan your:command) or add a dd(realpath($path), is_writable(dirname($path))) before the call. Nine times out of ten it's the parent directory, not the file.
  • Don't fight it on complex tasks. Recursive listings, globs with exclusions, symlink handling, and permissions-preserving copies are where minimal wrappers diverge from expectations. Drop to symfony/filesystem's Finder/Filesystem for those rather than chaining five calls here.

Bottom line for day-to-day use: this is a convenience shim for short, imperative file work on the local disk. The 2.0.1 release is a dependency-hygiene fix with no API implications in itself — the real news is that a 2.0 line exists at all, so re-baseline your assumptions (PHP constraint, class/method signatures, exception behaviour) against the 2.0.0 diff rather than against the 2022 tag. Then adopt it behind an interface, in one place, for tasks where File:: feels heavy or where you want framework independence — and keep symfony/filesystem and Storage available for everything else.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource