zip.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
  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_Archive_ZIP extends OC_Archive{
  9. /**
  10. * @var ZipArchive zip
  11. */
  12. private $zip=null;
  13. private $path;
  14. function __construct($source) {
  15. $this->path=$source;
  16. $this->zip=new ZipArchive();
  17. if($this->zip->open($source, ZipArchive::CREATE)) {
  18. }else{
  19. OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, OCP\Util::WARN);
  20. }
  21. }
  22. /**
  23. * add an empty folder to the archive
  24. * @param string path
  25. * @return bool
  26. */
  27. function addFolder($path) {
  28. return $this->zip->addEmptyDir($path);
  29. }
  30. /**
  31. * add a file to the archive
  32. * @param string path
  33. * @param string source either a local file or string data
  34. * @return bool
  35. */
  36. function addFile($path, $source='') {
  37. if($source and $source[0]=='/' and file_exists($source)) {
  38. $result=$this->zip->addFile($source, $path);
  39. }else{
  40. $result=$this->zip->addFromString($path, $source);
  41. }
  42. if($result) {
  43. $this->zip->close();//close and reopen to save the zip
  44. $this->zip->open($this->path);
  45. }
  46. return $result;
  47. }
  48. /**
  49. * rename a file or folder in the archive
  50. * @param string source
  51. * @param string dest
  52. * @return bool
  53. */
  54. function rename($source, $dest) {
  55. $source=$this->stripPath($source);
  56. $dest=$this->stripPath($dest);
  57. $this->zip->renameName($source, $dest);
  58. }
  59. /**
  60. * get the uncompressed size of a file in the archive
  61. * @param string path
  62. * @return int
  63. */
  64. function filesize($path) {
  65. $stat=$this->zip->statName($path);
  66. return $stat['size'];
  67. }
  68. /**
  69. * get the last modified time of a file in the archive
  70. * @param string path
  71. * @return int
  72. */
  73. function mtime($path) {
  74. return filemtime($this->path);
  75. }
  76. /**
  77. * get the files in a folder
  78. * @param path
  79. * @return array
  80. */
  81. function getFolder($path) {
  82. $files=$this->getFiles();
  83. $folderContent=array();
  84. $pathLength=strlen($path);
  85. foreach($files as $file) {
  86. if(substr($file, 0, $pathLength)==$path and $file!=$path) {
  87. if(strrpos(substr($file, 0, -1), '/')<=$pathLength) {
  88. $folderContent[]=substr($file, $pathLength);
  89. }
  90. }
  91. }
  92. return $folderContent;
  93. }
  94. /**
  95. *get all files in the archive
  96. * @return array
  97. */
  98. function getFiles() {
  99. $fileCount=$this->zip->numFiles;
  100. $files=array();
  101. for($i=0;$i<$fileCount;$i++) {
  102. $files[]=$this->zip->getNameIndex($i);
  103. }
  104. return $files;
  105. }
  106. /**
  107. * get the content of a file
  108. * @param string path
  109. * @return string
  110. */
  111. function getFile($path) {
  112. return $this->zip->getFromName($path);
  113. }
  114. /**
  115. * extract a single file from the archive
  116. * @param string path
  117. * @param string dest
  118. * @return bool
  119. */
  120. function extractFile($path, $dest) {
  121. $fp = $this->zip->getStream($path);
  122. file_put_contents($dest, $fp);
  123. }
  124. /**
  125. * extract the archive
  126. * @param string path
  127. * @param string dest
  128. * @return bool
  129. */
  130. function extract($dest) {
  131. return $this->zip->extractTo($dest);
  132. }
  133. /**
  134. * check if a file or folder exists in the archive
  135. * @param string path
  136. * @return bool
  137. */
  138. function fileExists($path) {
  139. return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false);
  140. }
  141. /**
  142. * remove a file or folder from the archive
  143. * @param string path
  144. * @return bool
  145. */
  146. function remove($path) {
  147. if($this->fileExists($path.'/')) {
  148. return $this->zip->deleteName($path.'/');
  149. }else{
  150. return $this->zip->deleteName($path);
  151. }
  152. }
  153. /**
  154. * get a file handler
  155. * @param string path
  156. * @param string mode
  157. * @return resource
  158. */
  159. function getStream($path, $mode) {
  160. if($mode=='r' or $mode=='rb') {
  161. return $this->zip->getStream($path);
  162. } else {
  163. //since we cant directly get a writable stream,
  164. //make a temp copy of the file and put it back
  165. //in the archive when the stream is closed
  166. if(strrpos($path, '.')!==false) {
  167. $ext=substr($path, strrpos($path, '.'));
  168. }else{
  169. $ext='';
  170. }
  171. $tmpFile=OCP\Files::tmpFile($ext);
  172. OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack');
  173. if($this->fileExists($path)) {
  174. $this->extractFile($path, $tmpFile);
  175. }
  176. self::$tempFiles[$tmpFile]=$path;
  177. return fopen('close://'.$tmpFile, $mode);
  178. }
  179. }
  180. private static $tempFiles=array();
  181. /**
  182. * write back temporary files
  183. */
  184. function writeBack($tmpFile) {
  185. if(isset(self::$tempFiles[$tmpFile])) {
  186. $this->addFile(self::$tempFiles[$tmpFile], $tmpFile);
  187. unlink($tmpFile);
  188. }
  189. }
  190. private function stripPath($path) {
  191. if(!$path || $path[0]=='/') {
  192. return substr($path, 1);
  193. }else{
  194. return $path;
  195. }
  196. }
  197. }