symfony/filesystem
Symfony Filesystem component offers convenient, robust filesystem utilities for PHP: create, copy, move, remove, chmod, and mirror files/directories, with error handling and cross-platform support. Ideal for safe file operations in Symfony and beyond.
## Getting Started
### Minimal Steps
1. **Installation**:
```bash
composer require symfony/filesystem:^8.1
No configuration is required—use the Symfony\Component\Filesystem\Filesystem class directly.
First Use Case:
Replace native PHP filesystem operations (e.g., mkdir, copy, unlink) with the Filesystem class for cross-platform reliability and mode preservation (new in v8.1.0-BETA2).
use Symfony\Component\Filesystem\Filesystem;
$fs = new Filesystem();
$fs->mkdir('path/to/directory'); // Cross-platform path handling
$fs->copy('source.txt', 'destination.txt', true); // `true` preserves file mode (NEW in v8.1.0-BETA2)
Where to Look First:
Symfony\Component\Filesystem\Filesystem class methods (e.g., dumpFile, exists, remove, mirror).app('filesystem') if wrapping in a Laravel service provider.Path Normalization:
Use Path helper for cross-platform path manipulation (e.g., joining, normalizing).
use Symfony\Component\Filesystem\Path;
$path = Path::makeAbsolute('relative/path', '/base/dir'); // Resolves to `/base/dir/relative/path`
$normalized = Path::normalize('/dir//with/../duplicates'); // `/dir`
Directory Operations:
$fs->mkdir(['dir1/dir2', 'dir3'], 0775); // Sets permissions
$fs->mirror('source', 'destination'); // Copies recursively
File Operations:
$fs->dumpFile('file.txt', 'content'); // Writes atomically
$fs->copy('source.txt', 'dest.txt', true); // `true` preserves file mode (NEW)
$tempFile = $fs->tempnam(sys_get_temp_dir(), 'prefix_');
$fs->remove($tempFile); // Cleanup
File Mode Handling (NEW in v8.1.0-BETA2): Explicitly preserve file permissions during copy/move operations:
$fs->copy('source.txt', 'dest.txt', true); // Preserves mode
$fs->move('source.txt', 'dest.txt', true); // Preserves mode (NEW in v8.1.0-BETA2)
Service Provider Binding:
Bind the Filesystem class for dependency injection:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton(Filesystem::class, function () {
return new Filesystem();
});
}
Artisan Commands: Use in commands for CLI operations (e.g., backups, deployments) with mode preservation:
use Symfony\Component\Filesystem\Filesystem;
class BackupCommand extends Command
{
protected $fs;
public function __construct(Filesystem $fs)
{
parent::__construct();
$this->fs = $fs;
}
protected function handle()
{
$this->fs->mirror(storage_path('app'), backup_path('app'));
$this->fs->chmod(backup_path('app'), 0755); // Ensure backup dir has correct permissions
}
}
Event Listeners: Handle filesystem events with mode-aware operations:
use Symfony\Component\Filesystem\Filesystem;
class HandleUpload
{
public function __construct(private Filesystem $fs) {}
public function handle($event)
{
$this->fs->copy($event->source, $event->destination, true); // Preserve mode
}
}
Testing:
Use Filesystem in tests to mock filesystem operations, including mode checks:
public function testFileCopyPreservesMode()
{
$fs = $this->createMock(Filesystem::class);
$fs->expects($this->once())->method('copy')->with('source.txt', 'dest.txt', true);
// ...
}
Windows/Linux Path Quirks:
Path::makeAbsolute may incorrectly replace backslashes on UNIX systems (fixed in v8.0.9). Always use forward slashes or DIRECTORY_SEPARATOR.makePathRelative may remove trailing slashes for existing files (fixed in v8.0.6). Use Path::canonicalize for consistency.Permission Issues:
Filesystem::remove() may fail on Windows due to locked files (fixed in v7.1.2). Use try-catch blocks:
try {
$fs->remove($file);
} catch (\RuntimeException $e) {
// Handle locked files
}
Atomic Writes:
dumpFile uses atomic writes, but large files may still cause partial writes on slow storage. For critical data, implement checksum verification.Temporary Files:
tempnam with explicit cleanup or try-finally blocks.Recursive Operations:
mirror and remove can be slow for large directories. Use limitDepth for performance:
$fs->mirror('source', 'dest', ['limitDepth' => 2]);
Mode Preservation Edge Cases (NEW in v8.1.0-BETA2):
lchmod if needed:
if (is_link('symlink.txt')) {
lchmod('symlink.txt', 0777);
} else {
$fs->copy('source.txt', 'dest.txt', true);
}
setgid) may not be preserved. Use chmod post-copy if required.Path Normalization:
Use Path::canonicalize to debug path issues:
$path = Path::canonicalize('/dir/../relative/path');
// Outputs: `/relative/path` (absolute)
File Existence: Check existence before operations to avoid errors:
if ($fs->exists('file.txt')) {
$fs->remove('file.txt');
}
Permissions:
Use chmod to debug permission issues or verify mode preservation:
$fs->chmod('file.txt', 0644); // Set expected mode
$actualMode = fileperms('file.txt'); // Verify
Logging: Enable Symfony’s debug mode to log filesystem operations:
$fs = new Filesystem();
$fs->setDebug(true); // Logs operations to stderr
Mode Verification (NEW in v8.1.0-BETA2): Verify mode preservation after copy/move:
$fs->copy('source.txt', 'dest.txt', true);
$sourceMode = fileperms('source.txt');
$destMode = fileperms('dest.txt');
$this->assertEquals($sourceMode, $destMode);
Custom Filesystem Adapter:
Extend Filesystem for custom storage backends (e.g., S3) with mode handling:
class CustomFilesystem extends Filesystem
{
public function customCopy($source, $dest, $preserveMode = true) {
if ($preserveMode) {
$mode = fileperms($source);
parent::copy($source, $dest, true);
chmod($dest, $mode);
} else {
parent::copy($source, $dest);
}
}
}
Event Dispatching: Dispatch events for critical operations (e.g., file creation with mode):
$fs->copy('source.txt', 'dest.txt', true);
event(new FileCopied('dest.txt', fileperms('dest.txt')));
Path Manipulation:
Override Path for project-specific rules or mode-aware paths
How can I help you explore Laravel packages today?