zip.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. /**
  3. * @author Bart Visscher <bartv@thisnet.nl>
  4. * @author Christopher Schäpers <kondou@ts.unde.re>
  5. * @author Felix Moeller <mail@felixmoeller.de>
  6. * @author Frank Karlitschek <frank@owncloud.org>
  7. * @author Joas Schilling <nickvergessen@owncloud.com>
  8. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Robin Appelman <icewind@owncloud.com>
  11. * @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
  12. * @author Thomas Müller <thomas.mueller@tmit.eu>
  13. *
  14. * @copyright Copyright (c) 2015, ownCloud, Inc.
  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_Archive_ZIP extends OC_Archive{
  31. /**
  32. * @var ZipArchive zip
  33. */
  34. private $zip=null;
  35. private $path;
  36. /**
  37. * @param string $source
  38. */
  39. function __construct($source) {
  40. $this->path=$source;
  41. $this->zip=new ZipArchive();
  42. if($this->zip->open($source, ZipArchive::CREATE)) {
  43. }else{
  44. OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, OCP\Util::WARN);
  45. }
  46. }
  47. /**
  48. * add an empty folder to the archive
  49. * @param string $path
  50. * @return bool
  51. */
  52. function addFolder($path) {
  53. return $this->zip->addEmptyDir($path);
  54. }
  55. /**
  56. * add a file to the archive
  57. * @param string $path
  58. * @param string $source either a local file or string data
  59. * @return bool
  60. */
  61. function addFile($path, $source='') {
  62. if($source and $source[0]=='/' and file_exists($source)) {
  63. $result=$this->zip->addFile($source, $path);
  64. }else{
  65. $result=$this->zip->addFromString($path, $source);
  66. }
  67. if($result) {
  68. $this->zip->close();//close and reopen to save the zip
  69. $this->zip->open($this->path);
  70. }
  71. return $result;
  72. }
  73. /**
  74. * rename a file or folder in the archive
  75. * @param string $source
  76. * @param string $dest
  77. * @return boolean|null
  78. */
  79. function rename($source, $dest) {
  80. $source=$this->stripPath($source);
  81. $dest=$this->stripPath($dest);
  82. $this->zip->renameName($source, $dest);
  83. }
  84. /**
  85. * get the uncompressed size of a file in the archive
  86. * @param string $path
  87. * @return int
  88. */
  89. function filesize($path) {
  90. $stat=$this->zip->statName($path);
  91. return $stat['size'];
  92. }
  93. /**
  94. * get the last modified time of a file in the archive
  95. * @param string $path
  96. * @return int
  97. */
  98. function mtime($path) {
  99. return filemtime($this->path);
  100. }
  101. /**
  102. * get the files in a folder
  103. * @param string $path
  104. * @return array
  105. */
  106. function getFolder($path) {
  107. $files=$this->getFiles();
  108. $folderContent=array();
  109. $pathLength=strlen($path);
  110. foreach($files as $file) {
  111. if(substr($file, 0, $pathLength)==$path and $file!=$path) {
  112. if(strrpos(substr($file, 0, -1), '/')<=$pathLength) {
  113. $folderContent[]=substr($file, $pathLength);
  114. }
  115. }
  116. }
  117. return $folderContent;
  118. }
  119. /**
  120. * get all files in the archive
  121. * @return array
  122. */
  123. function getFiles() {
  124. $fileCount=$this->zip->numFiles;
  125. $files=array();
  126. for($i=0;$i<$fileCount;$i++) {
  127. $files[]=$this->zip->getNameIndex($i);
  128. }
  129. return $files;
  130. }
  131. /**
  132. * get the content of a file
  133. * @param string $path
  134. * @return string
  135. */
  136. function getFile($path) {
  137. return $this->zip->getFromName($path);
  138. }
  139. /**
  140. * extract a single file from the archive
  141. * @param string $path
  142. * @param string $dest
  143. * @return boolean|null
  144. */
  145. function extractFile($path, $dest) {
  146. $fp = $this->zip->getStream($path);
  147. file_put_contents($dest, $fp);
  148. }
  149. /**
  150. * extract the archive
  151. * @param string $dest
  152. * @return bool
  153. */
  154. function extract($dest) {
  155. return $this->zip->extractTo($dest);
  156. }
  157. /**
  158. * check if a file or folder exists in the archive
  159. * @param string $path
  160. * @return bool
  161. */
  162. function fileExists($path) {
  163. return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
  164. }
  165. /**
  166. * remove a file or folder from the archive
  167. * @param string $path
  168. * @return bool
  169. */
  170. function remove($path) {
  171. if($this->fileExists($path.'/')) {
  172. return $this->zip->deleteName($path.'/');
  173. }else{
  174. return $this->zip->deleteName($path);
  175. }
  176. }
  177. /**
  178. * get a file handler
  179. * @param string $path
  180. * @param string $mode
  181. * @return resource
  182. */
  183. function getStream($path, $mode) {
  184. if($mode=='r' or $mode=='rb') {
  185. return $this->zip->getStream($path);
  186. } else {
  187. //since we cant directly get a writable stream,
  188. //make a temp copy of the file and put it back
  189. //in the archive when the stream is closed
  190. if(strrpos($path, '.')!==false) {
  191. $ext=substr($path, strrpos($path, '.'));
  192. }else{
  193. $ext='';
  194. }
  195. $tmpFile=OCP\Files::tmpFile($ext);
  196. \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
  197. if($this->fileExists($path)) {
  198. $this->extractFile($path, $tmpFile);
  199. }
  200. self::$tempFiles[$tmpFile]=$path;
  201. return fopen('close://'.$tmpFile, $mode);
  202. }
  203. }
  204. private static $tempFiles=array();
  205. /**
  206. * write back temporary files
  207. */
  208. function writeBack($tmpFile) {
  209. if(isset(self::$tempFiles[$tmpFile])) {
  210. $this->addFile(self::$tempFiles[$tmpFile], $tmpFile);
  211. unlink($tmpFile);
  212. }
  213. }
  214. /**
  215. * @param string $path
  216. * @return string
  217. */
  218. private function stripPath($path) {
  219. if(!$path || $path[0]=='/') {
  220. return substr($path, 1);
  221. }else{
  222. return $path;
  223. }
  224. }
  225. }