├── .gitignore ├── AmazonWebServices.php ├── AmazonWebServicesFactory.php ├── DependencyInjection ├── Configuration.php └── ThePhalconsAmazonWebServicesExtension.php ├── README.md ├── Resources ├── config │ ├── aws_config.xml │ └── aws_service.xml ├── doc │ ├── Changelog.md │ ├── README.md │ ├── Samples │ ├── cdn.md │ └── todo.md └── meta │ └── LICENSE ├── Services ├── SESMailingService.php ├── SQSLogger.php └── StorageService.php ├── StreamWrapper └── S3StreamWrapper.php ├── Tests ├── Services │ ├── SESMailingServiceTest.php │ └── StorageServiceTest.php ├── autoload.php.dist └── bootstrap.php ├── ThePhalconsAmazonWebServicesBundle.php ├── aws.config.yml ├── composer.json ├── phpunit.xml.dist └── vendor └── vendors.php /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | phpunit.xml 3 | Tests/autoload.php 4 | vendor/* 5 | !vendor/vendors.php 6 | 7 | 8 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 9 | 10 | *.iml 11 | 12 | ## Directory-based project format: 13 | .idea/ 14 | /.idea/dictionaries/elmehdi.xml 15 | # if you remove the above rule, at least ignore the following: 16 | 17 | # User-specific stuff: 18 | # .idea/workspace.xml 19 | # .idea/tasks.xml 20 | # .idea/dictionaries 21 | # .idea/shelf 22 | 23 | # Sensitive or high-churn files: 24 | # .idea/dataSources.ids 25 | # .idea/dataSources.xml 26 | # .idea/sqlDataSources.xml 27 | # .idea/dynamic.xml 28 | # .idea/uiDesigner.xml 29 | 30 | # Gradle: 31 | # .idea/gradle.xml 32 | # .idea/libraries 33 | 34 | # Mongo Explorer plugin: 35 | # .idea/mongoSettings.xml 36 | 37 | ## File-based project format: 38 | *.ipr 39 | *.iws -------------------------------------------------------------------------------- /AmazonWebServices.php: -------------------------------------------------------------------------------- 1 | 14 | * 15 | * Initial version created on: 10/28/2015 16 | * 17 | */ 18 | class AmazonWebServices { 19 | 20 | /** 21 | * @var array 22 | */ 23 | private $configs = array(); 24 | 25 | /** 26 | * @var Sdk 27 | */ 28 | private $sdk; 29 | 30 | /** 31 | * __constructor 32 | * @param array $config 33 | */ 34 | public function __construct($config = array()) 35 | { 36 | $this->configs = $config; 37 | 38 | $options = array( 39 | 'region' => $this->getRegion(), 40 | // use specific aws sdk php version or latest version if not defined 41 | 'version' => ($this->getVersion() !== '') ? $this->getVersion() : 'latest', 42 | ); 43 | 44 | if ($this->getKey() !== '' && $this->getSecret() !== '') { 45 | $options['credentials'] = new Credentials($this->getKey(), $this->getSecret()); 46 | } 47 | 48 | $this->sdk = new Sdk($options); 49 | } 50 | 51 | /** 52 | * Create aws service clients 53 | * @param $serviceType 54 | * @return mixed 55 | */ 56 | public function createAwsServiceClient($serviceType){ 57 | 58 | return $this->sdk->createClient($serviceType); 59 | } 60 | 61 | /** 62 | * Get the accountId 63 | * 64 | * @return string The account id provided via the bundle configuration 65 | */ 66 | public function accountId() 67 | { 68 | return $this->configs['account_id']; 69 | } 70 | /** 71 | * Get the canonicalId 72 | * 73 | * @return string The cononical id provided via the bundle configuration 74 | */ 75 | public function canonicalId() 76 | { 77 | return $this->configs['canonical_id']; 78 | } 79 | /** 80 | * Get the cononicalName 81 | * 82 | * @return string The canonical name provided via the bundle configuration 83 | */ 84 | public function canonicalName() 85 | { 86 | return $this->configs['canonical_name']; 87 | } 88 | /** 89 | * Get the certificateAuthority 90 | * 91 | * @return string The certificate authority provided via the bundle configuration 92 | */ 93 | public function certificateAuthority() 94 | { 95 | return (bool) $this->configs['certificate_authority']; 96 | } 97 | /** 98 | * Get the cloudFrontKeypair 99 | * 100 | * @return string The Cloudfront keypair id provided via the bundle configuration 101 | */ 102 | public function cloudfrontKeypair() 103 | { 104 | return $this->configs['cloudfront_keypair']; 105 | } 106 | /** 107 | * Get the cloudfrontPem 108 | * 109 | * @return string The Cloudfront private key pem provided via the bundle configuration 110 | */ 111 | public function cloudfrontPrivateKeyPem() 112 | { 113 | return $this->configs['cloudfront_pem']; 114 | } 115 | /** 116 | * Get the defaultCacheConfig 117 | * 118 | * @return string The default cache config provided via the bundle configuration 119 | */ 120 | public function defaultCacheConfig() 121 | { 122 | return $this->configs['default_cache_config']; 123 | } 124 | /** 125 | * enableExtensions 126 | * 127 | * @return boolean 128 | */ 129 | public function enableExtensions() 130 | { 131 | return (bool) $this->configs['enable_extensions']; 132 | } 133 | /** 134 | * Get the key 135 | * 136 | * @return string The key provided via the bundle configuration 137 | */ 138 | public function getKey() 139 | { 140 | return $this->configs['key']; 141 | } 142 | /** 143 | * Get the parameters 144 | * 145 | * @return array The array of all configuration parameters provided via the bundle configuration 146 | */ 147 | public function getConfigs() 148 | { 149 | return $this->configs; 150 | } 151 | /** 152 | * Get the mfaSerial 153 | * 154 | * @return string The mfa serial provided via the bundle configuration 155 | */ 156 | public function mfaSerial() 157 | { 158 | return $this->configs['mfa_serial']; 159 | } 160 | /** 161 | * Get the secret 162 | * 163 | * @return string The secret key provided via the bundle configuration 164 | */ 165 | public function getSecret() 166 | { 167 | return $this->configs['secret']; 168 | } 169 | 170 | /** 171 | * Get the mfaSerial 172 | * 173 | * @return string The mfa serial provided via the bundle configuration 174 | */ 175 | public function getVersion() 176 | { 177 | return $this->configs['version']; 178 | } 179 | /** 180 | * Get the secret 181 | * 182 | * @return string The secret key provided via the bundle configuration 183 | */ 184 | public function getRegion() 185 | { 186 | return $this->configs['region']; 187 | } 188 | } 189 | 190 | -------------------------------------------------------------------------------- /AmazonWebServicesFactory.php: -------------------------------------------------------------------------------- 1 | 19 | * 20 | * Initial version created on: 27/10/15 20:52 21 | * 22 | */ 23 | class AmazonWebServicesFactory { 24 | 25 | /** 26 | * @var array $validServiceTypes The names of the Amazon Web Services that may be used 27 | */ 28 | private $supportedServiceTypes = array( 29 | 'AS', 30 | 'CloudFormation', 31 | 'CloudFront', 32 | 'CloudSearch', 33 | 'CloudWatch', 34 | 'DynamoDB', 35 | 'EC2', 36 | 'ELB', 37 | 'EMR', 38 | 'ElastiCache', 39 | 'ElasticBeanstalk', 40 | 'IAM', 41 | 'ImportExport', 42 | 'RDS', 43 | 'S3', 44 | 'SDB', 45 | 'SES', 46 | 'SNS', 47 | 'SQS', 48 | 'STS', 49 | 'SWF', 50 | 'Route53', 51 | ); 52 | 53 | /** 54 | * checks if the given service type is supported 55 | * @param $serviceType 56 | * @return bool 57 | */ 58 | private function isSupportedServiceType($serviceType){ 59 | return in_array($serviceType, $this->supportedServiceTypes); 60 | } 61 | 62 | /** 63 | * Factory service creation method 64 | * @param SharedConfig $configs 65 | * @param $serviceType 66 | * @return mixed 67 | */ 68 | public function get(AmazonWebServices $aws, $serviceType) 69 | { 70 | //delegate service creation to aws sdk 71 | return $aws->createAwsServiceClient($serviceType); 72 | } 73 | } -------------------------------------------------------------------------------- /DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright Copyright (c) CyberNox Technologies. All rights reserved. 7 | * @license http://www.opensource.org/licenses/BSD-2-Clause BSD License 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace AmazonWebServicesBundle\DependencyInjection; 14 | 15 | use Aws\AwsClient; 16 | use Symfony\Component\Config\Definition\Builder\TreeBuilder; 17 | use Symfony\Component\Config\Definition\ConfigurationInterface; 18 | use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; 19 | 20 | /** 21 | * AmazonWebServicesBundle Configuration 22 | */ 23 | class Configuration implements ConfigurationInterface 24 | { 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | public function getConfigTreeBuilder() 29 | { 30 | $treeBuilder = new TreeBuilder(); 31 | $rootNode = $treeBuilder->root('the_phalcons_amazon_web_services'); 32 | 33 | $this->addWSConfiguration($rootNode); 34 | $this->addServicesConfiguration($rootNode); 35 | 36 | return $treeBuilder; 37 | } 38 | 39 | private function addWSConfiguration(ArrayNodeDefinition $node) 40 | { 41 | $node 42 | ->children() 43 | ->arrayNode('enable_extensions')->defaultValue(array())->prototype('scalar')->end()->end() 44 | ->arrayNode('credentials') 45 | ->children() 46 | ->scalarNode('key')->isRequired()->end() 47 | ->scalarNode('secret')->isRequired()->end() 48 | ->end()//children 49 | ->end()//credentials 50 | ->arrayNode('shared_config') 51 | ->children() 52 | ->scalarNode('region')->isRequired()->end() 53 | ->scalarNode('version')->defaultValue('latest')->end() 54 | ->scalarNode('account_id')->defaultValue(null)->end() 55 | ->scalarNode('canonical_id')->defaultValue(null)->end() 56 | ->scalarNode('canonical_name')->defaultValue(null)->end() 57 | ->scalarNode('mfa_serial')->defaultValue(null)->end() 58 | ->scalarNode('cloudfront_keypair')->defaultValue(null)->end() 59 | ->scalarNode('cloudfront_pem')->defaultValue(null)->end() 60 | ->scalarNode('default_cache_config')->defaultValue(null)->end() 61 | ->booleanNode('certificate_authority')->defaultFalse()->end() 62 | ->booleanNode('disable_auto_config')->defaultFalse()->end() 63 | ->end()//children 64 | ->end()//shared_config 65 | ->end(); //children 66 | } 67 | 68 | private function addServicesConfiguration(ArrayNodeDefinition $node) 69 | { 70 | $node 71 | ->children() 72 | ->arrayNode('services') 73 | ->children() 74 | ->arrayNode('S3') 75 | ->children() 76 | ->scalarNode('bucket')->isRequired()->end() 77 | ->end() 78 | ->end()//amazon s3 79 | ->arrayNode('CloudFront') 80 | ->children() 81 | ->scalarNode('web_distribution')->isRequired()->end() 82 | ->end()//children 83 | ->end()//Cloud front 84 | ->arrayNode('SES') 85 | ->children() 86 | ->scalarNode('verified_addresse')->isRequired()->end() 87 | ->end()//children 88 | ->end()//SES 89 | ->end()//children 90 | ->end()//services 91 | ->end(); //children 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /DependencyInjection/ThePhalconsAmazonWebServicesExtension.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright Copyright (c) CyberNox Technologies. All rights reserved. 7 | * @license http://www.opensource.org/licenses/BSD-2-Clause BSD License 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace AmazonWebServicesBundle\DependencyInjection; 14 | 15 | use Symfony\Component\DependencyInjection\ContainerBuilder; 16 | use Symfony\Component\Config\FileLocator; 17 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; 18 | use Symfony\Component\DependencyInjection\Loader; 19 | 20 | /** 21 | * AmazonWebServicesBundle Extension setup and configuration 22 | */ 23 | class ThePhalconsAmazonWebServicesExtension extends Extension 24 | { 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | public function load(array $configs, ContainerBuilder $container) 29 | { 30 | $configuration = new Configuration(); 31 | $config = $this->processConfiguration($configuration, $configs); 32 | 33 | //not used any more services will be defined during configuration loading 34 | $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 35 | $loader->load('aws_config.xml'); 36 | $loader->load('aws_service.xml'); 37 | 38 | foreach ($config as $key => $value) { 39 | $container->setParameter('the_phalcons_amazon_web_services.' . $key, $value); 40 | } 41 | 42 | 43 | foreach ($config['credentials'] as $key => $value) { 44 | $container->setParameter('the_phalcons_amazon_web_services.credentials.' . $key, $value); 45 | } 46 | foreach ($config['shared_config'] as $key => $value) { 47 | $container->setParameter('the_phalcons_amazon_web_services.shared_config.' . $key, $value); 48 | } 49 | 50 | 51 | } 52 | 53 | private function addFactoryDefinition(){ 54 | //TODO: define config and factory services 55 | } 56 | 57 | /** 58 | * Inject service definition based on provided configuration 59 | * @param ContainerBuilder $container 60 | * @param $serviceType 61 | */ 62 | private function addAwsSerivceDefinition(ContainerBuilder $container, $serviceType) 63 | { 64 | //TODO : implement aws services injection 65 | } 66 | 67 | public function getAlias() 68 | { 69 | return 'the_phalcons_amazon_web_services'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Amazon Web Services Bundle 2 | ========================== 3 | 4 | Notice 5 | ====== 6 | 7 | This bundle is now officially maintained. Special thanks to Mark Badolato [`mbadolato`](https://github.com/mbadolato) 8 | 9 | [![Latest Stable Version](https://poser.pugx.org/cybernox/amazon-webservices-bundle/v/stable.png)](https://packagist.org/packages/cybernox/amazon-webservices-bundle) 10 | [![Total Downloads](https://poser.pugx.org/cybernox/amazon-webservices-bundle/downloads.png)](https://packagist.org/packages/cybernox/amazon-webservices-bundle) 11 | 12 | 13 | Overview 14 | -------- 15 | This is a Symfony2 Bundle for interfacing with Amazon Web Services (AWS). 16 | 17 | This bundle uses the latest [AWS SDK for PHP](http://github.com/amazonwebservices/aws-sdk-for-php) by loading the SDK, and enabling you to instantiate the SDK's various web service objects, passing them back to you for direct use in your Symfony2 application.. 18 | 19 | For installation, configuration, and usage details, please see [`Resources/doc/README.md`](https://github.com/ThePhalcons/AmazonWebServicesBundle/blob/master/Resources/doc/README.md) 20 | 21 | 22 | ## Resources 23 | 24 | * [Get started] – For getting started usage information 25 | * [Sample Project][sdk-sample] - A quick, sample project to help get you started 26 | * [Issues][sdk-issues] – Report issues, submit pull requests, and get involved 27 | (see [Apache 2.0 License][sdk-license]) 28 | 29 | ## Features 30 | 31 | * Provides easy-to-use HTTP clients for all supported AWS 32 | [services][docs-services], [regions][docs-rande], and authentication 33 | protocols. 34 | * Is built on [Guzzle][guzzle-docs], and utilizes many of its features, 35 | including persistent connections, asynchronous requests, middlewares, etc. 36 | * Provides convenience features including easy result pagination via 37 | [Paginators][docs-paginators], [Waiters][docs-waiters], and simple 38 | [Result objects][docs-results]. 39 | * Provides a [multipart uploader tool][docs-s3-multipart] for Amazon S3 and 40 | Amazon Glacier that can be paused and resumed. 41 | * Provides an [Amazon S3 Stream Wrapper][docs-streamwrapper], so that you can 42 | use PHP's native file handling functions to interact with your S3 buckets and 43 | objects like a local filesystem. 44 | * Provides the [Amazon DynamoDB Session Handler][docs-ddbsh] for easily scaling 45 | sessions on a fast, NoSQL database. 46 | * Automatically uses [IAM Instance Profile Credentials][aws-iam-credentials] on 47 | configured Amazon EC2 instances. 48 | 49 | 50 | 51 | Example Use Cases 52 | ----------------- 53 | 1. Connect to, and manipulate, any of the available Amazon Web Services, such as EC2, Amazon S3, SQS, SES, Amazon DynamoDB, Amazon Glacier, etc. 54 | 55 | 2. Utilize Amazon S3 and CloudFront as a Content Delivery Network (CDN) for a Symfony 2 application. Please see the information, graciously provided by [adurieux](https://github.com/adurieux), in [`Resources/doc/cdn.md`](https://github.com/ThePhalcons/AmazonWebServicesBundle/blob/master/Resources/doc/cdn.md). 56 | 57 | 3. Score dates with Supermodels (This feature not yet implemented) 58 | 59 | License 60 | ------- 61 | 62 | This bundle is under the MIT license. See the complete license in the bundle: 63 | 64 | Resources/meta/LICENSE 65 | 66 | [Get started]: 67 | -------------------------------------------------------------------------------- /Resources/config/aws_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | AmazonWebServicesBundle\AmazonWebServices 9 | AmazonWebServicesBundle\AmazonWebServicesFactory 10 | 11 | 12 | 13 | 14 | 15 | %the_phalcons_amazon_web_services.enable_extensions% 16 | 17 | %the_phalcons_amazon_web_services.credentials.key% 18 | %the_phalcons_amazon_web_services.credentials.secret% 19 | 20 | %the_phalcons_amazon_web_services.shared_config.account_id% 21 | %the_phalcons_amazon_web_services.shared_config.region% 22 | %the_phalcons_amazon_web_services.shared_config.version% 23 | %the_phalcons_amazon_web_services.shared_config.canonical_id% 24 | %the_phalcons_amazon_web_services.shared_config.canonical_name% 25 | %the_phalcons_amazon_web_services.shared_config.mfa_serial% 26 | %the_phalcons_amazon_web_services.shared_config.cloudfront_keypair% 27 | %the_phalcons_amazon_web_services.shared_config.cloudfront_pem% 28 | %the_phalcons_amazon_web_services.shared_config.default_cache_config% 29 | %the_phalcons_amazon_web_services.shared_config.certificate_authority% 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | AS 42 | 43 | 44 | 45 | CloudFormation 46 | 47 | 48 | 49 | CloudFront 50 | 51 | 52 | 53 | CloudSearch 54 | 55 | 56 | 57 | CloudWatch 58 | 59 | 60 | 61 | DynamoDB 62 | 63 | 64 | 65 | EC2 66 | 67 | 68 | 69 | ELB 70 | 71 | 72 | 73 | EMR 74 | 75 | 76 | 77 | ElastiCache 78 | 79 | 80 | 81 | ElasticBeanstalk 82 | 83 | 84 | 85 | IAM 86 | 87 | 88 | 89 | ImportExport 90 | 91 | 92 | 93 | RDS 94 | 95 | 96 | 97 | S3 98 | 99 | 100 | 101 | SDB 102 | 103 | 104 | 105 | SES 106 | 107 | 108 | 109 | SNS 110 | 111 | 112 | 113 | SQS 114 | 115 | 116 | 117 | STS 118 | 119 | 120 | 121 | SWF 122 | 123 | 124 | 125 | Route53 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /Resources/config/aws_service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | AmazonWebServicesBundle\AmazonWebServices 9 | AmazonWebServicesBundle\AmazonWebServicesFactory 10 | 11 | 12 | 13 | 14 | 15 | %the_phalcons_amazon_web_services.enable_extensions% 16 | 17 | %the_phalcons_amazon_web_services.credentials.key% 18 | %the_phalcons_amazon_web_services.credentials.secret% 19 | 20 | %the_phalcons_amazon_web_services.shared_config.account_id% 21 | %the_phalcons_amazon_web_services.shared_config.region% 22 | %the_phalcons_amazon_web_services.shared_config.version% 23 | %the_phalcons_amazon_web_services.shared_config.canonical_id% 24 | %the_phalcons_amazon_web_services.shared_config.canonical_name% 25 | %the_phalcons_amazon_web_services.shared_config.mfa_serial% 26 | %the_phalcons_amazon_web_services.shared_config.cloudfront_keypair% 27 | %the_phalcons_amazon_web_services.shared_config.cloudfront_pem% 28 | %the_phalcons_amazon_web_services.shared_config.default_cache_config% 29 | %the_phalcons_amazon_web_services.shared_config.certificate_authority% 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | AS 42 | 43 | 44 | 45 | CloudFormation 46 | 47 | 48 | 49 | CloudFront 50 | 51 | 52 | 53 | CloudSearch 54 | 55 | 56 | 57 | CloudWatch 58 | 59 | 60 | 61 | DynamoDB 62 | 63 | 64 | 65 | EC2 66 | 67 | 68 | 69 | ELB 70 | 71 | 72 | 73 | EMR 74 | 75 | 76 | 77 | ElastiCache 78 | 79 | 80 | 81 | ElasticBeanstalk 82 | 83 | 84 | 85 | IAM 86 | 87 | 88 | 89 | ImportExport 90 | 91 | 92 | 93 | RDS 94 | 95 | 96 | 97 | S3 98 | 99 | 100 | 101 | SDB 102 | 103 | 104 | 105 | SES 106 | 107 | 108 | 109 | SNS 110 | 111 | 112 | 113 | SQS 114 | 115 | 116 | 117 | STS 118 | 119 | 120 | 121 | SWF 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /Resources/doc/Changelog.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | [2012-Apr-12] 5 | 6 | 1. Removed the need for requiring the sdk.class.php library in the autoload.php file by moving the require to the service.xml definition 7 | 2. Step 4 of the documentation removed to reflect the change above 8 | 3. Added a Changelog document 9 | 4. Other minor documentation tweaks 10 | 11 | -------------------------------------------------------------------------------- /Resources/doc/README.md: -------------------------------------------------------------------------------- 1 | # Amazon Web Services Bundle # 2 | 3 | This is a Symfony2 Bundle for interfacing with Amazon Web Services (AWS). 4 | 5 | ## AWS SDK for PHP ## 6 | 7 | This bundle utilizes the [AWS SDK for PHP](http://github.com/amazonwebservices/aws-sdk-for-php) by loading the SDK and providing the means to instantiate the SDK's various web service objects, passing them back to you for direct use. 8 | 9 | The AWS SDK for PHP is the official Amazon-supported library for interfacing with Amazon's Web Service offerings. As such, the bundle merely provides a means (via Dependency Injection) to get at the SDK's various web service objects. There is no additional functionality at present time. 10 | 11 | Once objects have been created, you have full access to the SDK. Please see the [AWS SDK for PHP documentation](http://docs.amazonwebservices.com/AWSSDKforPHP/latest/) for a list of each service's API calls. 12 | 13 | ## Installation ## 14 | 15 | AmazonWebServicesBundle may be installed via the deps file (Symfony 2.0.x) or via Composer (2.1+) 16 | 17 | 18 | 1) Via Composer 19 | 20 | Go to the ```require``` section of your composer.json file and add 21 | 22 | ```json 23 | "thephalcons/amazon-webservices-bundle": ">=2.1" 24 | ``` 25 | 26 | OR using command line 27 | 28 | ``` 29 | composer require thephalcons/amazon-webservices-bundle 30 | ``` 31 | to the section, along with other packages you require. Now run ```composer.phar install``` if this is a new installation, or ```composer.phar update``` if you are updating an existing installation. 32 | 33 | 2) Add AmazonWebServicesBundle to your application kernel: 34 | 35 | ```php 36 | registerNamespaces(array( 58 | // ... 59 | 'ThePhalcons' => __DIR__.'/../vendor/bundles', 60 | // ... 61 | )); 62 | ``` 63 | 64 | 4) Run `bin/vendors install` to have Symfony download and install the packages 65 | 66 | 5) Set up your configuration. 67 | 68 | 5a) First configure your parameters.ini: 69 | 70 | ```ini 71 | // app/config/parameters.ini 72 | [parameters] 73 | ... 74 | 75 | ; Amazon Web Services Configuration. Found in the AWS Security Credentials. 76 | aws_key = YOUR_KEY 77 | aws_secret = YOUR_SECRET_KEY 78 | aws_account_id = YOUR_ACCOUNT_ID 79 | aws_canonical_id = YOUR_CONONICAL_ID 80 | aws_canonical_name = YOUR_CONONICAL_NAME 81 | aws_mfa_serial = YOUR_MFA_SERIAL 82 | aws_cloudfront_keypair = YOUR_CLOUDFRONT_KEYPAIR_ID 83 | aws_cloudfront_pem = YOUR_CLOUDFRONT_PRIVATE_KEY_PEM 84 | aws_region = YOUR_REGION 85 | aws_version = 'latest' #or YOUR_VERSION 86 | ``` 87 | 88 | **Note, presently only aws_key and aws_secret are being used when constructing objects. Setting them is fine, but it won't do anything.** 89 | 90 | **aws_cloudfront_pem should be contents of your pem file, including startline and endline. To work with multiline add double quotes. Example:** 91 | 92 | ```ini 93 | aws_cloudfront_private_key_pem = "-----BEGIN RSA PRIVATE KEY----- 94 | *private key goes here* 95 | -----END RSA PRIVATE KEY-----" 96 | ``` 97 | 98 | 5b) Set up your application configuration: 99 | 100 | ```yml 101 | // app/config/config.yml 102 | # Amazon Web Services Configuration 103 | the_phalcons_amazon_web_services: 104 | # for stream wrapper use : [S3, SES ...] 105 | enable_extensions: [] 106 | credentials: 107 | key: 108 | secret: 109 | shared_config: 110 | region: %aws_region% 111 | version: %aws_version% 112 | account_id: %aws_account_id% 113 | canonical_id: %aws_canonical_id% 114 | canonical_name: %aws_canonical_name% 115 | mfa_serial: %aws_mfa_serial% 116 | cloudfront_keypair: %aws_cloudfront_keypair% 117 | cloudfront_pem: %aws_cloudfront_pem% 118 | default_cache_config: null 119 | certificate_authority: false 120 | disable_auto_config: false 121 | ``` 122 | 123 | **Note, as in 5a) above, only the key and secret are presently being used, so it is safe to omit the rest if you wish.** 124 | 125 | **The AWS SDK by default looks for configuration files in various standard locations. If they're not found, error messages are emitted to the web server's log, though performance is not impacted. If you do not use the auto-configuration and wish to suppress the error messages, enable the disable_auto_config option.** 126 | 127 | **You're welcome to skip setting the configurations in parameters.ini (5a) and set the values directly in config.yml, however, the setup shown here is following the example that Sensio used for Symfony with regards to database setup, and keeping the actual private configuration values in parameters.ini and utilizing them in config.yml.** 128 | 129 | ## Usage ## 130 | 131 | Once installed, you simply need to request the appropriate service for the Amazon Web Service object you wish to use. The returned object will then allow you full access the API for the requested service. 132 | 133 | **Please see the [AWS SDK for PHP documentation](http://docs.amazonwebservices.com/AWSSDKforPHP/latest/) for a list of each service's API calls.** 134 | 135 | In this example, we get an AmazonSQS object from the AWS SDK for PHP library by requesting the ```aws_sqs``` service. We then use that object to retrieve a message from an existing Amazon SQS queue. 136 | 137 | ```php 138 | container->get('aws_sqs'); 145 | 146 | // Get a message from an existing queue 147 | $response = $sqs->receive_message($queueUrl); 148 | 149 | // Do stuff with the received message response object 150 | // ... 151 | } 152 | ``` 153 | 154 | ### Available Services ### 155 | 156 | The following services are available, each returning an object allowing access to the respective Amazon Web Service 157 | 158 | _Please note, at this time, thorough testing has not been completed. Because this bundle merely creates object from the SDK and passes them though to you, there shouldn't be any issues. However, this message is here as warning, just in case. In the event that a bug exists within the bundle's service definitions (and not within the SDK itself), please let me know!_ 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 |
Symfony Service NameAWS SDK for PHP ObjectDescription
aws_asAmazonASAmazon Auto Scaling
aws_cloud_formationAmazonCloudFormationAmazon CloudFormation
aws_cloud_frontAmazonCloudFrontAmazon CloudFront
aws_cloud_searchAmazonCloudSearchAmazon CloudSearch
aws_cloud_watchAmazonCloudWatchAmazon CloudWatch
aws_dynamo_dbAmazonDynamoDBAmazon DynamoDB
aws_ec2AmazonEC2Amazon Elastic Compute Cloud (EC2)
aws_elbAmazonELBAmazon Elastic Load Balancing
aws_emrAmazonEMRAmazon Elastic MapReduce
aws_elasti_cacheAmazonElastiCacheAmazon ElastiCache
aws_elastic_beanstalkAmazonElasticBeanstalkAmazon Elastic Beanstalk
aws_iamAmazonIAMAmazon Identity and Access Management
aws_import_exportAmazonImportExportAmazon Import/Export
aws_rdsAmazonRDSAmazon Relational Database Service
aws_s3AmazonS3Amazon Simple Storage Service (S3)
aws_sdbAmazonSDBAmazon SimpleDB
aws_sesAmazonSESAmazon Simple Email Service
aws_snsAmazonSNSAmazon Simple Notification Service
aws_sqsAmazonSQSAmazon Simple Queue Service
aws_stsAmazonSTSAmazon Security Token Service
aws_swfAmazonSWFAmazon Simple Workflow
aws_Route53AmazonRoute53Amazon Route 53
298 | -------------------------------------------------------------------------------- /Resources/doc/Samples: -------------------------------------------------------------------------------- 1 | 2 | ## Quick Examples 3 | 4 | ### Create an Amazon S3 client 5 | 6 | ```php 7 | 8 | /** 9 | * @Route("/aws/test", name="_demo") 10 | * @Template() 11 | */ 12 | public function indexAction() 13 | { 14 | 15 | /** @var S3Client $s3 */ 16 | $s3 = $this->container->get('aws_s3'); 17 | 18 | } 19 | 20 | ``` 21 | 22 | ### Send file to a bucket 23 | 24 | ```php 25 | /** 26 | * send file to aws a bucket 27 | * @param $absolutePath String locale file 28 | * @param $awsTargetPath String aws targetPath 29 | * @return \Aws\Result 30 | * @throws \NotFoundBucket 31 | */ 32 | public function multipartUploader($absolutePath, $awsTargetPath) 33 | { 34 | $bucket = 'my_bucket_name'; 35 | 36 | $uploader = new MultipartUploader($this->s3, $absoluteFilePath, [ 37 | 'bucket' => $absolutePath, 38 | 'key' => $awsTargetPath, 39 | ]); 40 | 41 | 42 | do { 43 | try { 44 | $result = $uploader->upload(); 45 | } catch (MultipartUploadException $e) { 46 | $uploader = new MultipartUploader($this->s3, $absoluteFilePath, [ 47 | 'state' => $e->getState(), 48 | ]); 49 | } 50 | } while (!isset($result)); 51 | 52 | try { 53 | $result = $uploader->upload(); 54 | return $result; 55 | } catch (MultipartUploadException $e) { 56 | throw $e; 57 | } 58 | } 59 | ``` 60 | 61 | ### Send email using SES 62 | 63 | [SES Mailing sevice] 64 | 65 | [SES Mailing sevice]: 66 | -------------------------------------------------------------------------------- /Resources/doc/cdn.md: -------------------------------------------------------------------------------- 1 | # How to use Amazon S3 and Amazon CloudFront as a CDN ? 2 | 3 | Here is a step-by step tutorial on how to use Amazon CloudFront and Amazon S3 as 4 | a CDN for Symfony2, thanks to the AmazonWebServicesBundle and the AWS PHP SDK. 5 | 6 | It probably goes beyond the specificities of Symfony2. 7 | 8 | We will assume you have a website called acme.com, that runs with Symfony2. The 9 | configuration file paths are the ones that you could have under MacOS X with MAMP. 10 | 11 | ## Development server configuration 12 | 13 | ### Some helpers 14 | 15 | For testing purposes, we simulate the behavior of the production website the following way : 16 | 17 | * on development machines : 18 | * the URL of the project must be `http://local.acme.com` 19 | * and all the assets will be accessible through `http://localcdn.acme.com` 20 | * on production servers : 21 | * the URL of the project can be whatever you want. 22 | * the CDN will be hosted on Amazon S3, and accessible through `http://cdn.acme.com` 23 | 24 | Let's first try to make it work locally : append these lines to your `hosts`: 25 | 26 | ``` 27 | sudo nano /private/etc/hosts 28 | ``` 29 | 30 | ``` 31 | 127.0.0.1 local.acme.com 32 | 127.0.0.1 localcdn.acme.com 33 | ``` 34 | 35 | Then, update the Virtual Hosts of your local server in order to handle these calls : 36 | 37 | ``` 38 | sudo nano /Applications/MAMP/conf/apache/httpd.conf 39 | ``` 40 | 41 | ``` 42 | 43 | DocumentRoot "/Applications/MAMP/htdocs/Acme/web" 44 | ServerName local.acme.com 45 | 46 | 47 | 48 | DocumentRoot "/Applications/MAMP/htdocs/AcmeCDN/" 49 | ServerName localcdn.acme.com 50 | 51 | ``` 52 | 53 | Restart your local server to apply changes. Check you are able to see the local 54 | website and the CDN (empty) page in your browser. 55 | 56 | Let's now switch to Symfony. 57 | 58 | ### Templating vs Assetic 59 | 60 | There are 2 different things that need to be distinguished in Symfony2 : 61 | 62 | * The templating engine : handles the rendering or web pages, and, as matter of 63 | fact, writes every URL, especially the ones of the assets. 64 | * The AsseticBundle : his goal is to compress/merge/optimize assets. He is not 65 | the one that writes URL in templates, but he decides where to store these optimized 66 | assets. 67 | 68 | We thus have to configure both of them. 69 | 70 | ### Templating engine configuration 71 | 72 | The configuration of the templating engine is made in the `config.yml` file. 73 | Provided the templating engine is part of the Symfony2 framework, we have to 74 | configure it under the `framework.templating` path. 75 | 76 | Everytime a helper method will be called, Symfony has to append to the url a given 77 | domain. As a default, Symfony assumes that the assets are stored on the server 78 | itself. Thus, this prefix is simply `/`. But, because we use a CDN, we need to 79 | specify it here. 80 | 81 | ``` 82 | // app/config/config_dev.yml 83 | framework: 84 | templating: 85 | assets_base_urls: 86 | http: [%cdn_url_dev%] 87 | 88 | // app/config/parameters.ini 89 | cdn_url_dev= "http://localcdn.acme.com/web" 90 | ``` 91 | 92 | We now need to transfer our assets to the CDN (this syntax I quite hairy, I agree): 93 | 94 | ``` 95 | php app/console assets:install /Applications/MAMP/htdocs/AcmeCDN/web --symlink 96 | 97 | ``` 98 | 99 | We can load `http://local.acme.com` to check that the assets have correctly 100 | been migrated. 101 | 102 | See also : [Configuration reference](http://symfony.com/doc/2.0/reference/configuration/framework.html). 103 | 104 | ### Assetic Bundle configuration 105 | 106 | We now need to configure assetic so it also use the CDN. Assetic does three things : 107 | 108 | * he searches assets to optimize from the `read_from` directory, 109 | * deals with them, 110 | * and eventually writes them in the `write_to` directory. 111 | 112 | As a default, these two values are set to `%kernel.root_dir%/../web`, directly 113 | in the same server as the application. We can now change these values to the CDN : 114 | 115 | ``` 116 | // app/config/config_dev.yml 117 | assetic: 118 | read_from: %cdn_path_dev% 119 | write_to: %cdn_path_dev% 120 | 121 | // app/config/parameters.ini 122 | cdn_path_dev = "/Applications/MAMP/htdocs/AcmeCDN/web" 123 | ``` 124 | 125 | In the dev environnement, we need to specify the disk path, so the application 126 | can write directly in the directory. Eventually, we can dump the assets to the CDN : 127 | 128 | ``` 129 | php app/console assetic:dump 130 | ``` 131 | 132 | If you test your local pages in your browser, you will see that the assets have 133 | correctly moved. 134 | 135 | ## Setting up Amazon S3 and CloudFront as a CDN 136 | 137 | Amazon S3 is simply a storage system. In order to build an actual CDN, we need to 138 | use CloudFront, that replicates the content stored on Amazon S3 to various locations 139 | for maximum speed. 140 | 141 | ### Create S3 bucket 142 | 143 | First, we need to create a bucket that will hold the content that will be broadcasted on the CDN. 144 | 145 | * Log in the **AWS Console**. 146 | * Open the **S3** tab. 147 | * Click **Create new bucket** (name example : _cdn-acme_). 148 | * Click **Upload** and choose a test file `test.png`, and be sure to : 149 | * click **Set details**, tick **Reduced Redundancy Storage**. 150 | * click **Set Permissions** and **Make everything public**. 151 | 152 | ### Create a CloudFront distribution 153 | 154 | * Then, go on the **CloudFront** tab. 155 | * Click **Create distribution** 156 | * Select the bucket you just created 157 | * Setup the CNAME to _cdn.acme.com_ 158 | * Review changes and click **Create distribution** 159 | * Wait a bit, and copy paste the domain name (ex : _42jhdsqhdj.cloudfront.net_) 160 | to your browser, and append the test file name (ex : _test.png_). Check that you 161 | see your test file. 162 | 163 | ### Setup CNAMEs 164 | 165 | You finally need to create the CNAME that will redirect _http://cdn.acme.com_ 166 | to our distribution. 167 | 168 | * Copy the domain name that was just generated. 169 | * Go to the **Route 53** tab. 170 | * Select the _acme.com_ zone. 171 | * Create/update a CNAME with name _http://cdn.acme.com_ and redirect it to 172 | the CloudFront domaon Name. 173 | * Check that _http://cdn.acme.com/test.png_ works fine. 174 | 175 | References : 176 | 177 | - [CloudFront homepage](http://aws.amazon.com/cloudfront/) 178 | - [Getting started tutorial](http://docs.amazonwebservices.com/AmazonCloudFront/latest/GettingStartedGuide/StartingCloudFront.html) 179 | - [S3 homepage](http://aws.amazon.com/s3/) 180 | 181 | ## Production server configuration 182 | 183 | Now we need to setup the configuration for the Product server : 184 | 185 | ``` 186 | // app/config/config_prod.yml 187 | framework: 188 | templating: 189 | assets_base_urls: 190 | http: [%cdn_url_prod%] 191 | 192 | // app/config/config_prod.yml 193 | assetic: 194 | read_from: %cdn_path_prod% 195 | write_to: %cdn_path_prod% 196 | 197 | // app/config/parameters.ini 198 | cdn_url_prod= "http://cdn.acme.com/web" 199 | cdn_path_prod= "s3://cdn-acme" 200 | ``` 201 | 202 | NB : no need to be more accurate for the bucket path, we will use a special service 203 | to provide the key/secret (see below). 204 | 205 | ## Dump assets to the S3 bucket 206 | 207 | At this point, if we try to simply run the `assetic:dump` command, it will output 208 | an error : `Unable to find the wrapper "s3" - did you forget to enable it when you 209 | configured PHP?`. This is due to the fact that PHP does not know natively how to 210 | handle the `s3` protocol. 211 | 212 | In order to teach him to do so, there are several solutions. We could use the 213 | [Zend S3 Stream Wrapper](http://framework.zend.com/manual/en/zend.service.amazon.s3.html#zend.service.amazon.s3.streams) 214 | but it's quite overkill to load the entire Zend Framework just for that. 215 | 216 | A better thing to do is use the Amazon AWS PHP SDK, which (although it suffers some 217 | bugs), is integrated in Symfony thanks to the [AmazonWebServicesBundle](https://github.com/Cybernox/AmazonWebServicesBundle). 218 | 219 | Pittifully, simply installing the Bundle is not enough : at no point we load the 220 | S3 service when calling the Assetic command. We need to force the registration 221 | of the StreamWrapper some way. 222 | 223 | You can register the stream wrapper when the Kernel boot by editing your AppKernel.php 224 | Simply copy paste that code in it: 225 | 226 | ``` 227 | public function boot() 228 | { 229 | \Aws\S3\S3Client::factory()->registerStreamWrapper(); 230 | return parent::boot(); 231 | } 232 | ``` 233 | 234 | Now we can give it one more try : run `php app/console assetic:dump`. And one more 235 | bug : `Unable to create directory s3:/...`. According to [this link](https://github.com/symfony/AsseticBundle/issues/37), 236 | it seems that "S3 doesn't really have directories, it only pretends to.". 237 | 238 | An extremely quick and dirty way to solve that is to return systematically true 239 | in the `mkdir` method of the StreamWrapper : 240 | 241 | ``` 242 | // vendor/aws-sdk-for-php/extensions/s3streamwrapper.class.php 243 | 244 | public function mkdir($path, $mode, $options) 245 | { 246 | /** **/ 247 | return true; 248 | // return $response->isOK(); 249 | } 250 | ``` 251 | 252 | And then, one more try : 253 | 254 | ``` 255 | php app/console assetic:dump 256 | ``` 257 | 258 | It works ! But there is still a couple of issues : 259 | 260 | - As a default, none of the assets is set to be public. We need to run another script to do so. 261 | - Similarly, none of them is stored in Reduced Redundancy mode. Which you may want. 262 | 263 | References : 264 | 265 | - [StackOverflow question](http://stackoverflow.com/questions/8163717/dump-symfony2-assets-to-amazon-s3) 266 | - [Initial PR on Symfony](https://github.com/symfony/symfony/pull/108) 267 | - [Assetic presentation](http://www.slideshare.net/kriswallsmith/assetic-symfony-live-paris) (see slide 72) 268 | 269 | ## Optimize security 270 | 271 | -------------------------------------------------------------------------------- /Resources/doc/todo.md: -------------------------------------------------------------------------------- 1 | # Amazon Web Services Bundle - TODO# 2 | 3 | 1. Refactor aws-sdk-for-php (or find what we can pass in during instantiation to circumvent) so the config.inc.php file presence issue isn't an issue 4 | 5 | 2. Integrate the cloudfusion AmazonPAS functionality 6 | 7 | 3. update documentation 8 | 9 | 4. Using credentials from environment variables, credentials profiles or env provider 10 | 11 | ``` 12 | 13 | 14 | $this->sdk = new Sdk( 15 | array( 16 | 'region' => $this->getRegion(), 17 | // use specific aws sdk php version or latest version if not defined 18 | 'version' => ($this->getVersion() != '' ) ? $this->getVersion() : 'latest', 19 | 'credentials' => CredentialProvider::env() 20 | ) 21 | ); 22 | 23 | //instead of 24 | 25 | $credentials = new Credentials($this->getKey(), $this->getSecret()); 26 | 27 | // it's more better to use Credentials provide. 28 | // possibility to use memorize function which will cache your credentials 29 | // and optimize performances 30 | 31 | $this->sdk = new Sdk( 32 | array( 33 | 'region' => $this->getRegion(), 34 | // use specific aws sdk php version or latest version if not defined 35 | 'version' => ($this->getVersion() != '' ) ? $this->getVersion() : 'latest', 36 | 'credentials' => $credentials 37 | ) 38 | ); 39 | 40 | ``` 41 | 42 | -------------------------------------------------------------------------------- /Resources/meta/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2013 Mark Badolato, CyberNox Technologies. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED BY CYBERNOX TECHNOLOGIES ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CYBERNOX TECHNOLOGIES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 10 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | 12 | The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of CyberNox Technologies. 13 | -------------------------------------------------------------------------------- /Services/SESMailingService.php: -------------------------------------------------------------------------------- 1 | 21 | * 22 | * Initial version created on: 23/01/16 02:31 23 | * 24 | */ 25 | class SESMailingService 26 | { 27 | 28 | 29 | /** 30 | * @var Container 31 | */ 32 | private $container; 33 | 34 | /** 35 | * @var Logger 36 | */ 37 | protected $logger; 38 | 39 | /** 40 | * @var object 41 | */ 42 | protected $mailer; 43 | 44 | /** 45 | * The email address that is sending the email. 46 | * @var 47 | */ 48 | protected $source; 49 | 50 | /** 51 | * The sender name that is sending the email. 52 | * @var 53 | */ 54 | protected $name; 55 | 56 | /** 57 | * The subject of the message: A short summary of the content, which will appear in the recipient's inbox. 58 | * @var 59 | */ 60 | protected $subject; 61 | 62 | /** 63 | * The To: field(s) of the message. 64 | * @var array 65 | */ 66 | protected $toAddresses = array(); 67 | 68 | /** 69 | * The message body. 70 | * @var 71 | */ 72 | protected $body; 73 | 74 | /** 75 | * The CC: field(s) of the message. 76 | * @var array 77 | */ 78 | protected $ccAddresses = array(); 79 | 80 | /** 81 | * The To: field(s) of the message. 82 | * @var array 83 | */ 84 | protected $bccAddresses = array(); 85 | 86 | /** 87 | * he reply-to email address(es) for the message. If the recipient replies to the message, each reply-to address will receive the reply. 88 | * 89 | * @var array 90 | */ 91 | protected $replyToAddresses = array(); 92 | 93 | /** 94 | * f the message cannot be delivered to the recipient, then an error message will be returned from the recipient's 95 | * @var String 96 | */ 97 | protected $returnPath; 98 | 99 | /** 100 | * @param Container $container 101 | */ 102 | public function __construct(Container $container) 103 | { 104 | $this->container = $container; 105 | $this->mailer = $container->get('amazon_SES'); 106 | $this->logger = $container->get('logger'); 107 | $this->initMailer(); 108 | } 109 | 110 | /** 111 | * init mailer service 112 | */ 113 | private function initMailer() 114 | { 115 | $this->setDefaultSource(); 116 | } 117 | 118 | /** 119 | * set default source and reply addresses from global config 120 | */ 121 | public function setDefaultSource() 122 | { 123 | $this->source = $this->container->getParameter('ws.services.SES.mail_config.no_reply_address'); 124 | 125 | $this->replyToAddresses[] = $this->container->getParameter('ws.services.SES.mail_config.reply_address'); 126 | 127 | return $this; 128 | } 129 | 130 | /** 131 | * @param String $source 132 | * @return $this 133 | */ 134 | public function setSource($source) 135 | { 136 | $this->source = $source; 137 | 138 | return $this; 139 | } 140 | 141 | /** 142 | * @param $subject 143 | * @return $this 144 | */ 145 | public function setSubject($subject) 146 | { 147 | $this->subject = $subject; 148 | return $this; 149 | } 150 | 151 | /** 152 | * @param Array $to 153 | * @return $this 154 | */ 155 | public function setTo($to) 156 | { 157 | $this->toAddresses = $to; 158 | return $this; 159 | } 160 | 161 | /** 162 | * @param $toAddress 163 | * @return $this 164 | */ 165 | public function addToAddress($toAddress){ 166 | $this->toAddresses[] = $toAddress; 167 | return $this; 168 | } 169 | 170 | /** 171 | * @param $body 172 | * @return $this 173 | */ 174 | public function setMessage($body) 175 | { 176 | $this->body = $body; 177 | return $this; 178 | } 179 | 180 | /** 181 | * @param $ccAddress 182 | * @return $this 183 | */ 184 | public function addCCAddress($ccAddress){ 185 | $this->ccAddresses[] = $ccAddress; 186 | return $this; 187 | } 188 | 189 | /** 190 | * @param $bccAddress 191 | * @return $this 192 | */ 193 | public function addBccAddress($bccAddress){ 194 | $this->bccAddresses[] = $bccAddress; 195 | return $this; 196 | } 197 | 198 | /** 199 | * @return mixed 200 | */ 201 | public function sendEmail(){ 202 | $result = $this->mailer->sendEmail( 203 | array( 204 | // Source is required 205 | 'Source' => $this->source, 206 | 207 | // Destination is required 208 | 'Destination' => array( 209 | 'ToAddresses' => $this->toAddresses, 210 | 'CcAddresses' => $this->ccAddresses, 211 | 'BccAddresses' => $this->bccAddresses, 212 | ), 213 | // Message is required 214 | 'Message' => array( 215 | // Subject is required 216 | 'Subject' => array( 217 | // Data is required 218 | 'Charset' => 'UTF-8' , 219 | 'Data' => $this->subject, 220 | ), 221 | // Body is required 222 | 'Body' => array( 223 | 'Text' => array( 224 | // Data is required 225 | 'Charset' => 'UTF-8', 226 | 'Data' => $this->body, // REQUIRED 227 | ), 228 | 'Html' => array( 229 | // Data is required 230 | 'Charset' => 'UTF-8', 231 | 'Data' => $this->body, // REQUIRED 232 | ), 233 | ), 234 | ), 235 | 'ReplyToAddresses' => $this->replyToAddresses, 236 | //TODO: add below params 237 | // 'ReturnPath' => 'string', 238 | // 'SourceArn' => 'string', 239 | // 'ReturnPathArn' => 'string', 240 | )); 241 | return $result; 242 | } 243 | 244 | /** 245 | * @return mixed 246 | */ 247 | public function getSource() 248 | { 249 | return $this->source; 250 | } 251 | 252 | /** 253 | * @return mixed 254 | */ 255 | public function getName() 256 | { 257 | return $this->name; 258 | } 259 | 260 | /** 261 | * @return mixed 262 | */ 263 | public function getSubject() 264 | { 265 | return $this->subject; 266 | } 267 | 268 | /** 269 | * @return mixed 270 | */ 271 | public function getToAddresses() 272 | { 273 | return $this->toAddresses; 274 | } 275 | 276 | /** 277 | * @return mixed 278 | */ 279 | public function getBody() 280 | { 281 | return $this->body; 282 | } 283 | 284 | /** 285 | * @return array 286 | */ 287 | public function getCcAddresses() 288 | { 289 | return $this->ccAddresses; 290 | } 291 | 292 | /** 293 | * @return array 294 | */ 295 | public function getBccAddresses() 296 | { 297 | return $this->bccAddresses; 298 | } 299 | 300 | } 301 | -------------------------------------------------------------------------------- /Services/SQSLogger.php: -------------------------------------------------------------------------------- 1 | log($message); 12 | * $SQS->error($message); 13 | * $SQS->critical($message); 14 | * @package Core\AWSBundle\Service 15 | * @author El Mehdi Mouddene 16 | **/ 17 | 18 | class SQSLogger{ 19 | 20 | // Logging level 21 | const LEVEL_DEBUG = 'DEBUG'; //0 22 | const LEVEL_INFO = 'INFO'; //1 23 | const LEVEL_ERROR = 'ERROR'; //2 24 | const LEVEL_CRITICAL = 'CRITICAL'; //3 25 | const LEVEL_EMERGENCY = 'EMERGENCY'; //4 26 | const LEVEL_EXCEPTION = 'EXCEPTION'; //5 27 | 28 | private $container; 29 | private $client; 30 | 31 | public function __construct(Container $container) 32 | { 33 | $this->container = $container; 34 | $this->client = $this->container->get('aws_sqs'); 35 | } 36 | 37 | /** 38 | * @param $level 39 | * @return mixed 40 | */ 41 | private function getQueueUrl($level){ 42 | $result = $this->client->createQueue('project_logging_queue_'.$level); 43 | return $result->body->CreateQueueResult->QueueUrl; 44 | } 45 | 46 | /** 47 | * @param $message 48 | * @return mixed|void 49 | */ 50 | public function info($message){ 51 | $this->sendMessage($message, $this->getQueueUrl(self::LEVEL_INFO)); 52 | } 53 | 54 | public function debug($message){ 55 | $this->sendMessage($message, $this->getQueueUrl(self::LEVEL_DEBUG)); 56 | } 57 | 58 | public function error($message){ 59 | $this->sendMessage($message, $this->getQueueUrl(self::LEVEL_ERROR)); 60 | } 61 | 62 | public function critical($message){ 63 | $this->sendMessage($message, $this->getQueueUrl(self::LEVEL_CRITICAL)); 64 | } 65 | 66 | public function emergency($message) 67 | { 68 | $this->sendMessage($message, $this->getQueueUrl(self::LEVEL_EMERGENCY)); 69 | } 70 | 71 | public function exception(\Exception $e){ 72 | $this->sendMessage($e->getMessage(), self::LEVEL_EXCEPTION); 73 | } 74 | 75 | 76 | public function sendMessage($message, $queueUrl){ 77 | $this->client->sendMessage($queueUrl, $message); 78 | } 79 | 80 | 81 | } -------------------------------------------------------------------------------- /Services/StorageService.php: -------------------------------------------------------------------------------- 1 | 36 | * 37 | * Initial version created on: 25/10/15 19:01 38 | * 39 | */ 40 | class StorageService { 41 | 42 | /** 43 | * const ACL 44 | */ 45 | const ACL_PUBLIC = 'acl_public'; 46 | 47 | /** 48 | * @var Container 49 | */ 50 | private $container; 51 | 52 | /** 53 | * @var string 54 | */ 55 | private $target; 56 | 57 | /** 58 | * @var Logger 59 | */ 60 | private $logger; 61 | 62 | /** 63 | * @var EventDispatcher 64 | */ 65 | private $event_dispatcher; 66 | 67 | /** 68 | * @var EntityManager 69 | */ 70 | private $em; 71 | 72 | /** 73 | * @var Filesystem 74 | */ 75 | private $fs; 76 | 77 | /** 78 | * @var S3Client 79 | */ 80 | private $s3; 81 | 82 | /** 83 | * StorageService constructor. 84 | * @param Container $container 85 | */ 86 | public function __construct(Container $container) 87 | { 88 | $this->container = $container; 89 | $this->em = $container->get('doctrine.orm.default_entity_manager'); 90 | 91 | // AWS SQS logging queue 92 | $this->logger = $this->container->get('api.logger'); 93 | $this->event_dispatcher = $container->get('event_dispatcher'); 94 | $this->fs = new Filesystem(); 95 | $this->target = $container->get('kernel')->getRootDir() . '/../web/tmp_uploads'; 96 | $this->s3 = $this->container->get('amazon_s3'); 97 | } 98 | 99 | /** 100 | * send file to S3 aws bucket 101 | * @param $Path file to upload 102 | * @param $aws_key aws target path 103 | * @return JsonResponse 104 | * @throws 105 | * @throws Exception 106 | */ 107 | public function process($Path, $aws_key) 108 | { 109 | 110 | try { 111 | 112 | $this->multipartUploader($path, $aws_key); 113 | 114 | }catch (MultipartUploadException $e) { 115 | 116 | $this->logger->error('MultiPart Uploader error : ' . $e->getMessage()); 117 | 118 | return new JsonResponse(['Error' => $e->getMessage(), 'status' => 500], 200); 119 | } 120 | 121 | $webPath = $this->container->getParameter('api.imgix.source') . '/'. $aws_key; 122 | 123 | return new JsonResponse( 124 | ['message' => "success", 125 | 'status' => 200, 126 | 'callback_url' => $webPath, 127 | 'resource_id' => $image->getId() 128 | ], 200); 129 | } 130 | 131 | 132 | /** 133 | * @param $awsPath aws file to delete 134 | * @return mixed|null 135 | * @throws Exception 136 | */ 137 | private function deleteObject($bucket, $awsPath){ 138 | 139 | $this->logger->debug('delete ' . $awsPath . ' from ' . $bucket .' bucket ...'); 140 | 141 | $result = $this->s3->deleteObject( 142 | array( 143 | 'Bucket' => $bucket, 144 | 'Key' =>$awsPath, 145 | ) 146 | ); 147 | 148 | try { 149 | return $result; 150 | $this->logger->debug('delete ' . $awsPath . ' from ' . $bucket .' bucket ! done'); 151 | } catch (AwsException $e) { 152 | throw $e; 153 | } 154 | } 155 | 156 | /** 157 | * send file to aws bucket 158 | * @param $absolutePath String locale file 159 | * @param $awsTargetPath String aws targetPath 160 | * @return \Aws\Result 161 | * @throws \NotFoundBucket 162 | */ 163 | private function multipartUploader($absolutePath, $awsTargetPath) 164 | { 165 | $bucket = 'my_bucket_name'; 166 | 167 | $uploader = new MultipartUploader($this->s3, $absoluteFilePath, [ 168 | 'bucket' => $absolutePath, 169 | 'key' => $awsTargetPath, 170 | ]); 171 | 172 | 173 | do { 174 | try { 175 | $result = $uploader->upload(); 176 | } catch (MultipartUploadException $e) { 177 | $uploader = new MultipartUploader($this->s3, $absoluteFilePath, [ 178 | 'state' => $e->getState(), 179 | ]); 180 | } 181 | } while (!isset($result)); 182 | 183 | try { 184 | $result = $uploader->upload(); 185 | return $result; 186 | } catch (MultipartUploadException $e) { 187 | throw $e; 188 | } 189 | } 190 | 191 | } 192 | 193 | -------------------------------------------------------------------------------- /StreamWrapper/S3StreamWrapper.php: -------------------------------------------------------------------------------- 1 | buffer === null) 16 | { 17 | return false; 18 | } 19 | 20 | list($protocol, $bucket, $object_name) = $this->parse_path($this->path); 21 | 22 | $extension = explode('.', $object_name); 23 | $extension = array_pop($extension); 24 | if ('woff' === $extension) { 25 | $contentType = 'application/x-font-woff'; 26 | } else { 27 | $contentType = CFMimeTypes::get_mimetype($extension); 28 | } 29 | 30 | $response = $this->client($protocol)->create_object($bucket, $object_name, array( 31 | 'body' => $this->buffer, 32 | 'contentType' => $contentType, 33 | 'headers' => $this->buildHeadersForContent($this->buffer) 34 | )); 35 | 36 | $this->seek_position = 0; 37 | $this->buffer = null; 38 | $this->eof = true; 39 | 40 | return $response->isOK(); 41 | } 42 | 43 | public static function register(\AmazonS3 $s3 = null, $protocol = 's3') 44 | { 45 | self::$_clients[$protocol] = $s3 ? $s3 : new \AmazonS3(); 46 | 47 | return stream_wrapper_register($protocol, __CLASS__); 48 | } 49 | 50 | private function buildHeadersForContent($content) 51 | { 52 | $path = tempnam(sys_get_temp_dir(), 's3_mime_type'); 53 | file_put_contents($path, $content); 54 | 55 | $headers = array(); 56 | 57 | if($this->isFileGzipped($path)){ 58 | $headers['Content-Encoding'] = "gzip"; 59 | } 60 | 61 | unlink($path); 62 | 63 | return $headers; 64 | } 65 | 66 | private function isFileGzipped($path) 67 | { 68 | return $this->getFileMimeType($path) == "application/x-gzip"; 69 | } 70 | 71 | private function getFileMimeType($path) 72 | { 73 | $finfo = finfo_open(FILEINFO_MIME_TYPE); 74 | $mimeType = finfo_file($finfo, $path); 75 | finfo_close($finfo); 76 | 77 | return $mimeType; 78 | } 79 | } -------------------------------------------------------------------------------- /Tests/Services/SESMailingServiceTest.php: -------------------------------------------------------------------------------- 1 | createClient(); 22 | $ses = $client->getContainer()->get('amazon_SES'); 23 | assert($ses !== null, 'SES is not defined'); 24 | } 25 | 26 | /** 27 | * tests if verified email address exist in global config 28 | */ 29 | public function testMailingServiceInjection() 30 | { 31 | $client = $this->createClient(); 32 | $mailer = $client->getContainer()->get('ws.service.mailing'); 33 | assert($mailer !== null, 'Mailing Service injection is not working'); 34 | assert($mailer instanceof MailingService, 'given Object is not an instance of MailingService'); 35 | } 36 | 37 | // public function testSendMail() 38 | // { 39 | // $client = $this->createClient(); 40 | // /**@var $mailer MailingService */ 41 | // $mailer = $client->getContainer()->get('ws.service.mailing'); 42 | // $mailer->setSubject('Drivy UNIT TEST') 43 | // ->addToAddress('mouddene@gmail.com') 44 | // ->setMessage('UNIT TEST is working'); 45 | // $result = $mailer->sendEmail(); 46 | // 47 | // var_dump($result); 48 | // assert(true === true, "todo"); 49 | // } 50 | // 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Services/StorageServiceTest.php: -------------------------------------------------------------------------------- 1 | 9 | * 10 | * Initial version created on: 23/01/16 23:59 11 | * 12 | */ 13 | 14 | class StorageServiceTest extends WebTestCase 15 | { 16 | 17 | public function testServiceInjection(){ 18 | $client = $this->createClient(); 19 | $s3 = $client->getContainer()->get('amazon_S3'); 20 | assert( $s3 !== null, 'Requested service unavailble'); 21 | } 22 | 23 | 24 | public function testCreateBucket(){ 25 | /** @var S3Client $client */ 26 | $client = $this->createClient(); 27 | $s3 = $client->getContainer()->get('amazon_S3'); 28 | 29 | $s3->createBucket(array( 30 | 'Bucket' => 'mybucket', 31 | 'LocationConstraint' => 'us-west-2', 32 | )); 33 | 34 | assert($s3->doesBucketExist("mybucket") === true, "bucket doesn't exist !!!") 35 | $s3->deleteBucket(array( 36 | 'Bucket' => 'mybucket', 37 | 'LocationConstraint' => 'us-west-2', 38 | )); 39 | 40 | assert($s3->doesBucketExist("mybucket") === false, "bucket hasn't been deleted !!!") 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Tests/autoload.php.dist: -------------------------------------------------------------------------------- 1 | registerNamespaces(array( 10 | 'Symfony' => $vendorDir.'/symfony/src', 11 | )); 12 | $loader->register(); 13 | 14 | spl_autoload_register(function($class) { 15 | $class = ltrim($class, '\\'); 16 | if (0 === strpos($class, 'Cybernox\AmazonWebServicesBundle\\')) { 17 | $file = __DIR__.'/../'.str_replace('\\', '/', substr($class, strlen('Cybernox\AmazonWebServicesBundle\\'))).'.php'; 18 | if (file_exists($file)) { 19 | require $file; 20 | } 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /Tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright Copyright (c) CyberNox Technologies. All rights reserved. 7 | * @license http://www.opensource.org/licenses/BSD-2-Clause BSD License 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace AmazonWebServicesBundle; 14 | 15 | use Symfony\Component\HttpKernel\Bundle\Bundle; 16 | use AmazonWebServicesBundle\StreamWrapper\S3StreamWrapper; 17 | 18 | /** 19 | * AmazonWebServicesBundle Main Bundle Class 20 | */ 21 | class ThePhalconsAmazonWebServicesBundle extends Bundle 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function boot() 27 | { 28 | if (in_array('s3', $this->container->getParameter('the_phalcons_amazon_web_services.enable_extensions'))) { 29 | if (in_array('s3', stream_get_wrappers())) { 30 | stream_wrapper_unregister('s3'); 31 | } 32 | 33 | S3StreamWrapper::register($this->container->get('aws_s3'), 's3'); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /aws.config.yml: -------------------------------------------------------------------------------- 1 | 2 | thephalcons_amazon_web_services: 3 | # for stream wrapper use : [S3, SES ...] 4 | enable_extensions: [] 5 | credentials: 6 | key: 7 | secret: 8 | shared_config: 9 | region: %aws_region% 10 | version: %aws_version% 11 | account_id: %aws_account_id% 12 | canonical_id: %aws_canonical_id% 13 | canonical_name: %aws_canonical_name% 14 | mfa_serial: %aws_mfa_serial% 15 | cloudfront_keypair: %aws_cloudfront_keypair% 16 | cloudfront_pem: %aws_cloudfront_pem% 17 | default_cache_config: null 18 | certificate_authority: false 19 | disable_auto_config: false 20 | services: 21 | 22 | S3: 23 | bucket: 24 | #... add all used bucket like assets bucket or upload bucket, can be accessed 25 | # using container in your code 26 | CloudFront: 27 | web_distribution: http://xxxxxxxxxxxxxx.cloudfront.net 28 | #upload_distribution: http://xxxxxxxxxxxxxx.cloudfront.net 29 | SES: 30 | verified_addresse: 31 | #for more information how to use SES service 32 | #http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-ses.html 33 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "andrewlowther/amazon-webservices-bundle", 3 | "description": "A Symfony2 Bundle for interfacing with Amazon Web Services (AWS)", 4 | "keywords": ["amazon", "aws", "web services", "aws-sdk-php"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "El Mehdi Mouddene", 9 | "email": "mouddene@gmail.com" 10 | }, 11 | { 12 | "name": "Mark Badolato", 13 | "email": "mbadolato@cybernox.com" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.5", 18 | "symfony/framework-bundle": ">=2.3", 19 | "aws/aws-sdk-php": "*" 20 | }, 21 | "autoload": { 22 | "psr-0": { "AmazonWebServicesBundle": "" } 23 | }, 24 | "target-dir": "AmazonWebServicesBundle" 25 | } 26 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./Tests/ 7 | 8 | 9 | 10 | 11 | 12 | ./ 13 | 14 | ./DataFixtures 15 | ./Resources 16 | ./Tests 17 | ./vendor 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /vendor/vendors.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | Installing/Updating $name\n"; 15 | 16 | $installDir = $vendorDir.'/'.$name; 17 | if (!is_dir($installDir)) { 18 | system(sprintf('git clone -q %s %s', escapeshellarg($url), escapeshellarg($installDir))); 19 | } 20 | 21 | system(sprintf('cd %s && git fetch -q origin && git reset --hard %s', escapeshellarg($installDir), escapeshellarg($rev))); 22 | } 23 | --------------------------------------------------------------------------------