kinetis / storage-s3
S3 (and S3-compatible) file storage for Kinetis, plugging into kinetis/storage's FILESYSTEM_DRIVER=s3 — every S3 call travels on a Revolt-native HTTP transport.
Requires
- php: ^8.4
- amphp/http-client: ^5.3.6
- async-aws/core: ^1.29.2
- async-aws/s3: ^3.4.1
- kinetis/framework: ^1.27.1
- kinetis/revolt-http-client: ^1.6.0
- kinetis/storage: ^1.2.8
- league/flysystem: ^3.35.3
- league/flysystem-async-aws-s3: ^3.31.0
Requires (Dev)
- infection/infection: ^0.35.0
- phpstan/phpstan: ^2.2.8
- phpunit/phpunit: ^13.3.3
- vimeo/psalm: ^7.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
kinetis/storage-s3
S3 (and S3-compatible) file storage for Kinetis, plugging into kinetis/storage's FILESYSTEM_DRIVER=s3
Part of Kinetis, a non-blocking PHP framework for API-first applications, developed in the kinetis-dev/kinetis monorepo.
The same League\Flysystem\FilesystemOperator interface kinetis/storage
gives local disk, backed by League\Flysystem\AsyncAwsS3\AsyncAwsS3Adapter
over an AsyncAws S3 client instead. Every call travels on
kinetis/revolt-http-client's Revolt-native HTTP
transport, injected in place of the SDK's default blocking one, so it
suspends the calling Fiber.
Objects are private and writes and copies carry no ACL, so a bucket with
Object Ownership set to bucket owner enforced works unchanged; grant
public read through a bucket policy. The failures S3 reports under HTTP 200 — a
broken copy, a batch delete that refused keys — are read rather than
taken as success. deleteDirectory() lists and deletes one page of at
most 1,000 keys at a time, so a failure part-way leaves earlier pages
deleted.
use Kinetis\Storage\FilesystemFactory; $storage = FilesystemFactory::fromConfig($config); // FILESYSTEM_DRIVER=s3 $storage->write('avatars/user-42.png', $imageContents); $contents = $storage->read('avatars/user-42.png'); $storage->delete('avatars/user-42.png');
Configuration
FILESYSTEM_DRIVER=s3
FILESYSTEM_S3_BUCKET=my-app-bucket
FILESYSTEM_S3_REGION=us-east-1
| Key | Default | Purpose |
|---|---|---|
FILESYSTEM_S3_BUCKET |
(required) | Bucket name. |
FILESYSTEM_S3_REGION |
(required) | AWS region. |
FILESYSTEM_S3_PREFIX |
— | Key prefix. |
FILESYSTEM_S3_ENDPOINT |
— | S3-compatible endpoint instead of AWS (e.g. MinIO) — one origin, addressed path-style. |
FILESYSTEM_S3_PLAINTEXT |
false |
Allow an http:// endpoint. |
FILESYSTEM_S3_TIMEOUT |
60 |
Seconds per S3 request — connect, idle and transfer alike, not one deadline per operation. |
FILESYSTEM_S3_ACCESS_KEY_ID |
— | Static access key for this connection only; set with the secret or not at all. |
FILESYSTEM_S3_SECRET_ACCESS_KEY |
— | Secret for FILESYSTEM_S3_ACCESS_KEY_ID. |
Every key is scoped — FILESYSTEM_S3_BUCKET + backups →
FILESYSTEM_BACKUPS_S3_BUCKET. Full reference:
kinetis.dev/docs/config.html.
With both credential keys set, the connection signs with exactly those
keys and nothing else, so an S3-compatible service's keys stay out of
the AWS_* variables other AWS clients in the process read. Without
them, AsyncAws's standard provider chain resolves credentials. Every
provider in that chain that calls AWS uses the same Revolt transport as
the client, while the shared credentials and config files and any token
file are read with native blocking calls. Full detail:
kinetis.dev/docs/storage-s3.html.
Installation
composer require kinetis/storage-s3
Requires PHP 8.4+, kinetis/framework,
kinetis/storage, and
kinetis/revolt-http-client.
Full documentation:
kinetis.dev/docs/storage-s3.html.
License
MIT — see LICENSE.