Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting Good with the AWS SDK for PHP

Getting Good with the AWS SDK for PHP

Amazon Web Services and the AWS SDK for PHP continue to put more power into the hands of PHP developers to build robust and scalable applications. With version 2 of the SDK, PHP developers now have a more powerful, flexible, and modern library built on top of existing open source software like the Guzzle HTTP framework and the Symfony 2 Event Dispatcher. In this session you will learn how to use the new AWS SDK for PHP, and examine code samples showing how to work with Amazon S3 and Amazon DynamoDB. You will also learn about how you can quickly deploy your application to AWS Elastic Beanstalk and AWS OpsWorks.

Updated 09/2013.

Jeremy Lindblom

May 22, 2013
Tweet

More Decks by Jeremy Lindblom

Other Decks in Technology

Transcript

  1. Getting Good with the!
    AWS SDK for PHP!

    View Slide

  2. Hi there! I'm Jeremy!
    •  PHP So"ware Engineer at!
    •  Co-author of the AWS SDK for PHP!
    •  Co-organizer of the Seattle PHP User Group!
    •  @jeremeamia on and | webjeremy.com!
    •  I like making funny faces!

    View Slide

  3. Amazon Web Services o#ers a
    complete set of infrastructure and
    application services that enable you to
    run virtually everything in the cloud.!

    View Slide

  4. In other words…!
    AWS is a bunch of building blocks.!

    View Slide

  5. Some of these blocks are for!
    building your infrastructure,!
    Amazon Elastic
    Compute Cloud!
    (EC2)!
    Amazon Relational
    Database Service!
    (RDS)!
    Amazon!
    Route 53!

    View Slide

  6. Some of these blocks are for!
    building your application,!
    Amazon Simple
    Storage Service!
    (S3)!
    Amazon Simple
    Queue Service!
    (SQS)!
    Amazon Simple
    Email Service!
    (SES)!

    View Slide

  7. And some of these blocks build on each!
    other to create more complete solutions.!
    AWS
    CloudFormation!
    AWS!
    Elastic Beanstalk!
    AWS!
    OpsWorks!

    View Slide

  8. These building blocks enable you to!
    do virtually anything in the cloud, like…!
    Streaming movies to millions of
    users around the world,!
    Allowing millions people to quickly
    share things online with friends,!
    Processing, storing, and distributing
    images from Mars.!

    View Slide

  9. Hundreds of Thousands of
    Customers in 190 Countries!

    View Slide

  10. Amazon S3!
    Amazon SES!
    Amazon SimpleDB!
    Amazon SNS!
    Amazon SQS!
    Amazon SWF!
    Amazon VPC!
    Auto Scaling!
    AWS CloudHSM!
    AWS Data Pipeline!
    AWS Elastic Beanstalk!
    AWS Import/Export!
    AWS OpsWorks!
    AWS Marketplace!
    AWS Storage Gateway!
    AWS Support!
    Elastic Load Balancing!
    Amazon CloudFormation!
    Amazon CloudFront!
    Amazon CloudSearch!
    Amazon CloudWatch!
    Amazon Direct Connect!
    Amazon DynamoDB!
    Amazon EBS!
    Amazon EC2!
    Amazon ElastiCache!
    Amazon Elastic Transcoder!
    Amazon EMR!
    Amazon Glacier!
    Amazon IAM!
    Amazon Mechanical Turk!
    Amazon RDS!
    Amazon Redshi"!
    Amazon Route53!

    View Slide

  11. Amazon S3!
    Amazon SES!
    Amazon SimpleDB!
    Amazon SNS!
    Amazon SQS!
    Amazon SWF!
    Amazon VPC!
    Auto Scaling!
    AWS CloudHSM!
    AWS Data Pipeline!
    AWS Elastic Beanstalk!
    AWS Import/Export!
    AWS OpsWorks!
    AWS Marketplace!
    AWS Storage Gateway!
    AWS Support!
    Elastic Load Balancing!
    Amazon CloudFormation!
    Amazon CloudFront!
    Amazon CloudSearch!
    Amazon CloudWatch!
    Amazon Direct Connect!
    Amazon DynamoDB!
    Amazon EBS!
    Amazon EC2!
    Amazon ElastiCache!
    Amazon Elastic Transcoder!
    Amazon EMR!
    Amazon Glacier!
    Amazon IAM!
    Amazon Mechanical Turk!
    Amazon RDS!
    Amazon Redshi"!
    Amazon Route53!
    Compute & Networking!
    Storage & Content Delivery!
    Databases!
    Application Services!
    Deployment & Management!

    View Slide

  12. Amazon S3!
    Amazon SES!
    Amazon SimpleDB!
    Amazon SNS!
    Amazon SQS!
    Amazon SWF!
    Amazon VPC!
    Auto Scaling!
    AWS CloudHSM!
    AWS Data Pipeline!
    AWS Elastic Beanstalk!
    AWS Import/Export!
    AWS OpsWorks!
    AWS Marketplace!
    AWS Storage Gateway!
    AWS Support!
    Elastic Load Balancing!
    Amazon CloudFormation!
    Amazon CloudFront!
    Amazon CloudSearch!
    Amazon CloudWatch!
    Amazon Direct Connect!
    Amazon DynamoDB!
    Amazon EBS!
    Amazon EC2!
    Amazon ElastiCache!
    Amazon Elastic Transcoder!
    Amazon EMR!
    Amazon Glacier!
    Amazon IAM!
    Amazon Mechanical Turk!
    Amazon RDS!
    Amazon Redshi"!
    Amazon Route53!
    8 services!
    less than!
    a year old!

    View Slide

  13. Amazon S3!
    Amazon SES!
    Amazon SimpleDB!
    Amazon SNS!
    Amazon SQS!
    Amazon SWF!
    Amazon VPC!
    Auto Scaling!
    AWS CloudHSM!
    AWS Data Pipeline!
    AWS Elastic Beanstalk!
    AWS Import/Export!
    AWS OpsWorks!
    AWS Marketplace!
    AWS Storage Gateway!
    AWS Support!
    Elastic Load Balancing!
    Amazon CloudFormation!
    Amazon CloudFront!
    Amazon CloudSearch!
    Amazon CloudWatch!
    Amazon Direct Connect!
    Amazon DynamoDB!
    Amazon EBS!
    Amazon EC2!
    Amazon ElastiCache!
    Amazon Elastic Transcoder!
    Amazon EMR!
    Amazon Glacier!
    Amazon IAM!
    Amazon Mechanical Turk!
    Amazon RDS!
    Amazon Redshi"!
    Amazon Route53!
    Fastest Growing AWS Service Ever!
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    Amazon Redshi"!
    !

    View Slide

  14. You can manage AWS services via!
    the AWS Management Console, but…!

    View Slide

  15. AWS services each have an API,!
    so you can control your resources!
    through programs and scripts.!

    View Slide

  16. So let's provision some servers!
    from PHP by using the AWS SDK for PHP!
    to talk to the Amazon EC2 API!
    Amazon EC2!

    View Slide

  17.  
    require  'vendor/autoload.php';  
    use  Aws\Common\Aws;  
     
    $ec2  =  Aws::factory('config.php')-­‐>get('ec2');  
    $result  =  $ec2-­‐>runInstances(array(  
       'ImageId'            =>  'ami-­‐af45d59f',  
       'MinCount'          =>  1,  
       'MaxCount'          =>  3,  
       'InstanceType'  =>  'm1.small',  
    ));  
     
    $ids  =  $result-­‐>getPath('Instances/*/InstanceId');  
    $ec2-­‐>waitUntilInstanceRunning(array(  
       'InstanceIds'  =>  $ids,  
    ));  
    echo  'Provisioned  '  .  count($ids)  .  '  servers.';  
     

    View Slide

  18. AWS SDKs and Tools!
    PHP • Java • Python • .NET!
    Ruby • Node.js • iOS • Android!
    SDKs!
    AWS CLI • Visual Studio Plugin!
    Eclipse Plugin • PowerShell Tools!
    Management Console • iOS App!
    !
    Tools!
    https://github.com/aws!
    !

    View Slide

  19. AWS SDK for PHP!
    •  PHP 5.3+, PSR compliant!
    •  Built on top of Guzzle (guzzlephp.org)!
    •  Persistent connections, parallel requests!
    •  Easy pagination, "waiters", other helpers!
    •  Event hooks, plugins, wire logging!

    View Slide

  20. Installing the PHP SDK!
    •  Composer!
    •  Phar Download!
    •  Zip Download!
    •  PEAR!

    View Slide

  21. SDK History!
    •  Tarzan [2006] ( @skyzyx )!
    •  CloudFusion [2007] ( @skyzyx )!
    •  AWS SDK for PHP [2010]!
    ( @skyzyx & @jeremeamia )!
    •  AWS SDK for PHP 2 [Late 2012]!
    ( @mtdowling & @jeremeamia )!

    View Slide

  22. require  'vendor/autoload.php';  
     
    $s3  =  Aws\S3\S3Client::factory(array(    
       'key'        =>  'your_aws_access_key_id',  
       'secret'  =>  'your_aws_secret_key',  
    ));  
     
    $body  =  fopen('/path/to/file',  'r');  
    $result  =  $s3-­‐>putObject(array(  
       'Bucket'  =>  'my-­‐cool-­‐photos',  
       'Key'        =>  'photo.jpg',  
       'Body'      =>  $body,  
       'ACL'        =>  'public-­‐read',  
    ));  

    View Slide

  23. Concepts in the SDK!
    •  Client Factories & Service Builder!
    •  Commands!
    •  Modeled Results!
    •  Iterators!
    •  Waiters!
    •  Events & Plugins!

    View Slide

  24. use  Aws\Ec2\Ec2Client;  
     
    $client  =  Ec2Client::factory(array(    
       'key'        =>  'your-­‐aws-­‐access-­‐key-­‐id',  
       'secret'  =>  'your-­‐aws-­‐secret-­‐key',  
       'region'  =>  'us-­‐west-­‐2',  
    ));  
    Client Factory!

    View Slide

  25. use  Aws\Common\Aws;  
     
    $aws  =  Aws::factory(array(    
       'key'        =>  'your-­‐aws-­‐access-­‐key-­‐id',  
       'secret'  =>  'your-­‐aws-­‐secret-­‐key',  
       'region'  =>  'us-­‐west-­‐2',  
    ));  
     
    $client1  =  $aws-­‐>get('ec2');  
    $client2  =  $aws-­‐>get('ec2');  
    var_dump($client1  ===  $client2);  
    Service Builder!

    View Slide

  26. Commands!
    •  Encapsulates an operation to AWS!
    •  Contains Request and Response objects!
    •  Allows you set and get parameters!
    •  Returns modeled results when executed!

    View Slide

  27. Commands - Shorthand!
    $result  =  $s3-­‐>listObjects(array(  
       'Bucket'  =>  'my-­‐bucket-­‐name'  
    ));  
     
    echo  $result['Contents'][0]['Key'];  

    View Slide

  28. $command  =  $s3-­‐>getCommand('ListObjects');  
    $command-­‐>set('Bucket',  'my-­‐bucket-­‐name');  
    $command['Bucket']  =  'my-­‐bucket-­‐name';  
     
    $result  =  $command-­‐>getResult();  
    echo  $result['Contents'][0]['Key'];  
     
    $request  =  $command-­‐>getRequest();  
    $response  =  $command-­‐>getResponse();  
    echo  $response-­‐>getStatusCode();  
    echo  $response-­‐>getHeader('Content-­‐Length');  
     
    The Command Object!

    View Slide

  29. $c1  =  $s3-­‐>getCommand('PutObject',  array(  
       'Bucket'  =>  'my-­‐bucket-­‐name',  
       'Key'        =>  'my-­‐first-­‐key',  
       'Body'      =>  fopen('path/to/file1',  'r')  
    ));  
    $c2  =  $s3-­‐>getCommand('PutObject',  array(  
       'Bucket'  =>  'my-­‐bucket-­‐name',  
       'Key'        =>  'my-­‐second-­‐key',  
       'Body'      =>  fopen('path/to/file2',  'r')  
    ));  
     
    $s3-­‐>execute(array($c1,  $c2));  
    Parallel Commands!

    View Slide

  30. Modeled Results!
    •  Array-like object!
    •  Follows schema from service description!
    •  Convenience methods like getPath()  
    $result  =  $s3-­‐>listBuckets();  
     
    $result['Buckets'][0]['Name'];  
    $result-­‐>get('Buckets');  
    $result-­‐>getPath('Buckets/0/Name');  
    print_r($result-­‐>toArray());  

    View Slide

  31. Waiters!
    •  Poll resources until available!
    •  Handle asynchronous and eventually
    consistent operations more easily!
    $s3-­‐>createBucket(array(  
       'Bucket'  =>  'my-­‐bucket'  
    ));  
    $s3-­‐>waitUntilBucketExists(array(  
       'Bucket'  =>  'my-­‐bucket'  
    ));  

    View Slide

  32. Iterators!
    •  Iterate through entire result sets!
    •  No handling of markers or tokens!
    •  Uses SPL iterators!
    $list  =  $s3-­‐>getListObjectsIterator([  
       'Bucket'  =>  'my-­‐bucket'  
    ]);  
    foreach  ($list  as  $object)  {  
       echo  $object['Key']  .  "\n";  
    }  

    View Slide

  33. SDK 1.x – Before Iterators!
    $dynamo_db  =  new  AmazonDynamoDB();  
    $start_key  =  null;  
    $people  =  array();  
       
    do  {  
       $params  =  array(  
           'TableName'  =>  'people',  
       );  
       
       if  ($start_key)  {
           $params['ExclusiveStartKey']  =  array(
               'HashKeyElement'  =>  array(
                   'S'  =>  $start_key
               )
           );
           $start_key  =  null;
       }
     
       $response  =  $dynamo_db-­‐>scan($params);
       if  ($response-­‐>isOK())  {
           foreach  
    ($response-­‐>body-­‐>Items  as  $item)  {
               echo  (string)  $item-­‐>name-­‐>S;
           }
             
           if  ($response-­‐>body-­‐>LastEvaluatedKey)  {
               $start_key  =  (string)  $response-­‐>body  
    -­‐>LastEvaluatedKey-­‐>HashKeyElement-­‐>S;
           }  
       }  else  {
             
           throw  new  DynamoDB_Exception('…');
       }
    }  while  ($start_key);

    View Slide

  34. SDK 1.x – Before Iterators!
    $dynamo_db  =  new  AmazonDynamoDB();  
    $start_key  =  null;  
    $people  =  array();  
       
    do  {  
       $params  =  array(  
           'TableName'  =>  'people',  
       );  
       
       if  ($start_key)  {
           $params['ExclusiveStartKey']  =  array(
               'HashKeyElement'  =>  array(
                   'S'  =>  $start_key
               )
           );
           $start_key  =  null;
       }
     
       $response  =  $dynamo_db-­‐>scan($params);
       if  ($response-­‐>isOK())  {
           foreach  
    ($response-­‐>body-­‐>Items  as  $item)  {
               echo  (string)  $item-­‐>name-­‐>S;
           }
             
           if  ($response-­‐>body-­‐>LastEvaluatedKey)  {
               $start_key  =  (string)  $response-­‐>body  
    -­‐>LastEvaluatedKey-­‐>HashKeyElement-­‐>S;
           }  
       }  else  {
             
           throw  new  DynamoDB_Exception('…');
       }
    }  while  ($start_key);

    View Slide

  35. $db  =  $aws-­‐>get('DynamoDb');  
     
    $scan  =  $db-­‐>getScanIterator(array(  
       'TableName'              =>  'People',  
       'AttributesToGet'  =>  array('Id',  'Name')  
    ));  
     
    foreach  ($scan  as  $person)  {  
       echo  $item['Name']['S'];  
    }    
    Example: Scan Iterator!

    View Slide

  36. Events & Event Listeners!
    •  Event slots in various parts of SDK!
    (Clients, Requests, Waiters, Batches, etc.)!
    •  Inject logic without extending classes!
    •  Every client has an instance of the
    Symfony2 EventDispatcher!
    $s3-­‐>getEventDispatcher()  
         -­‐>addListener('',  );  

    View Slide

  37. Plugins!
    •  Implemented as event subscribers!
    •  Request signing implemented this way!
    •  Many built-in plugins from Guzzle
    including easy wire logging!
    use  Guzzle\Plugin\Log\LogPlugin;  
    $s3-­‐>addSubscriber(  
           LogPlugin::getDebugPlugin()  
    );  

    View Slide

  38. Simple Funny Face!
    Sharing App on AWS!

    View Slide

  39. Funny Face Sharing App!

    View Slide

  40. Funny Face Sharing App!

    View Slide

  41. AWS Services for our App!
    $ $AWS Elastic Beanstalk!
    $ $Amazon S3!
    $ $( Simple Storage Service )!
    $ $Amazon DynamoDB!
    $ $AWS IAM!
    $ $( Identity and Access Management )!

    View Slide

  42. AWS Elastic Beanstalk!
    •  Easy to get started!
    •  PHP 5.3 or PHP 5.4!
    •  Does load balancing and auto scaling!
    •  Deploy via Git, upload (console), or S3 (API)!
    •  Installs Composer dependencies for you!
    •  Customize via API/console, ebextensions
    con%g, and custom hook scripts!

    View Slide

  43. require  __DIR__  .  '/vendor/autoload.php';  
     
    use  Aws\Common\Enum\Region;  
    use  Aws\Silex\AwsServiceProvider;  
    use  Silex\Application;  
     
    $app  =  new  Application;  
    $app-­‐>register(new  AwsServiceProvider(),  array(  
       'aws.config'  =>  array(  
               'key'        =>  'AKEXAMPLE8FOO29JBAR8Q',  
               'secret'  =>  'Sf0Example24Foo0J4Bar3XBaz34',
               'region'  =>  Region::US_EAST_1,  
       )  
    ));  
    Let's Use Silex, Twig, & AWS!

    View Slide

  44. SDK Third-party Integrations!
    •  Silex service provider!
    •  Laravel 4 service provider!
    •  Zend Framework 2 module!
    •  Gaufrette adapter!

    View Slide

  45. require  __DIR__  .  '/vendor/autoload.php';  
     
    use  Aws\Common\Enum\Region;  
    use  Aws\Silex\AwsServiceProvider;  
    use  Silex\Application;  
     
    $app  =  new  Application;  
    $app-­‐>register(new  AwsServiceProvider(),  array(  
       'aws.config'  =>  array(  
               'key'        =>  'AKEXAMPLE8FOO29JBAR8Q',  
               'secret'  =>  'Sf0Example24Foo0J4Bar3XBaz34',
               'region'  =>  Region::US_EAST_1,  
       )  
    ));  
    Credential Problem!

    View Slide

  46. IAM Roles & Instance Pro%les!
    •  An IAM Role lets you give other AWS users and
    services access to your AWS resources.!
    •  An IAM Instance Pro%le is an association of an
    IAM Role to an Amazon EC2 Instance.!
    •  The AWS SDK for PHP will automatically use
    Instance Pro%le Credentials if available.!
    •  You can con%gure your Elastic Beanstalk
    environment with an Instance Pro%le.!

    View Slide

  47. require  __DIR__  .  '/vendor/autoload.php';  
     
    use  Aws\Common\Enum\Region;  
    use  Aws\Silex\AwsServiceProvider;  
    use  Silex\Application;  
     
    $app  =  new  Application;  
    $app-­‐>register(new  AwsServiceProvider(),  array(  
       'aws.config'  =>  array(  
               'region'  =>  Region::US_EAST_1,  
       )  
    ));  
    Instance Pro%le Credentials!
    Do not provide any credentials, and the SDK will
    automatically use your Instance Profile Credentials.

    View Slide

  48. $app-­‐>get('/photos',  function  ()  use  ($app)  {  
       $db  =  $app['aws']-­‐>get('dynamodb');  
       $faces  =  $db-­‐>getScanIterator([  
               'TableName'  =>  'funny-­‐face'  
       ]);  
     
       return  $app['twig']-­‐>render('index.twig',[  
               'faces'  =>  $faces  
       ]);  
    });  
    Index Controller!

    View Slide

  49. $app-­‐>get('/photos',  function  ()  use  ($app)  {  
       $db  =  $app['aws']-­‐>get('dynamodb');  
       $faces  =  $db-­‐>getScanIterator([  
               'TableName'  =>  'funny-­‐face'  
       ]);  
     
       return  $app['twig']-­‐>render('index.twig',[  
               'faces'  =>  $faces  
       ]);  
    });  
    Index Controller!

    View Slide

  50. The Shape of an Item!
    {  
         "src":  {  
               "S":  "https://funny-­‐face.s3.amazonaws.com/2rlDm.jpg"  
         },  
         "caption":  {  
               "S":  "You  had  one  job!"  
         }  ,  
         "size":  {  
               "N":  "205993423"  
         }  
    },  

    View Slide

  51. use  Aws\DynamoDb\Iterator\ItemIterator  as  Items;  
    $app-­‐>get('/photos',  function  ()  use  ($app)  {  
       $db  =  $app['aws']-­‐>get('dynamodb');  
       $faces  =  new  Items($db-­‐>getScanIterator([  
               'TableName'  =>  'funny-­‐face'  
       ]);  
     
       return  $app['twig']-­‐>render('index.twig',[  
               'faces'  =>  $faces  
       ]);  
    });  
    Index Controller Revisited!

    View Slide

  52. $app-­‐>match('/photos/add',  function()  use($app)  {  
       //  ...  ($file  is  a  Symfony\Component\HttpFoundation\File\UploadedFile)  
       $s3  =  $app['aws']-­‐>get('s3');  
       $url  =  $s3-­‐>putObject([  
               'Bucket'          =>  'funny-­‐face',  
               'Key'                =>  $file-­‐>getFileName(),  
               'SourceFile'  =>  $file-­‐>getPathname(),  
               'ACL'                =>  CannedAcl::PUBLIC_READ,  
       ])-­‐>get('ObjectURL');  
       //  ...  
    });  
    Add Controller - Upload!

    View Slide

  53. $app-­‐>match('/photos/add',  function($request)  use($app)  {  
       //  ...  
       $db  =  $app['aws']-­‐>get('dynamodb');  
       $msg  =  $request-­‐>request-­‐>get('caption',  'None');  
       $db-­‐>putItem([  
               'TableName'  =>  'funny-­‐face',  
               'Item'            =>  [  
                       'src'          =>  ['S'  =>  $url],  
                       'caption'  =>  ['S'  =>  $msg]  
               ],  
       ]);  
       //  ...  
    });  
    Add Controller - Save!

    View Slide

  54. AWS OpsWorks!
    •  DevOps solution for apps!
    •  Organized w/ stacks & layers!
    •  Deploy from a GitHub repo!
    •  Customize with Chef recipes!
    •  Nice management console!

    View Slide

  55. Special Features!
    in the AWS SDK for PHP!

    View Slide

  56. $s3  =  $aws-­‐>get('S3');  
    $uploader  =  UploadBuilder::newInstance()  
       -­‐>setClient($s3)  
       -­‐>setSource('./videos/video42.mov')  
       -­‐>setBucket('app-­‐media')  
       -­‐>setKey('videos/video42.mov')  
       -­‐>setConcurrency(3)  
       -­‐>build();  
    Multipart Uploader!

    View Slide

  57. $s3-­‐>upload(  
       'app-­‐media',                    //  Bucket  
       'videos/video42.mov',  //  Key  
       fopen('/tmp/vidz/video42.mov',  'r')  
    );  
    Simple Upload!
    Automatically uses single or multipart
    upload for you depending on %le size.!

    View Slide

  58. $s3-­‐>registerStreamWrapper();  
     
    $path  =  's3://jcl-­‐files/logs/04.log';  
    if  ($file  =  fopen($path,  'r'))  {  
       while  (!feof($file))  {  
           echo  fgets($file);  
       }  
       fclose($file)  
    }  
    Amazon S3 Stream Wrapper!

    View Slide

  59. $s3-­‐>registerStreamWrapper();  
     
    $finder  =  new  Finder();  
    $finder-­‐>files()  
       -­‐>in('s3://jcl-­‐files/family-­‐videos')  
       -­‐>size('<  50M')  
       -­‐>date('since  1  year  ago');  
     
    foreach  ($finder  as  $file)  {  
       echo  $file-­‐>getFilename()  .  "\n";  
    }  
    Stream Wrapper + Symfony Finder!

    View Slide

  60. Need Help with the SDK?!
    •  Homepage http://aws.amazon.com/sdkforphp/!
    •  Github https://github.com/aws/aws-sdk-php!
    •  User Guide http://docs.aws.amazon.com/aws-sdk-php-2/guide/latest/!
    •  API Docs http://docs.aws.amazon.com/aws-sdk-php-2/latest/!
    •  Blog http://blogs.aws.amazon.com/php!
    •  Forum https://forums.aws.amazon.com/forum.jspa?forumID=80!

    View Slide