[ Index ] |
PHP Cross Reference of phpBB 3.0 Beta 3 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package phpBB3 5 * @version $Id: functions_compress.php,v 1.43 2006/11/03 23:09:15 davidmj Exp $ 6 * @copyright (c) 2005 phpBB Group 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * Class for handling archives (compression/decompression) 13 * @package phpBB3 14 */ 15 class compress 16 { 17 var $fp = 0; 18 19 /** 20 * Add file to archive 21 */ 22 function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '') 23 { 24 global $phpbb_root_path; 25 26 $skip_files = explode(',', $skip_files); 27 28 // Remove rm prefix from src path 29 $src_path = ($src_rm_prefix) ? preg_replace('#^(' . preg_quote($src_rm_prefix, '#') . ')#', '', $src) : $src; 30 // Add src prefix 31 $src_path = ($src_add_prefix) ? ($src_add_prefix . ((substr($src_add_prefix, -1) != '/') ? '/' : '') . $src_path) : $src_path; 32 // Remove initial "/" if present 33 $src_path = (substr($src_path, 0, 1) == '/') ? substr($src_path, 1) : $src_path; 34 35 if (is_file($phpbb_root_path . $src)) 36 { 37 $this->data($src_path, file_get_contents("$phpbb_root_path$src"), false, stat("$phpbb_root_path$src")); 38 } 39 else if (is_dir($phpbb_root_path . $src)) 40 { 41 // Clean up path, add closing / if not present 42 $src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path; 43 44 $filelist = array(); 45 $filelist = filelist("$phpbb_root_path$src", '', '*'); 46 krsort($filelist); 47 48 if ($src_path) 49 { 50 $this->data($src_path, '', true, stat("$phpbb_root_path$src")); 51 } 52 53 foreach ($filelist as $path => $file_ary) 54 { 55 if ($path) 56 { 57 // Same as for src_path 58 $path = (substr($path, 0, 1) == '/') ? substr($path, 1) : $path; 59 $path = ($path && substr($path, -1) != '/') ? $path . '/' : $path; 60 61 $this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path")); 62 } 63 64 foreach ($file_ary as $file) 65 { 66 if (in_array($path . $file, $skip_files)) 67 { 68 continue; 69 } 70 71 $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), false, stat("$phpbb_root_path$src$path$file")); 72 } 73 } 74 } 75 76 return true; 77 } 78 79 /** 80 * Add custom file (the filepath will not be adjusted) 81 */ 82 function add_custom_file($src, $filename) 83 { 84 $this->data($filename, file_get_contents($src), false, stat($src)); 85 return true; 86 } 87 88 /** 89 * Add file data 90 */ 91 function add_data($src, $name) 92 { 93 $stat = array(); 94 $stat[2] = 436; //384 95 $stat[4] = $stat[5] = 0; 96 $stat[7] = strlen($src); 97 $stat[9] = time(); 98 $this->data($name, $src, false, $stat); 99 return true; 100 } 101 102 /** 103 * Return available methods 104 */ 105 function methods() 106 { 107 $methods = array('.tar'); 108 $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib'); 109 110 foreach ($available_methods as $type => $module) 111 { 112 if (!@extension_loaded($module)) 113 { 114 continue; 115 } 116 $methods[] = $type; 117 } 118 119 return $methods; 120 } 121 } 122 123 /** 124 * Zip creation class from phpMyAdmin 2.3.0 (c) Tobias Ratschiller, Olivier Müller, Loïc Chapeaux, 125 * Marc Delisle, http://www.phpmyadmin.net/ 126 * 127 * Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com 128 * 129 * Modified extensively by psoTFX and DavidMJ, (c) phpBB Group, 2003 130 * 131 * Based on work by Eric Mueller and Denis125 132 * Official ZIP file format: http://www.pkware.com/appnote.txt 133 * 134 * @package phpBB3 135 */ 136 class compress_zip extends compress 137 { 138 var $datasec = array(); 139 var $ctrl_dir = array(); 140 var $eof_cdh = "\x50\x4b\x05\x06\x00\x00\x00\x00"; 141 142 var $old_offset = 0; 143 var $datasec_len = 0; 144 145 /** 146 * Constructor 147 */ 148 function compress_zip($mode, $file) 149 { 150 return $this->fp = @fopen($file, $mode . 'b'); 151 } 152 153 /** 154 * Convert unix to dos time 155 */ 156 function unix_to_dos_time($time) 157 { 158 $timearray = (!$time) ? getdate() : getdate($time); 159 160 if ($timearray['year'] < 1980) 161 { 162 $timearray['year'] = 1980; 163 $timearray['mon'] = $timearray['mday'] = 1; 164 $timearray['hours'] = $timearray['minutes'] = $timearray['seconds'] = 0; 165 } 166 167 return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); 168 } 169 170 /** 171 * Extract archive 172 */ 173 function extract($dst) 174 { 175 // Loop the file, looking for files and folders 176 $dd_try = false; 177 rewind($this->fp); 178 179 while (!feof($this->fp)) 180 { 181 // Check if the signature is valid... 182 $signature = fread($this->fp, 4); 183 184 switch ($signature) 185 { 186 // 'Local File Header' 187 case "\x50\x4b\x03\x04": 188 // Lets get everything we need. 189 // We don't store the version needed to extract, the general purpose bit flag or the date and time fields 190 $data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field", fread($this->fp, 26)); 191 $file_name = fread($this->fp, $data['name_len']); // filename 192 193 if ($data['extra_field']) 194 { 195 fread($this->fp, $data['extra_field']); // extra field 196 } 197 198 $target_filename = "$dst$file_name"; 199 200 if (!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/') 201 { 202 if (!is_dir($target_filename)) 203 { 204 $str = ''; 205 $folders = explode('/', $target_filename); 206 207 // Create and folders and subfolders if they do not exist 208 foreach ($folders as $folder) 209 { 210 $str = (!empty($str)) ? $str . '/' . $folder : $folder; 211 if (!is_dir($str)) 212 { 213 if (!@mkdir($str, 0777)) 214 { 215 trigger_error("Could not create directory $folder"); 216 } 217 @chmod($str, 0777); 218 } 219 } 220 } 221 // This is a directory, we are not writting files 222 continue; 223 } 224 else 225 { 226 // Some archivers are punks, they don't don't include folders in their archives! 227 $str = ''; 228 $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); 229 230 // Create and folders and subfolders if they do not exist 231 foreach ($folders as $folder) 232 { 233 $str = (!empty($str)) ? $str . '/' . $folder : $folder; 234 if (!is_dir($str)) 235 { 236 if (!@mkdir($str, 0777)) 237 { 238 trigger_error("Could not create directory $folder"); 239 } 240 @chmod($str, 0777); 241 } 242 } 243 } 244 245 if (!$data['uc_size']) 246 { 247 $content = ''; 248 } 249 else 250 { 251 $content = fread($this->fp, $data['c_size']); 252 } 253 254 $fp = fopen($target_filename, "w"); 255 256 switch ($data['c_method']) 257 { 258 case 0: 259 // Not compressed 260 fwrite($fp, $content); 261 break; 262 263 case 8: 264 // Deflate 265 fwrite($fp, gzinflate($content, $data['uc_size'])); 266 break; 267 268 case 12: 269 // Bzip2 270 fwrite($fp, bzdecompress($content)); 271 break; 272 } 273 274 fclose($fp); 275 break; 276 277 // We hit the 'Central Directory Header', we can stop because nothing else in here requires our attention 278 // or we hit the end of the central directory record, we can safely end the loop as we are totally finished with looking for files and folders 279 case "\x50\x4b\x01\x02": 280 // This case should simply never happen.. but it does exist.. 281 case "\x50\x4b\x05\x06": 282 break 2; 283 284 // 'Packed to Removable Disk', ignore it and look for the next signature... 285 case 'PK00': 286 continue 2; 287 288 // We have encountered a header that is weird. Lets look for better data... 289 default: 290 if (!$dd_try) 291 { 292 // Unexpected header. Trying to detect wrong placed 'Data Descriptor'; 293 $dd_try = true; 294 fseek($this->fp, 8, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4) 295 continue 2; 296 } 297 trigger_error("Unexpected header, ending loop"); 298 break 2; 299 } 300 301 $dd_try = false; 302 } 303 } 304 305 /** 306 * Close archive 307 */ 308 function close() 309 { 310 // Write out central file directory and footer ... if it exists 311 if (sizeof($this->ctrl_dir)) 312 { 313 fwrite($this->fp, $this->file()); 314 } 315 fclose($this->fp); 316 } 317 318 /** 319 * Create the structures ... note we assume version made by is MSDOS 320 */ 321 function data($name, $data, $is_dir = false, $stat) 322 { 323 $name = str_replace('\\', '/', $name); 324 325 $hexdtime = pack('V', $this->unix_to_dos_time($stat[9])); 326 327 if ($is_dir) 328 { 329 $unc_len = $c_len = $crc = 0; 330 $zdata = ''; 331 $var_ext = 10; 332 } 333 else 334 { 335 $unc_len = strlen($data); 336 $crc = crc32($data); 337 $zdata = gzdeflate($data); 338 $c_len = strlen($zdata); 339 $var_ext = 20; 340 341 // Did we compress? No, then use data as is 342 if ($c_len >= $unc_len) 343 { 344 $zdata = $data; 345 $c_len = $unc_len; 346 $var_ext = 10; 347 } 348 } 349 unset($data); 350 351 // If we didn't compress set method to store, else deflate 352 $c_method = ($c_len == $unc_len) ? "\x00\x00" : "\x08\x00"; 353 354 // Are we a file or a directory? Set archive for file 355 $attrib = ($is_dir) ? 16 : 32; 356 357 // File Record Header 358 $fr = "\x50\x4b\x03\x04"; // Local file header 4bytes 359 $fr .= pack('v', $var_ext); // ver needed to extract 2bytes 360 $fr .= "\x00\x00"; // gen purpose bit flag 2bytes 361 $fr .= $c_method; // compression method 2bytes 362 $fr .= $hexdtime; // last mod time and date 2+2bytes 363 $fr .= pack('V', $crc); // crc32 4bytes 364 $fr .= pack('V', $c_len); // compressed filesize 4bytes 365 $fr .= pack('V', $unc_len); // uncompressed filesize 4bytes 366 $fr .= pack('v', strlen($name));// length of filename 2bytes 367 368 $fr .= pack('v', 0); // extra field length 2bytes 369 $fr .= $name; 370 $fr .= $zdata; 371 unset($zdata); 372 373 $this->datasec_len += strlen($fr); 374 375 // Add data to file ... by writing data out incrementally we save some memory 376 fwrite($this->fp, $fr); 377 unset($fr); 378 379 // Central Directory Header 380 $cdrec = "\x50\x4b\x01\x02"; // header 4bytes 381 $cdrec .= "\x00\x00"; // version made by 382 $cdrec .= pack('v', $var_ext); // version needed to extract 383 $cdrec .= "\x00\x00"; // gen purpose bit flag 384 $cdrec .= $c_method; // compression method 385 $cdrec .= $hexdtime; // last mod time & date 386 $cdrec .= pack('V', $crc); // crc32 387 $cdrec .= pack('V', $c_len); // compressed filesize 388 $cdrec .= pack('V', $unc_len); // uncompressed filesize 389 $cdrec .= pack('v', strlen($name)); // length of filename 390 $cdrec .= pack('v', 0); // extra field length 391 $cdrec .= pack('v', 0); // file comment length 392 $cdrec .= pack('v', 0); // disk number start 393 $cdrec .= pack('v', 0); // internal file attributes 394 $cdrec .= pack('V', $attrib); // external file attributes 395 $cdrec .= pack('V', $this->old_offset); // relative offset of local header 396 $cdrec .= $name; 397 398 // Save to central directory 399 $this->ctrl_dir[] = $cdrec; 400 401 $this->old_offset = $this->datasec_len; 402 } 403 404 /** 405 * file 406 */ 407 function file() 408 { 409 $ctrldir = implode('', $this->ctrl_dir); 410 411 return $ctrldir . $this->eof_cdh . 412 pack('v', sizeof($this->ctrl_dir)) . // total # of entries "on this disk" 413 pack('v', sizeof($this->ctrl_dir)) . // total # of entries overall 414 pack('V', strlen($ctrldir)) . // size of central dir 415 pack('V', $this->datasec_len) . // offset to start of central dir 416 "\x00\x00"; // .zip file comment length 417 } 418 419 /** 420 * Download archive 421 */ 422 function download($filename) 423 { 424 global $phpbb_root_path; 425 426 $mimetype = 'application/zip'; 427 428 header('Pragma: no-cache'); 429 header("Content-Type: $mimetype; name=\"$filename.zip\""); 430 header("Content-disposition: attachment; filename=$filename.zip"); 431 432 $fp = fopen("{$phpbb_root_path}store/$filename.zip", 'rb'); 433 while ($buffer = fread($fp, 1024)) 434 { 435 echo $buffer; 436 } 437 fclose($fp); 438 } 439 } 440 441 /** 442 * Tar/tar.gz compression routine 443 * Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994 444 * 445 * @package phpBB3 446 */ 447 class compress_tar extends compress 448 { 449 var $isgz = false; 450 var $isbz = false; 451 var $filename = ''; 452 var $mode = ''; 453 var $type = ''; 454 var $wrote = false; 455 456 /** 457 * Constructor 458 */ 459 function compress_tar($mode, $file, $type = '') 460 { 461 $type = (!$type) ? $file : $type; 462 $this->isgz = (strpos($type, '.tar.gz') !== false || strpos($type, '.tgz') !== false) ? true : false; 463 $this->isbz = (strpos($type, '.tar.bz2') !== false) ? true : false; 464 465 $this->mode = &$mode; 466 $this->file = &$file; 467 $this->type = &$type; 468 $this->open(); 469 } 470 471 /** 472 * Extract archive 473 */ 474 function extract($dst) 475 { 476 $fzread = ($this->isbz && function_exists('bzread')) ? 'bzread' : (($this->isgz && @extension_loaded('zlib')) ? 'gzread' : 'fread'); 477 478 // Run through the file and grab directory entries 479 while ($buffer = $fzread($this->fp, 512)) 480 { 481 $tmp = unpack('A6magic', substr($buffer, 257, 6)); 482 483 if (trim($tmp['magic']) == 'ustar') 484 { 485 $tmp = unpack('A100name', $buffer); 486 $filename = trim($tmp['name']); 487 488 $tmp = unpack('Atype', substr($buffer, 156, 1)); 489 $filetype = (int) trim($tmp['type']); 490 491 $tmp = unpack('A12size', substr($buffer, 124, 12)); 492 $filesize = octdec((int) trim($tmp['size'])); 493 494 if ($filetype == 5) 495 { 496 if (!is_dir("$dst$filename")) 497 { 498 $str = ''; 499 $folders = explode('/', "$dst$filename"); 500 501 // Create and folders and subfolders if they do not exist 502 foreach ($folders as $folder) 503 { 504 $str = (!empty($str)) ? $str . '/' . $folder : $folder; 505 if (!is_dir($str)) 506 { 507 if (!@mkdir($str, 0777)) 508 { 509 trigger_error("Could not create directory $folder"); 510 } 511 @chmod($str, 0777); 512 } 513 } 514 } 515 } 516 else if ($filesize != 0 && ($filetype == 0 || $filetype == "\0")) 517 { 518 // Write out the files 519 if (!($fp = fopen("$dst$filename", 'wb'))) 520 { 521 trigger_error("Couldn't create file $filename"); 522 } 523 @chmod("$dst$filename", 0777); 524 525 // Grab the file contents 526 fwrite($fp, $fzread($this->fp, ($filesize + 511) &~ 511), $filesize); 527 fclose($fp); 528 } 529 } 530 } 531 } 532 533 /** 534 * Close archive 535 */ 536 function close() 537 { 538 $fzclose = ($this->isbz && function_exists('bzclose')) ? 'bzclose' : (($this->isgz && @extension_loaded('zlib')) ? 'gzclose' : 'fclose'); 539 540 if ($this->wrote) 541 { 542 $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); 543 544 // Symbolizes that there are no more files 545 $fzwrite($this->fp, str_repeat("\0", 512)); 546 } 547 548 $fzclose($this->fp); 549 } 550 551 /** 552 * Create the structures 553 */ 554 function data($name, $data, $is_dir = false, $stat) 555 { 556 $this->wrote = true; 557 $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); 558 559 $typeflag = ($is_dir) ? '5' : ''; 560 561 // This is the header data, it contains all the info we know about the file or folder that we are about to archive 562 $header = ''; 563 $header .= pack('a100', $name); // file name 564 $header .= pack('a8', sprintf("%07o", $stat[2])); // file mode 565 $header .= pack('a8', sprintf("%07o", $stat[4])); // owner id 566 $header .= pack('a8', sprintf("%07o", $stat[5])); // group id 567 $header .= pack('a12', sprintf("%011o", $stat[7])); // file size 568 $header .= pack('a12', sprintf("%011o", $stat[9])); // last mod time 569 570 // Checksum 571 $checksum = 0; 572 for ($i = 0; $i < 148; $i++) 573 { 574 $checksum += ord($header[$i]); 575 } 576 577 // We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions 578 $checksum += 2415 + (($is_dir) ? 53 : 0); 579 580 $header .= pack('a8', sprintf("%07o", $checksum)); // checksum 581 $header .= pack('a1', $typeflag); // link indicator 582 $header .= pack('a100', ''); // name of linked file 583 $header .= pack('a6', 'ustar'); // ustar indicator 584 $header .= pack('a2', '00'); // ustar version 585 $header .= pack('a32', 'Unknown'); // owner name 586 $header .= pack('a32', 'Unknown'); // group name 587 $header .= pack('a8', ''); // device major number 588 $header .= pack('a8', ''); // device minor number 589 $header .= pack('a155', ''); // filename prefix 590 $header .= pack('a12', ''); // end 591 592 // This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512 593 $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : '')); 594 unset($data); 595 } 596 597 /** 598 * Open archive 599 */ 600 function open() 601 { 602 $fzopen = ($this->isbz && function_exists('bzopen')) ? 'bzopen' : (($this->isgz && @extension_loaded('zlib')) ? 'gzopen' : 'fopen'); 603 $this->fp = @$fzopen($this->file, $this->mode . 'b' . (($fzopen == 'gzopen') ? '9' : '')); 604 605 if (!$this->fp) 606 { 607 trigger_error('Unable to open file ' . $this->file . ' [' . $fzopen . ' - ' . $this->mode . 'b]'); 608 } 609 } 610 611 /** 612 * Download archive 613 */ 614 function download($filename) 615 { 616 global $phpbb_root_path; 617 618 switch ($this->type) 619 { 620 case '.tar': 621 $mimetype = 'application/x-tar'; 622 break; 623 624 case '.tar.gz': 625 $mimetype = 'application/x-gzip'; 626 break; 627 628 case '.tar.bz2': 629 $mimetype = 'application/x-bzip2'; 630 break; 631 632 default: 633 $mimetype = 'application/octet-stream'; 634 break; 635 } 636 637 header('Pragma: no-cache'); 638 header("Content-Type: $mimetype; name=\"$filename$this->type\""); 639 header("Content-disposition: attachment; filename=$filename$this->type"); 640 641 $fp = fopen("{$phpbb_root_path}store/$filename$this->type", 'rb'); 642 while ($buffer = fread($fp, 1024)) 643 { 644 echo $buffer; 645 } 646 fclose($fp); 647 } 648 } 649 650 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 22 00:35:05 2006 | Cross-referenced by PHPXref 0.6 |