filechunking.php 4.7 KB

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