/library/Zend/Cloud/StorageService/Adapter/S3.php

https://github.com/mrbanzai/zf2 · PHP · 326 lines · 147 code · 26 blank · 153 comment · 14 complexity · 9ca6217c6f2d0a3351130a3b54c65ad6 MD5 · raw file

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