pvmlibs/simple-s3

Lightweight S3 connector for PHP

Maintainers

Package info

github.com/pvmlibs/simple-s3

pkg:composer/pvmlibs/simple-s3

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-01-07 18:12 UTC

This package is auto-updated.

Last update: 2026-03-07 18:53:31 UTC


README

CI Status codecov

Simple, lightweight S3 connector for PHP

If you need just basic file operations for S3-compatible services, official AWS SDK seems overkill as it weights ~50MB (~4MB ofter stripping all non-essential services) and just loading it takes 15,03MB of RAM + 0,72MB for request to list bucket objects. This library is ~40kB in source size and uses 0,055MB of RAM (client object + request to list bucket objects).

Features:

  1. Uses only curl extension
  2. Supports asynchronous mode (*Async methods)
  3. Supports streaming
  4. Actions:
    • getObject
    • putObject
    • headObject
    • deleteObject
  5. Custom actions - assemble your own action e.g. list bucket objects

Requirements

  1. PHP >= 8.1
  2. curl extension

Installation

composer require pvmlibs/simple-s3

Usage

For domain use following schema:

  1. s3.<zone>.amazonaws.com for AWS
  2. <Accound ID>.r2.cloudflarestorage.com for R2

For AWS, bucket name can't include dot (.), otherwise it can't use tls (work with tls: false). R2 doesn't allow for dots in bucket name so problem don't exist here.

$client = new S3Client(/* credentials */);

// synchronous request with streaming to temp file
$response = $client->getObject(bucketPath: 'test.txt');
if ($response->success()) {
    readfile($response->getResponseFilePath());
    // or use resource
    echo fread($response->getResponseResource(), 1000);
}

// synchronous request with streaming directly to custom file
$response = $client->getObject(bucketPath: 'test.txt', customStreamFile: '/var/www/target.txt');

// synchronous request without streaming
$response = $client->getObject(bucketPath: 'test.txt');
if ($response->success()) {
    // no resource pointer available
    echo $response->getResponse();
}

// asynchronous request without streaming
$client->getObjectAsync(bucketPath: 'test-a.txt')
        ->setCustomData(['foo' => 'bar'] // optional
        ->then(function (HttpResponseInterface $response, array $customData): void {
            // do sth on success, $customData is from setCustomData
         })
         ->catch(function (HttpResponseInterface $response, array $customData): void {
            // do sth on fail, $customData is from setCustomData
         });
            
// you can schedule multiple async requests, but they won't be executed until you call this: 
// notice: when calling synchronous methods, it will automatically execute all previously scheduled async methods
$client->waitForRequests();

// upload local file, $contentType will be evaluated from file extension if not provided
$response = $client->putObject(bucketPath: 'test.txt', localFile: '/var/www/source.txt');

// upload local file from resource, $contentType will be evaluated from file extension associated to resource if not provided
$f = fopen('/var/www/source.txt');
$response = $client->putObject(bucketPath: 'test.txt', localFile: $f);
fclose($f);

// upload from string data, $contentType is required
$response = $client->putObjectFromBuffer(bucketPath: 'test.txt', data: 'foo', contentType: 'text/plain');

// custom action, this will list bucket objects
// you can pass additional headers like x-amz-security-token per action to promise here or globally per client in $client->setHeaders()
$response = $client->customAction(new HttpPromise(
            action: 'GET',
            path: '',
            domain: $client->getDomain(),
            query: ['list-type' => 2],
        ));
if ($response->success()) {
    // proceed with xml data from $response->getResponse()
}