11 * to license@zend.com so we can send you a copy immediately. |
11 * to license@zend.com so we can send you a copy immediately. |
12 * |
12 * |
13 * @category Zend |
13 * @category Zend |
14 * @package Zend_Cloud |
14 * @package Zend_Cloud |
15 * @subpackage StorageService |
15 * @subpackage StorageService |
16 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
16 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) |
17 * @license http://framework.zend.com/license/new-bsd New BSD License |
17 * @license http://framework.zend.com/license/new-bsd New BSD License |
18 */ |
18 */ |
19 |
19 |
20 require_once 'Zend/Service/Amazon/S3.php'; |
20 require_once 'Zend/Service/Amazon/S3.php'; |
21 require_once 'Zend/Cloud/StorageService/Adapter.php'; |
21 require_once 'Zend/Cloud/StorageService/Adapter.php'; |
25 * S3 adapter for unstructured cloud storage. |
25 * S3 adapter for unstructured cloud storage. |
26 * |
26 * |
27 * @category Zend |
27 * @category Zend |
28 * @package Zend_Cloud |
28 * @package Zend_Cloud |
29 * @subpackage StorageService |
29 * @subpackage StorageService |
30 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
30 * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) |
31 * @license http://framework.zend.com/license/new-bsd New BSD License |
31 * @license http://framework.zend.com/license/new-bsd New BSD License |
32 */ |
32 */ |
33 class Zend_Cloud_StorageService_Adapter_S3 |
33 class Zend_Cloud_StorageService_Adapter_S3 |
34 implements Zend_Cloud_StorageService_Adapter |
34 implements Zend_Cloud_StorageService_Adapter |
35 { |
35 { |
36 /* |
36 /* |
37 * Options array keys for the S3 adapter. |
37 * Options array keys for the S3 adapter. |
38 */ |
38 */ |
39 const BUCKET_NAME = 'bucket_name'; |
39 const BUCKET_NAME = 'bucket_name'; |
40 const BUCKET_AS_DOMAIN = 'bucket_as_domain?'; |
40 const BUCKET_AS_DOMAIN = 'bucket_as_domain?'; |
41 const FETCH_STREAM = 'fetch_stream'; |
41 const FETCH_STREAM = 'fetch_stream'; |
42 const METADATA = 'metadata'; |
42 const METADATA = 'metadata'; |
43 |
43 |
44 /** |
44 /** |
45 * AWS constants |
45 * AWS constants |
46 */ |
46 */ |
47 const AWS_ACCESS_KEY = 'aws_accesskey'; |
47 const AWS_ACCESS_KEY = 'aws_accesskey'; |
48 const AWS_SECRET_KEY = 'aws_secretkey'; |
48 const AWS_SECRET_KEY = 'aws_secretkey'; |
55 protected $_defaultBucketName = null; |
55 protected $_defaultBucketName = null; |
56 protected $_defaultBucketAsDomain = false; |
56 protected $_defaultBucketAsDomain = false; |
57 |
57 |
58 /** |
58 /** |
59 * Constructor |
59 * Constructor |
60 * |
60 * |
61 * @param array|Zend_Config $options |
61 * @param array|Zend_Config $options |
62 * @return void |
62 * @return void |
63 */ |
63 */ |
64 public function __construct($options = array()) |
64 public function __construct($options = array()) |
65 { |
65 { |
66 if ($options instanceof Zend_Config) { |
66 if ($options instanceof Zend_Config) { |
67 $options = $options->toArray(); |
67 $options = $options->toArray(); |
68 } |
68 } |
69 |
69 |
76 } |
76 } |
77 |
77 |
78 try { |
78 try { |
79 $this->_s3 = new Zend_Service_Amazon_S3($options[self::AWS_ACCESS_KEY], |
79 $this->_s3 = new Zend_Service_Amazon_S3($options[self::AWS_ACCESS_KEY], |
80 $options[self::AWS_SECRET_KEY]); |
80 $options[self::AWS_SECRET_KEY]); |
81 } catch (Zend_Service_Amazon_S3_Exception $e) { |
81 } catch (Zend_Service_Amazon_S3_Exception $e) { |
82 throw new Zend_Cloud_StorageService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); |
82 throw new Zend_Cloud_StorageService_Exception('Error on create: '.$e->getMessage(), $e->getCode(), $e); |
83 } |
83 } |
84 |
84 |
85 if (isset($options[self::HTTP_ADAPTER])) { |
85 if (isset($options[self::HTTP_ADAPTER])) { |
86 $this->_s3->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); |
86 $this->_s3->getHttpClient()->setAdapter($options[self::HTTP_ADAPTER]); |
87 } |
87 } |
88 |
88 |
89 if (isset($options[self::BUCKET_NAME])) { |
89 if (isset($options[self::BUCKET_NAME])) { |
90 $this->_defaultBucketName = $options[self::BUCKET_NAME]; |
90 $this->_defaultBucketName = $options[self::BUCKET_NAME]; |
91 } |
91 } |
92 |
92 |
102 * |
102 * |
103 * @param string $path |
103 * @param string $path |
104 * @param array $options |
104 * @param array $options |
105 * @return string |
105 * @return string |
106 */ |
106 */ |
107 public function fetchItem($path, $options = array()) |
107 public function fetchItem($path, $options = array()) |
108 { |
108 { |
109 $fullPath = $this->_getFullPath($path, $options); |
109 $fullPath = $this->_getFullPath($path, $options); |
110 try { |
110 try { |
111 if (!empty($options[self::FETCH_STREAM])) { |
111 if (!empty($options[self::FETCH_STREAM])) { |
112 return $this->_s3->getObjectStream($fullPath, $options[self::FETCH_STREAM]); |
112 return $this->_s3->getObjectStream($fullPath, $options[self::FETCH_STREAM]); |
113 } else { |
113 } else { |
114 return $this->_s3->getObject($fullPath); |
114 return $this->_s3->getObject($fullPath); |
115 } |
115 } |
116 } catch (Zend_Service_Amazon_S3_Exception $e) { |
116 } catch (Zend_Service_Amazon_S3_Exception $e) { |
117 throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); |
117 throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); |
118 } |
118 } |
119 } |
119 } |
120 |
120 |
121 /** |
121 /** |
129 * @param string $destinationPath |
129 * @param string $destinationPath |
130 * @param string|resource $data |
130 * @param string|resource $data |
131 * @param array $options |
131 * @param array $options |
132 * @return void |
132 * @return void |
133 */ |
133 */ |
134 public function storeItem($destinationPath, $data, $options = array()) |
134 public function storeItem($destinationPath, $data, $options = array()) |
135 { |
135 { |
136 try { |
136 try { |
137 $fullPath = $this->_getFullPath($destinationPath, $options); |
137 $fullPath = $this->_getFullPath($destinationPath, $options); |
138 return $this->_s3->putObject( |
138 return $this->_s3->putObject( |
139 $fullPath, |
139 $fullPath, |
140 $data, |
140 $data, |
141 empty($options[self::METADATA]) ? null : $options[self::METADATA] |
141 empty($options[self::METADATA]) ? null : $options[self::METADATA] |
142 ); |
142 ); |
143 } catch (Zend_Service_Amazon_S3_Exception $e) { |
143 } catch (Zend_Service_Amazon_S3_Exception $e) { |
144 throw new Zend_Cloud_StorageService_Exception('Error on store: '.$e->getMessage(), $e->getCode(), $e); |
144 throw new Zend_Cloud_StorageService_Exception('Error on store: '.$e->getMessage(), $e->getCode(), $e); |
145 } |
145 } |
146 } |
146 } |
147 |
147 |
148 /** |
148 /** |
150 * |
150 * |
151 * @param string $path |
151 * @param string $path |
152 * @param array $options |
152 * @param array $options |
153 * @return void |
153 * @return void |
154 */ |
154 */ |
155 public function deleteItem($path, $options = array()) |
155 public function deleteItem($path, $options = array()) |
156 { |
156 { |
157 try { |
157 try { |
158 $this->_s3->removeObject($this->_getFullPath($path, $options)); |
158 $this->_s3->removeObject($this->_getFullPath($path, $options)); |
159 } catch (Zend_Service_Amazon_S3_Exception $e) { |
159 } catch (Zend_Service_Amazon_S3_Exception $e) { |
160 throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e); |
160 throw new Zend_Cloud_StorageService_Exception('Error on delete: '.$e->getMessage(), $e->getCode(), $e); |
161 } |
161 } |
162 } |
162 } |
163 |
163 |
164 /** |
164 /** |
172 * @param string $sourcePath |
172 * @param string $sourcePath |
173 * @param string $destination path |
173 * @param string $destination path |
174 * @param array $options |
174 * @param array $options |
175 * @return void |
175 * @return void |
176 */ |
176 */ |
177 public function copyItem($sourcePath, $destinationPath, $options = array()) |
177 public function copyItem($sourcePath, $destinationPath, $options = array()) |
178 { |
178 { |
179 try { |
179 try { |
180 // TODO We *really* need to add support for object copying in the S3 adapter |
180 $fullSourcePath = $this->_getFullPath($sourcePath, $options); |
181 $item = $this->fetch($_getFullPath(sourcePath), $options); |
181 $fullDestPath = $this->_getFullPath($destinationPath, $options); |
182 $this->storeItem($item, $destinationPath, $options); |
182 return $this->_s3->copyObject( |
183 } catch (Zend_Service_Amazon_S3_Exception $e) { |
183 $fullSourcePath, |
|
184 $fullDestPath, |
|
185 empty($options[self::METADATA]) ? null : $options[self::METADATA] |
|
186 ); |
|
187 |
|
188 } catch (Zend_Service_Amazon_S3_Exception $e) { |
184 throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$e->getMessage(), $e->getCode(), $e); |
189 throw new Zend_Cloud_StorageService_Exception('Error on copy: '.$e->getMessage(), $e->getCode(), $e); |
185 } |
190 } |
186 } |
191 } |
187 |
192 |
188 /** |
193 /** |
193 * @param string $sourcePath |
198 * @param string $sourcePath |
194 * @param string $destination path |
199 * @param string $destination path |
195 * @param array $options |
200 * @param array $options |
196 * @return void |
201 * @return void |
197 */ |
202 */ |
198 public function moveItem($sourcePath, $destinationPath, $options = array()) |
203 public function moveItem($sourcePath, $destinationPath, $options = array()) |
199 { |
204 { |
200 try { |
205 try { |
201 $fullSourcePath = $this->_getFullPath($sourcePath, $options); |
206 $fullSourcePath = $this->_getFullPath($sourcePath, $options); |
202 $fullDestPath = $this->_getFullPath($destinationPath, $options); |
207 $fullDestPath = $this->_getFullPath($destinationPath, $options); |
203 return $this->_s3->moveObject( |
208 return $this->_s3->moveObject( |
204 $fullSourcePath, |
209 $fullSourcePath, |
205 $fullDestPath, |
210 $fullDestPath, |
206 empty($options[self::METADATA]) ? null : $options[self::METADATA] |
211 empty($options[self::METADATA]) ? null : $options[self::METADATA] |
207 ); |
212 ); |
208 } catch (Zend_Service_Amazon_S3_Exception $e) { |
213 } catch (Zend_Service_Amazon_S3_Exception $e) { |
209 throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage(), $e->getCode(), $e); |
214 throw new Zend_Cloud_StorageService_Exception('Error on move: '.$e->getMessage(), $e->getCode(), $e); |
210 } |
215 } |
211 } |
216 } |
212 |
217 |
213 /** |
218 /** |
217 * @param string $path |
222 * @param string $path |
218 * @param string $name |
223 * @param string $name |
219 * @param array $options |
224 * @param array $options |
220 * @return void |
225 * @return void |
221 */ |
226 */ |
222 public function renameItem($path, $name, $options = null) |
227 public function renameItem($path, $name, $options = null) |
223 { |
228 { |
224 require_once 'Zend/Cloud/OperationNotAvailableException.php'; |
229 require_once 'Zend/Cloud/OperationNotAvailableException.php'; |
225 throw new Zend_Cloud_OperationNotAvailableException('Rename not implemented'); |
230 throw new Zend_Cloud_OperationNotAvailableException('Rename not implemented'); |
226 } |
231 } |
227 |
232 |
233 * |
238 * |
234 * @param string $path Must be a directory |
239 * @param string $path Must be a directory |
235 * @param array $options |
240 * @param array $options |
236 * @return array A list of item names |
241 * @return array A list of item names |
237 */ |
242 */ |
238 public function listItems($path, $options = null) |
243 public function listItems($path, $options = null) |
239 { |
244 { |
240 try { |
245 try { |
241 // TODO Support 'prefix' parameter for Zend_Service_Amazon_S3::getObjectsByBucket() |
246 // TODO Support 'prefix' parameter for Zend_Service_Amazon_S3::getObjectsByBucket() |
242 return $this->_s3->getObjectsByBucket($this->_defaultBucketName); |
247 return $this->_s3->getObjectsByBucket($this->_defaultBucketName); |
243 } catch (Zend_Service_Amazon_S3_Exception $e) { |
248 } catch (Zend_Service_Amazon_S3_Exception $e) { |
244 throw new Zend_Cloud_StorageService_Exception('Error on list: '.$e->getMessage(), $e->getCode(), $e); |
249 throw new Zend_Cloud_StorageService_Exception('Error on list: '.$e->getMessage(), $e->getCode(), $e); |
245 } |
250 } |
246 } |
251 } |
247 |
252 |
248 /** |
253 /** |
250 * |
255 * |
251 * @param string $path |
256 * @param string $path |
252 * @param array $options |
257 * @param array $options |
253 * @return array |
258 * @return array |
254 */ |
259 */ |
255 public function fetchMetadata($path, $options = array()) |
260 public function fetchMetadata($path, $options = array()) |
256 { |
261 { |
257 try { |
262 try { |
258 return $this->_s3->getInfo($this->_getFullPath($path, $options)); |
263 return $this->_s3->getInfo($this->_getFullPath($path, $options)); |
259 } catch (Zend_Service_Amazon_S3_Exception $e) { |
264 } catch (Zend_Service_Amazon_S3_Exception $e) { |
260 throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); |
265 throw new Zend_Cloud_StorageService_Exception('Error on fetch: '.$e->getMessage(), $e->getCode(), $e); |
261 } |
266 } |
262 } |
267 } |
263 |
268 |
264 /** |
269 /** |
268 * |
273 * |
269 * @param string $destinationPath |
274 * @param string $destinationPath |
270 * @param array $options |
275 * @param array $options |
271 * @return void |
276 * @return void |
272 */ |
277 */ |
273 public function storeMetadata($destinationPath, $metadata, $options = array()) |
278 public function storeMetadata($destinationPath, $metadata, $options = array()) |
274 { |
279 { |
275 require_once 'Zend/Cloud/OperationNotAvailableException.php'; |
280 require_once 'Zend/Cloud/OperationNotAvailableException.php'; |
276 throw new Zend_Cloud_OperationNotAvailableException('Storing separate metadata is not supported, use storeItem() with \'metadata\' option key'); |
281 throw new Zend_Cloud_OperationNotAvailableException('Storing separate metadata is not supported, use storeItem() with \'metadata\' option key'); |
277 } |
282 } |
278 |
283 |
281 * |
286 * |
282 * @param string $path |
287 * @param string $path |
283 * @param array $options |
288 * @param array $options |
284 * @return void |
289 * @return void |
285 */ |
290 */ |
286 public function deleteMetadata($path) |
291 public function deleteMetadata($path) |
287 { |
292 { |
288 require_once 'Zend/Cloud/OperationNotAvailableException.php'; |
293 require_once 'Zend/Cloud/OperationNotAvailableException.php'; |
289 throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not supported'); |
294 throw new Zend_Cloud_OperationNotAvailableException('Deleting metadata not supported'); |
290 } |
295 } |
291 |
296 |
292 /** |
297 /** |
293 * Get full path, including bucket, for an object |
298 * Get full path, including bucket, for an object |
294 * |
299 * |
295 * @param string $path |
300 * @param string $path |
296 * @param array $options |
301 * @param array $options |
297 * @return void |
302 * @return void |
298 */ |
303 */ |
299 protected function _getFullPath($path, $options) |
304 protected function _getFullPath($path, $options) |
300 { |
305 { |
301 if (isset($options[self::BUCKET_NAME])) { |
306 if (isset($options[self::BUCKET_NAME])) { |
302 $bucket = $options[self::BUCKET_NAME]; |
307 $bucket = $options[self::BUCKET_NAME]; |
303 } else if (isset($this->_defaultBucketName)) { |
308 } else if (isset($this->_defaultBucketName)) { |
304 $bucket = $this->_defaultBucketName; |
309 $bucket = $this->_defaultBucketName; |