{"id":18736701,"url":"https://github.com/radiergummi/filesystem","last_synced_at":"2025-11-16T18:30:12.923Z","repository":{"id":88616932,"uuid":"244175840","full_name":"Radiergummi/filesystem","owner":"Radiergummi","description":"A simple and modern filesystem abstraction layer for PHP","archived":false,"fork":false,"pushed_at":"2020-03-02T09:25:10.000Z","size":30,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-28T16:46:46.229Z","etag":null,"topics":["filesystem","php","psr-17","psr-7","storage"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Radiergummi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-01T15:40:34.000Z","updated_at":"2020-05-31T07:39:26.000Z","dependencies_parsed_at":"2024-03-25T11:47:56.049Z","dependency_job_id":null,"html_url":"https://github.com/Radiergummi/filesystem","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Radiergummi%2Ffilesystem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Radiergummi%2Ffilesystem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Radiergummi%2Ffilesystem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Radiergummi%2Ffilesystem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Radiergummi","download_url":"https://codeload.github.com/Radiergummi/filesystem/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239611992,"owners_count":19668274,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filesystem","php","psr-17","psr-7","storage"],"created_at":"2024-11-07T15:22:11.114Z","updated_at":"2025-11-16T18:30:12.888Z","avatar_url":"https://github.com/Radiergummi.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"FileSystem\n==========\n\u003e A convenient abstraction layer for file system operations, wrapping all kinds of storage types with a single API.\n\nFeatures\n--------\n - **Use any kind of storage backend interchangeably.** FileSystem includes a generic \n   [`AdapterInterface`](./src/AdapterInterface.php) for storage adapters. They can be used as drop-in replacements.\n - **Streams and generators.** FileSystem relies on [PSR-7](https://www.php-fig.org/psr/psr-7/) and \n   [PSR 17](https://www.php-fig.org/psr/psr-17/) streams for reading file content. This has massive benefits in terms of\n   performance, as adapters can stream file content on demand.  \n   Directory content is delivered as traversable generators, reducing the memory footprint even further.\n - **Opt-in Caching.** FileSystem supports [PSR-16](tps://www.php-fig.org/psr/psr-16/) caches to improve performance, \n   independent of the adapter used.\n - **Common Exceptions for common errors.** FileSystem provides a range of default exceptions for common error cases \n   that might occur in any implementation: Missing or existing files, bad permissions or invalid target path specs, for\n   example.\n - **Easily extensible.** FileSystem exposes several interfaces, making it really easy to add new adapters. \n\n\n### Why shouldn't I just use [FlySystem](https://github.com/thephpleague/flysystem)?\nWhile FlySystem is an excellent library and has always been my go-to solution whenever I had to work with files, I think\nit has outlived it's usefulness: Since it's conception, the PHP ecosystem has vastly improved. We now have PSR \nstandards, ubiquitous exception handling, type hints and generators. FlySystem does not make use of any of these and in\nsome cases the maintainers have declared outright resistance.\n\nFileSystem strives to provide a modern, fast and standards-compliant way to work with storage, independent of the \nunderlying implementation.\n\nInstallation\n------------\n\u003e **Note:** FileSystem is still in early development and there is no package available via composer yet. If you would \n\u003e like to contribute, fork the project and clone it via git.\n\nInstall using composer:\n```bash\ncomposer require radiergummi/filesystem\n```\n\nUsage\n-----\nIn the simplest case, all you need is an adapter and a `FileSystem` instance:\n```php\nuse Radiergummi\\FileSystem\\Adapters\\LocalAdapter;\nuse Radiergummi\\FileSystem\\Exceptions\\FileSystemException;\nuse Radiergummi\\FileSystem\\FileSystem;\n\n$adapter = new LocalAdapter();\n$fileSystem = new FileSystem($adapter);\n\ntry {\n    $file = $fileSystem-\u003ereadFile('/foo/bar.txt');\n    $contents = $file-\u003egetStream(); // PSR-7 StreamInterface\n    $metaData = $file-\u003egetMetaData(); \n} catch (FileSystemException $exception) {\n    // Handle the error\n    $exception-\u003egetPath(); // Getter for the affected path\n}\n```\n\nMethod reference\n----------------\nThe file system exposes the following methods:\n\n - [`exists(string $path): bool`](#exists)\n - [`readFile(string $path): ?File`](#read-file)\n - [`getMetaData(string $path): ?MetaData`](#get-meta-data)\n - [`readDirectory(?string $directory = null, bool $recursive = false): Generator`](#read-directory)\n - [`writeFile(string $path, StreamInterface $contents, ?int $flags = null): void`](#write-file)\n - [`rename(string $sourcePath, string $newName): void`](#rename)\n - [`copy(string $sourcePath, string $destinationPath): void`](#copy)\n - [`move(string $sourcePath, string $destinationPath): void`](#move)\n - [`deleteFile(string $path): void`](#delete-file)\n - [`deleteDirectory(string $path): void`](#delete-directory)\n - [`createDirectory(string $path): void`](#create-directory)\n - [`getAdapter(): AdapterInterface`](#get-adapter)\n\n### Exists\nChecks whether an entity exists at a given path. This works for both files and directories.\n\n**Signature:**\n```php\npublic function exists(string $path): bool\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the entity does not exist.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the entity is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the entity is located outside of the configured file \n   system root.\n\n### Read File\nReads a file at a given path and returns a new [`File`](#file-objects) instance. Files expose a range of convenience \nmethods in addition to getters for the content stream and [`MetaData`](#metadata-objects) instance.  \n\n**Signature:**\n```php\npublic function readFile(string $path): ?File\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the file does not exist.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the parent segment of the file path is \n   not a directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the file is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the file is located outside of the configured file \n   system root.\n\n### Get Meta Data\nRetrieves a [`MetaData`](#metadata-objects) instance, _if the adapter supports it_. Null will be returned otherwise.\n\n**Signature:**\n```php\npublic function getMetaData(string $path): ?MetaData\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the file or directory does not exist.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the entity is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the entity is located outside of the configured file \n   system root.\n\n### Read Directory\nLists the contents of a directory at the given path. The method always returns a generator, allowing you to efficiently\niterate the results, even if they grow very large. It's up to the adapter implementation to make use of the generator, \nallowing for both files being fetched during iteration or beforehand, including pagination handling etc.  \nThe results will be instances of `FileSystemEntity`, giving you access to their content and meta data.\n\nAdapters that don't support directories should handle this call by returning a flat list of files or use the path to \notherwise figure out the files the user is looking for.\n\n**Signature:**\n```php\npublic function readDirectory(?string $path = null, bool $recursive = false): Generator\u003cFileSystemEntity\u003e\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the directory does not exist.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the entity at the target path is not a\n   directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the directory is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the directory is located outside of the configured file \n   system root.\n\n### Write File\nWrites to a file at the given path.\n\n**Signature:**\n```php\npublic function writeFile(string $path, StreamInterface $contents, ?int $flags = null): void\n```\n\n**Possible errors:**  \n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the parent segment of the file path is \n   not a directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the file is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the file is located outside of the configured file \n   system root.\n\n### Rename\nRenames a file _or directory_ in place: While the first parameter has to be the full file path, the second is designed \nto be the new file base name only. Therefore, to rename `/foo/bar/baz.txt` to `/foo/bar/quz.json`, you would call it as\n`rename('/foo/bar/baz.txt', 'quz.json')`. To move the file to a new path, use the\n[`move`](#movestring-sourcepath-string-destinationpath-void) method instead. Adapter implementations will forward this \nto a `move` call in most cases.\n\n**Signature:**\n```php\npublic function rename(string $path, string $newName): void\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the entity does not exist.\n - [Entity Exists](#entityexistsexception). Will be thrown if an entity exists at the target path.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the entity is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the entity is located outside of the configured file  \n   system root.\n\n### Copy\nCopies a file _or directory_ from the source path to the destination path. Directories will be copied recursively, if \nthe underlying file system supports it. \n\n**Signature:**\n```php\npublic function copy(string $sourcePath, string $destinationPath): void\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the source entity does not exist.\n - [Entity Exists](#entityexistsexception). Will be thrown if an entity exists at the target path.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the parent segment of the target path  \n   is not a directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the entity is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the entity is located outside of the configured file  \n   system root.\n\n### Move\nMoves a file _or directory_ from the source path to the destination path.\n\n**Signature:**\n```php\npublic function move(string $sourcePath, string $destinationPath): void\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the source entity does not exist.\n - [Entity Is A Directory](#entityisdirectoryexception). Will be thrown if the source entity is a file and the target\n   entity is a directory.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the source entity is a directory and \n   the target entity is a file, or the parent segment of the target path is not a directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the entity is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the entity is located outside of the configured file  \n   system root.\n\n### Delete File\nDeletes a file on the file system. This operation will fail for directories, so you should use the \n[`deleteDirectory`](#deletedirectorystring-path-void) method instead. While it would technically be possible do support\nboth from the same method, prohibiting this was a deliberate design choice: Using the `deleteDirectory` method makes the\nintent to delete a full directory absolutely clear, potentially helping to avoid shredding entire directory trees by \naccident.\n\n**Signature:**\n```php\npublic function deleteFile(string $path): void\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the directory does not exist.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the parent segment of the file path is \n   not a directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the file is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the file is located outside of the configured file  \n   system root.\n\n### Delete Directory\nDeletes a directory _and all its contents_. This may or may not be supported by the underlying file system but adapter \nimplementations should take care to handle this fact transparently.\n\n**Signature:**\n```php\npublic function deleteDirectory(string $path): void\n```\n\n**Possible errors:**  \n - [Entity Not Found](#entitynotfoundexception). Will be thrown if the directory does not exist.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the entity at the given path is not a \n   directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the file is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the directory is located outside of the configured file \n   system root.\n\n### Create Directory\nCreates a new directory. This may or may not be supported by the underlying file system but adapter implementations \nshould take care to handle this fact transparently.\n\n**Signature:**\n```php\npublic function createDirectory(string $path): void\n```\n\n**Possible errors:**  \n - [Entity Exists](#entityexistsexception). Will be thrown if an entity exists at the target path.\n - [Entity Is Not A Directory](#entityisnodirectoryexception). Will be thrown if the parent segment of the file path is \n   not a directory.\n - [Entity Is Not Accessible](#entitynotaccessibleexception). Will be thrown if the directory is not accessible due to \n   insufficient permissions, or other OS-level errors.\n - [Root Violation](#rootviolationexception). Will be thrown if the file is located outside of the configured file  \n   system root.\n   \n### Get Adapter\nRetrieves the adapter instance. This method exists as an escape hatch in case you need to perform an operation not \ndirectly supported by FileSystem without breaking the encapsulation. I recommend avoiding this, tho.\n\n**Signature:**\n```php\npublic function getAdapter(): AdapterInterface\n```\n\nErrors\n------\nFileSystem includes a range of exceptions for common file system errors. All of them inherit from a single base \nexception, which in turn inherits from the [`FileSystemException`](./src/Exceptions/FileSystemException.php). This \nallows you to handle errors as fine or coarse as needed.\n\n### [`EntityExistsException`](./src/Exceptions/EntityExistsException.php)\nWill be thrown if an entity exists but the current call requires it to not exist.\n\n### [`EntityIsDirectoryException`](./src/Exceptions/EntityIsDirectoryException.php)\nWill be thrown if an entity is a directory but the current call requires a file.\n\n### [`EntityIsNoDirectoryException`](./src/Exceptions/EntityIsNoDirectoryException.php)\nWill be thrown if an entity is not a directory but the current call requires a directory.\n\n### [`EntityNotAccessibleException`](./src/Exceptions/EntityNotAccessibleException.php)\nWill be thrown if an entity is not accessible. This might have a wide number of reasons, among them insufficient \npermissions, network or protocol errors or other OS-level failures.\n\n### [`EntityNotFoundException`](./src/Exceptions/EntityNotFoundException.php)\nWill be thrown if an entity cannot be found on the file system.\n\n### [`RootViolationException`](./src/Exceptions/RootViolationException.php)\nWill be thrown if a target path resolves to a target outside of the configured file system root. This effectively \nprevents [directory traversal attacks](https://en.wikipedia.org/wiki/Directory_traversal_attack).\n\n`File` Objects\n--------------\nFile objects provide a wrapper around files, their content and associated meta data. They are constructed with lazy\ngetters for content and meta data which are only invoked the first time you call them.\n\n`MetaData` Objects\n------------------\nMeta data objects provide a set of general meta data that _should_ be common to most storage backends:\n - **File size:** Size of the file in bytes. Should be `0` for directories.\n - **Last modification time:** Timestamp of the last modification as an immutable `DateTime`. Will be `null` if not \n   applicable.\n - **Creation time:** Timestamp of creation as an immutable `DateTime`. Will be `null` if not applicable.\n - **Other meta data:** Associative array of additional, adapter-specific meta data.\n\nCaching and Logging\n-------------------\nFileSystem includes several extension interfaces for the `FileSystem` class that add caching or logging as an add-in. To\nuse them, you need a file system instance that implements those interfaces. The default implementation already extends \nthese interfaces, so all you need to add caching (if your DI container doesn't inject it already), is using the \n`setCache(CacheInterface $cache)` method, and the same goes for PSR-3 logging.\n\nAvailable Adapters\n------------------\nFrom the get-go, only a small number of adapters is supported. This will increase over time as new adapters are added.  \nIf you feel an adapter is missing, please open a PR or an issue.\n\n### Included\n - Local disk file systems: `Radiergummi\\FileSystem\\Adapters\\LocalAdapter`\n - (S)FTP file systems: `Radiergummi\\FileSystem\\Adapters\\FtpAdapter`\n - AWS S3 file systems: `Radiergummi\\FileSystem\\Adapters\\AwsS3Adapter`\n\nCreating new Adapters\n---------------------\nAll adapters must implement the [`AdapterInterface`](./src/Interfaces/AdapterInterface.php). The methods define a clear\nset of parameter and return types, including `@throws` tags for all known exceptions the method might throw. Make sure\nto adhere to the reasons laid out [above](#method-reference).  \nFor any exception an adapter might throw _that doesn't fit in those categories_, you should clearly document the \nbehaviour. All exceptions should bubble up for the user to catch, but that requires them to know about it. \n\nContributing\n------------\nSend in a PR or open an issue :) The process will be fleshed out after the initial release.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradiergummi%2Ffilesystem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fradiergummi%2Ffilesystem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradiergummi%2Ffilesystem/lists"}