File indexing completed on 2025-01-26 05:24:52

0001 <?php
0002 /**
0003  * LICENSE
0004  *
0005  * This source file is subject to the new BSD license that is bundled
0006  * with this package in the file LICENSE.txt.
0007  * It is also available through the world-wide-web at this URL:
0008  * http://framework.zend.com/license/new-bsd
0009  * If you did not receive a copy of the license and are unable to
0010  * obtain it through the world-wide-web, please send an email
0011  * to license@zend.com so we can send you a copy immediately.
0012  *
0013  * @category   Zend
0014  * @package    Zend_Cloud
0015  * @subpackage StorageService
0016  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0017  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0018  */
0019 
0020 // require_once 'Zend/Service/Amazon/S3.php';
0021 // require_once 'Zend/Cloud/StorageService/Adapter.php';
0022 // require_once 'Zend/Cloud/StorageService/Exception.php';
0023 
0024 /**
0025  * S3 adapter for unstructured cloud storage.
0026  *
0027  * @category   Zend
0028  * @package    Zend_Cloud
0029  * @subpackage StorageService
0030  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0031  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0032  */
0033 class Zend_Cloud_StorageService_Adapter_S3
0034     implements Zend_Cloud_StorageService_Adapter
0035 {
0036     /*
0037      * Options array keys for the S3 adapter.
0038      */
0039     const BUCKET_NAME      = 'bucket_name';
0040     const BUCKET_AS_DOMAIN = 'bucket_as_domain?';
0041     const FETCH_STREAM     = 'fetch_stream';
0042     const METADATA         = 'metadata';
0043 
0044     /**
0045      * AWS constants
0046      */
0047     const AWS_ACCESS_KEY   = 'aws_accesskey';
0048     const AWS_SECRET_KEY   = 'aws_secretkey';
0049 
0050     /**
0051      * S3 service instance.
0052      * @var Zend_Service_Amazon_S3
0053      */
0054     protected $_s3;
0055     protected $_defaultBucketName = null;
0056     protected $_defaultBucketAsDomain = false;
0057 
0058     /**
0059      * Constructor
0060      *
0061      * @param  array|Zend_Config $options
0062      * @return void
0063      */
0064     public function __construct($options = array())
0065     {
0066         if ($options instanceof Zend_Config) {
0067             $options = $options->toArray();
0068         }
0069 
0070         if (!is_array($options)) {
0071             throw new Zend_Cloud_StorageService_Exception('Invalid options provided');
0072         }
0073 
0074         if (!isset($options[self::AWS_ACCESS_KEY]) || !isset($options[self::AWS_SECRET_KEY])) {
0075             throw new Zend_Cloud_StorageService_Exception('AWS keys not specified!');
0076         }
0077 
0078         try {
0079             $this->_s3 = new Zend_Service_Amazon_S3($options[self::AWS_ACCESS_KEY],
0080                                                 $options[self::AWS_SECRET_KEY]);
0081         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0082             throw new Zend_Cloud_StorageService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e);
0083         }
0084 
0085         if (isset($options[self::HTTP_ADAPTER])) {
0086             $this->_s3->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]);
0087         }
0088 
0089         if (isset($options[self::BUCKET_NAME])) {
0090             $this->_defaultBucketName = $options[self::BUCKET_NAME];
0091         }
0092 
0093         if (isset($options[self::BUCKET_AS_DOMAIN])) {
0094             $this->_defaultBucketAsDomain = $options[self::BUCKET_AS_DOMAIN];
0095         }
0096     }
0097 
0098     /**
0099      * Get an item from the storage service.
0100      *
0101      * @TODO Support streams
0102      *
0103      * @param  string $path
0104      * @param  array $options
0105      * @return string
0106      */
0107     public function fetchItem($path, $options = array())
0108     {
0109         $fullPath = $this->_getFullPath($path, $options);
0110         try {
0111             if (!empty($options[self::FETCH_STREAM])) {
0112                 return $this->_s3->getObjectStream($fullPath, $options[self::FETCH_STREAM]);
0113             } else {
0114                 return $this->_s3->getObject($fullPath);
0115             }
0116         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0117             throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e);
0118         }
0119     }
0120 
0121     /**
0122      * Store an item in the storage service.
0123      *
0124      * WARNING: This operation overwrites any item that is located at
0125      * $destinationPath.
0126      *
0127      * @TODO Support streams
0128      *
0129      * @param string $destinationPath
0130      * @param string|resource $data
0131      * @param  array $options
0132      * @return void
0133      */
0134     public function storeItem($destinationPath, $data, $options = array())
0135     {
0136         try {
0137             $fullPath = $this->_getFullPath($destinationPath, $options);
0138             return $this->_s3->putObject(
0139                 $fullPath,
0140                 $data,
0141                 empty($options[self::METADATA]) ? null : $options[self::METADATA]
0142             );
0143         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0144             throw new Zend_Cloud_StorageService_Exception('Error on store: '.$e->getMessage(), $e->getCode(), $e);
0145         }
0146     }
0147 
0148     /**
0149      * Delete an item in the storage service.
0150      *
0151      * @param  string $path
0152      * @param  array $options
0153      * @return void
0154      */
0155     public function deleteItem($path, $options = array())
0156     {
0157         try {
0158             $this->_s3->removeObject($this->_getFullPath($path, $options));
0159         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0160             throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e);
0161         }
0162     }
0163 
0164     /**
0165      * Copy an item in the storage service to a given path.
0166      *
0167      * WARNING: This operation is *very* expensive for services that do not
0168      * support copying an item natively.
0169      *
0170      * @TODO Support streams for those services that don't support natively
0171      *
0172      * @param  string $sourcePath
0173      * @param  string $destination path
0174      * @param  array $options
0175      * @return void
0176      */
0177     public function copyItem($sourcePath, $destinationPath, $options = array())
0178     {
0179         try {
0180             $fullSourcePath = $this->_getFullPath($sourcePath, $options);
0181             $fullDestPath   = $this->_getFullPath($destinationPath, $options);
0182             return $this->_s3->copyObject(
0183                 $fullSourcePath,
0184                 $fullDestPath,
0185                 empty($options[self::METADATA]) ? null : $options[self::METADATA]
0186             );
0187 
0188         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0189             throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$e->getMessage(), $e->getCode(), $e);
0190         }
0191     }
0192 
0193     /**
0194      * Move an item in the storage service to a given path.
0195      *
0196      * @TODO Support streams for those services that don't support natively
0197      *
0198      * @param  string $sourcePath
0199      * @param  string $destination path
0200      * @param  array $options
0201      * @return void
0202      */
0203     public function moveItem($sourcePath, $destinationPath, $options = array())
0204     {
0205         try {
0206             $fullSourcePath = $this->_getFullPath($sourcePath, $options);
0207             $fullDestPath   = $this->_getFullPath($destinationPath, $options);
0208             return $this->_s3->moveObject(
0209                 $fullSourcePath,
0210                 $fullDestPath,
0211                 empty($options[self::METADATA]) ? null : $options[self::METADATA]
0212             );
0213         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0214             throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage(), $e->getCode(), $e);
0215         }
0216      }
0217 
0218     /**
0219      * Rename an item in the storage service to a given name.
0220      *
0221      *
0222      * @param  string $path
0223      * @param  string $name
0224      * @param  array $options
0225      * @return void
0226      */
0227     public function renameItem($path, $name, $options = null)
0228     {
0229         // require_once 'Zend/Cloud/OperationNotAvailableException.php';
0230         throw new Zend_Cloud_OperationNotAvailableException('Rename not implemented');
0231     }
0232 
0233     /**
0234      * List items in the given directory in the storage service
0235      *
0236      * The $path must be a directory
0237      *
0238      *
0239      * @param  string $path Must be a directory
0240      * @param  array $options
0241      * @return array A list of item names
0242      */
0243     public function listItems($path, $options = null)
0244     {
0245         try {
0246             // TODO Support 'prefix' parameter for Zend_Service_Amazon_S3::getObjectsByBucket()
0247             return $this->_s3->getObjectsByBucket($this->_defaultBucketName);
0248         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0249             throw new Zend_Cloud_StorageService_Exception('Error on list: '.$e->getMessage(), $e->getCode(), $e);
0250         }
0251     }
0252 
0253     /**
0254      * Get a key/value array of metadata for the given path.
0255      *
0256      * @param  string $path
0257      * @param  array $options
0258      * @return array
0259      */
0260     public function fetchMetadata($path, $options = array())
0261     {
0262         try {
0263             return $this->_s3->getInfo($this->_getFullPath($path, $options));
0264         } catch (Zend_Service_Amazon_S3_Exception  $e) {
0265             throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e);
0266         }
0267     }
0268 
0269     /**
0270      * Store a key/value array of metadata at the given path.
0271      * WARNING: This operation overwrites any metadata that is located at
0272      * $destinationPath.
0273      *
0274      * @param  string $destinationPath
0275      * @param  array $options
0276      * @return void
0277      */
0278     public function storeMetadata($destinationPath, $metadata, $options = array())
0279     {
0280         // require_once 'Zend/Cloud/OperationNotAvailableException.php';
0281         throw new Zend_Cloud_OperationNotAvailableException('Storing separate metadata is not supported, use storeItem() with \'metadata\' option key');
0282     }
0283 
0284     /**
0285      * Delete a key/value array of metadata at the given path.
0286      *
0287      * @param  string $path
0288      * @param  array $options
0289      * @return void
0290      */
0291     public function deleteMetadata($path)
0292     {
0293         // require_once 'Zend/Cloud/OperationNotAvailableException.php';
0294         throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not supported');
0295     }
0296 
0297     /**
0298      * Get full path, including bucket, for an object
0299      *
0300      * @param  string $path
0301      * @param  array $options
0302      * @return void
0303      */
0304     protected function _getFullPath($path, $options)
0305     {
0306         if (isset($options[self::BUCKET_NAME])) {
0307             $bucket = $options[self::BUCKET_NAME];
0308         } else if (isset($this->_defaultBucketName)) {
0309             $bucket = $this->_defaultBucketName;
0310         } else {
0311             // require_once 'Zend/Cloud/StorageService/Exception.php';
0312             throw new Zend_Cloud_StorageService_Exception('Bucket name must be specified for S3 adapter.');
0313         }
0314 
0315         if (isset($options[self::BUCKET_AS_DOMAIN])) {
0316             // TODO: support bucket domain names
0317             // require_once 'Zend/Cloud/StorageService/Exception.php';
0318             throw new Zend_Cloud_StorageService_Exception('The S3 adapter does not currently support buckets in domain names.');
0319         }
0320 
0321         return trim($bucket) . '/' . trim($path);
0322     }
0323 
0324     /**
0325      * Get the concrete client.
0326      * @return Zend_Service_Amazon_S3
0327      */
0328     public function getClient()
0329     {
0330          return $this->_s3;
0331     }
0332 }