PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/apps/files_external/lib/swift.php

https://github.com/hutchic/core
PHP | 517 lines | 393 code | 79 blank | 45 comment | 61 complexity | 7931eebd33ae149dc6bad3f8783117a2 MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, Apache-2.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Christian Berendt
  6. * @copyright 2013 Christian Berendt berendt@b1-systems.de
  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. set_include_path(get_include_path() . PATH_SEPARATOR .
  23. \OC_App::getAppPath('files_external') . '/3rdparty/php-opencloud/lib');
  24. require_once 'openstack.php';
  25. use \OpenCloud;
  26. use \OpenCloud\Common\Exceptions;
  27. class Swift extends \OC\Files\Storage\Common {
  28. /**
  29. * @var \OpenCloud\ObjectStore
  30. */
  31. private $connection;
  32. /**
  33. * @var \OpenCloud\ObjectStore\Container
  34. */
  35. private $container;
  36. /**
  37. * @var \OpenCloud\OpenStack
  38. */
  39. private $anchor;
  40. /**
  41. * @var string
  42. */
  43. private $bucket;
  44. /**
  45. * @var array
  46. */
  47. private static $tmpFiles = array();
  48. /**
  49. * @param string $path
  50. */
  51. private function normalizePath($path) {
  52. $path = trim($path, '/');
  53. if (!$path) {
  54. $path = '.';
  55. }
  56. return $path;
  57. }
  58. const SUBCONTAINER_FILE='.subcontainers';
  59. /**
  60. * translate directory path to container name
  61. * @param string $path
  62. * @return string
  63. */
  64. private function getContainerName($path) {
  65. $path=trim(trim($this->root, '/') . "/".$path, '/.');
  66. return str_replace('/', '\\', $path);
  67. }
  68. /**
  69. * @param string $path
  70. */
  71. private function doesObjectExist($path) {
  72. try {
  73. $object = $this->container->DataObject($path);
  74. return true;
  75. } catch (Exceptions\ObjFetchError $e) {
  76. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  77. return false;
  78. } catch (Exceptions\HttpError $e) {
  79. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  80. return false;
  81. }
  82. }
  83. public function __construct($params) {
  84. if ((!isset($params['key']) and !isset($params['password']))
  85. or !isset($params['user']) or !isset($params['bucket'])
  86. or !isset($params['region'])) {
  87. throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
  88. }
  89. $this->id = 'swift::' . $params['user'] . md5($params['bucket']);
  90. $this->bucket = $params['bucket'];
  91. if (!isset($params['url'])) {
  92. $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
  93. }
  94. if (!isset($params['service_name'])) {
  95. $params['service_name'] = 'cloudFiles';
  96. }
  97. $settings = array(
  98. 'username' => $params['user'],
  99. );
  100. if (isset($params['password'])) {
  101. $settings['password'] = $params['password'];
  102. } else if (isset($params['key'])) {
  103. $settings['apiKey'] = $params['key'];
  104. }
  105. if (isset($params['tenant'])) {
  106. $settings['tenantName'] = $params['tenant'];
  107. }
  108. $this->anchor = new \OpenCloud\OpenStack($params['url'], $settings);
  109. if (isset($params['timeout'])) {
  110. $this->anchor->setHttpTimeout($params['timeout']);
  111. }
  112. $this->connection = $this->anchor->ObjectStore($params['service_name'], $params['region'], 'publicURL');
  113. try {
  114. $this->container = $this->connection->Container($this->bucket);
  115. } catch (Exceptions\ContainerNotFoundError $e) {
  116. $this->container = $this->connection->Container();
  117. $this->container->Create(array('name' => $this->bucket));
  118. }
  119. if (!$this->file_exists('.')) {
  120. $this->mkdir('.');
  121. }
  122. }
  123. public function mkdir($path) {
  124. $path = $this->normalizePath($path);
  125. if ($this->is_dir($path)) {
  126. return false;
  127. }
  128. if($path !== '.') {
  129. $path .= '/';
  130. }
  131. try {
  132. $object = $this->container->DataObject();
  133. $object->Create(array(
  134. 'name' => $path,
  135. 'content_type' => 'httpd/unix-directory'
  136. ));
  137. } catch (Exceptions\CreateUpdateError $e) {
  138. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  139. return false;
  140. }
  141. return true;
  142. }
  143. public function file_exists($path) {
  144. $path = $this->normalizePath($path);
  145. if ($path !== '.' && $this->is_dir($path)) {
  146. $path .= '/';
  147. }
  148. return $this->doesObjectExist($path);
  149. }
  150. public function rmdir($path) {
  151. $path = $this->normalizePath($path);
  152. if (!$this->is_dir($path)) {
  153. return false;
  154. }
  155. $dh = $this->opendir($path);
  156. while ($file = readdir($dh)) {
  157. if ($file === '.' || $file === '..') {
  158. continue;
  159. }
  160. if ($this->is_dir($path . '/' . $file)) {
  161. $this->rmdir($path . '/' . $file);
  162. } else {
  163. $this->unlink($path . '/' . $file);
  164. }
  165. }
  166. try {
  167. $object = $this->container->DataObject($path . '/');
  168. $object->Delete();
  169. } catch (Exceptions\DeleteError $e) {
  170. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  171. return false;
  172. }
  173. return true;
  174. }
  175. public function opendir($path) {
  176. $path = $this->normalizePath($path);
  177. if ($path === '.') {
  178. $path = '';
  179. } else {
  180. $path .= '/';
  181. }
  182. try {
  183. $files = array();
  184. $objects = $this->container->ObjectList(array(
  185. 'prefix' => $path,
  186. 'delimiter' => '/'
  187. ));
  188. while ($object = $objects->Next()) {
  189. $file = basename($object->Name());
  190. if ($file !== basename($path)) {
  191. $files[] = $file;
  192. }
  193. }
  194. \OC\Files\Stream\Dir::register('swift' . $path, $files);
  195. return opendir('fakedir://swift' . $path);
  196. } catch (Exception $e) {
  197. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  198. return false;
  199. }
  200. }
  201. public function stat($path) {
  202. $path = $this->normalizePath($path);
  203. if ($this->is_dir($path) && $path != '.') {
  204. $path .= '/';
  205. }
  206. try {
  207. $object = $this->container->DataObject($path);
  208. } catch (Exceptions\ObjFetchError $e) {
  209. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  210. return false;
  211. }
  212. $mtime = $object->extra_headers['X-Timestamp'];
  213. if (isset($object->extra_headers['X-Object-Meta-Timestamp'])) {
  214. $mtime = $object->extra_headers['X-Object-Meta-Timestamp'];
  215. }
  216. if (!empty($mtime)) {
  217. $mtime = floor($mtime);
  218. }
  219. $stat = array();
  220. $stat['size'] = $object->content_length;
  221. $stat['mtime'] = $mtime;
  222. $stat['atime'] = time();
  223. return $stat;
  224. }
  225. public function filetype($path) {
  226. $path = $this->normalizePath($path);
  227. if ($path !== '.' && $this->doesObjectExist($path)) {
  228. return 'file';
  229. }
  230. if ($path !== '.') {
  231. $path .= '/';
  232. }
  233. if ($this->doesObjectExist($path)) {
  234. return 'dir';
  235. }
  236. }
  237. public function unlink($path) {
  238. $path = $this->normalizePath($path);
  239. try {
  240. $object = $this->container->DataObject($path);
  241. $object->Delete();
  242. } catch (Exceptions\DeleteError $e) {
  243. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  244. return false;
  245. } catch (Exceptions\ObjFetchError $e) {
  246. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  247. return false;
  248. }
  249. return true;
  250. }
  251. public function fopen($path, $mode) {
  252. $path = $this->normalizePath($path);
  253. switch ($mode) {
  254. case 'r':
  255. case 'rb':
  256. $tmpFile = \OC_Helper::tmpFile();
  257. self::$tmpFiles[$tmpFile] = $path;
  258. try {
  259. $object = $this->container->DataObject($path);
  260. } catch (Exceptions\ObjFetchError $e) {
  261. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  262. return false;
  263. }
  264. try {
  265. $object->SaveToFilename($tmpFile);
  266. } catch (Exceptions\IOError $e) {
  267. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  268. return false;
  269. }
  270. return fopen($tmpFile, 'r');
  271. case 'w':
  272. case 'wb':
  273. case 'a':
  274. case 'ab':
  275. case 'r+':
  276. case 'w+':
  277. case 'wb+':
  278. case 'a+':
  279. case 'x':
  280. case 'x+':
  281. case 'c':
  282. case 'c+':
  283. if (strrpos($path, '.') !== false) {
  284. $ext = substr($path, strrpos($path, '.'));
  285. } else {
  286. $ext = '';
  287. }
  288. $tmpFile = \OC_Helper::tmpFile($ext);
  289. \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
  290. if ($this->file_exists($path)) {
  291. $source = $this->fopen($path, 'r');
  292. file_put_contents($tmpFile, $source);
  293. }
  294. self::$tmpFiles[$tmpFile] = $path;
  295. return fopen('close://' . $tmpFile, $mode);
  296. }
  297. }
  298. public function getMimeType($path) {
  299. $path = $this->normalizePath($path);
  300. if ($this->is_dir($path)) {
  301. return 'httpd/unix-directory';
  302. } else if ($this->file_exists($path)) {
  303. $object = $this->container->DataObject($path);
  304. return $object->extra_headers["Content-Type"];
  305. }
  306. return false;
  307. }
  308. public function touch($path, $mtime = null) {
  309. $path = $this->normalizePath($path);
  310. if ($this->file_exists($path)) {
  311. if ($this->is_dir($path) && $path != '.') {
  312. $path .= '/';
  313. }
  314. $object = $this->container->DataObject($path);
  315. if( is_null($mtime)) {
  316. $mtime = time();
  317. }
  318. $settings = array(
  319. 'name' => $path,
  320. 'extra_headers' => array(
  321. 'X-Object-Meta-Timestamp' => $mtime
  322. )
  323. );
  324. return $object->UpdateMetadata($settings);
  325. } else {
  326. $object = $this->container->DataObject();
  327. if (is_null($mtime)) {
  328. $mtime = time();
  329. }
  330. $settings = array(
  331. 'name' => $path,
  332. 'content_type' => 'text/plain',
  333. 'extra_headers' => array(
  334. 'X-Object-Meta-Timestamp' => $mtime
  335. )
  336. );
  337. return $object->Create($settings);
  338. }
  339. }
  340. public function copy($path1, $path2) {
  341. $path1 = $this->normalizePath($path1);
  342. $path2 = $this->normalizePath($path2);
  343. if ($this->is_file($path1)) {
  344. try {
  345. $source = $this->container->DataObject($path1);
  346. $target = $this->container->DataObject();
  347. $target->Create(array(
  348. 'name' => $path2,
  349. ));
  350. $source->Copy($target);
  351. } catch (Exceptions\ObjectCopyError $e) {
  352. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  353. return false;
  354. }
  355. } else {
  356. if ($this->file_exists($path2)) {
  357. return false;
  358. }
  359. try {
  360. $source = $this->container->DataObject($path1 . '/');
  361. $target = $this->container->DataObject();
  362. $target->Create(array(
  363. 'name' => $path2 . '/',
  364. ));
  365. $source->Copy($target);
  366. } catch (Exceptions\ObjectCopyError $e) {
  367. \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
  368. return false;
  369. }
  370. $dh = $this->opendir($path1);
  371. while ($file = readdir($dh)) {
  372. if ($file === '.' || $file === '..') {
  373. continue;
  374. }
  375. $source = $path1 . '/' . $file;
  376. $target = $path2 . '/' . $file;
  377. $this->copy($source, $target);
  378. }
  379. }
  380. return true;
  381. }
  382. public function rename($path1, $path2) {
  383. $path1 = $this->normalizePath($path1);
  384. $path2 = $this->normalizePath($path2);
  385. if ($this->is_file($path1)) {
  386. if ($this->copy($path1, $path2) === false) {
  387. return false;
  388. }
  389. if ($this->unlink($path1) === false) {
  390. $this->unlink($path2);
  391. return false;
  392. }
  393. } else {
  394. if ($this->file_exists($path2)) {
  395. return false;
  396. }
  397. if ($this->copy($path1, $path2) === false) {
  398. return false;
  399. }
  400. if ($this->rmdir($path1) === false) {
  401. $this->rmdir($path2);
  402. return false;
  403. }
  404. }
  405. return true;
  406. }
  407. public function getId() {
  408. return $this->id;
  409. }
  410. public function getConnection() {
  411. return $this->connection;
  412. }
  413. public function writeBack($tmpFile) {
  414. if (!isset(self::$tmpFiles[$tmpFile])) {
  415. return false;
  416. }
  417. $object = $this->container->DataObject();
  418. $object->Create(array(
  419. 'name' => self::$tmpFiles[$tmpFile],
  420. 'content_type' => \OC_Helper::getMimeType($tmpFile)
  421. ), $tmpFile);
  422. unlink($tmpFile);
  423. }
  424. /**
  425. * check if curl is installed
  426. */
  427. public static function checkDependencies() {
  428. if (function_exists('curl_init')) {
  429. return true;
  430. } else {
  431. return array('curl');
  432. }
  433. }
  434. }