/src/Gaufrette/Adapter/AmazonS3.php

https://github.com/Rohea/Gaufrette · PHP · 302 lines · 182 code · 48 blank · 72 comment · 12 complexity · aac3e0d921496d87d4fbe26130b65049 MD5 · raw file

  1. <?php
  2. namespace Gaufrette\Adapter;
  3. use \AmazonS3 as AmazonClient;
  4. use Gaufrette\Adapter;
  5. /**
  6. * Amazon S3 adapter
  7. *
  8. * @package Gaufrette
  9. * @author Antoine Hérault <antoine.herault@gmail.com>
  10. * @author Leszek Prabucki <leszek.prabucki@gmail.com>
  11. */
  12. class AmazonS3 implements Adapter,
  13. MetadataSupporter
  14. {
  15. protected $service;
  16. protected $bucket;
  17. protected $ensureBucket = false;
  18. protected $metadata;
  19. protected $options;
  20. public function __construct(AmazonClient $service, $bucket, $options = array())
  21. {
  22. $this->service = $service;
  23. $this->bucket = $bucket;
  24. $this->options = array_replace_recursive(
  25. array('directory' => '', 'create' => false, 'region' => AmazonClient::REGION_US_E1, 'acl' => AmazonClient::ACL_PUBLIC),
  26. $options
  27. );
  28. }
  29. /**
  30. * Set the acl used when writing files
  31. *
  32. * @param string $acl
  33. */
  34. public function setAcl($acl)
  35. {
  36. $this->options['acl'] = $acl;
  37. }
  38. /**
  39. * Get the acl used when writing files
  40. *
  41. * @return string
  42. */
  43. public function getAcl()
  44. {
  45. return $this->options['acl'];
  46. }
  47. /**
  48. * Set the base directory the user will have access to
  49. *
  50. * @param string $directory
  51. */
  52. public function setDirectory($directory)
  53. {
  54. $this->options['directory'] = $directory;
  55. }
  56. /**
  57. * Get the directory the user has access to
  58. *
  59. * @return string
  60. */
  61. public function getDirectory()
  62. {
  63. return $this->options['directory'];
  64. }
  65. /**
  66. * {@inheritDoc}
  67. */
  68. public function setMetadata($key, $metadata)
  69. {
  70. $path = $this->computePath($key);
  71. $this->metadata[$path] = $metadata;
  72. }
  73. /**
  74. * {@inheritDoc}
  75. */
  76. public function getMetadata($key)
  77. {
  78. $path = $this->computePath($key);
  79. return isset($this->metadata[$path]) ? $this->metadata[$path] : array();
  80. }
  81. /**
  82. * {@inheritDoc}
  83. */
  84. public function read($key)
  85. {
  86. $this->ensureBucketExists();
  87. $response = $this->service->get_object(
  88. $this->bucket,
  89. $this->computePath($key),
  90. $this->getMetadata($key)
  91. );
  92. if (!$response->isOK()) {
  93. return false;
  94. }
  95. return $response->body;
  96. }
  97. /**
  98. * {@inheritDoc}
  99. */
  100. public function rename($sourceKey, $targetKey)
  101. {
  102. $this->ensureBucketExists();
  103. $response = $this->service->copy_object(
  104. array( // source
  105. 'bucket' => $this->bucket,
  106. 'filename' => $this->computePath($sourceKey)
  107. ),
  108. array( // target
  109. 'bucket' => $this->bucket,
  110. 'filename' => $this->computePath($targetKey)
  111. ),
  112. $this->getMetadata($sourceKey)
  113. );
  114. return $response->isOK() && $this->delete($sourceKey);
  115. }
  116. /**
  117. * {@inheritDoc}
  118. */
  119. public function write($key, $content)
  120. {
  121. $this->ensureBucketExists();
  122. $opt = array_replace_recursive(
  123. array('acl' => $this->options['acl']),
  124. $this->getMetadata($key),
  125. array('body' => $content)
  126. );
  127. $response = $this->service->create_object(
  128. $this->bucket,
  129. $this->computePath($key),
  130. $opt
  131. );
  132. if (!$response->isOK()) {
  133. return false;
  134. };
  135. return intval($response->header["x-aws-requestheaders"]["Content-Length"]);
  136. }
  137. /**
  138. * {@inheritDoc}
  139. */
  140. public function exists($key)
  141. {
  142. $this->ensureBucketExists();
  143. return $this->service->if_object_exists(
  144. $this->bucket,
  145. $this->computePath($key)
  146. );
  147. }
  148. /**
  149. * {@inheritDoc}
  150. */
  151. public function mtime($key)
  152. {
  153. $this->ensureBucketExists();
  154. $response = $this->service->get_object_metadata(
  155. $this->bucket,
  156. $this->computePath($key),
  157. $this->getMetadata($key)
  158. );
  159. return isset($response['Headers']['last-modified']) ? strtotime($response['Headers']['last-modified']) : false;
  160. }
  161. /**
  162. * {@inheritDoc}
  163. */
  164. public function keys()
  165. {
  166. $this->ensureBucketExists();
  167. $list = $this->service->get_object_list($this->bucket);
  168. $keys = array();
  169. foreach ($list as $file) {
  170. if ('.' !== dirname($file)) {
  171. $keys[] = dirname($file);
  172. }
  173. $keys[] = $file;
  174. }
  175. sort($keys);
  176. return $keys;
  177. }
  178. /**
  179. * {@inheritDoc}
  180. */
  181. public function delete($key)
  182. {
  183. $this->ensureBucketExists();
  184. $response = $this->service->delete_object(
  185. $this->bucket,
  186. $this->computePath($key),
  187. $this->getMetadata($key)
  188. );
  189. return $response->isOK();
  190. }
  191. /**
  192. * {@inheritDoc}
  193. */
  194. public function isDirectory($key)
  195. {
  196. if ($this->exists($key.'/')) {
  197. return true;
  198. }
  199. return false;
  200. }
  201. /**
  202. * Ensures the specified bucket exists. If the bucket does not exists
  203. * and the create parameter is set to true, it will try to create the
  204. * bucket
  205. *
  206. * @throws \RuntimeException if the bucket does not exists or could not be
  207. * created
  208. */
  209. private function ensureBucketExists()
  210. {
  211. if ($this->ensureBucket) {
  212. return;
  213. }
  214. if (isset($this->options['region'])) {
  215. $this->service->set_region($this->options['region']);
  216. }
  217. if ($this->service->if_bucket_exists($this->bucket)) {
  218. $this->ensureBucket = true;
  219. return;
  220. }
  221. if (!$this->options['create']) {
  222. throw new \RuntimeException(sprintf(
  223. 'The configured bucket "%s" does not exist.',
  224. $this->bucket
  225. ));
  226. }
  227. $response = $this->service->create_bucket(
  228. $this->bucket,
  229. $this->options['region']
  230. );
  231. if (!$response->isOK()) {
  232. throw new \RuntimeException(sprintf(
  233. 'Failed to create the configured bucket "%s".',
  234. $this->bucket
  235. ));
  236. }
  237. $this->ensureBucket = true;
  238. }
  239. /**
  240. * Computes the path for the specified key taking the bucket in account
  241. *
  242. * @param string $key The key for which to compute the path
  243. *
  244. * @return string
  245. */
  246. private function computePath($key)
  247. {
  248. $directory = $this->getDirectory();
  249. if (null === $directory || '' === $directory) {
  250. return $key;
  251. }
  252. return sprintf('%s/%s', $directory, $key);
  253. }
  254. }