1<?php 2 3/** 4 * @author bouchon 5 * @link http://dev.maxg.info 6 * @link http://forum.maxg.info 7 * 8 * Modified for Dokuwiki 9 * @author Christopher Smith <chris@jalakai.co.uk> 10 */ 11class ZipLib 12{ 13 14 var $datasec, $ctrl_dir = array(); 15 var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; 16 var $old_offset = 0; var $dirs = Array("."); 17 18 function get_List($zip_name) 19 { 20 $zip = @fopen($zip_name, 'rb'); 21 if(!$zip) return(0); 22 $centd = $this->ReadCentralDir($zip,$zip_name); 23 24 @rewind($zip); 25 @fseek($zip, $centd['offset']); 26 27 for ($i=0; $i<$centd['entries']; $i++) 28 { 29 $header = $this->ReadCentralFileHeaders($zip); 30 $header['index'] = $i;$info['filename'] = $header['filename']; 31 $info['stored_filename'] = $header['stored_filename']; 32 $info['size'] = $header['size'];$info['compressed_size']=$header['compressed_size']; 33 $info['crc'] = strtoupper(dechex( $header['crc'] )); 34 $info['mtime'] = $header['mtime']; $info['comment'] = $header['comment']; 35 $info['folder'] = ($header['external']==0x41FF0010||$header['external']==16)?1:0; 36 $info['index'] = $header['index'];$info['status'] = $header['status']; 37 $ret[]=$info; unset($header); 38 } 39 return $ret; 40 } 41 42 function Add($files,$compact) 43 { 44 if(!is_array($files[0])) $files=Array($files); 45 46 for($i=0;$files[$i];$i++){ 47 $fn = $files[$i]; 48 if(!in_Array(dirname($fn[0]),$this->dirs)) 49 $this->add_Dir(dirname($fn[0])); 50 if(basename($fn[0])) 51 $ret[basename($fn[0])]=$this->add_File($fn[1],$fn[0],$compact); 52 } 53 return $ret; 54 } 55 56 /** 57 * Zips recursively the $folder directory, from the $basedir directory 58 */ 59 function Compress($folder, $basedir=null, $parent=null) 60 { 61 $full_path = $basedir."/".$parent.$folder; 62 $zip_path = $parent.$folder; 63 if ($zip_path) { 64 $zip_path .= "/"; 65 $this->add_dir($zip_path); 66 } 67 $dir = opendir($full_path); 68 while (false !== ($filename = readdir($dir))) { 69 if ($filename != "." && $filename != "..") { 70 if (is_dir($full_path."/".$filename)) { 71 $this->Compress($filename, $basedir, $zip_path); 72 } else { 73 $content = join('', file($full_path.'/'.$filename)); 74 $this->add_File($content, $zip_path.$filename); 75 } 76 } 77 } 78 } 79 80 /** 81 * Returns the Zip file 82 */ 83 function get_file() 84 { 85 $data = implode('', $this -> datasec); 86 $ctrldir = implode('', $this -> ctrl_dir); 87 88 return $data . $ctrldir . $this -> eof_ctrl_dir . 89 pack('v', sizeof($this -> ctrl_dir)).pack('v', sizeof($this -> ctrl_dir)). 90 pack('V', strlen($ctrldir)) . pack('V', strlen($data)) . "\x00\x00"; 91 } 92 93 function add_dir($name) 94 { 95 $name = str_replace("\\", "/", $name); 96 $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 97 98 $fr .= pack("V",0).pack("V",0).pack("V",0).pack("v", strlen($name) ); 99 $fr .= pack("v", 0 ).$name.pack("V", 0).pack("V", 0).pack("V", 0); 100 $this -> datasec[] = $fr; 101 102 $new_offset = strlen(implode("", $this->datasec)); 103 104 $cdrec = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 105 $cdrec .= pack("V",0).pack("V",0).pack("V",0).pack("v", strlen($name) ); 106 $cdrec .= pack("v", 0 ).pack("v", 0 ).pack("v", 0 ).pack("v", 0 ); 107 $ext = "\xff\xff\xff\xff"; 108 $cdrec .= pack("V", 16 ).pack("V", $this -> old_offset ).$name; 109 110 $this -> ctrl_dir[] = $cdrec; 111 $this -> old_offset = $new_offset; 112 $this -> dirs[] = $name; 113 } 114 115 /** 116 * Add a file named $name from a string $data 117 */ 118 function add_File($data, $name, $compact = 1) 119 { 120 $name = str_replace('\\', '/', $name); 121 $dtime = dechex($this->DosTime()); 122 123 $hexdtime = '\x' . $dtime[6] . $dtime[7].'\x'.$dtime[4] . $dtime[5] 124 . '\x' . $dtime[2] . $dtime[3].'\x'.$dtime[0].$dtime[1]; 125 eval('$hexdtime = "' . $hexdtime . '";'); 126 127 if($compact) 128 $fr = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$hexdtime; 129 else $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00".$hexdtime; 130 $unc_len = strlen($data); $crc = crc32($data); 131 132 if($compact){ 133 $zdata = gzcompress($data); $c_len = strlen($zdata); 134 $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); 135 }else{ 136 $zdata = $data; 137 } 138 $c_len=strlen($zdata); 139 $fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len); 140 $fr .= pack('v', strlen($name)).pack('v', 0).$name.$zdata; 141 142 $fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len); 143 144 $this -> datasec[] = $fr; 145 $new_offset = strlen(implode('', $this->datasec)); 146 if($compact) 147 $cdrec = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00"; 148 else $cdrec = "\x50\x4b\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00"; 149 $cdrec .= $hexdtime.pack('V', $crc).pack('V', $c_len).pack('V', $unc_len); 150 $cdrec .= pack('v', strlen($name) ).pack('v', 0 ).pack('v', 0 ); 151 $cdrec .= pack('v', 0 ).pack('v', 0 ).pack('V', 32 ); 152 $cdrec .= pack('V', $this -> old_offset ); 153 154 $this -> old_offset = $new_offset; 155 $cdrec .= $name; 156 $this -> ctrl_dir[] = $cdrec; 157 return true; 158 } 159 160 function DosTime() { 161 $timearray = getdate(); 162 if ($timearray['year'] < 1980) { 163 $timearray['year'] = 1980; $timearray['mon'] = 1; 164 $timearray['mday'] = 1; $timearray['hours'] = 0; 165 $timearray['minutes'] = 0; $timearray['seconds'] = 0; 166 } 167 return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | 168 ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); 169 } 170 171 /** 172 * Extract a zip file $zn to the $to directory 173 */ 174 function Extract ( $zn, $to, $index = Array(-1) ) 175 { 176 if(!@is_dir($to)) @mkdir($to,0777); 177 $ok = 0; $zip = @fopen($zn,'rb'); 178 if(!$zip) return(-1); 179 $cdir = $this->ReadCentralDir($zip,$zn); 180 $pos_entry = $cdir['offset']; 181 182 if(!is_array($index)){ $index = array($index); } 183 for($i=0; isset($index[$i]);$i++){ 184 if(intval($index[$i])!=$index[$i]||$index[$i]>$cdir['entries']) 185 return(-1); 186 } 187 188 for ($i=0; $i<$cdir['entries']; $i++) 189 { 190 @fseek($zip, $pos_entry); 191 $header = $this->ReadCentralFileHeaders($zip); 192 $header['index'] = $i; $pos_entry = ftell($zip); 193 @rewind($zip); fseek($zip, $header['offset']); 194 if(in_array("-1",$index)||in_array($i,$index)) 195 $stat[$header['filename']]=$this->ExtractFile($header, $to, $zip); 196 197 } 198 fclose($zip); 199 return $stat; 200 } 201 202 function ReadFileHeader($zip, $header) 203 { 204 $binary_data = fread($zip, 30); 205 $data = unpack('vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $binary_data); 206 207 $header['filename'] = fread($zip, $data['filename_len']); 208 if ($data['extra_len'] != 0) { 209 $header['extra'] = fread($zip, $data['extra_len']); 210 } else { $header['extra'] = ''; } 211 212 $header['compression'] = $data['compression']; 213 $header['flag'] = $data['flag']; 214 $header['mdate'] = $data['mdate'];$header['mtime'] = $data['mtime']; 215 if (($header['flag'] & 8) != 8) { // Purpose bit flag bit 3 not set, overwrite the central header values 216 foreach (array('size','compressed_size','crc') as $hd) { 217 $header[$hd] = $data[$hd]; 218 } 219 } 220 221 if ($header['mdate'] && $header['mtime']){ 222 $hour=($header['mtime']&0xF800)>>11;$minute=($header['mtime']&0x07E0)>>5; 223 $seconde=($header['mtime']&0x001F)*2;$year=(($header['mdate']&0xFE00)>>9)+1980; 224 $month=($header['mdate']&0x01E0)>>5;$day=$header['mdate']&0x001F; 225 $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year); 226 }else{$header['mtime'] = time();} 227 228 $header['stored_filename'] = $header['filename']; 229 $header['status'] = "ok"; 230 return $header; 231 } 232 233 function ReadCentralFileHeaders($zip){ 234 $binary_data = fread($zip, 46); 235 $header = unpack('vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $binary_data); 236 237 if ($header['filename_len'] != 0) 238 $header['filename'] = fread($zip,$header['filename_len']); 239 else $header['filename'] = ''; 240 241 if ($header['extra_len'] != 0) 242 $header['extra'] = fread($zip, $header['extra_len']); 243 else $header['extra'] = ''; 244 245 if ($header['comment_len'] != 0) 246 $header['comment'] = fread($zip, $header['comment_len']); 247 else $header['comment'] = ''; 248 249 if ($header['mdate'] && $header['mtime']) 250 { 251 $hour = ($header['mtime'] & 0xF800) >> 11; 252 $minute = ($header['mtime'] & 0x07E0) >> 5; 253 $seconde = ($header['mtime'] & 0x001F)*2; 254 $year = (($header['mdate'] & 0xFE00) >> 9) + 1980; 255 $month = ($header['mdate'] & 0x01E0) >> 5; 256 $day = $header['mdate'] & 0x001F; 257 $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year); 258 } else { 259 $header['mtime'] = time(); 260 } 261 $header['stored_filename'] = $header['filename']; 262 $header['status'] = 'ok'; 263 if (substr($header['filename'], -1) == '/') 264 $header['external'] = 0x41FF0010; 265 return $header; 266 } 267 268 function ReadCentralDir($zip,$zip_name) 269 { 270 $size = filesize($zip_name); 271 if ($size < 277) $maximum_size = $size; 272 else $maximum_size=277; 273 274 @fseek($zip, $size-$maximum_size); 275 $pos = ftell($zip); $bytes = 0x00000000; 276 277 while ($pos < $size) 278 { 279 $byte = @fread($zip, 1); 280 $bytes=(($bytes << 8) & 0xFFFFFFFF) | Ord($byte); 281 if ($bytes == 0x504b0506){ $pos++; break; } $pos++; 282 } 283 284 $data=unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', 285 fread($zip, 18)); 286 287 if ($data['comment_size'] != 0) 288 $centd['comment'] = fread($zip, $data['comment_size']); 289 else $centd['comment'] = ''; $centd['entries'] = $data['entries']; 290 $centd['disk_entries'] = $data['disk_entries']; 291 $centd['offset'] = $data['offset'];$centd['disk_start'] = $data['disk_start']; 292 $centd['size'] = $data['size']; $centd['disk'] = $data['disk']; 293 return $centd; 294 } 295 296 function ExtractFile($header,$to,$zip) 297 { 298 $header = $this->readfileheader($zip, $header); 299 300 if(substr($to,-1)!="/") $to.="/"; 301 if(substr($header['filename'],-1)=="/") 302 { 303// @mkdir($to.$header['filename']); --CS 304 $this->_mkdir($to.$header['filename']); //-- CS 305 return +2; 306 } 307 308// $pth = explode("/",dirname($header['filename'])); 309// for($i=0,$tmp="";isset($pth[$i]);$i++){ 310// if(!$pth[$i]) continue; 311// if(!is_dir($to.$tmp.$pth[$i])) @mkdir($to.$pth[$i],0777); 312// $tmp.=$pth[$i]."/"; 313// } 314 if (!$this->_mkdir($to.dirname($header['filename']))) return (-1); //--CS 315 316 if (!array_key_exists("external", $header) || (!($header['external']==0x41FF0010)&&!($header['external']==16))) 317 { 318 if ($header['compression']==0) 319 { 320 $fp = @fopen($to.$header['filename'], 'wb'); 321 if(!$fp) return(-1); 322 $size = $header['compressed_size']; 323 324 while ($size != 0) 325 { 326 $read_size = ($size < 2048 ? $size : 2048); 327 $buffer = fread($zip, $read_size); 328 $binary_data = pack('a'.$read_size, $buffer); 329 @fwrite($fp, $binary_data, $read_size); 330 $size -= $read_size; 331 } 332 fclose($fp); 333 touch($to.$header['filename'], $header['mtime']); 334 335 }else{ 336 if (!is_dir(dirname($to.$header['filename']))) $this->_mkdir(dirname($to.$header['filename'])); //-CS 337 $fp = fopen($to.$header['filename'].'.gz','wb'); 338 if(!$fp) return(-1); 339 $binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($header['compression']), 340 Chr(0x00), time(), Chr(0x00), Chr(3)); 341 342 fwrite($fp, $binary_data, 10); 343 $size = $header['compressed_size']; 344 345 while ($size != 0) 346 { 347 $read_size = ($size < 1024 ? $size : 1024); 348 $buffer = fread($zip, $read_size); 349 $binary_data = pack('a'.$read_size, $buffer); 350 @fwrite($fp, $binary_data, $read_size); 351 $size -= $read_size; 352 } 353 354 $binary_data = pack('VV', $header['crc'], $header['size']); 355 fwrite($fp, $binary_data,8); fclose($fp); 356 357 $gzp = @gzopen($to.$header['filename'].'.gz','rb'); 358 if(!$gzp){ 359 @gzclose($gzp); @unlink($to.$header['filename']); 360 die("Archive is compressed whereas ZLIB is not enabled."); 361 } 362 $fp = @fopen($to.$header['filename'],'wb'); 363 if(!$fp) return(-1); 364 $size = $header['size']; 365 366 while ($size != 0) 367 { 368 $read_size = ($size < 2048 ? $size : 2048); 369 $buffer = gzread($gzp, $read_size); 370 $binary_data = pack('a'.$read_size, $buffer); 371 @fwrite($fp, $binary_data, $read_size); 372 $size -= $read_size; 373 } 374 fclose($fp); gzclose($gzp); 375 376 touch($to.$header['filename'], $header['mtime']); 377 @unlink($to.$header['filename'].'.gz'); 378 379 }} 380 return true; 381 } 382 383 //--CS start 384 // centralize mkdir calls and use dokuwiki io functions 385 function _mkdir($d) { 386 return io_mkdir_p($d); // --AB 387 //return ap_mkdir($d); 388 } 389 //--CS end 390} 391 392