Page 1
© 2013 Amazon.com, Inc. and its affiliates. All rights reserved. May not be copied, modified, or distributed in whole or in part without the express consent of Amazon.com, Inc.
Mastering the AWS SDK for PHP
Michael Dowling & Jeremy Lindblom, AWS Developer Resources
November 15, 2013
Page 2
PART 1
PART 2
Using the AWS SDK for PHP
by working with
Amazon S3
High-level features
for common use cases
with the AWS SDK for PHP
Page 3
AWS SDK for PHP
https://github.com/aws/aws-sdk-php
@awsforphp
Follow Us!
Page 4
AWS SDK for PHP
• Suite of HTTP clients for AWS services
• Built on top of Guzzle (guzzlephp.org) – Persistent connections, parallel requests
– Event hooks, plugins, wire logging
• Helpful functionality – Easy pagination
– "waiters"
– Automatic retries
– etc.
Page 5
AWS SDK for PHP – Installing
• Composer / Packagist
• Phar
• Zip
• PEAR
• Yum (Amazon Linux)
Page 6
AWS SDK for PHP – Installing via Composer
{
"require": {
"aws/aws-sdk-php": "~2.4"
}
}
> composer.phar install
In your composer.json:
From your terminal:
http://getcomposer.org
Page 7
Using the AWS SDK for PHP
PART 1
Page 8
Using the AWS SDK for PHP
CreateBucket
PutObject
ListObjects
Amazon S3 operations
Page 9
Amazon Simple Storage Service (Amazon S3)
Scalable storage in the cloud
http://my-stuff.s3.amazonaws.com/photos/kittens.jpg
Bucket Name Object Key
Page 10
Using the AWS SDK for PHP
CreateBucket
PutObject
ListObjects
Page 11
Creating a Bucket – Complete Example
<?php
require 'vendor/autoload.php';
use Aws\Common\Aws;
use Aws\S3\Exception\S3Exception;
$aws = Aws::factory('config.php');
$s3 = $aws->get('s3');
try {
$result = $s3->createBucket([
'Bucket' => 'bucket-name',
]);
$s3->waitUntilBucketExists([
'Bucket' => 'bucket-name',
]);
} catch (S3Exception $e) {
echo $e->getMessage();
}
Page 12
Two Ways to Instantiate a Service Client
1. Client factory method
2. Service builder (Aws\Common\Aws)
Page 13
Instantiate a Client via its Factory Method
use Aws\S3\S3Client;
$s3 = S3Client::factory([
'key' => '{your-aws-access-key-id}',
'secret' => '{your-aws-secret-key}',
// 'region' => 'us-east-1',
]);
Page 14
Instantiate a Client via the Service Builder
<?php
require 'vendor/autoload.php';
use Aws\Common\Aws;
$aws = Aws::factory('/path/to/config.php');
$s3 = $aws->get('s3');
$s3again = $aws->get('s3');
var_dump($s3 === $s3again); #> bool(true)
Page 15
Providing Credentials
• Options array ['key' => '?', 'secret' => '?']
• Configuration file
• Environment credentials – AWS_ACCESS_KEY_ID
– AWS_SECRET_KEY
• IAM Instance Profile credentials
See http://blogs.aws.amazon.com/php
(Providing credentials to the AWS SDK for PHP)
Page 16
Executing a Command
try {
$result = $s3->createBucket([
'Bucket' => $bucket,
]);
} catch (Aws\S3\Exception\S3Exception $e) {
echo $e->getMessage();
}
Page 17
Executing a Command – API Docs
Page 18
Handling a Response – Modeled Responses
$result = $s3->listBuckets();
$result['Buckets']; // Implements ArrayAccess
print_r($result->toArray());
echo $result;
$result->getPath('Buckets/0/Name');
$result->getPath('Buckets/*/Name');
Page 19
Handling a Response – API Docs
Page 20
Wire Logging – Debug Easily
<?php
require 'vendor/autoload.php';
use Aws\Common\Aws;
use Aws\S3\Exception\S3Exception;
use Guzzle\Plugin\Log\LogPlugin;
$aws = Aws::factory('config.php');
$s3 = $aws->get('s3');
$log = LogPlugin::getDebugPlugin();
$s3->addSubscriber($log);
try {
$result = $s3->createBucket([
'Bucket' => 'bucket-name',
]);
$s3->waitUntilBucketExists([
'Bucket' => 'bucket-name',
]);
} catch (S3Exception $e) {
echo $e->getMessage();
}
use Guzzle\Plugin\Log\LogPlugin;
$log = LogPlugin::getDebugPlugin();
$s3->addSubscriber($log);
Page 21
Wire Logging – Output
# Request:
PUT / HTTP/1.1
Host: this-is-my-test-wonderful-bucket.s3.amazonaws.com
User-Agent: aws-sdk-php2/2.4.6 Guzzle/3.7.3 curl/7.25.0 PHP/5.3.27
Date: Wed, 25 Sep 2013 23:03:13 +0000
Authorization: AWS AKIAEXAMPLEEXAMPLE:Xn2lJPREXAMPLEQkPmY0IAUng=
Content-Length: 0
# Response:
HTTP/1.1 200 OK
x-amz-id-2: eNUZEXAMPLEM4U7c/4WPIlshkfVUEXAMPLEUkyKirVgjEXAMPLEsfwZ3Mx
x-amz-request-id: C91E6E8CD19680F7
Date: Wed, 25 Sep 2013 23:03:15 GMT
Location: /this-is-my-test-wonderful-bucket
Page 22
Plugins
• Plugin architecture from Guzzle
• Uses the Symfony Event Dispatcher
• Many plugins included with Guzzle
(Log, Backoff, History, Mock, HTTP Cache, etc.)
Page 23
Wait for it…
<?php
require 'vendor/autoload.php';
use Aws\Common\Aws;
use Aws\S3\Exception\S3Exception;
$aws = Aws::factory('config.php');
$s3 = $aws->get('s3');
try {
$result = $s3->createBucket([
'Bucket' => 'bucket-name',
]);
$s3->waitUntilBucketExists([
'Bucket' => 'bucket-name',
]);
} catch (S3Exception $e) {
echo $e->getMessage();
}
Page 24
Waiters
• Poll resources until available
• Handle asynchronous and eventually consistent
operations more easily
$result = $s3->createBucket([ 'Bucket' => $bucket ]);
$s3->waitUntilBucketExists([ 'Bucket' => $bucket ]);
Page 25
Using the AWS SDK for PHP
CreateBucket
PutObject
ListObjects
Page 26
Uploading an Object to Amazon S3
$result = $s3->putObject([
'Bucket' => 'my-cool-photos',
'Key' => 'photos/photo01.jpg',
'Body' => fopen('/path/to/photo01.jpg', 'r'),
'ACL' => 'public-read',
]);
$url = $result->get('ObjectURL');
Page 27
Command Syntax – Short vs. Long Form
// Short form
$result = $s3->putObject([
// ...
]);
// Long form
$command = $s3->getCommand('PutObject', [
// ...
]);
$result = $command->getResult();
Page 28
Executing Commands in Parallel
$command1 = $s3->getCommand('PutObject', [
'Bucket' => 'my-bucket-name',
'Key' => 'my-first-key',
'Body' => fopen('path/to/file1.ext', 'r')
]);
$command2 = $s3->getCommand('PutObject', [
'Bucket' => 'my-bucket-name',
'Key' => 'my-second-key',
'Body' => fopen('path/to/file2.ext', 'r')
]);
$s3->execute([$command1, $command2]);
Page 29
Using the AWS SDK for PHP
CreateBucket
PutObject
ListObjects
Page 30
Listing Objects in Your Bucket
$result = $s3->listObjects([
'Bucket' => 'my-bucket-name',
]);
$nextResult = $s3->listObjects([
'Bucket' => 'my-bucket-name',
'Marker' => 'photos/photo-1000.jpg',
]);
Page 31
Iterators – Enumerate Your Data Easily
• Iterate through entire result sets
• No handling of markers or tokens
• Lazy loads results
• Compatible with SPL iterators
Page 32
Iterators – Enumerating Your Data Easily
$objects = $s3->getListObjectsIterator([
'Bucket' => 'my-bucket-name',
]);
foreach ($objects as $object) {
echo $object['Key'] . "\n";
}
Page 33
SDK 1.x – A Time Before Iterators
$sk = null;
$people = array();
do {
$params = array('TableName'=>'people');
if ($sk) {
$params['ExclusiveStartKey'] = array(
'HashKeyElement' => array(
'S' => $sk
)
);
$sk= null;
}
$r = $dynamo_db->scan($params);
if ($r->isOK()) {
foreach ($r->body->Items as $item) {
echo (string) $item->name->S;
}
if ($lk = $r->body->LastEvaluatedKey) {
$sk = (string) $lk->HashKeyElement->S;
}
} else {
throw new DynamoDB_Exception('...');
}
}
while ($sk);
Page 34
SDK 1.x – A Time Before Iterators
$sk = null;
$people = array();
do {
$params = array('TableName'=>'people');
if ($sk) {
$params['ExclusiveStartKey'] = array(
'HashKeyElement' => array(
'S' => $sk
)
);
$sk= null;
}
$r = $dynamo_db->scan($params);
if ($r->isOK()) {
foreach ($r->body->Items as $item) {
echo (string) $item->name->S;
}
if ($lk = $r->body->LastEvaluatedKey) {
$sk = (string) $lk->HashKeyElement->S;
}
} else {
throw new DynamoDB_Exception('...');
}
}
while ($sk);
Page 35
SDK 2.x – The Era of Iterators
$scan = $db->getScanIterator([
'TableName' => 'People',
'AttributesToGet' => ['Id', 'Name']
]);
foreach ($scan as $person) {
echo $item['Name']['S'];
}
Page 36
Advanced Iterator Usage – Example
$objects = $s3->getListObjectsIterator([
'Bucket' => 'my-bucket-name',
]);
$objects = new LimitIterator($objects, 0, 5);
foreach ($objects as $object) {
echo $object['Key'] . "\n";
}
Page 37
Using the AWS SDK for PHP
CreateBucket
PutObject
ListObjects
Page 38
High-level Abstractions in the AWS SDK for PHP
PART 2
Page 39
"I want to use Amazon S3 like a local filesystem."
Amazon S3 Stream Wrapper
Page 40
PHP Stream Wrappers
• Provide a
consistent I/O
interface for
various protocols – fopen(), fread(),
file_get_contents(), mkdir(), etc…
– file://, http://, ftp://,
php://, …
Page 41
PHP Stream Wrapper Protocols
echo file_get_contents('/path/to/file');
Is equivalent to…
echo file_get_contents('file:///path/to/file');
file:// is the protocol
Page 42
PHP Stream Wrapper Protocols
echo file_get_contents('http://www.amazon.com');
http:// is the protocol
Page 43
Amazon S3 Stream Wrapper
// First, register the wrapper
$s3 = Aws\S3\S3Client::factory();
$s3->registerStreamWrapper();
echo file_get_contents('s3://bucket_name/key');
file_put_contents('s3://bucket_name/key', 'hi!');
s3:// bucket_name /key
Page 44
Pseudo-directory
• Amazon S3 knows about buckets and keys
• There aren't real subdirectories
• Pseudo-directories can be created using a key
prefix
Bucket: foo
Key: baz/bar/bam
URL: http://foo.s3.amazonaws.com/baz/bar/bam
Page 45
Reading bytes off of a stream
$fp = fopen('s3://bucket_name/key', 'r');
while (!feof($fp)) {
echo fread($fp, 1024);
}
fclose($fp);
Instead of reading all bytes up front and then using them
Page 46
Using Stream Filters
$in = fopen('s3://bucket_name/key.zip', 'r');
$out = fopen('/path/to/file', 'w');
stream_filter_append($out, 'zlib.inflate');
stream_copy_to_stream($in, $out);
fclose($in);
fclose($out);
Filters are used for: Conversion, Compression, Encryption, etc.
Page 47
Listing Objects and Buckets
$dir = "s3://bucket_name/";
if (is_dir($dir) && ($dh = opendir($dir))) {
while (($file = readdir($dh)) !== false) {
echo "Name: {$file}\n";
}
closedir($dh);
}
Page 48
Listing Objects and Buckets
$dir = 's3://bucket_name';
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iterator as $file) {
echo $file->getType() . ': ' . $file . "\n";
}
The more intuitive recursive iterator iterator iterator iterator …
Page 49
Listing Objects and Buckets
file: s3://bucket/aws_logo.png
file: s3://bucket/background.gif
file: s3://bucket/channel.xml
file: s3://bucket/data.txt
file: s3://bucket/destruct
dir: s3://bucket/dirupload
file: s3://bucket/dirupload/aws-autoloader.php
file: s3://bucket/dirupload/aws.zip
file: s3://bucket/dirupload/guzzle/guzzle/.gitignore
file: s3://bucket/dirupload/guzzle/guzzle/.travis.yml
file: s3://bucket/dirupload/guzzle/guzzle/CHANGELOG.md
file: s3://bucket/dirupload/guzzle/guzzle/LICENSE
Page 50
PHP Stream Wrappers: Summary
• Access Amazon S3 like a local filesystem
• Read bytes off of a stream on demand
• Use familiar methods like file_get_contents
• Access to PHP's stream filters
Page 51
"I need to upload a local directory to
an Amazon S3 bucket"
For static blogs, websites, etc.
Page 56
.
├── images
│ ├── dotted-border.png
│ ├── email.png
│ ├── noise.png
│ ├── rss.png
│ └── search.png
├── index.html
Local filesystem
.
├── images
│ ├── dotted-border.png
│ ├── email.png
│ ├── noise.png
│ ├── rss.png
│ └── search.png
├── index.html
Amazon S3 Bucket
Page 57
uploadDirectory()
$client->uploadDirectory('/local/directory', 'bucket');
1. Recursively iterates over all local files
2. Checks if the file does not exist or if it has changed
3. Uploads matching files (single or multipart)
public function uploadDirectory(
$directory,
$bucket,
$keyPrefix = null,
array $options = array()
)
Page 58
Key Prefix?
https://bucket.s3.amazonaws.com/blogs/index.html
$client->uploadDirectory(
'/local/dir',
'bucket',
'blogs/' // Key prefix
);
Page 59
uploadDirectory() Options
$client->uploadDirectory('/local/dir', 'bucket', '', [
'params' => ['ACL' => 'public-read'],
'concurrency' => 20,
'debug' => true
]);
Debug output:
Uploading /local/dir/images/email.png -> images/email.png (8 bytes)
Uploading /local/dir/images/noise.png -> images/noise.png (12 bytes)
Uploading /local/dir/images/rss.png -> images/rss.png (100 bytes)
Uploading /local/dir/images/search.png -> images/search.png (200 bytes)
Uploading /local/dir/index.html -> index.html (1024 bytes)
Page 60
"I need to download an Amazon S3 bucket to
my local filesystem"
Page 61
downloadBucket()
$client->downloadBucket ('/local/directory', 'bucket');
Works exactly like uploadDirectory()
public function downloadBucket(
$directory,
$bucket,
$keyPrefix = null,
array $options = array()
)
Page 62
Sync Amazon S3 -> Amazon S3
$client->uploadDirectory(
's3://bucket_src',
'bucket_dest'
);
Upload the contents of one Amazon S3 bucket to another using
uploadDirectory().
Page 63
"I need to use the SDK with my framework."
Page 64
Third-party Integrations
• Laravel 4 Service Provider
• Zend Framework 2 Module
• Silex Service Provider
https://github.com/aws
If you'd like to help us or contribute to another
framework integration, please come talk to us.
Page 65
Mastering the AWS SDK for PHP
Learned how to use the AWS SDK for PHP by
working with some basic Amazon S3 operations.
Learned how to speed up some common
development use cases by using some of the
SDK's high-level abstractions.
Page 66
What you will do next
• Star ★ the AWS SDK for PHP GitHub repo https://github.com/aws/aws-sdk-php
• composer install the SDK into your project https://packagist.org/packages/aws/aws-sdk-php
• Subscribe to the AWS PHP Development Blog http://blogs.aws.amazon.com/php
• Build cool PHP apps on the AWS cloud!
Page 67
Please give us your feedback on this
presentation
As a thank you, we will select prize
winners daily for completed surveys!
TLS306
Mastering the AWS SDK for PHP
Follow us: @awsforphp