AdachSoft FileSystem Library

A robust PHP filesystem abstraction library providing both physical and in-memory filesystem implementations with security features and comprehensive error handling.
🚀 Features
- Dual filesystem implementations: Physical filesystem and in-memory filesystem
- Security-first design: Path traversal protection and input validation
- Immutable models: Path, FileInfo, and FileSearchCriteria classes
- Comprehensive error handling: Custom exception hierarchy
- Collection support: PathCollection integration with AdachSoft Collection
- File search capabilities: Advanced file filtering with criteria
- Cross-platform compatibility: Unix and Windows path normalization
- PSR-4 autoloading: Modern PHP standards
📦 Installation
Method 1: Composer Configuration via CLI (Recommended)
Add the private repository and install:
composer config repositories.adachsoft/filesystem vcs https://gitlab.com/a.adach/filesystem.git
composer config repositories.adachsoft/collection vcs https://gitlab.com/a.adach/collections.git
composer require adachsoft/filesystem
Method 2: Manual composer.json Configuration
Add the repositories to your composer.json:
{
"repositories": [
{
"type": "vcs",
"url": "https://gitlab.com/a.adach/filesystem.git"
},
{
"type": "vcs",
"url": "https://gitlab.com/a.adach/collections.git"
}
],
"require": {
"adachsoft/filesystem": "^1.0"
}
}
Then run:
composer install
Method 3: One-liner Command
Execute all commands at once:
composer config repositories.adachsoft/filesystem vcs https://gitlab.com/a.adach/filesystem.git && composer config repositories.adachsoft/collection vcs https://gitlab.com/a.adach/collections.git && composer require adachsoft/filesystem
🎯 Quick Start
Physical FileSystem
<?php
use AdachSoft\FileSystem\PhysicalFileSystem;
use AdachSoft\FileSystem\Model\Path;
$fs = new PhysicalFileSystem('/var/www/project');
$fs->writeFile(new Path('config/app.yml'), 'database: mysql');
$content = $fs->readFile(new Path('config/app.yml'));
if ($fs->fileExists(new Path('config/app.yml'))) {
echo "File exists!";
}
$fs->createDirectory(new Path('uploads/images'));
$contents = $fs->listContents(new Path('uploads'));
foreach ($contents as $path) {
echo $path->toString() . "\n";
}
In-Memory FileSystem
<?php
use AdachSoft\FileSystem\InMemoryFileSystem;
use AdachSoft\FileSystem\Model\Path;
$fs = new InMemoryFileSystem();
$fs->writeFile(new Path('test.txt'), 'Hello World');
$fs->createDirectory(new Path('docs'));
$fs->reset();
Working with Paths
<?php
use AdachSoft\FileSystem\Model\Path;
$path = new Path('config/database.yml');
$basename = $path->getBasename();
$parent = $path->getParent();
$newPath = $path->getParent()->join('cache.yml');
echo $path->toString();
File Search with Criteria
<?php
use AdachSoft\FileSystem\PhysicalFileSystem;
use AdachSoft\FileSystem\Model\Path;
use AdachSoft\FileSystem\Model\FileSearchCriteria;
$fs = new PhysicalFileSystem('/var/www/project');
$criteria = new FileSearchCriteria(
directory: new Path('src'),
filename: '*.php',
extension: 'php',
recursive: true
);
$phpFiles = $fs->findFiles($criteria);
$criteria = FileSearchCriteria::create(new Path('tests'))
->withFilename('Test.php')
->withExtension('php')
->withRecursive(false);
$testFiles = $fs->findFiles($criteria);
Working with File Information
<?php
use AdachSoft\FileSystem\PhysicalFileSystem;
use AdachSoft\FileSystem\Model\Path;
$fs = new PhysicalFileSystem('/var/www/project');
$fileInfo = $fs->getFileInfo(new Path('composer.json'));
echo "Path: " . $fileInfo->getPath()->toString() . "\n";
echo "Size: " . $fileInfo->getSize() . " bytes\n";
echo "Modified: " . $fileInfo->getLastModified()->format('Y-m-d H:i:s') . "\n";
echo "Is file: " . ($fileInfo->isFile() ? 'Yes' : 'No') . "\n";
echo "Is directory: " . ($fileInfo->isDirectory() ? 'Yes' : 'No') . "\n";
$timestamp = $fs->getLastModifiedTime(new Path('composer.json'));
$fileSize = $fs->getFileSize(new Path('composer.json'));
Path Collections
<?php
use AdachSoft\FileSystem\Model\PathCollection;
use AdachSoft\FileSystem\Model\Path;
$paths = new PathCollection([
new Path('src/FileSystem.php'),
new Path('src/Model/Path.php'),
new Path('tests/FileSystemTest.php')
]);
foreach ($paths as $path) {
echo $path->toString() . "\n";
}
📚 API Reference
FileSystemInterface Methods
writeFile(Path $path, string $content): void | Write content to file |
readFile(Path $path): string | Read file content |
deleteFile(Path $path): void | Delete file |
fileExists(Path $path): bool | Check if file exists |
createDirectory(Path $path): void | Create directory |
deleteDirectory(Path $path, bool $recursive = false): void | Delete directory |
directoryExists(Path $path): bool | Check if directory exists |
pathExists(Path $path): bool | Check if path exists |
isDir(Path $path): bool | Check if path is directory |
isFile(Path $path): bool | Check if path is file |
listContents(Path $path): PathCollection | List direct children of a directory as paths relative to the filesystem root (base path) |
move(Path $source, Path $destination): void | Move/rename file or directory |
getFileInfo(Path $path): FileInfo | Get file information |
getLastModifiedTime(Path $path): int | Get last modified timestamp |
getFileSize(Path $path): int | Get file size in bytes |
findFiles(FileSearchCriteria $criteria): PathCollection | Find files by criteria |
Model Classes
Path
__construct(string $path) - Create path object
toString(): string - Get string representation
getBasename(): string - Get filename/directory name
getParent(): Path - Get parent directory
join(string|Path $path): Path - Join with another path
FileInfo
getPath(): Path - Get file path
getSize(): int - Get file size
getLastModified(): DateTimeImmutable - Get modification date
isFile(): bool - Check if is file
isDirectory(): bool - Check if is directory
FileSearchCriteria
create(Path $directory): self - Create search criteria
withFilename(string $filename): self - Set filename pattern
withExtension(string $extension): self - Set file extension
withExcludedDirectories(PathCollection $dirs): self - Set excluded directories
withRecursive(bool $recursive): self - Set recursive search
PathCollection
- Extends
AbstractImmutableCollection<Path>
- Type-safe collection of Path objects
Exception Classes
FileSystemException - Base exception class
FileNotFoundException - File not found
DirectoryNotFoundException - Directory not found
FileSystemIOException - I/O operation failed
PathTraversalException - Path traversal attempt detected
🧪 Testing
Run the test suite:
composer test
Run tests with coverage:
composer test-coverage
🔒 Security Features
- Path traversal protection: All paths are validated against base directory
- Input sanitization: Windows and Unix path normalization
- Safe directory operations: Recursive deletion requires explicit flag
- Immutable models: Prevents accidental state changes
🏗️ Development Setup
git clone https://gitlab.com/a.adach/filesystem.git
cd filesystem
composer install
composer test
🤝 Contributing
Contributions are welcome! Please feel free to submit a Merge Request.
- Fork the repository on GitLab
- Create your feature branch (
git checkout -b feature/amazing-feature)
- Commit your changes (
git commit -m 'Add some amazing feature')
- Push to the branch (
git push origin feature/amazing-feature)
- Open a Merge Request on GitLab
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Support
For support and questions:
🔗 Links