zip.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed
  163. if(strrpos($path,'.')!==false){
  164. $ext=substr($path,strrpos($path,'.'));
  165. }else{
  166. $ext='';
  167. }
  168. $tmpFile=OCP\Files::tmpFile($ext);
  169. OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
  170. if($this->fileExists($path)){
  171. $this->extractFile($path,$tmpFile);
  172. }
  173. self::$tempFiles[$tmpFile]=$path;
  174. return fopen('close://'.$tmpFile,$mode);
  175. }
  176. }
  177. private static $tempFiles=array();
  178. /**
  179. * write back temporary files
  180. */
  181. function writeBack($tmpFile){
  182. if(isset(self::$tempFiles[$tmpFile])){
  183. $this->addFile(self::$tempFiles[$tmpFile],$tmpFile);
  184. unlink($tmpFile);
  185. }
  186. }
  187. private function stripPath($path){
  188. if(!$path || $path[0]=='/'){
  189. return substr($path,1);
  190. }else{
  191. return $path;
  192. }
  193. }
  194. }