filechunking.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. class OC_FileChunking {
  9. protected $info;
  10. protected $cache;
  11. static public function decodeName($name) {
  12. preg_match('/(?P<name>.*)-chunking-(?P<transferid>\d+)-(?P<chunkcount>\d+)-(?P<index>\d+)/', $name, $matches);
  13. return $matches;
  14. }
  15. public function __construct($info) {
  16. $this->info = $info;
  17. }
  18. public function getPrefix() {
  19. $name = $this->info['name'];
  20. $transferid = $this->info['transferid'];
  21. return $name.'-chunking-'.$transferid.'-';
  22. }
  23. protected function getCache() {
  24. if (!isset($this->cache)) {
  25. $this->cache = new OC_Cache_File();
  26. }
  27. return $this->cache;
  28. }
  29. public function store($index, $data) {
  30. $cache = $this->getCache();
  31. $name = $this->getPrefix().$index;
  32. $cache->set($name, $data);
  33. }
  34. public function isComplete() {
  35. $prefix = $this->getPrefix();
  36. $parts = 0;
  37. $cache = $this->getCache();
  38. for($i=0; $i < $this->info['chunkcount']; $i++) {
  39. if ($cache->hasKey($prefix.$i)) {
  40. $parts ++;
  41. }
  42. }
  43. return $parts == $this->info['chunkcount'];
  44. }
  45. public function assemble($f) {
  46. $cache = $this->getCache();
  47. $prefix = $this->getPrefix();
  48. $count = 0;
  49. for($i=0; $i < $this->info['chunkcount']; $i++) {
  50. $chunk = $cache->get($prefix.$i);
  51. $cache->remove($prefix.$i);
  52. $count += fwrite($f,$chunk);
  53. }
  54. return $count;
  55. }
  56. public function signature_split($orgfile, $input) {
  57. $info = unpack('n', fread($input, 2));
  58. $blocksize = $info[1];
  59. $this->info['transferid'] = mt_rand();
  60. $count = 0;
  61. $needed = array();
  62. $cache = $this->getCache();
  63. $prefix = $this->getPrefix();
  64. while (!feof($orgfile)) {
  65. $new_md5 = fread($input, 16);
  66. if (feof($input)) {
  67. break;
  68. }
  69. $data = fread($orgfile, $blocksize);
  70. $org_md5 = md5($data, true);
  71. if ($org_md5 == $new_md5) {
  72. $cache->set($prefix.$count, $data);
  73. } else {
  74. $needed[] = $count;
  75. }
  76. $count++;
  77. }
  78. return array(
  79. 'transferid' => $this->info['transferid'],
  80. 'needed' => $needed,
  81. 'count' => $count,
  82. );
  83. }
  84. public function file_assemble($path) {
  85. $absolutePath = OC_Filesystem::normalizePath(OC_Filesystem::getView()->getAbsolutePath($path));
  86. $data = '';
  87. // use file_put_contents as method because that best matches what this function does
  88. if (OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data) && OC_Filesystem::isValidPath($path)) {
  89. $path = OC_Filesystem::getView()->getRelativePath($absolutePath);
  90. $exists = OC_Filesystem::file_exists($path);
  91. $run = true;
  92. if(!$exists) {
  93. OC_Hook::emit(
  94. OC_Filesystem::CLASSNAME,
  95. OC_Filesystem::signal_create,
  96. array(
  97. OC_Filesystem::signal_param_path => $path,
  98. OC_Filesystem::signal_param_run => &$run
  99. )
  100. );
  101. }
  102. OC_Hook::emit(
  103. OC_Filesystem::CLASSNAME,
  104. OC_Filesystem::signal_write,
  105. array(
  106. OC_Filesystem::signal_param_path => $path,
  107. OC_Filesystem::signal_param_run => &$run
  108. )
  109. );
  110. if(!$run) {
  111. return false;
  112. }
  113. $target = OC_Filesystem::fopen($path, 'w');
  114. if($target) {
  115. $count = $this->assemble($target);
  116. fclose($target);
  117. if(!$exists) {
  118. OC_Hook::emit(
  119. OC_Filesystem::CLASSNAME,
  120. OC_Filesystem::signal_post_create,
  121. array( OC_Filesystem::signal_param_path => $path)
  122. );
  123. }
  124. OC_Hook::emit(
  125. OC_Filesystem::CLASSNAME,
  126. OC_Filesystem::signal_post_write,
  127. array( OC_Filesystem::signal_param_path => $path)
  128. );
  129. OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count);
  130. return $count > 0;
  131. }else{
  132. return false;
  133. }
  134. }
  135. }
  136. }