PageRenderTime 143ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/apps/files_external/lib/amazons3.php

https://github.com/sezuan/core
PHP | 255 lines | 202 code | 25 blank | 28 comment | 66 complexity | 499f88d70a06601b16c1b29719700925 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. namespace OC\Files\Storage;
  22. require_once 'aws-sdk/sdk.class.php';
  23. class AmazonS3 extends \OC\Files\Storage\Common {
  24. private $s3;
  25. private $bucket;
  26. private $objects = array();
  27. private $id;
  28. private static $tempFiles = array();
  29. // TODO Update to new AWS SDK
  30. public function __construct($params) {
  31. if (isset($params['key']) && isset($params['secret']) && isset($params['bucket'])) {
  32. $this->id = 'amazon::' . $params['key'] . md5($params['secret']);
  33. $this->s3 = new \AmazonS3(array('key' => $params['key'], 'secret' => $params['secret']));
  34. $this->bucket = $params['bucket'];
  35. } else {
  36. throw new \Exception();
  37. }
  38. }
  39. private function getObject($path) {
  40. if (array_key_exists($path, $this->objects)) {
  41. return $this->objects[$path];
  42. } else {
  43. $response = $this->s3->get_object_metadata($this->bucket, $path);
  44. if ($response) {
  45. $this->objects[$path] = $response;
  46. return $response;
  47. // This object could be a folder, a '/' must be at the end of the path
  48. } else if (substr($path, -1) != '/') {
  49. $response = $this->s3->get_object_metadata($this->bucket, $path . '/');
  50. if ($response) {
  51. $this->objects[$path] = $response;
  52. return $response;
  53. }
  54. }
  55. }
  56. return false;
  57. }
  58. public function getId() {
  59. return $this->id;
  60. }
  61. public function mkdir($path) {
  62. // Folders in Amazon S3 are 0 byte objects with a '/' at the end of the name
  63. if (substr($path, -1) != '/') {
  64. $path .= '/';
  65. }
  66. $response = $this->s3->create_object($this->bucket, $path, array('body' => ''));
  67. return $response->isOK();
  68. }
  69. public function rmdir($path) {
  70. if (substr($path, -1) != '/') {
  71. $path .= '/';
  72. }
  73. return $this->unlink($path);
  74. }
  75. public function opendir($path) {
  76. if ($path == '' || $path == '/') {
  77. // Use the '/' delimiter to only fetch objects inside the folder
  78. $opt = array('delimiter' => '/');
  79. } else {
  80. if (substr($path, -1) != '/') {
  81. $path .= '/';
  82. }
  83. $opt = array('delimiter' => '/', 'prefix' => $path);
  84. }
  85. $response = $this->s3->list_objects($this->bucket, $opt);
  86. if ($response->isOK()) {
  87. $files = array();
  88. foreach ($response->body->Contents as $object) {
  89. // The folder being opened also shows up in the list of objects, don't add it to the files
  90. if ($object->Key != $path) {
  91. $files[] = basename($object->Key);
  92. }
  93. }
  94. // Sub folders show up as CommonPrefixes
  95. foreach ($response->body->CommonPrefixes as $object) {
  96. $files[] = basename($object->Prefix);
  97. }
  98. \OC\Files\Stream\Dir::register('amazons3' . $path, $files);
  99. return opendir('fakedir://amazons3' . $path);
  100. }
  101. return false;
  102. }
  103. public function stat($path) {
  104. if ($path == '' || $path == '/') {
  105. $stat['size'] = $this->s3->get_bucket_filesize($this->bucket);
  106. $stat['atime'] = time();
  107. $stat['mtime'] = $stat['atime'];
  108. } else if ($object = $this->getObject($path)) {
  109. $stat['size'] = $object['Size'];
  110. $stat['atime'] = time();
  111. $stat['mtime'] = strtotime($object['LastModified']);
  112. }
  113. if (isset($stat)) {
  114. return $stat;
  115. }
  116. return false;
  117. }
  118. public function filetype($path) {
  119. if ($path == '' || $path == '/') {
  120. return 'dir';
  121. } else {
  122. $object = $this->getObject($path);
  123. if ($object) {
  124. // Amazon S3 doesn't have typical folders, this is an alternative method to detect a folder
  125. if (substr($object['Key'], -1) == '/' && $object['Size'] == 0) {
  126. return 'dir';
  127. } else {
  128. return 'file';
  129. }
  130. }
  131. }
  132. return false;
  133. }
  134. public function isReadable($path) {
  135. // TODO Check acl and determine who grantee is
  136. return true;
  137. }
  138. public function isUpdatable($path) {
  139. // TODO Check acl and determine who grantee is
  140. return true;
  141. }
  142. public function file_exists($path) {
  143. if ($this->filetype($path) == 'dir' && substr($path, -1) != '/') {
  144. $path .= '/';
  145. }
  146. return $this->s3->if_object_exists($this->bucket, $path);
  147. }
  148. public function unlink($path) {
  149. $response = $this->s3->delete_object($this->bucket, $path);
  150. return $response->isOK();
  151. }
  152. public function fopen($path, $mode) {
  153. switch ($mode) {
  154. case 'r':
  155. case 'rb':
  156. $tmpFile = \OC_Helper::tmpFile();
  157. $handle = fopen($tmpFile, 'w');
  158. $response = $this->s3->get_object($this->bucket, $path, array('fileDownload' => $handle));
  159. if ($response->isOK()) {
  160. return fopen($tmpFile, 'r');
  161. }
  162. break;
  163. case 'w':
  164. case 'wb':
  165. case 'a':
  166. case 'ab':
  167. case 'r+':
  168. case 'w+':
  169. case 'wb+':
  170. case 'a+':
  171. case 'x':
  172. case 'x+':
  173. case 'c':
  174. case 'c+':
  175. if (strrpos($path, '.') !== false) {
  176. $ext = substr($path, strrpos($path, '.'));
  177. } else {
  178. $ext = '';
  179. }
  180. $tmpFile = \OC_Helper::tmpFile($ext);
  181. \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
  182. if ($this->file_exists($path)) {
  183. $source = $this->fopen($path, 'r');
  184. file_put_contents($tmpFile, $source);
  185. }
  186. self::$tempFiles[$tmpFile] = $path;
  187. return fopen('close://' . $tmpFile, $mode);
  188. }
  189. return false;
  190. }
  191. public function writeBack($tmpFile) {
  192. if (isset(self::$tempFiles[$tmpFile])) {
  193. $handle = fopen($tmpFile, 'r');
  194. $response = $this->s3->create_object($this->bucket,
  195. self::$tempFiles[$tmpFile],
  196. array('fileUpload' => $handle));
  197. if ($response->isOK()) {
  198. unlink($tmpFile);
  199. }
  200. }
  201. }
  202. public function getMimeType($path) {
  203. if ($this->filetype($path) == 'dir') {
  204. return 'httpd/unix-directory';
  205. } else {
  206. $object = $this->getObject($path);
  207. if ($object) {
  208. return $object['ContentType'];
  209. }
  210. }
  211. return false;
  212. }
  213. public function touch($path, $mtime = null) {
  214. if (is_null($mtime)) {
  215. $mtime = time();
  216. }
  217. if ($this->filetype($path) == 'dir' && substr($path, -1) != '/') {
  218. $path .= '/';
  219. }
  220. $response = $this->s3->update_object($this->bucket, $path, array('meta' => array('LastModified' => $mtime)));
  221. return $response->isOK();
  222. }
  223. public function test() {
  224. $test = $this->s3->get_canonical_user_id();
  225. if (isset($test['id']) && $test['id'] != '') {
  226. return true;
  227. }
  228. return false;
  229. }
  230. }