web/lib/Zend/Cloud/StorageService/Adapter/S3.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * LICENSE
       
     4  *
       
     5  * This source file is subject to the new BSD license that is bundled
       
     6  * with this package in the file LICENSE.txt.
       
     7  * It is also available through the world-wide-web at this URL:
       
     8  * http://framework.zend.com/license/new-bsd
       
     9  * If you did not receive a copy of the license and are unable to
       
    10  * obtain it through the world-wide-web, please send an email
       
    11  * to license@zend.com so we can send you a copy immediately.
       
    12  *
       
    13  * @category   Zend
       
    14  * @package    Zend_Cloud
       
    15  * @subpackage StorageService
       
    16  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    17  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    18  */
       
    19 
       
    20 require_once 'Zend/Service/Amazon/S3.php';
       
    21 require_once 'Zend/Cloud/StorageService/Adapter.php';
       
    22 require_once 'Zend/Cloud/StorageService/Exception.php';
       
    23 
       
    24 /**
       
    25  * S3 adapter for unstructured cloud storage.
       
    26  *
       
    27  * @category   Zend
       
    28  * @package    Zend_Cloud
       
    29  * @subpackage StorageService
       
    30  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    31  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    32  */
       
    33 class Zend_Cloud_StorageService_Adapter_S3 
       
    34     implements Zend_Cloud_StorageService_Adapter
       
    35 {
       
    36     /*
       
    37      * Options array keys for the S3 adapter.
       
    38      */
       
    39     const BUCKET_NAME      = 'bucket_name';
       
    40     const BUCKET_AS_DOMAIN = 'bucket_as_domain?';
       
    41     const FETCH_STREAM     = 'fetch_stream';
       
    42     const METADATA         = 'metadata';
       
    43     
       
    44     /**
       
    45      * AWS constants
       
    46      */
       
    47     const AWS_ACCESS_KEY   = 'aws_accesskey';
       
    48     const AWS_SECRET_KEY   = 'aws_secretkey';
       
    49 
       
    50     /**
       
    51      * S3 service instance.
       
    52      * @var Zend_Service_Amazon_S3
       
    53      */
       
    54     protected $_s3;
       
    55     protected $_defaultBucketName = null;
       
    56     protected $_defaultBucketAsDomain = false;
       
    57 
       
    58     /**
       
    59      * Constructor
       
    60      * 
       
    61      * @param  array|Zend_Config $options 
       
    62      * @return void
       
    63      */
       
    64     public function __construct($options = array()) 
       
    65     {
       
    66         if ($options instanceof Zend_Config) {
       
    67             $options = $options->toArray();
       
    68         }
       
    69 
       
    70         if (!is_array($options)) {
       
    71             throw new Zend_Cloud_StorageService_Exception('Invalid options provided');
       
    72         }
       
    73 
       
    74         if (!isset($options[self::AWS_ACCESS_KEY]) || !isset($options[self::AWS_SECRET_KEY])) {
       
    75             throw new Zend_Cloud_StorageService_Exception('AWS keys not specified!');
       
    76         }
       
    77 
       
    78         try {
       
    79             $this->_s3 = new Zend_Service_Amazon_S3($options[self::AWS_ACCESS_KEY],
       
    80                                                 $options[self::AWS_SECRET_KEY]);
       
    81         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
    82             throw new Zend_Cloud_StorageService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e);
       
    83         }
       
    84                                                 
       
    85         if (isset($options[self::HTTP_ADAPTER])) {
       
    86             $this->_s3->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]);
       
    87         } 
       
    88 
       
    89         if (isset($options[self::BUCKET_NAME])) {
       
    90             $this->_defaultBucketName = $options[self::BUCKET_NAME];
       
    91         }
       
    92 
       
    93         if (isset($options[self::BUCKET_AS_DOMAIN])) {
       
    94             $this->_defaultBucketAsDomain = $options[self::BUCKET_AS_DOMAIN];
       
    95         }
       
    96     }
       
    97 
       
    98     /**
       
    99      * Get an item from the storage service.
       
   100      *
       
   101      * @TODO Support streams
       
   102      *
       
   103      * @param  string $path
       
   104      * @param  array $options
       
   105      * @return string
       
   106      */
       
   107     public function fetchItem($path, $options = array()) 
       
   108     {
       
   109         $fullPath = $this->_getFullPath($path, $options);
       
   110         try {
       
   111             if (!empty($options[self::FETCH_STREAM])) {
       
   112                 return $this->_s3->getObjectStream($fullPath, $options[self::FETCH_STREAM]);
       
   113             } else {
       
   114                 return $this->_s3->getObject($fullPath);
       
   115             }
       
   116         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   117             throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e);
       
   118         }
       
   119     }
       
   120 
       
   121     /**
       
   122      * Store an item in the storage service.
       
   123      *
       
   124      * WARNING: This operation overwrites any item that is located at
       
   125      * $destinationPath.
       
   126      *
       
   127      * @TODO Support streams
       
   128      *
       
   129      * @param string $destinationPath
       
   130      * @param string|resource $data
       
   131      * @param  array $options
       
   132      * @return void
       
   133      */
       
   134     public function storeItem($destinationPath, $data, $options = array()) 
       
   135     {
       
   136         try {
       
   137             $fullPath = $this->_getFullPath($destinationPath, $options);
       
   138             return $this->_s3->putObject(
       
   139                 $fullPath, 
       
   140                 $data, 
       
   141                 empty($options[self::METADATA]) ? null : $options[self::METADATA]
       
   142             );
       
   143         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   144             throw new Zend_Cloud_StorageService_Exception('Error on store: '.$e->getMessage(), $e->getCode(), $e);
       
   145         }
       
   146     }
       
   147 
       
   148     /**
       
   149      * Delete an item in the storage service.
       
   150      *
       
   151      * @param  string $path
       
   152      * @param  array $options
       
   153      * @return void
       
   154      */
       
   155     public function deleteItem($path, $options = array()) 
       
   156     {    
       
   157         try {
       
   158             $this->_s3->removeObject($this->_getFullPath($path, $options));
       
   159         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   160             throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e);
       
   161         }
       
   162     }
       
   163 
       
   164     /**
       
   165      * Copy an item in the storage service to a given path.
       
   166      *
       
   167      * WARNING: This operation is *very* expensive for services that do not
       
   168      * support copying an item natively.
       
   169      *
       
   170      * @TODO Support streams for those services that don't support natively
       
   171      *
       
   172      * @param  string $sourcePath
       
   173      * @param  string $destination path
       
   174      * @param  array $options
       
   175      * @return void
       
   176      */
       
   177     public function copyItem($sourcePath, $destinationPath, $options = array()) 
       
   178     {
       
   179         try {
       
   180             // TODO We *really* need to add support for object copying in the S3 adapter
       
   181             $item = $this->fetch($_getFullPath(sourcePath), $options);
       
   182             $this->storeItem($item, $destinationPath, $options);
       
   183         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   184             throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$e->getMessage(), $e->getCode(), $e);
       
   185         }
       
   186     }
       
   187 
       
   188     /**
       
   189      * Move an item in the storage service to a given path.
       
   190      *
       
   191      * @TODO Support streams for those services that don't support natively
       
   192      *
       
   193      * @param  string $sourcePath
       
   194      * @param  string $destination path
       
   195      * @param  array $options
       
   196      * @return void
       
   197      */
       
   198     public function moveItem($sourcePath, $destinationPath, $options = array()) 
       
   199     {
       
   200         try {
       
   201             $fullSourcePath = $this->_getFullPath($sourcePath, $options);
       
   202             $fullDestPath   = $this->_getFullPath($destinationPath, $options);
       
   203             return $this->_s3->moveObject(
       
   204                 $fullSourcePath,
       
   205                 $fullDestPath,
       
   206                 empty($options[self::METADATA]) ? null : $options[self::METADATA]
       
   207             );
       
   208         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   209             throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage(), $e->getCode(), $e);
       
   210         }
       
   211      }
       
   212 
       
   213     /**
       
   214      * Rename an item in the storage service to a given name.
       
   215      *
       
   216      *
       
   217      * @param  string $path
       
   218      * @param  string $name
       
   219      * @param  array $options
       
   220      * @return void
       
   221      */
       
   222     public function renameItem($path, $name, $options = null) 
       
   223     {
       
   224         require_once 'Zend/Cloud/OperationNotAvailableException.php';
       
   225         throw new Zend_Cloud_OperationNotAvailableException('Rename not implemented');
       
   226     }
       
   227 
       
   228     /**
       
   229      * List items in the given directory in the storage service
       
   230      *
       
   231      * The $path must be a directory
       
   232      *
       
   233      *
       
   234      * @param  string $path Must be a directory
       
   235      * @param  array $options
       
   236      * @return array A list of item names
       
   237      */
       
   238     public function listItems($path, $options = null) 
       
   239     {
       
   240         try {
       
   241             // TODO Support 'prefix' parameter for Zend_Service_Amazon_S3::getObjectsByBucket()
       
   242             return $this->_s3->getObjectsByBucket($this->_defaultBucketName);
       
   243         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   244             throw new Zend_Cloud_StorageService_Exception('Error on list: '.$e->getMessage(), $e->getCode(), $e);
       
   245         }
       
   246     }
       
   247 
       
   248     /**
       
   249      * Get a key/value array of metadata for the given path.
       
   250      *
       
   251      * @param  string $path
       
   252      * @param  array $options
       
   253      * @return array
       
   254      */
       
   255     public function fetchMetadata($path, $options = array()) 
       
   256     {
       
   257         try {
       
   258             return $this->_s3->getInfo($this->_getFullPath($path, $options));
       
   259         } catch (Zend_Service_Amazon_S3_Exception  $e) { 
       
   260             throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e);
       
   261         }
       
   262     }
       
   263 
       
   264     /**
       
   265      * Store a key/value array of metadata at the given path.
       
   266      * WARNING: This operation overwrites any metadata that is located at
       
   267      * $destinationPath.
       
   268      *
       
   269      * @param  string $destinationPath
       
   270      * @param  array $options
       
   271      * @return void
       
   272      */
       
   273     public function storeMetadata($destinationPath, $metadata, $options = array()) 
       
   274     {
       
   275         require_once 'Zend/Cloud/OperationNotAvailableException.php';
       
   276         throw new Zend_Cloud_OperationNotAvailableException('Storing separate metadata is not supported, use storeItem() with \'metadata\' option key');
       
   277     }
       
   278 
       
   279     /**
       
   280      * Delete a key/value array of metadata at the given path.
       
   281      *
       
   282      * @param  string $path
       
   283      * @param  array $options
       
   284      * @return void
       
   285      */
       
   286     public function deleteMetadata($path) 
       
   287     {
       
   288         require_once 'Zend/Cloud/OperationNotAvailableException.php';
       
   289         throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not supported');
       
   290     }
       
   291 
       
   292     /**
       
   293      * Get full path, including bucket, for an object
       
   294      * 
       
   295      * @param  string $path 
       
   296      * @param  array $options 
       
   297      * @return void
       
   298      */
       
   299     protected function _getFullPath($path, $options) 
       
   300     {
       
   301         if (isset($options[self::BUCKET_NAME])) {
       
   302             $bucket = $options[self::BUCKET_NAME];
       
   303         } else if (isset($this->_defaultBucketName)) {
       
   304             $bucket = $this->_defaultBucketName;
       
   305         } else {
       
   306             require_once 'Zend/Cloud/StorageService/Exception.php';
       
   307             throw new Zend_Cloud_StorageService_Exception('Bucket name must be specified for S3 adapter.');
       
   308         }
       
   309 
       
   310         if (isset($options[self::BUCKET_AS_DOMAIN])) {
       
   311             // TODO: support bucket domain names
       
   312             require_once 'Zend/Cloud/StorageService/Exception.php';
       
   313             throw new Zend_Cloud_StorageService_Exception('The S3 adapter does not currently support buckets in domain names.');
       
   314         }
       
   315 
       
   316         return trim($bucket) . '/' . trim($path);
       
   317     }
       
   318 
       
   319     /**
       
   320      * Get the concrete client.
       
   321      * @return Zend_Service_Amazon_S3
       
   322      */
       
   323     public function getClient()
       
   324     {
       
   325          return $this->_s3;       
       
   326     }
       
   327 }