PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/veriler/f3/lib/zip.php

https://gitlab.com/fbi/razyo-api-server
PHP | 315 lines | 194 code | 16 blank | 105 comment | 22 complexity | 891b3c79d3b35106c4df4a410849c0ef MD5 | raw file
  1. <?php
  2. /**
  3. ZIP archive utility for the Fat-Free Framework
  4. The contents of this file are subject to the terms of the GNU General
  5. Public License Version 3.0. You may not use this file except in
  6. compliance with the license. Any of the license terms and conditions
  7. can be waived if you get permission from the copyright holder.
  8. Copyright (c) 2009-2011 F3::Factory
  9. Bong Cosca <bong.cosca@yahoo.com>
  10. @package Zip
  11. @version 2.0.4
  12. **/
  13. //! Utility class for ZIP archives
  14. class Zip extends Base {
  15. //@{ Locale-specific error/exception messages
  16. const
  17. TEXT_Required='A ZIP archive must be specified',
  18. TEXT_NotValid='File %s is not a valid ZIP archive',
  19. TEXT_UnMethod='Unsupported compression method';
  20. //@}
  21. //@{ ZIP header signatures
  22. const
  23. LFHDR_Sig='504B0304',
  24. CDHDR_Sig='504B0102',
  25. CDEND_Sig='504B0506';
  26. //@}
  27. const
  28. //! Read-granularity of ZIP archive
  29. BLOCK_Size=4096;
  30. private
  31. //! ZIP file name
  32. $file,
  33. //! Central directory container
  34. $cdir,
  35. //! Central directory relative offset
  36. $cofs;
  37. /**
  38. Return central directory structure
  39. @return array
  40. @public
  41. **/
  42. function dir() {
  43. return $this->cdir;
  44. }
  45. /**
  46. Return content of specified file from ZIP archive; FALSE if
  47. compression method is not supported
  48. @return mixed
  49. @param $path string
  50. @public
  51. **/
  52. function get($path) {
  53. if (!$path || $path[strlen($path)-1]=='/')
  54. return FALSE;
  55. $chdr=$this->cdir[$path];
  56. // Find local file header
  57. $zip=fopen($this->file,'rb');
  58. fseek($zip,implode('',unpack('V',substr($chdr,42,4))));
  59. // Read local file header
  60. $fhdr=fread($zip,30+strlen($path));
  61. $comp=self::binhex(substr($fhdr,8,2));
  62. if ($comp!='0800' && $comp!='0000') {
  63. trigger_error(self::TEXT_UnMethod);
  64. return FALSE;
  65. }
  66. if ($len=implode(unpack('v',substr($fhdr,28,2))))
  67. // Append extra field
  68. $fhdr.=fread($zip,$len);
  69. $len=unpack('V',substr($fhdr,22,4));
  70. $data='';
  71. if ($len)
  72. $data=fread($zip,implode('',$len));
  73. fclose($zip);
  74. return hexdec($comp) && $data?gzinflate($data):$data;
  75. }
  76. /**
  77. Add or replace file in ZIP archive using specified content;
  78. Create folder if content is NULL or unspecified
  79. @param $path string
  80. @param $data string
  81. @param $time integer
  82. @public
  83. **/
  84. function set($path,$data=NULL,$time=0) {
  85. $this->parse('set',$path,$data,$time);
  86. }
  87. /**
  88. Delete file from ZIP archive
  89. @param $path string
  90. @public
  91. **/
  92. function clear($path) {
  93. $this->parse('clear',$path);
  94. }
  95. /**
  96. Parse ZIP archive
  97. @param $path string
  98. @param $func mixed
  99. @public
  100. **/
  101. private function parse($action,$path,$data=NULL,$time=0) {
  102. if (!$time)
  103. $time=time();
  104. $tfn=self::$vars['TEMP'].$_SERVER['SERVER_NAME'].'.zip.'.
  105. self::hash($path);
  106. $tmp=fopen($tfn,'wb+');
  107. if (is_file($this->file)) {
  108. $zip=fopen($this->file,'rb');
  109. // Copy data from ZIP archive to temporary file
  110. foreach ($this->cdir as $name=>$chdr)
  111. if ($name!=$path) {
  112. // Find local file header
  113. fseek($zip,implode('',
  114. unpack('V',substr($chdr,42,4))));
  115. $fhdr=fread($zip,30+strlen($name));
  116. $len=implode(unpack('v',substr($fhdr,28,2)));
  117. if ($len)
  118. // Append extra field
  119. $fhdr.=fread($zip,$len);
  120. // Update relative offset
  121. $this->cdir[$name]=substr_replace(
  122. $this->cdir[$name],pack('V',ftell($tmp)),42,4);
  123. // Copy header and compressed content
  124. $len=implode('',unpack('V',substr($fhdr,18,4)));
  125. fwrite($tmp,$fhdr.($len?fread($zip,$len):''));
  126. }
  127. fclose($zip);
  128. }
  129. switch ($action) {
  130. case 'set':
  131. $path=self::fixslashes($path).
  132. (is_null($data) && $path[strlen($path)]!='/'?'/':'');
  133. $chdr=&$this->cdir[$path];
  134. // Blank headers
  135. $fhdr=str_repeat(chr(0),30).$path;
  136. $chdr=str_repeat(chr(0),46).$path;
  137. // Signatures
  138. $fhdr=substr_replace(
  139. $fhdr,self::hexbin(self::LFHDR_Sig),0,4);
  140. $chdr=substr_replace(
  141. $chdr,self::hexbin(self::CDHDR_Sig),0,4);
  142. // Version needed to extract
  143. $ver=self::hexbin(is_null($data)?'0A00':'1400');
  144. $fhdr=substr_replace($fhdr,$ver,4,2);
  145. $chdr=substr_replace($chdr,$ver,6,2);
  146. // Last modification time
  147. $mod=pack('V',self::unix2dostime($time));
  148. $fhdr=substr_replace($fhdr,$mod,10,4);
  149. $chdr=substr_replace($chdr,$mod,12,4);
  150. // File name length
  151. $len=pack('v',strlen($path));
  152. $fhdr=substr_replace($fhdr,$len,26,2);
  153. $chdr=substr_replace($chdr,$len,28,2);
  154. // File header relative offset
  155. $chdr=substr_replace(
  156. $chdr,pack('V',ftell($tmp)),42,4);
  157. if (!is_null($data)) {
  158. // Compress data/Fix CRC bug
  159. $comp=gzdeflate($data);
  160. // Compression method
  161. $def=self::hexbin('0800');
  162. $fhdr=substr_replace($fhdr,$def,8,2);
  163. $chdr=substr_replace($chdr,$def,10,2);
  164. // CRC32
  165. $crc=pack('V',crc32($data));
  166. $fhdr=substr_replace($fhdr,$crc,14,4);
  167. $chdr=substr_replace($chdr,$crc,16,4);
  168. // Compressed size
  169. $size=pack('V',strlen($comp));
  170. $fhdr=substr_replace($fhdr,$size,18,4);
  171. $chdr=substr_replace($chdr,$size,20,4);
  172. // Uncompressed size
  173. $size=pack('V',strlen($data));
  174. $fhdr=substr_replace($fhdr,$size,22,4);
  175. $chdr=substr_replace($chdr,$size,24,4);
  176. // Copy header and compressed content
  177. fwrite($tmp,$fhdr.$comp);
  178. }
  179. break;
  180. case 'clear':
  181. $path=self::fixslashes($path);
  182. unset($this->cdir[$path]);
  183. break;
  184. }
  185. // Central directory relative offset
  186. $this->cofs=ftell($tmp);
  187. foreach ($this->cdir as $raw)
  188. // Copy central directory file headers
  189. fwrite($tmp,$raw);
  190. // Blank end of central directory record
  191. $cend=str_repeat(chr(0),22);
  192. // Signature
  193. $cend=substr_replace($cend,self::hexbin(self::CDEND_Sig),0,4);
  194. // Total number of central directory records
  195. $total=pack('v',count($this->cdir));
  196. $cend=substr_replace($cend,$total,8,2);
  197. $cend=substr_replace($cend,$total,10,2);
  198. // Size of central directory
  199. $cend=substr_replace(
  200. $cend,pack('V',strlen(implode('',$this->cdir))),12,4);
  201. // Relative offset of central directory
  202. $cend=substr_replace($cend,pack('V',$this->cofs),16,4);
  203. fwrite($tmp,$cend);
  204. fclose($tmp);
  205. if (is_file($this->file))
  206. // Delete old ZIP archive
  207. unlink($this->file);
  208. rename($tfn,$this->file);
  209. }
  210. /**
  211. Convert 4-byte DOS time to Un*x timestamp
  212. @return integer
  213. @param $time integer
  214. @public
  215. **/
  216. static function dos2unixtime($time) {
  217. $date=$time>>16;
  218. return mktime(
  219. ($time & 0xF800)>>11,
  220. ($time & 0x07E0)>>5,
  221. ($time & 0x001F)<<1,
  222. ($date & 0x01E0)>>5,
  223. ($date & 0x001F),
  224. (($date & 0xFE00)>>9)+1980
  225. );
  226. }
  227. /**
  228. Convert Un*x timestamp to 4-byte DOS time
  229. @return integer
  230. @param $time integer
  231. @public
  232. **/
  233. static function unix2dostime($time=0) {
  234. $time=$time?getdate($time):getdate();
  235. if ($time['year']<1980)
  236. $time=array_combine(
  237. array('hours','minutes','seconds','mon','mday','year'),
  238. array(0,0,0,1,1,1980)
  239. );
  240. return
  241. ($time['hours']<<11) |
  242. ($time['minutes']<<5) |
  243. ($time['seconds']>>1) |
  244. ($time['mon']<<21) |
  245. ($time['mday']<<16) |
  246. (($time['year']-1980)<<25);
  247. }
  248. /**
  249. Class constructor
  250. @param $path string
  251. @public
  252. **/
  253. function __construct($path=NULL) {
  254. if (is_null($path)) {
  255. trigger_error(self::TEXT_Required);
  256. return;
  257. }
  258. $path=self::resolve($path);
  259. $this->file=$path;
  260. $this->cdir=array();
  261. if (!is_file($path))
  262. return;
  263. // Parse file contents
  264. $zip=fopen($path,'rb');
  265. $found=FALSE;
  266. $cdir='';
  267. while (!feof($zip)) {
  268. $cdir.=fread($zip,self::BLOCK_Size);
  269. if (is_bool($found)) {
  270. $found=strstr($cdir,self::hexbin(self::CDHDR_Sig));
  271. if (is_string($found)) {
  272. // Start of central directory record
  273. $cdir=$found;
  274. $this->cofs=ftell($zip)-strlen($found);
  275. }
  276. elseif (strlen($cdir)>self::BLOCK_Size)
  277. // Conserve memory
  278. $cdir=substr($cdir,self::BLOCK_Size);
  279. }
  280. }
  281. fclose($zip);
  282. if (is_bool(strstr($cdir,self::hexbin(self::CDEND_Sig)))) {
  283. // Invalid ZIP archive
  284. trigger_error(sprintf(self::TEXT_NotValid,$path));
  285. return;
  286. }
  287. // Save central directory record
  288. foreach (array_slice(explode(self::hexbin(self::CDHDR_Sig),
  289. strstr($cdir,self::hexbin(self::CDEND_Sig),TRUE)),1)
  290. as $raw)
  291. // Extract name and use as array key
  292. $this->cdir[substr(
  293. $raw,42,implode('',unpack('v',substr($raw,24,2)))
  294. )]=self::hexbin(self::CDHDR_Sig).$raw;
  295. }
  296. }