async-aws/s3
AsyncAws S3 is a lightweight, async-friendly PHP client for Amazon S3. Install via Composer and interact with S3 using the AsyncAws ecosystem, with CI/BC checks and full docs available at async-aws.com.
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require async-aws/s3
Requires PHP 8.2+ and Laravel 9+ (or standalone usage).
Basic Client Initialization:
use AsyncAws\S3\S3Client;
$client = new S3Client([
'region' => 'us-east-1',
'version' => 'latest',
'credentials' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
],
]);
First Use Case: Upload a File
$result = $client->putObject([
'Bucket' => 'my-bucket',
'Key' => 'path/to/file.txt',
'Body' => fopen('local-file.txt', 'r'),
]);
Where to Look First:
AsyncAws\S3\S3Client class (core methods)AsyncAws\S3\Input\* and AsyncAws\S3\Result\* namespaces (request/response objects)$client->putObject([
'Bucket' => 'my-bucket',
'Key' => 'file.jpg',
'Body' => fopen('image.jpg', 'r'),
'Metadata' => ['author' => 'John Doe'],
]);
$result = $client->getObject([
'Bucket' => 'my-bucket',
'Key' => 'file.jpg',
]);
file_put_contents('local-file.jpg', $result->getBody()->getContents());
$result = $client->getObject(['Bucket' => 'my-bucket', 'Key' => 'large-file.zip']);
$result->getBody()->pipe($outputStream); // Stream directly to another location
$client->createBucket(['Bucket' => 'new-bucket']);
$client->deleteBucket(['Bucket' => 'empty-bucket']);
$buckets = $client->listBuckets()->getBuckets();
// Initiate
$uploadId = $client->createMultipartUpload([
'Bucket' => 'my-bucket',
'Key' => 'large-file.zip',
])->getUploadId();
// Upload parts
$parts = [];
foreach (range(1, 10) as $partNumber) {
$result = $client->uploadPart([
'Bucket' => 'my-bucket',
'Key' => 'large-file.zip',
'PartNumber' => $partNumber,
'UploadId' => $uploadId,
'Body' => fopen("part-$partNumber.dat", 'r'),
]);
$parts[] = $result->getPart();
}
// Complete
$client->completeMultipartUpload([
'Bucket' => 'my-bucket',
'Key' => 'large-file.zip',
'UploadId' => $uploadId,
'MultipartUpload' => ['Parts' => $parts],
]);
$client->putBucketVersioning([
'Bucket' => 'my-bucket',
'VersioningConfiguration' => ['Status' => 'Enabled'],
]);
$client->putBucketLifecycleConfiguration([
'Bucket' => 'my-bucket',
'LifecycleConfiguration' => [
'Rules' => [
[
'ID' => 'rule1',
'Status' => 'Enabled',
'Filter' => ['Prefix' => 'logs/'],
'Transitions' => [
['StorageClass' => 'GLACIER', 'Days' => 30],
],
],
],
],
]);
$presignedUrl = $client->getObjectUrl(
'my-bucket',
'file.jpg',
'+1 hour' // Expiry time
);
use AsyncAws\S3\S3Client;
class S3ServiceProvider extends ServiceProvider {
public function register() {
$this->app->singleton(S3Client::class, function ($app) {
return new S3Client([
'region' => config('aws.region'),
'credentials' => [
'key' => config('aws.key'),
'secret' => config('aws.secret'),
],
]);
});
}
}
use Illuminate\Support\Facades\Facade;
class S3Facade extends Facade {
protected static function getFacadeAccessor() {
return S3Client::class;
}
}
use App\Facades\S3;
public function upload() {
$result = S3::putObject([...]);
}
try {
$client->getObject(['Bucket' => 'my-bucket', 'Key' => 'nonexistent.txt']);
} catch (\AsyncAws\Core\Exception\S3Exception $e) {
if ($e->getAwsErrorCode() === 'NoSuchKey') {
// Handle missing file
}
}
Region Configuration:
createBucket) require LocationConstraint for non-us-east-1 regions.$client->createBucket([
'Bucket' => 'my-bucket',
'CreateBucketConfiguration' => ['LocationConstraint' => 'eu-west-1'],
]);
Path vs. Virtual Hosted-Style Endpoints:
https://bucket.s3.amazonaws.com). To use path-style (e.g., https://s3.amazonaws.com/bucket), set:
$client = new S3Client(['s3PathStyleEndpoint' => true]);
Metadata Handling:
x-amz-meta- prefix when setting. AsyncAws handles this internally.// Correct
$client->putObject([
'Bucket' => 'my-bucket',
'Key' => 'file.txt',
'Metadata' => ['author' => 'John Doe'], // No prefix
]);
Large File Uploads:
createMultipartUpload, uploadPart, and completeMultipartUpload methods.CORS Configuration:
AllowedHeaders, AllowedMethods, and ExposeHeaders are correctly formatted as arrays.$client->putBucketCors([
'Bucket' => 'my-bucket',
'CORSConfiguration' => [
'CORSRules' => [
[
'AllowedHeaders' => ['*'],
'AllowedMethods' => ['GET', 'PUT', 'POST', 'DELETE'],
'AllowedOrigins' => ['https://example.com'],
'ExposeHeaders' => ['ETag'],
],
],
],
]);
Presigned URLs:
// Relative time
$url = $client->getObjectUrl('bucket', 'key', '+1 hour');
// Absolute time (DateTimeImmutable)
$url = $client->getObjectUrl('bucket', 'key', new \DateTimeImmutable('+1 hour'));
Concurrency and Retries:
$client = new S3Client([
'retry' => [
'max_attempts' => 3,
'delay' => 100, // ms
],
]);
**PHP 8.2+
How can I help you explore Laravel packages today?