You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
4.5 KiB

10 years ago
12 years ago
12 years ago
  1. <?php
  2. /**
  3. * @author Bart Visscher <bartv@thisnet.nl>
  4. * @author Felix Moeller <mail@felixmoeller.de>
  5. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  6. * @author Morris Jobke <hey@morrisjobke.de>
  7. * @author Robin Appelman <icewind@owncloud.com>
  8. * @author Thomas Müller <thomas.mueller@tmit.eu>
  9. * @author Thomas Tanghus <thomas@tanghus.net>
  10. * @author Vincent Petry <pvince81@owncloud.com>
  11. *
  12. * @copyright Copyright (c) 2016, ownCloud, Inc.
  13. * @license AGPL-3.0
  14. *
  15. * This code is free software: you can redistribute it and/or modify
  16. * it under the terms of the GNU Affero General Public License, version 3,
  17. * as published by the Free Software Foundation.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU Affero General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Affero General Public License, version 3,
  25. * along with this program. If not, see <http://www.gnu.org/licenses/>
  26. *
  27. */
  28. class OC_FileChunking {
  29. protected $info;
  30. protected $cache;
  31. static public function decodeName($name) {
  32. preg_match('/(?P<name>.*)-chunking-(?P<transferid>\d+)-(?P<chunkcount>\d+)-(?P<index>\d+)/', $name, $matches);
  33. return $matches;
  34. }
  35. /**
  36. * @param string[] $info
  37. */
  38. public function __construct($info) {
  39. $this->info = $info;
  40. }
  41. public function getPrefix() {
  42. $name = $this->info['name'];
  43. $transferid = $this->info['transferid'];
  44. return $name.'-chunking-'.$transferid.'-';
  45. }
  46. protected function getCache() {
  47. if (!isset($this->cache)) {
  48. $this->cache = new \OC\Cache\File();
  49. }
  50. return $this->cache;
  51. }
  52. /**
  53. * Stores the given $data under the given $key - the number of stored bytes is returned
  54. *
  55. * @param string $index
  56. * @param resource $data
  57. * @return int
  58. */
  59. public function store($index, $data) {
  60. $cache = $this->getCache();
  61. $name = $this->getPrefix().$index;
  62. $cache->set($name, $data);
  63. return $cache->size($name);
  64. }
  65. public function isComplete() {
  66. $prefix = $this->getPrefix();
  67. $cache = $this->getCache();
  68. $chunkcount = (int)$this->info['chunkcount'];
  69. for($i=($chunkcount-1); $i >= 0; $i--) {
  70. if (!$cache->hasKey($prefix.$i)) {
  71. return false;
  72. }
  73. }
  74. return true;
  75. }
  76. /**
  77. * Assembles the chunks into the file specified by the path.
  78. * Chunks are deleted afterwards.
  79. *
  80. * @param resource $f target path
  81. *
  82. * @return integer assembled file size
  83. *
  84. * @throws \OC\InsufficientStorageException when file could not be fully
  85. * assembled due to lack of free space
  86. */
  87. public function assemble($f) {
  88. $cache = $this->getCache();
  89. $prefix = $this->getPrefix();
  90. $count = 0;
  91. for ($i = 0; $i < $this->info['chunkcount']; $i++) {
  92. $chunk = $cache->get($prefix.$i);
  93. // remove after reading to directly save space
  94. $cache->remove($prefix.$i);
  95. $count += fwrite($f, $chunk);
  96. // let php release the memory to work around memory exhausted error with php 5.6
  97. $chunk = null;
  98. }
  99. return $count;
  100. }
  101. /**
  102. * Returns the size of the chunks already present
  103. * @return integer size in bytes
  104. */
  105. public function getCurrentSize() {
  106. $cache = $this->getCache();
  107. $prefix = $this->getPrefix();
  108. $total = 0;
  109. for ($i = 0; $i < $this->info['chunkcount']; $i++) {
  110. $total += $cache->size($prefix.$i);
  111. }
  112. return $total;
  113. }
  114. /**
  115. * Removes all chunks which belong to this transmission
  116. */
  117. public function cleanup() {
  118. $cache = $this->getCache();
  119. $prefix = $this->getPrefix();
  120. for($i=0; $i < $this->info['chunkcount']; $i++) {
  121. $cache->remove($prefix.$i);
  122. }
  123. }
  124. /**
  125. * Removes one specific chunk
  126. * @param string $index
  127. */
  128. public function remove($index) {
  129. $cache = $this->getCache();
  130. $prefix = $this->getPrefix();
  131. $cache->remove($prefix.$index);
  132. }
  133. /**
  134. * Assembles the chunks into the file specified by the path.
  135. * Also triggers the relevant hooks and proxies.
  136. *
  137. * @param \OC\Files\Storage\Storage $storage storage
  138. * @param string $path target path relative to the storage
  139. * @return bool true on success or false if file could not be created
  140. *
  141. * @throws \OC\ServerNotAvailableException
  142. */
  143. public function file_assemble($storage, $path) {
  144. // use file_put_contents as method because that best matches what this function does
  145. if (\OC\Files\Filesystem::isValidPath($path)) {
  146. $target = $storage->fopen($path, 'w');
  147. if ($target) {
  148. $count = $this->assemble($target);
  149. fclose($target);
  150. return $count > 0;
  151. } else {
  152. return false;
  153. }
  154. }
  155. return false;
  156. }
  157. }