PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libraries/adapters/FileSystemS3.php

https://github.com/geraintp/frontend
PHP | 175 lines | 93 code | 9 blank | 73 comment | 8 complexity | 0048f34e12ec0d5a7bbf311d9c7c723c MD5 | raw file
  1. <?php
  2. /**
  3. * Amazon AWS S3 implementation for FileSystemInterface
  4. *
  5. * This class defines the functionality defined by FileSystemInterface for AWS S3.
  6. * @author Jaisen Mathai <jaisen@jmathai.com>
  7. */
  8. class FileSystemS3 implements FileSystemInterface
  9. {
  10. /**
  11. * Member variables holding the names to the bucket and the file system object itself.
  12. * @access private
  13. * @var array
  14. */
  15. private $bucket, $fs;
  16. /**
  17. * Constructor
  18. *
  19. * @return void
  20. */
  21. public function __construct()
  22. {
  23. $this->fs = new AmazonS3(getConfig()->get('credentials')->awsKey, getConfig()->get('credentials')->awsSecret);
  24. $this->bucket = getConfig()->get('aws')->s3BucketName;
  25. }
  26. /**
  27. * Deletes a photo (and all generated versions) from the file system.
  28. * To get a list of all the files to delete we first have to query the database and find out what versions exist.
  29. *
  30. * @param string $id ID of the photo to delete
  31. * @return boolean
  32. */
  33. public function deletePhoto($id)
  34. {
  35. $photo = getDb()->getPhoto($id);
  36. $queue = new CFBatchRequest();
  37. foreach($photo as $key => $value)
  38. {
  39. if(strncmp($key, 'path', 4) === 0)
  40. $this->fs->batch($queue)->delete_object($this->bucket, self::normalizePath($value));
  41. }
  42. $responses = $this->fs->batch($queue)->send();
  43. return $responses->areOK();
  44. }
  45. /**
  46. * Retrieves a photo from the remote file system as specified by $filename.
  47. * This file is stored locally and the path to the local file is returned.
  48. *
  49. * @param string $filename File name on the remote file system.
  50. * @return mixed String on success, FALSE on failure.
  51. */
  52. public function getPhoto($filename)
  53. {
  54. $filename = self::normalizePath($filename);
  55. $tmpname = '/tmp/'.uniqid('opme', true);
  56. $fp = fopen($tmpname, 'w+');
  57. $res = $this->fs->get_object($this->bucket, $filename, array('fileDownload' => $fp));
  58. fclose($fp);
  59. return $res->isOK() ? $tmpname : false;
  60. }
  61. /**
  62. * Writes/uploads a new photo to the remote file system.
  63. *
  64. * @param string $localFile File name on the local file system.
  65. * @param string $remoteFile File name to be saved on the remote file system.
  66. * @param string $acl Permission setting for this photo.
  67. * @return boolean
  68. */
  69. public function putPhoto($localFile, $remoteFile, $acl = AmazonS3::ACL_PUBLIC)
  70. {
  71. $remoteFile = self::normalizePath($remoteFile);
  72. $opts = array('fileUpload' => $localFile, 'acl' => $acl, 'contentType' => 'image/jpeg');
  73. $res = $this->fs->create_object($this->bucket, $remoteFile, $opts);
  74. if(!$res->isOK())
  75. getLogger()->crit(var_export($res));
  76. return $res->isOK();
  77. }
  78. /**
  79. * Writes/uploads new photos in bulk and in parallel to the remote file system.
  80. *
  81. * @param array $files Array where each row represents a file with the key being the local file name and the value being the remote.
  82. * [{"/path/to/local/file.jpg": "/path/to/save/on/remote.jpg"}...]
  83. * @param string $remoteFile File name to be saved on the remote file system.
  84. * @param string $acl Permission setting for this photo.
  85. * @return boolean
  86. */
  87. public function putPhotos($files, $acl = AmazonS3::ACL_PUBLIC)
  88. {
  89. $queue = new CFBatchRequest();
  90. foreach($files as $file)
  91. {
  92. list($localFile, $remoteFile) = each($file);
  93. $opts = array('fileUpload' => $localFile, 'acl' => $acl, 'contentType' => 'image/jpeg');
  94. $remoteFile = self::normalizePath($remoteFile);
  95. $this->fs->batch($queue)->create_object($this->bucket, $remoteFile, $opts);
  96. }
  97. $responses = $this->fs->batch($queue)->send();
  98. if(!$responses->areOK())
  99. {
  100. foreach($responses as $resp)
  101. getLogger()->crit(var_export($resp, 1));
  102. }
  103. return $responses->areOK();
  104. }
  105. /**
  106. * Get the hostname for the remote filesystem to be used in constructing public URLs.
  107. * @return string
  108. */
  109. public function getHost()
  110. {
  111. return getConfig()->get('aws')->s3Host;
  112. }
  113. /**
  114. * Initialize the remote file system by creating buckets and setting permissions and settings.
  115. * This is called from the Setup controller.
  116. * @return boolean
  117. */
  118. public function initialize()
  119. {
  120. getLogger()->info('Initializing file system');
  121. if(!$this->fs->validate_bucketname_create($this->bucket) || !$this->fs->validate_bucketname_support($this->bucket))
  122. return false;
  123. $buckets = $this->fs->get_bucket_list("/^{$this->bucket}$/");
  124. if(count($buckets) == 0)
  125. {
  126. getLogger()->info("Bucket {$this->bucket} does not exist, adding");
  127. $res = $this->fs->create_bucket($this->bucket, AmazonS3::REGION_US_E1, AmazonS3::ACL_PUBLIC);
  128. if(!$res->isOK())
  129. {
  130. getLogger()->crit('Failed initializing file system: ' . var_export($res, 1));
  131. return false;
  132. }
  133. }
  134. // TODO add versioning?
  135. // Set a policy for this bucket only
  136. $policy = new CFPolicy($this->fs, array(
  137. 'Version' => '2008-10-17',
  138. 'Statement' => array(
  139. array(
  140. 'Sid' => 'AddPerm',
  141. 'Effect' => 'Allow',
  142. 'Principal' => array(
  143. 'AWS' => '*'
  144. ),
  145. 'Action' => array('s3:*'),
  146. 'Resource' => array("arn:aws:s3:::{$this->bucket}/*")
  147. )
  148. )
  149. ));
  150. $res = $this->fs->set_bucket_policy($this->bucket, $policy);
  151. if(!$res->isOK())
  152. getLogger()->crit('Failed to set bucket policy');
  153. return $res->isOK();
  154. }
  155. /**
  156. * Removes leading slashes since it's not needed when putting new files on S3.
  157. *
  158. * @param string $path Path of the photo to have leading slashes removed.
  159. * @return string
  160. */
  161. private function normalizePath($path)
  162. {
  163. return preg_replace('/^\/+/', '', $path);
  164. }
  165. }