fidry/filesystem
Tiny wrapper around Symfony Filesystem providing a FileSystem interface plus handy extras: path escaping for OS separators, real/normalized real path helpers, and consistent temp file/dir creation (incl. custom stream wrappers).
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require fidry/filesystem
Register the package in config/app.php under providers:
Fidry\FileSystem\FileSystemServiceProvider::class,
Basic Usage:
Bind the FileSystem interface in your service container:
$this->app->bind(FileSystem::class, NativeFileSystem::class);
Or use the static FS helper for quick operations:
use Fidry\FileSystem\FS;
FS::touch('test.txt'); // Creates a file
First Use Case:
Replace Laravel’s native filesystem operations (e.g., Storage::put()) with this package for cross-platform path handling:
$path = FS::escapePath('C:/path/to/file'); // Converts to `C:\path\to\file` on Windows
FS::dumpFile($path, 'Hello, World!'); // Writes content
$this->app->bind(FileSystem::class, function () {
return new NativeFileSystem();
});
ReadOnlyFileSystem in tests or read-heavy environments:
$readOnlyFS = new ReadOnlyFileSystem(failOnWrite: true);
$normalized = FS::normalizedRealPath('C:\Users\Name\file.txt'); // Returns `C:/Users/Name/file.txt`
$tempFile = FS::tmpFile('upload', '.tmp'); // e.g., `/tmp/upload1234.tmp`
$tempDir = FS::tmpDir('cache'); // e.g., `/tmp/cache5678`
FileSystemTestCase for isolated tests:
class MyTest extends FileSystemTestCase {
public function test_file_operations() {
FS::dumpFile('test.txt', 'content');
$this->assertFileExists('test.txt');
}
}
SplFileInfo: Use SplFileInfoBuilder to avoid verbose mocks:
$fakeFile = SplFileInfoBuilder::withTestData()
->withFile('test.txt')
->withContents('mocked')
->build();
Finder instance with the package:
$finder = FS::createFinder()
->files()
->in(storage_path('app'));
Path Normalization:
realPath() vs. normalizedRealPath(): The former preserves OS-specific separators (e.g., \ on Windows), while the latter forces /.normalizedRealPath() for consistent paths in logs/URLs.Temporary Files:
tmpFile()/tmpDir() may fail if the target directory lacks write permissions.FS::tmpFile('data', '.tmp', storage_path('framework/cache'));
Read-Only Mode:
ReadOnlyFileSystem silently ignores writes when failOnWrite: false. Enable failOnWrite: true to catch accidental writes in tests.Symfony Finder SplFileInfo:
getContents() method is deprecated in Symfony 7.1+. Use FS::readFile() instead:
$content = FS::readFile($filePath);
FS::escapePath() to debug cross-platform path inconsistencies.isReadable() before operations:
if (!FS::isReadable($file)) {
throw new \RuntimeException("File not readable: {$file}");
}
Custom Stream Wrappers:
NativeFileSystem to support custom streams (e.g., S3, SFTP):
class CustomFileSystem extends NativeFileSystem {
protected function getStreamWrapper(): string {
return 's3://';
}
}
Test Isolation:
getTmpDirPrefix() in FileSystemTestCase to avoid conflicts:
protected function getTmpDirPrefix(): string {
return 'myapp_';
}
Legacy Code:
SplFileInfo::getContents() with FS::readFile() in tests:
$content = FS::readFile($filePath); // Modern alternative
Finder for bulk file operations (e.g., renaming, deleting):
FS::createFinder()
->files()
->in($directory)
->each(function (SplFileInfo $file) {
FS::rename($file->getPathname(), $file->getPathname() . '.bak');
});
Storage::disk() calls for filesystem operations:
$filesystem = app(FileSystem::class);
$filesystem->put('file.txt', 'content'); // Uses Laravel’s filesystem adapter
FS for CLI scripts to avoid DI overhead:
use Fidry\FileSystem\FS;
FS::mkdir(storage_path('logs/backup'));
---
How can I help you explore Laravel packages today?