PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/files_external/lib/amazons3.php

https://github.com/jlgg/simple_trash
PHP | 245 lines | 193 code | 23 blank | 29 comment | 59 complexity | 5258a0e7b9b084f38bdf0e0d9fb59dbe MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Michael Gapczynski
  6. * @copyright 2012 Michael Gapczynski mtgap@owncloud.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. require_once 'aws-sdk/sdk.class.php';
  22. class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common {
  23. private $s3;
  24. private $bucket;
  25. private $objects = array();
  26. private static $tempFiles = array();
  27. // TODO options: storage class, encryption server side, encrypt before upload?
  28. public function __construct($params) {
  29. $this->s3 = new AmazonS3(array('key' => $params['key'], 'secret' => $params['secret']));
  30. $this->bucket = $params['bucket'];
  31. }
  32. private function getObject($path) {
  33. if (array_key_exists($path, $this->objects)) {
  34. return $this->objects[$path];
  35. } else {
  36. $response = $this->s3->get_object_metadata($this->bucket, $path);
  37. if ($response) {
  38. $this->objects[$path] = $response;
  39. return $response;
  40. // This object could be a folder, a '/' must be at the end of the path
  41. } else if (substr($path, -1) != '/') {
  42. $response = $this->s3->get_object_metadata($this->bucket, $path.'/');
  43. if ($response) {
  44. $this->objects[$path] = $response;
  45. return $response;
  46. }
  47. }
  48. }
  49. return false;
  50. }
  51. public function mkdir($path) {
  52. // Folders in Amazon S3 are 0 byte objects with a '/' at the end of the name
  53. if (substr($path, -1) != '/') {
  54. $path .= '/';
  55. }
  56. $response = $this->s3->create_object($this->bucket, $path, array('body' => ''));
  57. return $response->isOK();
  58. }
  59. public function rmdir($path) {
  60. if (substr($path, -1) != '/') {
  61. $path .= '/';
  62. }
  63. return $this->unlink($path);
  64. }
  65. public function opendir($path) {
  66. if ($path == '' || $path == '/') {
  67. // Use the '/' delimiter to only fetch objects inside the folder
  68. $opt = array('delimiter' => '/');
  69. } else {
  70. if (substr($path, -1) != '/') {
  71. $path .= '/';
  72. }
  73. $opt = array('delimiter' => '/', 'prefix' => $path);
  74. }
  75. $response = $this->s3->list_objects($this->bucket, $opt);
  76. if ($response->isOK()) {
  77. $files = array();
  78. foreach ($response->body->Contents as $object) {
  79. // The folder being opened also shows up in the list of objects, don't add it to the files
  80. if ($object->Key != $path) {
  81. $files[] = basename($object->Key);
  82. }
  83. }
  84. // Sub folders show up as CommonPrefixes
  85. foreach ($response->body->CommonPrefixes as $object) {
  86. $files[] = basename($object->Prefix);
  87. }
  88. OC_FakeDirStream::$dirs['amazons3'.$path] = $files;
  89. return opendir('fakedir://amazons3'.$path);
  90. }
  91. return false;
  92. }
  93. public function stat($path) {
  94. if ($path == '' || $path == '/') {
  95. $stat['size'] = $this->s3->get_bucket_filesize($this->bucket);
  96. $stat['atime'] = time();
  97. $stat['mtime'] = $stat['atime'];
  98. $stat['ctime'] = $stat['atime'];
  99. } else {
  100. $object = $this->getObject($path);
  101. if ($object) {
  102. $stat['size'] = $object['Size'];
  103. $stat['atime'] = time();
  104. $stat['mtime'] = strtotime($object['LastModified']);
  105. $stat['ctime'] = $stat['mtime'];
  106. }
  107. }
  108. if (isset($stat)) {
  109. return $stat;
  110. }
  111. return false;
  112. }
  113. public function filetype($path) {
  114. if ($path == '' || $path == '/') {
  115. return 'dir';
  116. } else {
  117. $object = $this->getObject($path);
  118. if ($object) {
  119. // Amazon S3 doesn't have typical folders, this is an alternative method to detect a folder
  120. if (substr($object['Key'], -1) == '/' && $object['Size'] == 0) {
  121. return 'dir';
  122. } else {
  123. return 'file';
  124. }
  125. }
  126. }
  127. return false;
  128. }
  129. public function isReadable($path) {
  130. // TODO Check acl and determine who grantee is
  131. return true;
  132. }
  133. public function isUpdatable($path) {
  134. // TODO Check acl and determine who grantee is
  135. return true;
  136. }
  137. public function file_exists($path) {
  138. if ($this->filetype($path) == 'dir' && substr($path, -1) != '/') {
  139. $path .= '/';
  140. }
  141. return $this->s3->if_object_exists($this->bucket, $path);
  142. }
  143. public function unlink($path) {
  144. $response = $this->s3->delete_object($this->bucket, $path);
  145. return $response->isOK();
  146. }
  147. public function fopen($path, $mode) {
  148. switch ($mode) {
  149. case 'r':
  150. case 'rb':
  151. $tmpFile = OC_Helper::tmpFile();
  152. $handle = fopen($tmpFile, 'w');
  153. $response = $this->s3->get_object($this->bucket, $path, array('fileDownload' => $handle));
  154. if ($response->isOK()) {
  155. return fopen($tmpFile, 'r');
  156. }
  157. break;
  158. case 'w':
  159. case 'wb':
  160. case 'a':
  161. case 'ab':
  162. case 'r+':
  163. case 'w+':
  164. case 'wb+':
  165. case 'a+':
  166. case 'x':
  167. case 'x+':
  168. case 'c':
  169. case 'c+':
  170. if (strrpos($path, '.') !== false) {
  171. $ext = substr($path, strrpos($path, '.'));
  172. } else {
  173. $ext = '';
  174. }
  175. $tmpFile = OC_Helper::tmpFile($ext);
  176. OC_CloseStreamWrapper::$callBacks[$tmpFile] = array($this, 'writeBack');
  177. if ($this->file_exists($path)) {
  178. $source = $this->fopen($path, 'r');
  179. file_put_contents($tmpFile, $source);
  180. }
  181. self::$tempFiles[$tmpFile] = $path;
  182. return fopen('close://'.$tmpFile, $mode);
  183. }
  184. return false;
  185. }
  186. public function writeBack($tmpFile) {
  187. if (isset(self::$tempFiles[$tmpFile])) {
  188. $handle = fopen($tmpFile, 'r');
  189. $response = $this->s3->create_object($this->bucket,
  190. self::$tempFiles[$tmpFile],
  191. array('fileUpload' => $handle));
  192. if ($response->isOK()) {
  193. unlink($tmpFile);
  194. }
  195. }
  196. }
  197. public function getMimeType($path) {
  198. if ($this->filetype($path) == 'dir') {
  199. return 'httpd/unix-directory';
  200. } else {
  201. $object = $this->getObject($path);
  202. if ($object) {
  203. return $object['ContentType'];
  204. }
  205. }
  206. return false;
  207. }
  208. public function free_space($path) {
  209. // Infinite?
  210. return false;
  211. }
  212. public function touch($path, $mtime = null) {
  213. if (is_null($mtime)) {
  214. $mtime = time();
  215. }
  216. if ($this->filetype($path) == 'dir' && substr($path, -1) != '/') {
  217. $path .= '/';
  218. }
  219. $response = $this->s3->update_object($this->bucket, $path, array('meta' => array('LastModified' => $mtime)));
  220. return $response->isOK();
  221. }
  222. }