1<?php 2// -------------------------------------------------------------------------------- 3// PhpConcept Library - Zip Module 2.8.2 4// -------------------------------------------------------------------------------- 5// License GNU/LGPL - Vincent Blavet - August 2009 6// http://www.phpconcept.net 7// -------------------------------------------------------------------------------- 8// 9// Presentation : 10// PclZip is a PHP library that manage ZIP archives. 11// So far tests show that archives generated by PclZip are readable by 12// WinZip application and other tools. 13// 14// Description : 15// See readme.txt and http://www.phpconcept.net 16// 17// Warning : 18// This library and the associated files are non commercial, non professional 19// work. 20// It should not have unexpected results. However if any damage is caused by 21// this software the author can not be responsible. 22// The use of this software is at the risk of the user. 23// 24// -------------------------------------------------------------------------------- 25// $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $ 26// -------------------------------------------------------------------------------- 27 28// ----- Constants 29if (!defined('PCLZIP_READ_BLOCK_SIZE')) { 30 define('PCLZIP_READ_BLOCK_SIZE', 2048); 31} 32 33// ----- File list separator 34// In version 1.x of PclZip, the separator for file list is a space 35// (which is not a very smart choice, specifically for windows paths !). 36// A better separator should be a comma (,). This constant gives you the 37// abilty to change that. 38// However notice that changing this value, may have impact on existing 39// scripts, using space separated filenames. 40// Recommanded values for compatibility with older versions : 41//define( 'PCLZIP_SEPARATOR', ' ' ); 42// Recommanded values for smart separation of filenames. 43if (!defined('PCLZIP_SEPARATOR')) { 44 define('PCLZIP_SEPARATOR', ','); 45} 46 47// ----- Error configuration 48// 0 : PclZip Class integrated error handling 49// 1 : PclError external library error handling. By enabling this 50// you must ensure that you have included PclError library. 51// [2,...] : reserved for futur use 52if (!defined('PCLZIP_ERROR_EXTERNAL')) { 53 define('PCLZIP_ERROR_EXTERNAL', 0); 54} 55 56// ----- Optional static temporary directory 57// By default temporary files are generated in the script current 58// path. 59// If defined : 60// - MUST BE terminated by a '/'. 61// - MUST be a valid, already created directory 62// Samples : 63// define( 'PCLZIP_TEMPORARY_DIR', '/temp/' ); 64// define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' ); 65if (!defined('PCLZIP_TEMPORARY_DIR')) { 66 define('PCLZIP_TEMPORARY_DIR', ''); 67} 68 69// ----- Optional threshold ratio for use of temporary files 70// Pclzip sense the size of the file to add/extract and decide to 71// use or not temporary file. The algorythm is looking for 72// memory_limit of PHP and apply a ratio. 73// threshold = memory_limit * ratio. 74// Recommended values are under 0.5. Default 0.47. 75// Samples : 76// define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 ); 77if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) { 78 define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47); 79} 80 81// -------------------------------------------------------------------------------- 82// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED ***** 83// -------------------------------------------------------------------------------- 84 85// ----- Global variables 86$g_pclzip_version = "2.8.2"; 87 88// ----- Error codes 89// -1 : Unable to open file in binary write mode 90// -2 : Unable to open file in binary read mode 91// -3 : Invalid parameters 92// -4 : File does not exist 93// -5 : Filename is too long (max. 255) 94// -6 : Not a valid zip file 95// -7 : Invalid extracted file size 96// -8 : Unable to create directory 97// -9 : Invalid archive extension 98// -10 : Invalid archive format 99// -11 : Unable to delete file (unlink) 100// -12 : Unable to rename file (rename) 101// -13 : Invalid header checksum 102// -14 : Invalid archive size 103define('PCLZIP_ERR_USER_ABORTED', 2); 104define('PCLZIP_ERR_NO_ERROR', 0); 105define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1); 106define('PCLZIP_ERR_READ_OPEN_FAIL', -2); 107define('PCLZIP_ERR_INVALID_PARAMETER', -3); 108define('PCLZIP_ERR_MISSING_FILE', -4); 109define('PCLZIP_ERR_FILENAME_TOO_LONG', -5); 110define('PCLZIP_ERR_INVALID_ZIP', -6); 111define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7); 112define('PCLZIP_ERR_DIR_CREATE_FAIL', -8); 113define('PCLZIP_ERR_BAD_EXTENSION', -9); 114define('PCLZIP_ERR_BAD_FORMAT', -10); 115define('PCLZIP_ERR_DELETE_FILE_FAIL', -11); 116define('PCLZIP_ERR_RENAME_FILE_FAIL', -12); 117define('PCLZIP_ERR_BAD_CHECKSUM', -13); 118define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14); 119define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15); 120define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16); 121define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17); 122define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18); 123define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19); 124define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20); 125define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21); 126 127// ----- Options values 128define('PCLZIP_OPT_PATH', 77001); 129define('PCLZIP_OPT_ADD_PATH', 77002); 130define('PCLZIP_OPT_REMOVE_PATH', 77003); 131define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004); 132define('PCLZIP_OPT_SET_CHMOD', 77005); 133define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006); 134define('PCLZIP_OPT_NO_COMPRESSION', 77007); 135define('PCLZIP_OPT_BY_NAME', 77008); 136define('PCLZIP_OPT_BY_INDEX', 77009); 137define('PCLZIP_OPT_BY_EREG', 77010); 138define('PCLZIP_OPT_BY_PREG', 77011); 139define('PCLZIP_OPT_COMMENT', 77012); 140define('PCLZIP_OPT_ADD_COMMENT', 77013); 141define('PCLZIP_OPT_PREPEND_COMMENT', 77014); 142define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015); 143define('PCLZIP_OPT_REPLACE_NEWER', 77016); 144define('PCLZIP_OPT_STOP_ON_ERROR', 77017); 145// Having big trouble with crypt. Need to multiply 2 long int 146// which is not correctly supported by PHP ... 147//define( 'PCLZIP_OPT_CRYPT', 77018 ); 148define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019); 149define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020); 150define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias 151define('PCLZIP_OPT_TEMP_FILE_ON', 77021); 152define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias 153define('PCLZIP_OPT_TEMP_FILE_OFF', 77022); 154define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias 155 156// ----- File description attributes 157define('PCLZIP_ATT_FILE_NAME', 79001); 158define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002); 159define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003); 160define('PCLZIP_ATT_FILE_MTIME', 79004); 161define('PCLZIP_ATT_FILE_CONTENT', 79005); 162define('PCLZIP_ATT_FILE_COMMENT', 79006); 163 164// ----- Call backs values 165define('PCLZIP_CB_PRE_EXTRACT', 78001); 166define('PCLZIP_CB_POST_EXTRACT', 78002); 167define('PCLZIP_CB_PRE_ADD', 78003); 168define('PCLZIP_CB_POST_ADD', 78004); 169/* For futur use 170define( 'PCLZIP_CB_PRE_LIST', 78005 ); 171define( 'PCLZIP_CB_POST_LIST', 78006 ); 172define( 'PCLZIP_CB_PRE_DELETE', 78007 ); 173define( 'PCLZIP_CB_POST_DELETE', 78008 ); 174*/ 175 176// -------------------------------------------------------------------------------- 177// Class : PclZip 178// Description : 179// PclZip is the class that represent a Zip archive. 180// The public methods allow the manipulation of the archive. 181// Attributes : 182// Attributes must not be accessed directly. 183// Methods : 184// PclZip() : Object creator 185// create() : Creates the Zip archive 186// listContent() : List the content of the Zip archive 187// extract() : Extract the content of the archive 188// properties() : List the properties of the archive 189// -------------------------------------------------------------------------------- 190class PclZip 191{ 192 // ----- Filename of the zip file 193 public $zipname = ''; 194 195 // ----- File descriptor of the zip file 196 public $zip_fd = 0; 197 198 // ----- Internal error handling 199 public $error_code = 1; 200 public $error_string = ''; 201 202 // ----- Current status of the magic_quotes_runtime 203 // This value store the php configuration for magic_quotes 204 // The class can then disable the magic_quotes and reset it after 205 public $magic_quotes_status; 206 207 // -------------------------------------------------------------------------------- 208 // Function : PclZip() 209 // Description : 210 // Creates a PclZip object and set the name of the associated Zip archive 211 // filename. 212 // Note that no real action is taken, if the archive does not exist it is not 213 // created. Use create() for that. 214 // -------------------------------------------------------------------------------- 215 public function __construct($p_zipname) 216 { 217 218 // ----- Tests the zlib 219 if (!function_exists('gzopen')) { 220 die('Abort ' . basename(__FILE__) . ' : Missing zlib extensions'); 221 } 222 223 // ----- Set the attributes 224 $this->zipname = $p_zipname; 225 $this->zip_fd = 0; 226 $this->magic_quotes_status = -1; 227 228 // ----- Return 229 return; 230 } 231 // -------------------------------------------------------------------------------- 232 233 // -------------------------------------------------------------------------------- 234 // Function : 235 // create($p_filelist, $p_add_dir="", $p_remove_dir="") 236 // create($p_filelist, $p_option, $p_option_value, ...) 237 // Description : 238 // This method supports two different synopsis. The first one is historical. 239 // This method creates a Zip Archive. The Zip file is created in the 240 // filesystem. The files and directories indicated in $p_filelist 241 // are added in the archive. See the parameters description for the 242 // supported format of $p_filelist. 243 // When a directory is in the list, the directory and its content is added 244 // in the archive. 245 // In this synopsis, the function takes an optional variable list of 246 // options. See bellow the supported options. 247 // Parameters : 248 // $p_filelist : An array containing file or directory names, or 249 // a string containing one filename or one directory name, or 250 // a string containing a list of filenames and/or directory 251 // names separated by spaces. 252 // $p_add_dir : A path to add before the real path of the archived file, 253 // in order to have it memorized in the archive. 254 // $p_remove_dir : A path to remove from the real path of the file to archive, 255 // in order to have a shorter path memorized in the archive. 256 // When $p_add_dir and $p_remove_dir are set, $p_remove_dir 257 // is removed first, before $p_add_dir is added. 258 // Options : 259 // PCLZIP_OPT_ADD_PATH : 260 // PCLZIP_OPT_REMOVE_PATH : 261 // PCLZIP_OPT_REMOVE_ALL_PATH : 262 // PCLZIP_OPT_COMMENT : 263 // PCLZIP_CB_PRE_ADD : 264 // PCLZIP_CB_POST_ADD : 265 // Return Values : 266 // 0 on failure, 267 // The list of the added files, with a status of the add action. 268 // (see PclZip::listContent() for list entry format) 269 // -------------------------------------------------------------------------------- 270 public function create($p_filelist) 271 { 272 $v_result = 1; 273 274 // ----- Reset the error handler 275 $this->privErrorReset(); 276 277 // ----- Set default values 278 $v_options = array(); 279 $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; 280 281 // ----- Look for variable options arguments 282 $v_size = func_num_args(); 283 284 // ----- Look for arguments 285 if ($v_size > 1) { 286 // ----- Get the arguments 287 $v_arg_list = func_get_args(); 288 289 // ----- Remove from the options list the first argument 290 array_shift($v_arg_list); 291 $v_size--; 292 293 // ----- Look for first arg 294 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { 295 296 // ----- Parse the options 297 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( 298 PCLZIP_OPT_REMOVE_PATH => 'optional', 299 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', 300 PCLZIP_OPT_ADD_PATH => 'optional', 301 PCLZIP_CB_PRE_ADD => 'optional', 302 PCLZIP_CB_POST_ADD => 'optional', 303 PCLZIP_OPT_NO_COMPRESSION => 'optional', 304 PCLZIP_OPT_COMMENT => 'optional', 305 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', 306 PCLZIP_OPT_TEMP_FILE_ON => 'optional', 307 PCLZIP_OPT_TEMP_FILE_OFF => 'optional' 308 //, PCLZIP_OPT_CRYPT => 'optional' 309 )); 310 if ($v_result != 1) { 311 return 0; 312 } 313 314 // ----- Look for 2 args 315 // Here we need to support the first historic synopsis of the 316 // method. 317 } else { 318 319 // ----- Get the first argument 320 $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; 321 322 // ----- Look for the optional second argument 323 if ($v_size == 2) { 324 $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; 325 } elseif ($v_size > 2) { 326 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); 327 328 return 0; 329 } 330 } 331 } 332 333 // ----- Look for default option values 334 $this->privOptionDefaultThreshold($v_options); 335 336 // ----- Init 337 $v_string_list = array(); 338 $v_att_list = array(); 339 $v_filedescr_list = array(); 340 $p_result_list = array(); 341 342 // ----- Look if the $p_filelist is really an array 343 if (is_array($p_filelist)) { 344 345 // ----- Look if the first element is also an array 346 // This will mean that this is a file description entry 347 if (isset($p_filelist[0]) && is_array($p_filelist[0])) { 348 $v_att_list = $p_filelist; 349 350 // ----- The list is a list of string names 351 } else { 352 $v_string_list = $p_filelist; 353 } 354 355 // ----- Look if the $p_filelist is a string 356 } elseif (is_string($p_filelist)) { 357 // ----- Create a list from the string 358 $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); 359 360 // ----- Invalid variable type for $p_filelist 361 } else { 362 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); 363 364 return 0; 365 } 366 367 // ----- Reformat the string list 368 if (sizeof($v_string_list) != 0) { 369 foreach ($v_string_list as $v_string) { 370 if ($v_string != '') { 371 $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; 372 } else { 373 } 374 } 375 } 376 377 // ----- For each file in the list check the attributes 378 $v_supported_attributes = array( 379 PCLZIP_ATT_FILE_NAME => 'mandatory', 380 PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', 381 PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', 382 PCLZIP_ATT_FILE_MTIME => 'optional', 383 PCLZIP_ATT_FILE_CONTENT => 'optional', 384 PCLZIP_ATT_FILE_COMMENT => 'optional' 385 ); 386 foreach ($v_att_list as $v_entry) { 387 $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); 388 if ($v_result != 1) { 389 return 0; 390 } 391 } 392 393 // ----- Expand the filelist (expand directories) 394 $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); 395 if ($v_result != 1) { 396 return 0; 397 } 398 399 // ----- Call the create fct 400 $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); 401 if ($v_result != 1) { 402 return 0; 403 } 404 405 // ----- Return 406 return $p_result_list; 407 } 408 // -------------------------------------------------------------------------------- 409 410 // -------------------------------------------------------------------------------- 411 // Function : 412 // add($p_filelist, $p_add_dir="", $p_remove_dir="") 413 // add($p_filelist, $p_option, $p_option_value, ...) 414 // Description : 415 // This method supports two synopsis. The first one is historical. 416 // This methods add the list of files in an existing archive. 417 // If a file with the same name already exists, it is added at the end of the 418 // archive, the first one is still present. 419 // If the archive does not exist, it is created. 420 // Parameters : 421 // $p_filelist : An array containing file or directory names, or 422 // a string containing one filename or one directory name, or 423 // a string containing a list of filenames and/or directory 424 // names separated by spaces. 425 // $p_add_dir : A path to add before the real path of the archived file, 426 // in order to have it memorized in the archive. 427 // $p_remove_dir : A path to remove from the real path of the file to archive, 428 // in order to have a shorter path memorized in the archive. 429 // When $p_add_dir and $p_remove_dir are set, $p_remove_dir 430 // is removed first, before $p_add_dir is added. 431 // Options : 432 // PCLZIP_OPT_ADD_PATH : 433 // PCLZIP_OPT_REMOVE_PATH : 434 // PCLZIP_OPT_REMOVE_ALL_PATH : 435 // PCLZIP_OPT_COMMENT : 436 // PCLZIP_OPT_ADD_COMMENT : 437 // PCLZIP_OPT_PREPEND_COMMENT : 438 // PCLZIP_CB_PRE_ADD : 439 // PCLZIP_CB_POST_ADD : 440 // Return Values : 441 // 0 on failure, 442 // The list of the added files, with a status of the add action. 443 // (see PclZip::listContent() for list entry format) 444 // -------------------------------------------------------------------------------- 445 public function add($p_filelist) 446 { 447 $v_result = 1; 448 449 // ----- Reset the error handler 450 $this->privErrorReset(); 451 452 // ----- Set default values 453 $v_options = array(); 454 $v_options[PCLZIP_OPT_NO_COMPRESSION] = false; 455 456 // ----- Look for variable options arguments 457 $v_size = func_num_args(); 458 459 // ----- Look for arguments 460 if ($v_size > 1) { 461 // ----- Get the arguments 462 $v_arg_list = func_get_args(); 463 464 // ----- Remove form the options list the first argument 465 array_shift($v_arg_list); 466 $v_size--; 467 468 // ----- Look for first arg 469 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { 470 471 // ----- Parse the options 472 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( 473 PCLZIP_OPT_REMOVE_PATH => 'optional', 474 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', 475 PCLZIP_OPT_ADD_PATH => 'optional', 476 PCLZIP_CB_PRE_ADD => 'optional', 477 PCLZIP_CB_POST_ADD => 'optional', 478 PCLZIP_OPT_NO_COMPRESSION => 'optional', 479 PCLZIP_OPT_COMMENT => 'optional', 480 PCLZIP_OPT_ADD_COMMENT => 'optional', 481 PCLZIP_OPT_PREPEND_COMMENT => 'optional', 482 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', 483 PCLZIP_OPT_TEMP_FILE_ON => 'optional', 484 PCLZIP_OPT_TEMP_FILE_OFF => 'optional' 485 //, PCLZIP_OPT_CRYPT => 'optional' 486 )); 487 if ($v_result != 1) { 488 return 0; 489 } 490 491 // ----- Look for 2 args 492 // Here we need to support the first historic synopsis of the 493 // method. 494 } else { 495 496 // ----- Get the first argument 497 $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; 498 499 // ----- Look for the optional second argument 500 if ($v_size == 2) { 501 $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; 502 } elseif ($v_size > 2) { 503 // ----- Error log 504 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); 505 506 // ----- Return 507 return 0; 508 } 509 } 510 } 511 512 // ----- Look for default option values 513 $this->privOptionDefaultThreshold($v_options); 514 515 // ----- Init 516 $v_string_list = array(); 517 $v_att_list = array(); 518 $v_filedescr_list = array(); 519 $p_result_list = array(); 520 521 // ----- Look if the $p_filelist is really an array 522 if (is_array($p_filelist)) { 523 524 // ----- Look if the first element is also an array 525 // This will mean that this is a file description entry 526 if (isset($p_filelist[0]) && is_array($p_filelist[0])) { 527 $v_att_list = $p_filelist; 528 529 // ----- The list is a list of string names 530 } else { 531 $v_string_list = $p_filelist; 532 } 533 534 // ----- Look if the $p_filelist is a string 535 } elseif (is_string($p_filelist)) { 536 // ----- Create a list from the string 537 $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); 538 539 // ----- Invalid variable type for $p_filelist 540 } else { 541 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '" . gettype($p_filelist) . "' for p_filelist"); 542 543 return 0; 544 } 545 546 // ----- Reformat the string list 547 if (sizeof($v_string_list) != 0) { 548 foreach ($v_string_list as $v_string) { 549 $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; 550 } 551 } 552 553 // ----- For each file in the list check the attributes 554 $v_supported_attributes = array( 555 PCLZIP_ATT_FILE_NAME => 'mandatory', 556 PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional', 557 PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional', 558 PCLZIP_ATT_FILE_MTIME => 'optional', 559 PCLZIP_ATT_FILE_CONTENT => 'optional', 560 PCLZIP_ATT_FILE_COMMENT => 'optional' 561 ); 562 foreach ($v_att_list as $v_entry) { 563 $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes); 564 if ($v_result != 1) { 565 return 0; 566 } 567 } 568 569 // ----- Expand the filelist (expand directories) 570 $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); 571 if ($v_result != 1) { 572 return 0; 573 } 574 575 // ----- Call the create fct 576 $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); 577 if ($v_result != 1) { 578 return 0; 579 } 580 581 // ----- Return 582 return $p_result_list; 583 } 584 // -------------------------------------------------------------------------------- 585 586 // -------------------------------------------------------------------------------- 587 // Function : listContent() 588 // Description : 589 // This public method, gives the list of the files and directories, with their 590 // properties. 591 // The properties of each entries in the list are (used also in other functions) : 592 // filename : Name of the file. For a create or add action it is the filename 593 // given by the user. For an extract function it is the filename 594 // of the extracted file. 595 // stored_filename : Name of the file / directory stored in the archive. 596 // size : Size of the stored file. 597 // compressed_size : Size of the file's data compressed in the archive 598 // (without the headers overhead) 599 // mtime : Last known modification date of the file (UNIX timestamp) 600 // comment : Comment associated with the file 601 // folder : true | false 602 // index : index of the file in the archive 603 // status : status of the action (depending of the action) : 604 // Values are : 605 // ok : OK ! 606 // filtered : the file / dir is not extracted (filtered by user) 607 // already_a_directory : the file can not be extracted because a 608 // directory with the same name already exists 609 // write_protected : the file can not be extracted because a file 610 // with the same name already exists and is 611 // write protected 612 // newer_exist : the file was not extracted because a newer file exists 613 // path_creation_fail : the file is not extracted because the folder 614 // does not exist and can not be created 615 // write_error : the file was not extracted because there was a 616 // error while writing the file 617 // read_error : the file was not extracted because there was a error 618 // while reading the file 619 // invalid_header : the file was not extracted because of an archive 620 // format error (bad file header) 621 // Note that each time a method can continue operating when there 622 // is an action error on a file, the error is only logged in the file status. 623 // Return Values : 624 // 0 on an unrecoverable failure, 625 // The list of the files in the archive. 626 // -------------------------------------------------------------------------------- 627 public function listContent() 628 { 629 $v_result = 1; 630 631 // ----- Reset the error handler 632 $this->privErrorReset(); 633 634 // ----- Check archive 635 if (!$this->privCheckFormat()) { 636 return (0); 637 } 638 639 // ----- Call the extracting fct 640 $p_list = array(); 641 if (($v_result = $this->privList($p_list)) != 1) { 642 unset($p_list); 643 644 return (0); 645 } 646 647 // ----- Return 648 return $p_list; 649 } 650 // -------------------------------------------------------------------------------- 651 652 // -------------------------------------------------------------------------------- 653 // Function : 654 // extract($p_path="./", $p_remove_path="") 655 // extract([$p_option, $p_option_value, ...]) 656 // Description : 657 // This method supports two synopsis. The first one is historical. 658 // This method extract all the files / directories from the archive to the 659 // folder indicated in $p_path. 660 // If you want to ignore the 'root' part of path of the memorized files 661 // you can indicate this in the optional $p_remove_path parameter. 662 // By default, if a newer file with the same name already exists, the 663 // file is not extracted. 664 // 665 // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions 666 // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append 667 // at the end of the path value of PCLZIP_OPT_PATH. 668 // Parameters : 669 // $p_path : Path where the files and directories are to be extracted 670 // $p_remove_path : First part ('root' part) of the memorized path 671 // (if any similar) to remove while extracting. 672 // Options : 673 // PCLZIP_OPT_PATH : 674 // PCLZIP_OPT_ADD_PATH : 675 // PCLZIP_OPT_REMOVE_PATH : 676 // PCLZIP_OPT_REMOVE_ALL_PATH : 677 // PCLZIP_CB_PRE_EXTRACT : 678 // PCLZIP_CB_POST_EXTRACT : 679 // Return Values : 680 // 0 or a negative value on failure, 681 // The list of the extracted files, with a status of the action. 682 // (see PclZip::listContent() for list entry format) 683 // -------------------------------------------------------------------------------- 684 public function extract() 685 { 686 $v_result = 1; 687 688 // ----- Reset the error handler 689 $this->privErrorReset(); 690 691 // ----- Check archive 692 if (!$this->privCheckFormat()) { 693 return (0); 694 } 695 696 // ----- Set default values 697 $v_options = array(); 698 // $v_path = "./"; 699 $v_path = ''; 700 $v_remove_path = ""; 701 $v_remove_all_path = false; 702 703 // ----- Look for variable options arguments 704 $v_size = func_num_args(); 705 706 // ----- Default values for option 707 $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; 708 709 // ----- Look for arguments 710 if ($v_size > 0) { 711 // ----- Get the arguments 712 $v_arg_list = func_get_args(); 713 714 // ----- Look for first arg 715 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { 716 717 // ----- Parse the options 718 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( 719 PCLZIP_OPT_PATH => 'optional', 720 PCLZIP_OPT_REMOVE_PATH => 'optional', 721 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', 722 PCLZIP_OPT_ADD_PATH => 'optional', 723 PCLZIP_CB_PRE_EXTRACT => 'optional', 724 PCLZIP_CB_POST_EXTRACT => 'optional', 725 PCLZIP_OPT_SET_CHMOD => 'optional', 726 PCLZIP_OPT_BY_NAME => 'optional', 727 PCLZIP_OPT_BY_EREG => 'optional', 728 PCLZIP_OPT_BY_PREG => 'optional', 729 PCLZIP_OPT_BY_INDEX => 'optional', 730 PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', 731 PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', 732 PCLZIP_OPT_REPLACE_NEWER => 'optional', 733 PCLZIP_OPT_STOP_ON_ERROR => 'optional', 734 PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', 735 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', 736 PCLZIP_OPT_TEMP_FILE_ON => 'optional', 737 PCLZIP_OPT_TEMP_FILE_OFF => 'optional' 738 )); 739 if ($v_result != 1) { 740 return 0; 741 } 742 743 // ----- Set the arguments 744 if (isset($v_options[PCLZIP_OPT_PATH])) { 745 $v_path = $v_options[PCLZIP_OPT_PATH]; 746 } 747 if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { 748 $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; 749 } 750 if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { 751 $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; 752 } 753 if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { 754 // ----- Check for '/' in last path char 755 if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { 756 $v_path .= '/'; 757 } 758 $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; 759 } 760 761 // ----- Look for 2 args 762 // Here we need to support the first historic synopsis of the 763 // method. 764 } else { 765 766 // ----- Get the first argument 767 $v_path = $v_arg_list[0]; 768 769 // ----- Look for the optional second argument 770 if ($v_size == 2) { 771 $v_remove_path = $v_arg_list[1]; 772 } elseif ($v_size > 2) { 773 // ----- Error log 774 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); 775 776 // ----- Return 777 return 0; 778 } 779 } 780 } 781 782 // ----- Look for default option values 783 $this->privOptionDefaultThreshold($v_options); 784 785 // ----- Trace 786 787 // ----- Call the extracting fct 788 $p_list = array(); 789 $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options); 790 if ($v_result < 1) { 791 unset($p_list); 792 793 return (0); 794 } 795 796 // ----- Return 797 return $p_list; 798 } 799 // -------------------------------------------------------------------------------- 800 801 802 // -------------------------------------------------------------------------------- 803 // Function : 804 // extractByIndex($p_index, $p_path="./", $p_remove_path="") 805 // extractByIndex($p_index, [$p_option, $p_option_value, ...]) 806 // Description : 807 // This method supports two synopsis. The first one is historical. 808 // This method is doing a partial extract of the archive. 809 // The extracted files or folders are identified by their index in the 810 // archive (from 0 to n). 811 // Note that if the index identify a folder, only the folder entry is 812 // extracted, not all the files included in the archive. 813 // Parameters : 814 // $p_index : A single index (integer) or a string of indexes of files to 815 // extract. The form of the string is "0,4-6,8-12" with only numbers 816 // and '-' for range or ',' to separate ranges. No spaces or ';' 817 // are allowed. 818 // $p_path : Path where the files and directories are to be extracted 819 // $p_remove_path : First part ('root' part) of the memorized path 820 // (if any similar) to remove while extracting. 821 // Options : 822 // PCLZIP_OPT_PATH : 823 // PCLZIP_OPT_ADD_PATH : 824 // PCLZIP_OPT_REMOVE_PATH : 825 // PCLZIP_OPT_REMOVE_ALL_PATH : 826 // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and 827 // not as files. 828 // The resulting content is in a new field 'content' in the file 829 // structure. 830 // This option must be used alone (any other options are ignored). 831 // PCLZIP_CB_PRE_EXTRACT : 832 // PCLZIP_CB_POST_EXTRACT : 833 // Return Values : 834 // 0 on failure, 835 // The list of the extracted files, with a status of the action. 836 // (see PclZip::listContent() for list entry format) 837 // -------------------------------------------------------------------------------- 838 //function extractByIndex($p_index, options...) 839 public function extractByIndex($p_index) 840 { 841 $v_result = 1; 842 843 // ----- Reset the error handler 844 $this->privErrorReset(); 845 846 // ----- Check archive 847 if (!$this->privCheckFormat()) { 848 return (0); 849 } 850 851 // ----- Set default values 852 $v_options = array(); 853 // $v_path = "./"; 854 $v_path = ''; 855 $v_remove_path = ""; 856 $v_remove_all_path = false; 857 858 // ----- Look for variable options arguments 859 $v_size = func_num_args(); 860 861 // ----- Default values for option 862 $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; 863 864 // ----- Look for arguments 865 if ($v_size > 1) { 866 // ----- Get the arguments 867 $v_arg_list = func_get_args(); 868 869 // ----- Remove form the options list the first argument 870 array_shift($v_arg_list); 871 $v_size--; 872 873 // ----- Look for first arg 874 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { 875 876 // ----- Parse the options 877 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( 878 PCLZIP_OPT_PATH => 'optional', 879 PCLZIP_OPT_REMOVE_PATH => 'optional', 880 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', 881 PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', 882 PCLZIP_OPT_ADD_PATH => 'optional', 883 PCLZIP_CB_PRE_EXTRACT => 'optional', 884 PCLZIP_CB_POST_EXTRACT => 'optional', 885 PCLZIP_OPT_SET_CHMOD => 'optional', 886 PCLZIP_OPT_REPLACE_NEWER => 'optional', 887 PCLZIP_OPT_STOP_ON_ERROR => 'optional', 888 PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', 889 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', 890 PCLZIP_OPT_TEMP_FILE_ON => 'optional', 891 PCLZIP_OPT_TEMP_FILE_OFF => 'optional' 892 )); 893 if ($v_result != 1) { 894 return 0; 895 } 896 897 // ----- Set the arguments 898 if (isset($v_options[PCLZIP_OPT_PATH])) { 899 $v_path = $v_options[PCLZIP_OPT_PATH]; 900 } 901 if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { 902 $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; 903 } 904 if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { 905 $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; 906 } 907 if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { 908 // ----- Check for '/' in last path char 909 if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { 910 $v_path .= '/'; 911 } 912 $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; 913 } 914 if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { 915 $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false; 916 } else { 917 } 918 919 // ----- Look for 2 args 920 // Here we need to support the first historic synopsis of the 921 // method. 922 } else { 923 924 // ----- Get the first argument 925 $v_path = $v_arg_list[0]; 926 927 // ----- Look for the optional second argument 928 if ($v_size == 2) { 929 $v_remove_path = $v_arg_list[1]; 930 } elseif ($v_size > 2) { 931 // ----- Error log 932 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); 933 934 // ----- Return 935 return 0; 936 } 937 } 938 } 939 940 // ----- Trace 941 942 // ----- Trick 943 // Here I want to reuse extractByRule(), so I need to parse the $p_index 944 // with privParseOptions() 945 $v_arg_trick = array( 946 PCLZIP_OPT_BY_INDEX, 947 $p_index 948 ); 949 $v_options_trick = array(); 950 $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array( 951 PCLZIP_OPT_BY_INDEX => 'optional' 952 )); 953 if ($v_result != 1) { 954 return 0; 955 } 956 $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; 957 958 // ----- Look for default option values 959 $this->privOptionDefaultThreshold($v_options); 960 961 // ----- Call the extracting fct 962 if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { 963 return (0); 964 } 965 966 // ----- Return 967 return $p_list; 968 } 969 // -------------------------------------------------------------------------------- 970 971 // -------------------------------------------------------------------------------- 972 // Function : 973 // delete([$p_option, $p_option_value, ...]) 974 // Description : 975 // This method removes files from the archive. 976 // If no parameters are given, then all the archive is emptied. 977 // Parameters : 978 // None or optional arguments. 979 // Options : 980 // PCLZIP_OPT_BY_INDEX : 981 // PCLZIP_OPT_BY_NAME : 982 // PCLZIP_OPT_BY_EREG : 983 // PCLZIP_OPT_BY_PREG : 984 // Return Values : 985 // 0 on failure, 986 // The list of the files which are still present in the archive. 987 // (see PclZip::listContent() for list entry format) 988 // -------------------------------------------------------------------------------- 989 public function delete() 990 { 991 $v_result = 1; 992 993 // ----- Reset the error handler 994 $this->privErrorReset(); 995 996 // ----- Check archive 997 if (!$this->privCheckFormat()) { 998 return (0); 999 } 1000 1001 // ----- Set default values 1002 $v_options = array(); 1003 1004 // ----- Look for variable options arguments 1005 $v_size = func_num_args(); 1006 1007 // ----- Look for arguments 1008 if ($v_size > 0) { 1009 // ----- Get the arguments 1010 $v_arg_list = func_get_args(); 1011 1012 // ----- Parse the options 1013 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array( 1014 PCLZIP_OPT_BY_NAME => 'optional', 1015 PCLZIP_OPT_BY_EREG => 'optional', 1016 PCLZIP_OPT_BY_PREG => 'optional', 1017 PCLZIP_OPT_BY_INDEX => 'optional' 1018 )); 1019 if ($v_result != 1) { 1020 return 0; 1021 } 1022 } 1023 1024 // ----- Magic quotes trick 1025 $this->privDisableMagicQuotes(); 1026 1027 // ----- Call the delete fct 1028 $v_list = array(); 1029 if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { 1030 $this->privSwapBackMagicQuotes(); 1031 unset($v_list); 1032 1033 return (0); 1034 } 1035 1036 // ----- Magic quotes trick 1037 $this->privSwapBackMagicQuotes(); 1038 1039 // ----- Return 1040 return $v_list; 1041 } 1042 // -------------------------------------------------------------------------------- 1043 1044 // -------------------------------------------------------------------------------- 1045 // Function : deleteByIndex() 1046 // Description : 1047 // ***** Deprecated ***** 1048 // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. 1049 // -------------------------------------------------------------------------------- 1050 public function deleteByIndex($p_index) 1051 { 1052 1053 $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); 1054 1055 // ----- Return 1056 return $p_list; 1057 } 1058 // -------------------------------------------------------------------------------- 1059 1060 // -------------------------------------------------------------------------------- 1061 // Function : properties() 1062 // Description : 1063 // This method gives the properties of the archive. 1064 // The properties are : 1065 // nb : Number of files in the archive 1066 // comment : Comment associated with the archive file 1067 // status : not_exist, ok 1068 // Parameters : 1069 // None 1070 // Return Values : 1071 // 0 on failure, 1072 // An array with the archive properties. 1073 // -------------------------------------------------------------------------------- 1074 public function properties() 1075 { 1076 1077 // ----- Reset the error handler 1078 $this->privErrorReset(); 1079 1080 // ----- Magic quotes trick 1081 $this->privDisableMagicQuotes(); 1082 1083 // ----- Check archive 1084 if (!$this->privCheckFormat()) { 1085 $this->privSwapBackMagicQuotes(); 1086 1087 return (0); 1088 } 1089 1090 // ----- Default properties 1091 $v_prop = array(); 1092 $v_prop['comment'] = ''; 1093 $v_prop['nb'] = 0; 1094 $v_prop['status'] = 'not_exist'; 1095 1096 // ----- Look if file exists 1097 if (@is_file($this->zipname)) { 1098 // ----- Open the zip file 1099 if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { 1100 $this->privSwapBackMagicQuotes(); 1101 1102 // ----- Error log 1103 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); 1104 1105 // ----- Return 1106 return 0; 1107 } 1108 1109 // ----- Read the central directory informations 1110 $v_central_dir = array(); 1111 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 1112 $this->privSwapBackMagicQuotes(); 1113 1114 return 0; 1115 } 1116 1117 // ----- Close the zip file 1118 $this->privCloseFd(); 1119 1120 // ----- Set the user attributes 1121 $v_prop['comment'] = $v_central_dir['comment']; 1122 $v_prop['nb'] = $v_central_dir['entries']; 1123 $v_prop['status'] = 'ok'; 1124 } 1125 1126 // ----- Magic quotes trick 1127 $this->privSwapBackMagicQuotes(); 1128 1129 // ----- Return 1130 return $v_prop; 1131 } 1132 // -------------------------------------------------------------------------------- 1133 1134 // -------------------------------------------------------------------------------- 1135 // Function : duplicate() 1136 // Description : 1137 // This method creates an archive by copying the content of an other one. If 1138 // the archive already exist, it is replaced by the new one without any warning. 1139 // Parameters : 1140 // $p_archive : The filename of a valid archive, or 1141 // a valid PclZip object. 1142 // Return Values : 1143 // 1 on success. 1144 // 0 or a negative value on error (error code). 1145 // -------------------------------------------------------------------------------- 1146 public function duplicate($p_archive) 1147 { 1148 $v_result = 1; 1149 1150 // ----- Reset the error handler 1151 $this->privErrorReset(); 1152 1153 // ----- Look if the $p_archive is a PclZip object 1154 if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) { 1155 1156 // ----- Duplicate the archive 1157 $v_result = $this->privDuplicate($p_archive->zipname); 1158 1159 // ----- Look if the $p_archive is a string (so a filename) 1160 } elseif (is_string($p_archive)) { 1161 1162 // ----- Check that $p_archive is a valid zip file 1163 // TBC : Should also check the archive format 1164 if (!is_file($p_archive)) { 1165 // ----- Error log 1166 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'"); 1167 $v_result = PCLZIP_ERR_MISSING_FILE; 1168 } else { 1169 // ----- Duplicate the archive 1170 $v_result = $this->privDuplicate($p_archive); 1171 } 1172 1173 // ----- Invalid variable 1174 } else { 1175 // ----- Error log 1176 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); 1177 $v_result = PCLZIP_ERR_INVALID_PARAMETER; 1178 } 1179 1180 // ----- Return 1181 return $v_result; 1182 } 1183 // -------------------------------------------------------------------------------- 1184 1185 // -------------------------------------------------------------------------------- 1186 // Function : merge() 1187 // Description : 1188 // This method merge the $p_archive_to_add archive at the end of the current 1189 // one ($this). 1190 // If the archive ($this) does not exist, the merge becomes a duplicate. 1191 // If the $p_archive_to_add archive does not exist, the merge is a success. 1192 // Parameters : 1193 // $p_archive_to_add : It can be directly the filename of a valid zip archive, 1194 // or a PclZip object archive. 1195 // Return Values : 1196 // 1 on success, 1197 // 0 or negative values on error (see below). 1198 // -------------------------------------------------------------------------------- 1199 public function merge($p_archive_to_add) 1200 { 1201 $v_result = 1; 1202 1203 // ----- Reset the error handler 1204 $this->privErrorReset(); 1205 1206 // ----- Check archive 1207 if (!$this->privCheckFormat()) { 1208 return (0); 1209 } 1210 1211 // ----- Look if the $p_archive_to_add is a PclZip object 1212 if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) { 1213 1214 // ----- Merge the archive 1215 $v_result = $this->privMerge($p_archive_to_add); 1216 1217 // ----- Look if the $p_archive_to_add is a string (so a filename) 1218 } elseif (is_string($p_archive_to_add)) { 1219 1220 // ----- Create a temporary archive 1221 $v_object_archive = new PclZip($p_archive_to_add); 1222 1223 // ----- Merge the archive 1224 $v_result = $this->privMerge($v_object_archive); 1225 1226 // ----- Invalid variable 1227 } else { 1228 // ----- Error log 1229 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); 1230 $v_result = PCLZIP_ERR_INVALID_PARAMETER; 1231 } 1232 1233 // ----- Return 1234 return $v_result; 1235 } 1236 // -------------------------------------------------------------------------------- 1237 1238 // -------------------------------------------------------------------------------- 1239 // Function : errorCode() 1240 // Description : 1241 // Parameters : 1242 // -------------------------------------------------------------------------------- 1243 public function errorCode() 1244 { 1245 if (PCLZIP_ERROR_EXTERNAL == 1) { 1246 return (PclErrorCode()); 1247 } else { 1248 return ($this->error_code); 1249 } 1250 } 1251 // -------------------------------------------------------------------------------- 1252 1253 // -------------------------------------------------------------------------------- 1254 // Function : errorName() 1255 // Description : 1256 // Parameters : 1257 // -------------------------------------------------------------------------------- 1258 public function errorName($p_with_code = false) 1259 { 1260 $v_name = array( 1261 PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', 1262 PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', 1263 PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', 1264 PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', 1265 PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', 1266 PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', 1267 PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', 1268 PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', 1269 PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', 1270 PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', 1271 PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', 1272 PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', 1273 PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', 1274 PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', 1275 PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', 1276 PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', 1277 PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', 1278 PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', 1279 PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', 1280 PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', 1281 PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' 1282 ); 1283 1284 if (isset($v_name[$this->error_code])) { 1285 $v_value = $v_name[$this->error_code]; 1286 } else { 1287 $v_value = 'NoName'; 1288 } 1289 1290 if ($p_with_code) { 1291 return ($v_value . ' (' . $this->error_code . ')'); 1292 } else { 1293 return ($v_value); 1294 } 1295 } 1296 // -------------------------------------------------------------------------------- 1297 1298 // -------------------------------------------------------------------------------- 1299 // Function : errorInfo() 1300 // Description : 1301 // Parameters : 1302 // -------------------------------------------------------------------------------- 1303 public function errorInfo($p_full = false) 1304 { 1305 if (PCLZIP_ERROR_EXTERNAL == 1) { 1306 return (PclErrorString()); 1307 } else { 1308 if ($p_full) { 1309 return ($this->errorName(true) . " : " . $this->error_string); 1310 } else { 1311 return ($this->error_string . " [code " . $this->error_code . "]"); 1312 } 1313 } 1314 } 1315 // -------------------------------------------------------------------------------- 1316 1317 // -------------------------------------------------------------------------------- 1318 // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** 1319 // ***** ***** 1320 // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** 1321 // -------------------------------------------------------------------------------- 1322 1323 // -------------------------------------------------------------------------------- 1324 // Function : privCheckFormat() 1325 // Description : 1326 // This method check that the archive exists and is a valid zip archive. 1327 // Several level of check exists. (futur) 1328 // Parameters : 1329 // $p_level : Level of check. Default 0. 1330 // 0 : Check the first bytes (magic codes) (default value)) 1331 // 1 : 0 + Check the central directory (futur) 1332 // 2 : 1 + Check each file header (futur) 1333 // Return Values : 1334 // true on success, 1335 // false on error, the error code is set. 1336 // -------------------------------------------------------------------------------- 1337 public function privCheckFormat($p_level = 0) 1338 { 1339 $v_result = true; 1340 1341 // ----- Reset the file system cache 1342 clearstatcache(); 1343 1344 // ----- Reset the error handler 1345 $this->privErrorReset(); 1346 1347 // ----- Look if the file exits 1348 if (!is_file($this->zipname)) { 1349 // ----- Error log 1350 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->zipname . "'"); 1351 1352 return (false); 1353 } 1354 1355 // ----- Check that the file is readeable 1356 if (!is_readable($this->zipname)) { 1357 // ----- Error log 1358 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->zipname . "'"); 1359 1360 return (false); 1361 } 1362 1363 // ----- Check the magic code 1364 // TBC 1365 1366 // ----- Check the central header 1367 // TBC 1368 1369 // ----- Check each file header 1370 // TBC 1371 1372 // ----- Return 1373 return $v_result; 1374 } 1375 // -------------------------------------------------------------------------------- 1376 1377 // -------------------------------------------------------------------------------- 1378 // Function : privParseOptions() 1379 // Description : 1380 // This internal methods reads the variable list of arguments ($p_options_list, 1381 // $p_size) and generate an array with the options and values ($v_result_list). 1382 // $v_requested_options contains the options that can be present and those that 1383 // must be present. 1384 // $v_requested_options is an array, with the option value as key, and 'optional', 1385 // or 'mandatory' as value. 1386 // Parameters : 1387 // See above. 1388 // Return Values : 1389 // 1 on success. 1390 // 0 on failure. 1391 // -------------------------------------------------------------------------------- 1392 public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false) 1393 { 1394 $v_result = 1; 1395 1396 // ----- Read the options 1397 $i = 0; 1398 while ($i < $p_size) { 1399 1400 // ----- Check if the option is supported 1401 if (!isset($v_requested_options[$p_options_list[$i]])) { 1402 // ----- Error log 1403 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '" . $p_options_list[$i] . "' for this method"); 1404 1405 // ----- Return 1406 return PclZip::errorCode(); 1407 } 1408 1409 // ----- Look for next option 1410 switch ($p_options_list[$i]) { 1411 // ----- Look for options that request a path value 1412 case PCLZIP_OPT_PATH: 1413 case PCLZIP_OPT_REMOVE_PATH: 1414 case PCLZIP_OPT_ADD_PATH: 1415 // ----- Check the number of parameters 1416 if (($i + 1) >= $p_size) { 1417 // ----- Error log 1418 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1419 1420 // ----- Return 1421 return PclZip::errorCode(); 1422 } 1423 1424 // ----- Get the value 1425 $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); 1426 $i++; 1427 break; 1428 1429 case PCLZIP_OPT_TEMP_FILE_THRESHOLD: 1430 // ----- Check the number of parameters 1431 if (($i + 1) >= $p_size) { 1432 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1433 1434 return PclZip::errorCode(); 1435 } 1436 1437 // ----- Check for incompatible options 1438 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { 1439 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); 1440 1441 return PclZip::errorCode(); 1442 } 1443 1444 // ----- Check the value 1445 $v_value = $p_options_list[$i + 1]; 1446 if ((!is_integer($v_value)) || ($v_value < 0)) { 1447 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1448 1449 return PclZip::errorCode(); 1450 } 1451 1452 // ----- Get the value (and convert it in bytes) 1453 $v_result_list[$p_options_list[$i]] = $v_value * 1048576; 1454 $i++; 1455 break; 1456 1457 case PCLZIP_OPT_TEMP_FILE_ON: 1458 // ----- Check for incompatible options 1459 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { 1460 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); 1461 1462 return PclZip::errorCode(); 1463 } 1464 1465 $v_result_list[$p_options_list[$i]] = true; 1466 break; 1467 1468 case PCLZIP_OPT_TEMP_FILE_OFF: 1469 // ----- Check for incompatible options 1470 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { 1471 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); 1472 1473 return PclZip::errorCode(); 1474 } 1475 // ----- Check for incompatible options 1476 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { 1477 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); 1478 1479 return PclZip::errorCode(); 1480 } 1481 1482 $v_result_list[$p_options_list[$i]] = true; 1483 break; 1484 1485 case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION: 1486 // ----- Check the number of parameters 1487 if (($i + 1) >= $p_size) { 1488 // ----- Error log 1489 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1490 1491 // ----- Return 1492 return PclZip::errorCode(); 1493 } 1494 1495 // ----- Get the value 1496 if (is_string($p_options_list[$i + 1]) && ($p_options_list[$i + 1] != '')) { 1497 $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false); 1498 $i++; 1499 } else { 1500 } 1501 break; 1502 1503 // ----- Look for options that request an array of string for value 1504 case PCLZIP_OPT_BY_NAME: 1505 // ----- Check the number of parameters 1506 if (($i + 1) >= $p_size) { 1507 // ----- Error log 1508 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1509 1510 // ----- Return 1511 return PclZip::errorCode(); 1512 } 1513 1514 // ----- Get the value 1515 if (is_string($p_options_list[$i + 1])) { 1516 $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1]; 1517 } elseif (is_array($p_options_list[$i + 1])) { 1518 $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; 1519 } else { 1520 // ----- Error log 1521 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1522 1523 // ----- Return 1524 return PclZip::errorCode(); 1525 } 1526 $i++; 1527 break; 1528 1529 // ----- Look for options that request an EREG or PREG expression 1530 case PCLZIP_OPT_BY_EREG: 1531 $p_options_list[$i] = PCLZIP_OPT_BY_PREG; 1532 // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG 1533 // to PCLZIP_OPT_BY_PREG 1534 case PCLZIP_OPT_BY_PREG: 1535 //case PCLZIP_OPT_CRYPT : 1536 // ----- Check the number of parameters 1537 if (($i + 1) >= $p_size) { 1538 // ----- Error log 1539 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1540 1541 // ----- Return 1542 return PclZip::errorCode(); 1543 } 1544 1545 // ----- Get the value 1546 if (is_string($p_options_list[$i + 1])) { 1547 $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; 1548 } else { 1549 // ----- Error log 1550 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1551 1552 // ----- Return 1553 return PclZip::errorCode(); 1554 } 1555 $i++; 1556 break; 1557 1558 // ----- Look for options that takes a string 1559 case PCLZIP_OPT_COMMENT: 1560 case PCLZIP_OPT_ADD_COMMENT: 1561 case PCLZIP_OPT_PREPEND_COMMENT: 1562 // ----- Check the number of parameters 1563 if (($i + 1) >= $p_size) { 1564 // ----- Error log 1565 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1566 1567 // ----- Return 1568 return PclZip::errorCode(); 1569 } 1570 1571 // ----- Get the value 1572 if (is_string($p_options_list[$i + 1])) { 1573 $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; 1574 } else { 1575 // ----- Error log 1576 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1577 1578 // ----- Return 1579 return PclZip::errorCode(); 1580 } 1581 $i++; 1582 break; 1583 1584 // ----- Look for options that request an array of index 1585 case PCLZIP_OPT_BY_INDEX: 1586 // ----- Check the number of parameters 1587 if (($i + 1) >= $p_size) { 1588 // ----- Error log 1589 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1590 1591 // ----- Return 1592 return PclZip::errorCode(); 1593 } 1594 1595 // ----- Get the value 1596 $v_work_list = array(); 1597 if (is_string($p_options_list[$i + 1])) { 1598 1599 // ----- Remove spaces 1600 $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', ''); 1601 1602 // ----- Parse items 1603 $v_work_list = explode(",", $p_options_list[$i + 1]); 1604 } elseif (is_integer($p_options_list[$i + 1])) { 1605 $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1]; 1606 } elseif (is_array($p_options_list[$i + 1])) { 1607 $v_work_list = $p_options_list[$i + 1]; 1608 } else { 1609 // ----- Error log 1610 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1611 1612 // ----- Return 1613 return PclZip::errorCode(); 1614 } 1615 1616 // ----- Reduce the index list 1617 // each index item in the list must be a couple with a start and 1618 // an end value : [0,3], [5-5], [8-10], ... 1619 // ----- Check the format of each item 1620 $v_sort_flag = false; 1621 $v_sort_value = 0; 1622 for ($j = 0; $j < sizeof($v_work_list); $j++) { 1623 // ----- Explode the item 1624 $v_item_list = explode("-", $v_work_list[$j]); 1625 $v_size_item_list = sizeof($v_item_list); 1626 1627 // ----- TBC : Here we might check that each item is a 1628 // real integer ... 1629 1630 // ----- Look for single value 1631 if ($v_size_item_list == 1) { 1632 // ----- Set the option value 1633 $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; 1634 $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0]; 1635 } elseif ($v_size_item_list == 2) { 1636 // ----- Set the option value 1637 $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0]; 1638 $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1]; 1639 } else { 1640 // ----- Error log 1641 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1642 1643 // ----- Return 1644 return PclZip::errorCode(); 1645 } 1646 1647 // ----- Look for list sort 1648 if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) { 1649 $v_sort_flag = true; 1650 1651 // ----- TBC : An automatic sort should be writen ... 1652 // ----- Error log 1653 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1654 1655 // ----- Return 1656 return PclZip::errorCode(); 1657 } 1658 $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start']; 1659 } 1660 1661 // ----- Sort the items 1662 if ($v_sort_flag) { 1663 // TBC : To Be Completed 1664 } 1665 1666 // ----- Next option 1667 $i++; 1668 break; 1669 1670 // ----- Look for options that request no value 1671 case PCLZIP_OPT_REMOVE_ALL_PATH: 1672 case PCLZIP_OPT_EXTRACT_AS_STRING: 1673 case PCLZIP_OPT_NO_COMPRESSION: 1674 case PCLZIP_OPT_EXTRACT_IN_OUTPUT: 1675 case PCLZIP_OPT_REPLACE_NEWER: 1676 case PCLZIP_OPT_STOP_ON_ERROR: 1677 $v_result_list[$p_options_list[$i]] = true; 1678 break; 1679 1680 // ----- Look for options that request an octal value 1681 case PCLZIP_OPT_SET_CHMOD: 1682 // ----- Check the number of parameters 1683 if (($i + 1) >= $p_size) { 1684 // ----- Error log 1685 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1686 1687 // ----- Return 1688 return PclZip::errorCode(); 1689 } 1690 1691 // ----- Get the value 1692 $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1]; 1693 $i++; 1694 break; 1695 1696 // ----- Look for options that request a call-back 1697 case PCLZIP_CB_PRE_EXTRACT: 1698 case PCLZIP_CB_POST_EXTRACT: 1699 case PCLZIP_CB_PRE_ADD: 1700 case PCLZIP_CB_POST_ADD: 1701 /* for futur use 1702 case PCLZIP_CB_PRE_DELETE : 1703 case PCLZIP_CB_POST_DELETE : 1704 case PCLZIP_CB_PRE_LIST : 1705 case PCLZIP_CB_POST_LIST : 1706 */ 1707 // ----- Check the number of parameters 1708 if (($i + 1) >= $p_size) { 1709 // ----- Error log 1710 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1711 1712 // ----- Return 1713 return PclZip::errorCode(); 1714 } 1715 1716 // ----- Get the value 1717 $v_function_name = $p_options_list[$i + 1]; 1718 1719 // ----- Check that the value is a valid existing function 1720 if (!function_exists($v_function_name)) { 1721 // ----- Error log 1722 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '" . $v_function_name . "()' is not an existing function for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'"); 1723 1724 // ----- Return 1725 return PclZip::errorCode(); 1726 } 1727 1728 // ----- Set the attribute 1729 $v_result_list[$p_options_list[$i]] = $v_function_name; 1730 $i++; 1731 break; 1732 1733 default: 1734 // ----- Error log 1735 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $p_options_list[$i] . "'"); 1736 1737 // ----- Return 1738 return PclZip::errorCode(); 1739 } 1740 1741 // ----- Next options 1742 $i++; 1743 } 1744 1745 // ----- Look for mandatory options 1746 if ($v_requested_options !== false) { 1747 for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { 1748 // ----- Look for mandatory option 1749 if ($v_requested_options[$key] == 'mandatory') { 1750 // ----- Look if present 1751 if (!isset($v_result_list[$key])) { 1752 // ----- Error log 1753 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); 1754 1755 // ----- Return 1756 return PclZip::errorCode(); 1757 } 1758 } 1759 } 1760 } 1761 1762 // ----- Look for default values 1763 if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { 1764 1765 } 1766 1767 // ----- Return 1768 return $v_result; 1769 } 1770 // -------------------------------------------------------------------------------- 1771 1772 // -------------------------------------------------------------------------------- 1773 // Function : privOptionDefaultThreshold() 1774 // Description : 1775 // Parameters : 1776 // Return Values : 1777 // -------------------------------------------------------------------------------- 1778 public function privOptionDefaultThreshold(&$p_options) 1779 { 1780 $v_result = 1; 1781 1782 if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { 1783 return $v_result; 1784 } 1785 1786 // ----- Get 'memory_limit' configuration value 1787 $v_memory_limit = ini_get('memory_limit'); 1788 $v_memory_limit = trim($v_memory_limit); 1789 $last = strtolower(substr($v_memory_limit, -1)); 1790 1791 if ($last == 'g') { 1792 //$v_memory_limit = $v_memory_limit*1024*1024*1024; 1793 $v_memory_limit = $v_memory_limit * 1073741824; 1794 } 1795 if ($last == 'm') { 1796 //$v_memory_limit = $v_memory_limit*1024*1024; 1797 $v_memory_limit = $v_memory_limit * 1048576; 1798 } 1799 if ($last == 'k') { 1800 $v_memory_limit = $v_memory_limit * 1024; 1801 } 1802 1803 $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO); 1804 1805 // ----- Sanity check : No threshold if value lower than 1M 1806 if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { 1807 unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); 1808 } 1809 1810 // ----- Return 1811 return $v_result; 1812 } 1813 // -------------------------------------------------------------------------------- 1814 1815 // -------------------------------------------------------------------------------- 1816 // Function : privFileDescrParseAtt() 1817 // Description : 1818 // Parameters : 1819 // Return Values : 1820 // 1 on success. 1821 // 0 on failure. 1822 // -------------------------------------------------------------------------------- 1823 public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false) 1824 { 1825 $v_result = 1; 1826 1827 // ----- For each file in the list check the attributes 1828 foreach ($p_file_list as $v_key => $v_value) { 1829 1830 // ----- Check if the option is supported 1831 if (!isset($v_requested_options[$v_key])) { 1832 // ----- Error log 1833 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file"); 1834 1835 // ----- Return 1836 return PclZip::errorCode(); 1837 } 1838 1839 // ----- Look for attribute 1840 switch ($v_key) { 1841 case PCLZIP_ATT_FILE_NAME: 1842 if (!is_string($v_value)) { 1843 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1844 1845 return PclZip::errorCode(); 1846 } 1847 1848 $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); 1849 1850 if ($p_filedescr['filename'] == '') { 1851 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1852 1853 return PclZip::errorCode(); 1854 } 1855 1856 break; 1857 1858 case PCLZIP_ATT_FILE_NEW_SHORT_NAME: 1859 if (!is_string($v_value)) { 1860 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1861 1862 return PclZip::errorCode(); 1863 } 1864 1865 $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); 1866 1867 if ($p_filedescr['new_short_name'] == '') { 1868 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1869 1870 return PclZip::errorCode(); 1871 } 1872 break; 1873 1874 case PCLZIP_ATT_FILE_NEW_FULL_NAME: 1875 if (!is_string($v_value)) { 1876 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1877 1878 return PclZip::errorCode(); 1879 } 1880 1881 $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); 1882 1883 if ($p_filedescr['new_full_name'] == '') { 1884 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1885 1886 return PclZip::errorCode(); 1887 } 1888 break; 1889 1890 // ----- Look for options that takes a string 1891 case PCLZIP_ATT_FILE_COMMENT: 1892 if (!is_string($v_value)) { 1893 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1894 1895 return PclZip::errorCode(); 1896 } 1897 1898 $p_filedescr['comment'] = $v_value; 1899 break; 1900 1901 case PCLZIP_ATT_FILE_MTIME: 1902 if (!is_integer($v_value)) { 1903 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1904 1905 return PclZip::errorCode(); 1906 } 1907 1908 $p_filedescr['mtime'] = $v_value; 1909 break; 1910 1911 case PCLZIP_ATT_FILE_CONTENT: 1912 $p_filedescr['content'] = $v_value; 1913 break; 1914 1915 default: 1916 // ----- Error log 1917 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $v_key . "'"); 1918 1919 // ----- Return 1920 return PclZip::errorCode(); 1921 } 1922 1923 // ----- Look for mandatory options 1924 if ($v_requested_options !== false) { 1925 for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { 1926 // ----- Look for mandatory option 1927 if ($v_requested_options[$key] == 'mandatory') { 1928 // ----- Look if present 1929 if (!isset($p_file_list[$key])) { 1930 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); 1931 1932 return PclZip::errorCode(); 1933 } 1934 } 1935 } 1936 } 1937 1938 // end foreach 1939 } 1940 1941 // ----- Return 1942 return $v_result; 1943 } 1944 // -------------------------------------------------------------------------------- 1945 1946 // -------------------------------------------------------------------------------- 1947 // Function : privFileDescrExpand() 1948 // Description : 1949 // This method look for each item of the list to see if its a file, a folder 1950 // or a string to be added as file. For any other type of files (link, other) 1951 // just ignore the item. 1952 // Then prepare the information that will be stored for that file. 1953 // When its a folder, expand the folder with all the files that are in that 1954 // folder (recursively). 1955 // Parameters : 1956 // Return Values : 1957 // 1 on success. 1958 // 0 on failure. 1959 // -------------------------------------------------------------------------------- 1960 public function privFileDescrExpand(&$p_filedescr_list, &$p_options) 1961 { 1962 $v_result = 1; 1963 1964 // ----- Create a result list 1965 $v_result_list = array(); 1966 1967 // ----- Look each entry 1968 for ($i = 0; $i < sizeof($p_filedescr_list); $i++) { 1969 1970 // ----- Get filedescr 1971 $v_descr = $p_filedescr_list[$i]; 1972 1973 // ----- Reduce the filename 1974 $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false); 1975 $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); 1976 1977 // ----- Look for real file or folder 1978 if (file_exists($v_descr['filename'])) { 1979 if (@is_file($v_descr['filename'])) { 1980 $v_descr['type'] = 'file'; 1981 } elseif (@is_dir($v_descr['filename'])) { 1982 $v_descr['type'] = 'folder'; 1983 } elseif (@is_link($v_descr['filename'])) { 1984 // skip 1985 continue; 1986 } else { 1987 // skip 1988 continue; 1989 } 1990 1991 // ----- Look for string added as file 1992 } elseif (isset($v_descr['content'])) { 1993 $v_descr['type'] = 'virtual_file'; 1994 1995 // ----- Missing file 1996 } else { 1997 // ----- Error log 1998 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist"); 1999 2000 // ----- Return 2001 return PclZip::errorCode(); 2002 } 2003 2004 // ----- Calculate the stored filename 2005 $this->privCalculateStoredFilename($v_descr, $p_options); 2006 2007 // ----- Add the descriptor in result list 2008 $v_result_list[sizeof($v_result_list)] = $v_descr; 2009 2010 // ----- Look for folder 2011 if ($v_descr['type'] == 'folder') { 2012 // ----- List of items in folder 2013 $v_dirlist_descr = array(); 2014 $v_dirlist_nb = 0; 2015 if ($v_folder_handler = @opendir($v_descr['filename'])) { 2016 while (($v_item_handler = @readdir($v_folder_handler)) !== false) { 2017 2018 // ----- Skip '.' and '..' 2019 if (($v_item_handler == '.') || ($v_item_handler == '..')) { 2020 continue; 2021 } 2022 2023 // ----- Compose the full filename 2024 $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler; 2025 2026 // ----- Look for different stored filename 2027 // Because the name of the folder was changed, the name of the 2028 // files/sub-folders also change 2029 if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { 2030 if ($v_descr['stored_filename'] != '') { 2031 $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler; 2032 } else { 2033 $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; 2034 } 2035 } 2036 2037 $v_dirlist_nb++; 2038 } 2039 2040 @closedir($v_folder_handler); 2041 } else { 2042 // TBC : unable to open folder in read mode 2043 } 2044 2045 // ----- Expand each element of the list 2046 if ($v_dirlist_nb != 0) { 2047 // ----- Expand 2048 if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { 2049 return $v_result; 2050 } 2051 2052 // ----- Concat the resulting list 2053 $v_result_list = array_merge($v_result_list, $v_dirlist_descr); 2054 } else { 2055 } 2056 2057 // ----- Free local array 2058 unset($v_dirlist_descr); 2059 } 2060 } 2061 2062 // ----- Get the result list 2063 $p_filedescr_list = $v_result_list; 2064 2065 // ----- Return 2066 return $v_result; 2067 } 2068 // -------------------------------------------------------------------------------- 2069 2070 // -------------------------------------------------------------------------------- 2071 // Function : privCreate() 2072 // Description : 2073 // Parameters : 2074 // Return Values : 2075 // -------------------------------------------------------------------------------- 2076 public function privCreate($p_filedescr_list, &$p_result_list, &$p_options) 2077 { 2078 $v_result = 1; 2079 $v_list_detail = array(); 2080 2081 // ----- Magic quotes trick 2082 $this->privDisableMagicQuotes(); 2083 2084 // ----- Open the file in write mode 2085 if (($v_result = $this->privOpenFd('wb')) != 1) { 2086 // ----- Return 2087 return $v_result; 2088 } 2089 2090 // ----- Add the list of files 2091 $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); 2092 2093 // ----- Close 2094 $this->privCloseFd(); 2095 2096 // ----- Magic quotes trick 2097 $this->privSwapBackMagicQuotes(); 2098 2099 // ----- Return 2100 return $v_result; 2101 } 2102 // -------------------------------------------------------------------------------- 2103 2104 // -------------------------------------------------------------------------------- 2105 // Function : privAdd() 2106 // Description : 2107 // Parameters : 2108 // Return Values : 2109 // -------------------------------------------------------------------------------- 2110 public function privAdd($p_filedescr_list, &$p_result_list, &$p_options) 2111 { 2112 $v_result = 1; 2113 $v_list_detail = array(); 2114 2115 // ----- Look if the archive exists or is empty 2116 if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) { 2117 2118 // ----- Do a create 2119 $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); 2120 2121 // ----- Return 2122 return $v_result; 2123 } 2124 // ----- Magic quotes trick 2125 $this->privDisableMagicQuotes(); 2126 2127 // ----- Open the zip file 2128 if (($v_result = $this->privOpenFd('rb')) != 1) { 2129 // ----- Magic quotes trick 2130 $this->privSwapBackMagicQuotes(); 2131 2132 // ----- Return 2133 return $v_result; 2134 } 2135 2136 // ----- Read the central directory informations 2137 $v_central_dir = array(); 2138 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 2139 $this->privCloseFd(); 2140 $this->privSwapBackMagicQuotes(); 2141 2142 return $v_result; 2143 } 2144 2145 // ----- Go to beginning of File 2146 @rewind($this->zip_fd); 2147 2148 // ----- Creates a temporay file 2149 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; 2150 2151 // ----- Open the temporary file in write mode 2152 if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { 2153 $this->privCloseFd(); 2154 $this->privSwapBackMagicQuotes(); 2155 2156 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); 2157 2158 // ----- Return 2159 return PclZip::errorCode(); 2160 } 2161 2162 // ----- Copy the files from the archive to the temporary file 2163 // TBC : Here I should better append the file and go back to erase the central dir 2164 $v_size = $v_central_dir['offset']; 2165 while ($v_size != 0) { 2166 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2167 $v_buffer = fread($this->zip_fd, $v_read_size); 2168 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 2169 $v_size -= $v_read_size; 2170 } 2171 2172 // ----- Swap the file descriptor 2173 // Here is a trick : I swap the temporary fd with the zip fd, in order to use 2174 // the following methods on the temporary fil and not the real archive 2175 $v_swap = $this->zip_fd; 2176 $this->zip_fd = $v_zip_temp_fd; 2177 $v_zip_temp_fd = $v_swap; 2178 2179 // ----- Add the files 2180 $v_header_list = array(); 2181 if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { 2182 fclose($v_zip_temp_fd); 2183 $this->privCloseFd(); 2184 @unlink($v_zip_temp_name); 2185 $this->privSwapBackMagicQuotes(); 2186 2187 // ----- Return 2188 return $v_result; 2189 } 2190 2191 // ----- Store the offset of the central dir 2192 $v_offset = @ftell($this->zip_fd); 2193 2194 // ----- Copy the block of file headers from the old archive 2195 $v_size = $v_central_dir['size']; 2196 while ($v_size != 0) { 2197 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2198 $v_buffer = @fread($v_zip_temp_fd, $v_read_size); 2199 @fwrite($this->zip_fd, $v_buffer, $v_read_size); 2200 $v_size -= $v_read_size; 2201 } 2202 2203 // ----- Create the Central Dir files header 2204 for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { 2205 // ----- Create the file header 2206 if ($v_header_list[$i]['status'] == 'ok') { 2207 if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { 2208 fclose($v_zip_temp_fd); 2209 $this->privCloseFd(); 2210 @unlink($v_zip_temp_name); 2211 $this->privSwapBackMagicQuotes(); 2212 2213 // ----- Return 2214 return $v_result; 2215 } 2216 $v_count++; 2217 } 2218 2219 // ----- Transform the header to a 'usable' info 2220 $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); 2221 } 2222 2223 // ----- Zip file comment 2224 $v_comment = $v_central_dir['comment']; 2225 if (isset($p_options[PCLZIP_OPT_COMMENT])) { 2226 $v_comment = $p_options[PCLZIP_OPT_COMMENT]; 2227 } 2228 if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { 2229 $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT]; 2230 } 2231 if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { 2232 $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment; 2233 } 2234 2235 // ----- Calculate the size of the central header 2236 $v_size = @ftell($this->zip_fd) - $v_offset; 2237 2238 // ----- Create the central dir footer 2239 if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) { 2240 // ----- Reset the file list 2241 unset($v_header_list); 2242 $this->privSwapBackMagicQuotes(); 2243 2244 // ----- Return 2245 return $v_result; 2246 } 2247 2248 // ----- Swap back the file descriptor 2249 $v_swap = $this->zip_fd; 2250 $this->zip_fd = $v_zip_temp_fd; 2251 $v_zip_temp_fd = $v_swap; 2252 2253 // ----- Close 2254 $this->privCloseFd(); 2255 2256 // ----- Close the temporary file 2257 @fclose($v_zip_temp_fd); 2258 2259 // ----- Magic quotes trick 2260 $this->privSwapBackMagicQuotes(); 2261 2262 // ----- Delete the zip file 2263 // TBC : I should test the result ... 2264 @unlink($this->zipname); 2265 2266 // ----- Rename the temporary file 2267 // TBC : I should test the result ... 2268 //@rename($v_zip_temp_name, $this->zipname); 2269 PclZipUtilRename($v_zip_temp_name, $this->zipname); 2270 2271 // ----- Return 2272 return $v_result; 2273 } 2274 // -------------------------------------------------------------------------------- 2275 2276 // -------------------------------------------------------------------------------- 2277 // Function : privOpenFd() 2278 // Description : 2279 // Parameters : 2280 // -------------------------------------------------------------------------------- 2281 public function privOpenFd($p_mode) 2282 { 2283 $v_result = 1; 2284 2285 // ----- Look if already open 2286 if ($this->zip_fd != 0) { 2287 // ----- Error log 2288 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open'); 2289 2290 // ----- Return 2291 return PclZip::errorCode(); 2292 } 2293 2294 // ----- Open the zip file 2295 if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) { 2296 // ----- Error log 2297 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode'); 2298 2299 // ----- Return 2300 return PclZip::errorCode(); 2301 } 2302 2303 // ----- Return 2304 return $v_result; 2305 } 2306 // -------------------------------------------------------------------------------- 2307 2308 // -------------------------------------------------------------------------------- 2309 // Function : privCloseFd() 2310 // Description : 2311 // Parameters : 2312 // -------------------------------------------------------------------------------- 2313 public function privCloseFd() 2314 { 2315 $v_result = 1; 2316 2317 if ($this->zip_fd != 0) { 2318 @fclose($this->zip_fd); 2319 } 2320 $this->zip_fd = 0; 2321 2322 // ----- Return 2323 return $v_result; 2324 } 2325 // -------------------------------------------------------------------------------- 2326 2327 // -------------------------------------------------------------------------------- 2328 // Function : privAddList() 2329 // Description : 2330 // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is 2331 // different from the real path of the file. This is usefull if you want to have PclTar 2332 // running in any directory, and memorize relative path from an other directory. 2333 // Parameters : 2334 // $p_list : An array containing the file or directory names to add in the tar 2335 // $p_result_list : list of added files with their properties (specially the status field) 2336 // $p_add_dir : Path to add in the filename path archived 2337 // $p_remove_dir : Path to remove in the filename path archived 2338 // Return Values : 2339 // -------------------------------------------------------------------------------- 2340 // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) 2341 public function privAddList($p_filedescr_list, &$p_result_list, &$p_options) 2342 { 2343 $v_result = 1; 2344 2345 // ----- Add the files 2346 $v_header_list = array(); 2347 if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { 2348 // ----- Return 2349 return $v_result; 2350 } 2351 2352 // ----- Store the offset of the central dir 2353 $v_offset = @ftell($this->zip_fd); 2354 2355 // ----- Create the Central Dir files header 2356 for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { 2357 // ----- Create the file header 2358 if ($v_header_list[$i]['status'] == 'ok') { 2359 if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { 2360 // ----- Return 2361 return $v_result; 2362 } 2363 $v_count++; 2364 } 2365 2366 // ----- Transform the header to a 'usable' info 2367 $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); 2368 } 2369 2370 // ----- Zip file comment 2371 $v_comment = ''; 2372 if (isset($p_options[PCLZIP_OPT_COMMENT])) { 2373 $v_comment = $p_options[PCLZIP_OPT_COMMENT]; 2374 } 2375 2376 // ----- Calculate the size of the central header 2377 $v_size = @ftell($this->zip_fd) - $v_offset; 2378 2379 // ----- Create the central dir footer 2380 if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) { 2381 // ----- Reset the file list 2382 unset($v_header_list); 2383 2384 // ----- Return 2385 return $v_result; 2386 } 2387 2388 // ----- Return 2389 return $v_result; 2390 } 2391 // -------------------------------------------------------------------------------- 2392 2393 // -------------------------------------------------------------------------------- 2394 // Function : privAddFileList() 2395 // Description : 2396 // Parameters : 2397 // $p_filedescr_list : An array containing the file description 2398 // or directory names to add in the zip 2399 // $p_result_list : list of added files with their properties (specially the status field) 2400 // Return Values : 2401 // -------------------------------------------------------------------------------- 2402 public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) 2403 { 2404 $v_result = 1; 2405 $v_header = array(); 2406 2407 // ----- Recuperate the current number of elt in list 2408 $v_nb = sizeof($p_result_list); 2409 2410 // ----- Loop on the files 2411 for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) { 2412 // ----- Format the filename 2413 $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); 2414 2415 // ----- Skip empty file names 2416 // TBC : Can this be possible ? not checked in DescrParseAtt ? 2417 if ($p_filedescr_list[$j]['filename'] == "") { 2418 continue; 2419 } 2420 2421 // ----- Check the filename 2422 if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) { 2423 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist"); 2424 2425 return PclZip::errorCode(); 2426 } 2427 2428 // ----- Look if it is a file or a dir with no all path remove option 2429 // or a dir with all its path removed 2430 // if ( (is_file($p_filedescr_list[$j]['filename'])) 2431 // || ( is_dir($p_filedescr_list[$j]['filename']) 2432 if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { 2433 2434 // ----- Add the file 2435 $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options); 2436 if ($v_result != 1) { 2437 return $v_result; 2438 } 2439 2440 // ----- Store the file infos 2441 $p_result_list[$v_nb++] = $v_header; 2442 } 2443 } 2444 2445 // ----- Return 2446 return $v_result; 2447 } 2448 // -------------------------------------------------------------------------------- 2449 2450 // -------------------------------------------------------------------------------- 2451 // Function : privAddFile() 2452 // Description : 2453 // Parameters : 2454 // Return Values : 2455 // -------------------------------------------------------------------------------- 2456 public function privAddFile($p_filedescr, &$p_header, &$p_options) 2457 { 2458 $v_result = 1; 2459 2460 // ----- Working variable 2461 $p_filename = $p_filedescr['filename']; 2462 2463 // TBC : Already done in the fileAtt check ... ? 2464 if ($p_filename == "") { 2465 // ----- Error log 2466 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); 2467 2468 // ----- Return 2469 return PclZip::errorCode(); 2470 } 2471 2472 // ----- Look for a stored different filename 2473 /* TBC : Removed 2474 if (isset($p_filedescr['stored_filename'])) { 2475 $v_stored_filename = $p_filedescr['stored_filename']; 2476 } else { 2477 $v_stored_filename = $p_filedescr['stored_filename']; 2478 } 2479 */ 2480 2481 // ----- Set the file properties 2482 clearstatcache(); 2483 $p_header['version'] = 20; 2484 $p_header['version_extracted'] = 10; 2485 $p_header['flag'] = 0; 2486 $p_header['compression'] = 0; 2487 $p_header['crc'] = 0; 2488 $p_header['compressed_size'] = 0; 2489 $p_header['filename_len'] = strlen($p_filename); 2490 $p_header['extra_len'] = 0; 2491 $p_header['disk'] = 0; 2492 $p_header['internal'] = 0; 2493 $p_header['offset'] = 0; 2494 $p_header['filename'] = $p_filename; 2495 // TBC : Removed $p_header['stored_filename'] = $v_stored_filename; 2496 $p_header['stored_filename'] = $p_filedescr['stored_filename']; 2497 $p_header['extra'] = ''; 2498 $p_header['status'] = 'ok'; 2499 $p_header['index'] = -1; 2500 2501 // ----- Look for regular file 2502 if ($p_filedescr['type'] == 'file') { 2503 $p_header['external'] = 0x00000000; 2504 $p_header['size'] = filesize($p_filename); 2505 2506 // ----- Look for regular folder 2507 } elseif ($p_filedescr['type'] == 'folder') { 2508 $p_header['external'] = 0x00000010; 2509 $p_header['mtime'] = filemtime($p_filename); 2510 $p_header['size'] = filesize($p_filename); 2511 2512 // ----- Look for virtual file 2513 } elseif ($p_filedescr['type'] == 'virtual_file') { 2514 $p_header['external'] = 0x00000000; 2515 $p_header['size'] = strlen($p_filedescr['content']); 2516 } 2517 2518 // ----- Look for filetime 2519 if (isset($p_filedescr['mtime'])) { 2520 $p_header['mtime'] = $p_filedescr['mtime']; 2521 } elseif ($p_filedescr['type'] == 'virtual_file') { 2522 $p_header['mtime'] = time(); 2523 } else { 2524 $p_header['mtime'] = filemtime($p_filename); 2525 } 2526 2527 // ------ Look for file comment 2528 if (isset($p_filedescr['comment'])) { 2529 $p_header['comment_len'] = strlen($p_filedescr['comment']); 2530 $p_header['comment'] = $p_filedescr['comment']; 2531 } else { 2532 $p_header['comment_len'] = 0; 2533 $p_header['comment'] = ''; 2534 } 2535 2536 // ----- Look for pre-add callback 2537 if (isset($p_options[PCLZIP_CB_PRE_ADD])) { 2538 2539 // ----- Generate a local information 2540 $v_local_header = array(); 2541 $this->privConvertHeader2FileInfo($p_header, $v_local_header); 2542 2543 // ----- Call the callback 2544 // Here I do not use call_user_func() because I need to send a reference to the 2545 // header. 2546 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); 2547 $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); 2548 if ($v_result == 0) { 2549 // ----- Change the file status 2550 $p_header['status'] = "skipped"; 2551 $v_result = 1; 2552 } 2553 2554 // ----- Update the informations 2555 // Only some fields can be modified 2556 if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { 2557 $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); 2558 } 2559 } 2560 2561 // ----- Look for empty stored filename 2562 if ($p_header['stored_filename'] == "") { 2563 $p_header['status'] = "filtered"; 2564 } 2565 2566 // ----- Check the path length 2567 if (strlen($p_header['stored_filename']) > 0xFF) { 2568 $p_header['status'] = 'filename_too_long'; 2569 } 2570 2571 // ----- Look if no error, or file not skipped 2572 if ($p_header['status'] == 'ok') { 2573 2574 // ----- Look for a file 2575 if ($p_filedescr['type'] == 'file') { 2576 // ----- Look for using temporary file to zip 2577 if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) { 2578 $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); 2579 if ($v_result < PCLZIP_ERR_NO_ERROR) { 2580 return $v_result; 2581 } 2582 2583 // ----- Use "in memory" zip algo 2584 } else { 2585 2586 // ----- Open the source file 2587 if (($v_file = @fopen($p_filename, "rb")) == 0) { 2588 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); 2589 2590 return PclZip::errorCode(); 2591 } 2592 2593 // ----- Read the file content 2594 $v_content = @fread($v_file, $p_header['size']); 2595 2596 // ----- Close the file 2597 @fclose($v_file); 2598 2599 // ----- Calculate the CRC 2600 $p_header['crc'] = @crc32($v_content); 2601 2602 // ----- Look for no compression 2603 if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { 2604 // ----- Set header parameters 2605 $p_header['compressed_size'] = $p_header['size']; 2606 $p_header['compression'] = 0; 2607 2608 // ----- Look for normal compression 2609 } else { 2610 // ----- Compress the content 2611 $v_content = @gzdeflate($v_content); 2612 2613 // ----- Set header parameters 2614 $p_header['compressed_size'] = strlen($v_content); 2615 $p_header['compression'] = 8; 2616 } 2617 2618 // ----- Call the header generation 2619 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2620 @fclose($v_file); 2621 2622 return $v_result; 2623 } 2624 2625 // ----- Write the compressed (or not) content 2626 @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); 2627 2628 } 2629 2630 // ----- Look for a virtual file (a file from string) 2631 } elseif ($p_filedescr['type'] == 'virtual_file') { 2632 2633 $v_content = $p_filedescr['content']; 2634 2635 // ----- Calculate the CRC 2636 $p_header['crc'] = @crc32($v_content); 2637 2638 // ----- Look for no compression 2639 if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { 2640 // ----- Set header parameters 2641 $p_header['compressed_size'] = $p_header['size']; 2642 $p_header['compression'] = 0; 2643 2644 // ----- Look for normal compression 2645 } else { 2646 // ----- Compress the content 2647 $v_content = @gzdeflate($v_content); 2648 2649 // ----- Set header parameters 2650 $p_header['compressed_size'] = strlen($v_content); 2651 $p_header['compression'] = 8; 2652 } 2653 2654 // ----- Call the header generation 2655 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2656 @fclose($v_file); 2657 2658 return $v_result; 2659 } 2660 2661 // ----- Write the compressed (or not) content 2662 @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); 2663 2664 // ----- Look for a directory 2665 } elseif ($p_filedescr['type'] == 'folder') { 2666 // ----- Look for directory last '/' 2667 if (@substr($p_header['stored_filename'], -1) != '/') { 2668 $p_header['stored_filename'] .= '/'; 2669 } 2670 2671 // ----- Set the file properties 2672 $p_header['size'] = 0; 2673 //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked 2674 $p_header['external'] = 0x00000010; // Value for a folder : to be checked 2675 2676 // ----- Call the header generation 2677 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2678 return $v_result; 2679 } 2680 } 2681 } 2682 2683 // ----- Look for post-add callback 2684 if (isset($p_options[PCLZIP_CB_POST_ADD])) { 2685 2686 // ----- Generate a local information 2687 $v_local_header = array(); 2688 $this->privConvertHeader2FileInfo($p_header, $v_local_header); 2689 2690 // ----- Call the callback 2691 // Here I do not use call_user_func() because I need to send a reference to the 2692 // header. 2693 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); 2694 $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); 2695 if ($v_result == 0) { 2696 // ----- Ignored 2697 $v_result = 1; 2698 } 2699 2700 // ----- Update the informations 2701 // Nothing can be modified 2702 } 2703 2704 // ----- Return 2705 return $v_result; 2706 } 2707 // -------------------------------------------------------------------------------- 2708 2709 // -------------------------------------------------------------------------------- 2710 // Function : privAddFileUsingTempFile() 2711 // Description : 2712 // Parameters : 2713 // Return Values : 2714 // -------------------------------------------------------------------------------- 2715 public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) 2716 { 2717 $v_result = PCLZIP_ERR_NO_ERROR; 2718 2719 // ----- Working variable 2720 $p_filename = $p_filedescr['filename']; 2721 2722 // ----- Open the source file 2723 if (($v_file = @fopen($p_filename, "rb")) == 0) { 2724 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); 2725 2726 return PclZip::errorCode(); 2727 } 2728 2729 // ----- Creates a compressed temporary file 2730 $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; 2731 if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { 2732 fclose($v_file); 2733 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); 2734 2735 return PclZip::errorCode(); 2736 } 2737 2738 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 2739 $v_size = filesize($p_filename); 2740 while ($v_size != 0) { 2741 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2742 $v_buffer = @fread($v_file, $v_read_size); 2743 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 2744 @gzputs($v_file_compressed, $v_buffer, $v_read_size); 2745 $v_size -= $v_read_size; 2746 } 2747 2748 // ----- Close the file 2749 @fclose($v_file); 2750 @gzclose($v_file_compressed); 2751 2752 // ----- Check the minimum file size 2753 if (filesize($v_gzip_temp_name) < 18) { 2754 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes'); 2755 2756 return PclZip::errorCode(); 2757 } 2758 2759 // ----- Extract the compressed attributes 2760 if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { 2761 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); 2762 2763 return PclZip::errorCode(); 2764 } 2765 2766 // ----- Read the gzip file header 2767 $v_binary_data = @fread($v_file_compressed, 10); 2768 $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); 2769 2770 // ----- Check some parameters 2771 $v_data_header['os'] = bin2hex($v_data_header['os']); 2772 2773 // ----- Read the gzip file footer 2774 @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8); 2775 $v_binary_data = @fread($v_file_compressed, 8); 2776 $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); 2777 2778 // ----- Set the attributes 2779 $p_header['compression'] = ord($v_data_header['cm']); 2780 //$p_header['mtime'] = $v_data_header['mtime']; 2781 $p_header['crc'] = $v_data_footer['crc']; 2782 $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18; 2783 2784 // ----- Close the file 2785 @fclose($v_file_compressed); 2786 2787 // ----- Call the header generation 2788 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2789 return $v_result; 2790 } 2791 2792 // ----- Add the compressed data 2793 if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { 2794 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); 2795 2796 return PclZip::errorCode(); 2797 } 2798 2799 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 2800 fseek($v_file_compressed, 10); 2801 $v_size = $p_header['compressed_size']; 2802 while ($v_size != 0) { 2803 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2804 $v_buffer = @fread($v_file_compressed, $v_read_size); 2805 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 2806 @fwrite($this->zip_fd, $v_buffer, $v_read_size); 2807 $v_size -= $v_read_size; 2808 } 2809 2810 // ----- Close the file 2811 @fclose($v_file_compressed); 2812 2813 // ----- Unlink the temporary file 2814 @unlink($v_gzip_temp_name); 2815 2816 // ----- Return 2817 return $v_result; 2818 } 2819 // -------------------------------------------------------------------------------- 2820 2821 // -------------------------------------------------------------------------------- 2822 // Function : privCalculateStoredFilename() 2823 // Description : 2824 // Based on file descriptor properties and global options, this method 2825 // calculate the filename that will be stored in the archive. 2826 // Parameters : 2827 // Return Values : 2828 // -------------------------------------------------------------------------------- 2829 public function privCalculateStoredFilename(&$p_filedescr, &$p_options) 2830 { 2831 $v_result = 1; 2832 2833 // ----- Working variables 2834 $p_filename = $p_filedescr['filename']; 2835 if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { 2836 $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; 2837 } else { 2838 $p_add_dir = ''; 2839 } 2840 if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { 2841 $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; 2842 } else { 2843 $p_remove_dir = ''; 2844 } 2845 if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { 2846 $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; 2847 } else { 2848 $p_remove_all_dir = 0; 2849 } 2850 2851 // ----- Look for full name change 2852 if (isset($p_filedescr['new_full_name'])) { 2853 // ----- Remove drive letter if any 2854 $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); 2855 2856 // ----- Look for path and/or short name change 2857 } else { 2858 2859 // ----- Look for short name change 2860 // Its when we cahnge just the filename but not the path 2861 if (isset($p_filedescr['new_short_name'])) { 2862 $v_path_info = pathinfo($p_filename); 2863 $v_dir = ''; 2864 if ($v_path_info['dirname'] != '') { 2865 $v_dir = $v_path_info['dirname'] . '/'; 2866 } 2867 $v_stored_filename = $v_dir . $p_filedescr['new_short_name']; 2868 } else { 2869 // ----- Calculate the stored filename 2870 $v_stored_filename = $p_filename; 2871 } 2872 2873 // ----- Look for all path to remove 2874 if ($p_remove_all_dir) { 2875 $v_stored_filename = basename($p_filename); 2876 2877 // ----- Look for partial path remove 2878 } elseif ($p_remove_dir != "") { 2879 if (substr($p_remove_dir, -1) != '/') { 2880 $p_remove_dir .= "/"; 2881 } 2882 2883 if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) { 2884 2885 if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) { 2886 $p_remove_dir = "./" . $p_remove_dir; 2887 } 2888 if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) { 2889 $p_remove_dir = substr($p_remove_dir, 2); 2890 } 2891 } 2892 2893 $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename); 2894 if ($v_compare > 0) { 2895 if ($v_compare == 2) { 2896 $v_stored_filename = ""; 2897 } else { 2898 $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir)); 2899 } 2900 } 2901 } 2902 2903 // ----- Remove drive letter if any 2904 $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); 2905 2906 // ----- Look for path to add 2907 if ($p_add_dir != "") { 2908 if (substr($p_add_dir, -1) == "/") { 2909 $v_stored_filename = $p_add_dir . $v_stored_filename; 2910 } else { 2911 $v_stored_filename = $p_add_dir . "/" . $v_stored_filename; 2912 } 2913 } 2914 } 2915 2916 // ----- Filename (reduce the path of stored name) 2917 $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); 2918 $p_filedescr['stored_filename'] = $v_stored_filename; 2919 2920 // ----- Return 2921 return $v_result; 2922 } 2923 // -------------------------------------------------------------------------------- 2924 2925 // -------------------------------------------------------------------------------- 2926 // Function : privWriteFileHeader() 2927 // Description : 2928 // Parameters : 2929 // Return Values : 2930 // -------------------------------------------------------------------------------- 2931 public function privWriteFileHeader(&$p_header) 2932 { 2933 $v_result = 1; 2934 2935 // ----- Store the offset position of the file 2936 $p_header['offset'] = ftell($this->zip_fd); 2937 2938 // ----- Transform UNIX mtime to DOS format mdate/mtime 2939 $v_date = getdate($p_header['mtime']); 2940 $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; 2941 $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; 2942 2943 // ----- Packed data 2944 $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']); 2945 2946 // ----- Write the first 148 bytes of the header in the archive 2947 fputs($this->zip_fd, $v_binary_data, 30); 2948 2949 // ----- Write the variable fields 2950 if (strlen($p_header['stored_filename']) != 0) { 2951 fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); 2952 } 2953 if ($p_header['extra_len'] != 0) { 2954 fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); 2955 } 2956 2957 // ----- Return 2958 return $v_result; 2959 } 2960 // -------------------------------------------------------------------------------- 2961 2962 // -------------------------------------------------------------------------------- 2963 // Function : privWriteCentralFileHeader() 2964 // Description : 2965 // Parameters : 2966 // Return Values : 2967 // -------------------------------------------------------------------------------- 2968 public function privWriteCentralFileHeader(&$p_header) 2969 { 2970 $v_result = 1; 2971 2972 // TBC 2973 //for (reset($p_header); $key = key($p_header); next($p_header)) { 2974 //} 2975 2976 // ----- Transform UNIX mtime to DOS format mdate/mtime 2977 $v_date = getdate($p_header['mtime']); 2978 $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; 2979 $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; 2980 2981 // ----- Packed data 2982 $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); 2983 2984 // ----- Write the 42 bytes of the header in the zip file 2985 fputs($this->zip_fd, $v_binary_data, 46); 2986 2987 // ----- Write the variable fields 2988 if (strlen($p_header['stored_filename']) != 0) { 2989 fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); 2990 } 2991 if ($p_header['extra_len'] != 0) { 2992 fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); 2993 } 2994 if ($p_header['comment_len'] != 0) { 2995 fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); 2996 } 2997 2998 // ----- Return 2999 return $v_result; 3000 } 3001 // -------------------------------------------------------------------------------- 3002 3003 // -------------------------------------------------------------------------------- 3004 // Function : privWriteCentralHeader() 3005 // Description : 3006 // Parameters : 3007 // Return Values : 3008 // -------------------------------------------------------------------------------- 3009 public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) 3010 { 3011 $v_result = 1; 3012 3013 // ----- Packed data 3014 $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); 3015 3016 // ----- Write the 22 bytes of the header in the zip file 3017 fputs($this->zip_fd, $v_binary_data, 22); 3018 3019 // ----- Write the variable fields 3020 if (strlen($p_comment) != 0) { 3021 fputs($this->zip_fd, $p_comment, strlen($p_comment)); 3022 } 3023 3024 // ----- Return 3025 return $v_result; 3026 } 3027 // -------------------------------------------------------------------------------- 3028 3029 // -------------------------------------------------------------------------------- 3030 // Function : privList() 3031 // Description : 3032 // Parameters : 3033 // Return Values : 3034 // -------------------------------------------------------------------------------- 3035 public function privList(&$p_list) 3036 { 3037 $v_result = 1; 3038 3039 // ----- Magic quotes trick 3040 $this->privDisableMagicQuotes(); 3041 3042 // ----- Open the zip file 3043 if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { 3044 // ----- Magic quotes trick 3045 $this->privSwapBackMagicQuotes(); 3046 3047 // ----- Error log 3048 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); 3049 3050 // ----- Return 3051 return PclZip::errorCode(); 3052 } 3053 3054 // ----- Read the central directory informations 3055 $v_central_dir = array(); 3056 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 3057 $this->privSwapBackMagicQuotes(); 3058 3059 return $v_result; 3060 } 3061 3062 // ----- Go to beginning of Central Dir 3063 @rewind($this->zip_fd); 3064 if (@fseek($this->zip_fd, $v_central_dir['offset'])) { 3065 $this->privSwapBackMagicQuotes(); 3066 3067 // ----- Error log 3068 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 3069 3070 // ----- Return 3071 return PclZip::errorCode(); 3072 } 3073 3074 // ----- Read each entry 3075 for ($i = 0; $i < $v_central_dir['entries']; $i++) { 3076 // ----- Read the file header 3077 if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { 3078 $this->privSwapBackMagicQuotes(); 3079 3080 return $v_result; 3081 } 3082 $v_header['index'] = $i; 3083 3084 // ----- Get the only interesting attributes 3085 $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); 3086 unset($v_header); 3087 } 3088 3089 // ----- Close the zip file 3090 $this->privCloseFd(); 3091 3092 // ----- Magic quotes trick 3093 $this->privSwapBackMagicQuotes(); 3094 3095 // ----- Return 3096 return $v_result; 3097 } 3098 // -------------------------------------------------------------------------------- 3099 3100 // -------------------------------------------------------------------------------- 3101 // Function : privConvertHeader2FileInfo() 3102 // Description : 3103 // This function takes the file informations from the central directory 3104 // entries and extract the interesting parameters that will be given back. 3105 // The resulting file infos are set in the array $p_info 3106 // $p_info['filename'] : Filename with full path. Given by user (add), 3107 // extracted in the filesystem (extract). 3108 // $p_info['stored_filename'] : Stored filename in the archive. 3109 // $p_info['size'] = Size of the file. 3110 // $p_info['compressed_size'] = Compressed size of the file. 3111 // $p_info['mtime'] = Last modification date of the file. 3112 // $p_info['comment'] = Comment associated with the file. 3113 // $p_info['folder'] = true/false : indicates if the entry is a folder or not. 3114 // $p_info['status'] = status of the action on the file. 3115 // $p_info['crc'] = CRC of the file content. 3116 // Parameters : 3117 // Return Values : 3118 // -------------------------------------------------------------------------------- 3119 public function privConvertHeader2FileInfo($p_header, &$p_info) 3120 { 3121 $v_result = 1; 3122 3123 // ----- Get the interesting attributes 3124 $v_temp_path = PclZipUtilPathReduction($p_header['filename']); 3125 $p_info['filename'] = $v_temp_path; 3126 $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); 3127 $p_info['stored_filename'] = $v_temp_path; 3128 $p_info['size'] = $p_header['size']; 3129 $p_info['compressed_size'] = $p_header['compressed_size']; 3130 $p_info['mtime'] = $p_header['mtime']; 3131 $p_info['comment'] = $p_header['comment']; 3132 $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010); 3133 $p_info['index'] = $p_header['index']; 3134 $p_info['status'] = $p_header['status']; 3135 $p_info['crc'] = $p_header['crc']; 3136 3137 // ----- Return 3138 return $v_result; 3139 } 3140 // -------------------------------------------------------------------------------- 3141 3142 // -------------------------------------------------------------------------------- 3143 // Function : privExtractByRule() 3144 // Description : 3145 // Extract a file or directory depending of rules (by index, by name, ...) 3146 // Parameters : 3147 // $p_file_list : An array where will be placed the properties of each 3148 // extracted file 3149 // $p_path : Path to add while writing the extracted files 3150 // $p_remove_path : Path to remove (from the file memorized path) while writing the 3151 // extracted files. If the path does not match the file path, 3152 // the file is extracted with its memorized path. 3153 // $p_remove_path does not apply to 'list' mode. 3154 // $p_path and $p_remove_path are commulative. 3155 // Return Values : 3156 // 1 on success,0 or less on error (see error code list) 3157 // -------------------------------------------------------------------------------- 3158 public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) 3159 { 3160 $v_result = 1; 3161 3162 // ----- Magic quotes trick 3163 $this->privDisableMagicQuotes(); 3164 3165 // ----- Check the path 3166 if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2) != ":/"))) { 3167 $p_path = "./" . $p_path; 3168 } 3169 3170 // ----- Reduce the path last (and duplicated) '/' 3171 if (($p_path != "./") && ($p_path != "/")) { 3172 // ----- Look for the path end '/' 3173 while (substr($p_path, -1) == "/") { 3174 $p_path = substr($p_path, 0, strlen($p_path) - 1); 3175 } 3176 } 3177 3178 // ----- Look for path to remove format (should end by /) 3179 if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { 3180 $p_remove_path .= '/'; 3181 } 3182 $p_remove_path_size = strlen($p_remove_path); 3183 3184 // ----- Open the zip file 3185 if (($v_result = $this->privOpenFd('rb')) != 1) { 3186 $this->privSwapBackMagicQuotes(); 3187 3188 return $v_result; 3189 } 3190 3191 // ----- Read the central directory informations 3192 $v_central_dir = array(); 3193 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 3194 // ----- Close the zip file 3195 $this->privCloseFd(); 3196 $this->privSwapBackMagicQuotes(); 3197 3198 return $v_result; 3199 } 3200 3201 // ----- Start at beginning of Central Dir 3202 $v_pos_entry = $v_central_dir['offset']; 3203 3204 // ----- Read each entry 3205 $j_start = 0; 3206 for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { 3207 3208 // ----- Read next Central dir entry 3209 @rewind($this->zip_fd); 3210 if (@fseek($this->zip_fd, $v_pos_entry)) { 3211 // ----- Close the zip file 3212 $this->privCloseFd(); 3213 $this->privSwapBackMagicQuotes(); 3214 3215 // ----- Error log 3216 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 3217 3218 // ----- Return 3219 return PclZip::errorCode(); 3220 } 3221 3222 // ----- Read the file header 3223 $v_header = array(); 3224 if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { 3225 // ----- Close the zip file 3226 $this->privCloseFd(); 3227 $this->privSwapBackMagicQuotes(); 3228 3229 return $v_result; 3230 } 3231 3232 // ----- Store the index 3233 $v_header['index'] = $i; 3234 3235 // ----- Store the file position 3236 $v_pos_entry = ftell($this->zip_fd); 3237 3238 // ----- Look for the specific extract rules 3239 $v_extract = false; 3240 3241 // ----- Look for extract by name rule 3242 if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { 3243 3244 // ----- Look if the filename is in the list 3245 for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { 3246 3247 // ----- Look for a directory 3248 if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { 3249 3250 // ----- Look if the directory is in the filename path 3251 if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { 3252 $v_extract = true; 3253 } 3254 3255 // ----- Look for a filename 3256 } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { 3257 $v_extract = true; 3258 } 3259 } 3260 // ----- Look for extract by ereg rule 3261 // ereg() is deprecated with PHP 5.3 3262 /* 3263 elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) 3264 && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { 3265 3266 if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { 3267 $v_extract = true; 3268 } 3269 } 3270 */ 3271 3272 // ----- Look for extract by preg rule 3273 } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { 3274 3275 if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { 3276 $v_extract = true; 3277 } 3278 3279 // ----- Look for extract by index rule 3280 } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { 3281 3282 // ----- Look if the index is in the list 3283 for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { 3284 3285 if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { 3286 $v_extract = true; 3287 } 3288 if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { 3289 $j_start = $j + 1; 3290 } 3291 3292 if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { 3293 break; 3294 } 3295 } 3296 3297 // ----- Look for no rule, which means extract all the archive 3298 } else { 3299 $v_extract = true; 3300 } 3301 3302 // ----- Check compression method 3303 if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) { 3304 $v_header['status'] = 'unsupported_compression'; 3305 3306 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3307 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3308 3309 $this->privSwapBackMagicQuotes(); 3310 3311 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '" . $v_header['stored_filename'] . "' is " . "compressed by an unsupported compression " . "method (" . $v_header['compression'] . ") "); 3312 3313 return PclZip::errorCode(); 3314 } 3315 } 3316 3317 // ----- Check encrypted files 3318 if (($v_extract) && (($v_header['flag'] & 1) == 1)) { 3319 $v_header['status'] = 'unsupported_encryption'; 3320 3321 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3322 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3323 3324 $this->privSwapBackMagicQuotes(); 3325 3326 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for " . " filename '" . $v_header['stored_filename'] . "'"); 3327 3328 return PclZip::errorCode(); 3329 } 3330 } 3331 3332 // ----- Look for real extraction 3333 if (($v_extract) && ($v_header['status'] != 'ok')) { 3334 $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]); 3335 if ($v_result != 1) { 3336 $this->privCloseFd(); 3337 $this->privSwapBackMagicQuotes(); 3338 3339 return $v_result; 3340 } 3341 3342 $v_extract = false; 3343 } 3344 3345 // ----- Look for real extraction 3346 if ($v_extract) { 3347 3348 // ----- Go to the file position 3349 @rewind($this->zip_fd); 3350 if (@fseek($this->zip_fd, $v_header['offset'])) { 3351 // ----- Close the zip file 3352 $this->privCloseFd(); 3353 3354 $this->privSwapBackMagicQuotes(); 3355 3356 // ----- Error log 3357 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 3358 3359 // ----- Return 3360 return PclZip::errorCode(); 3361 } 3362 3363 // ----- Look for extraction as string 3364 if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { 3365 3366 $v_string = ''; 3367 3368 // ----- Extracting the file 3369 $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); 3370 if ($v_result1 < 1) { 3371 $this->privCloseFd(); 3372 $this->privSwapBackMagicQuotes(); 3373 3374 return $v_result1; 3375 } 3376 3377 // ----- Get the only interesting attributes 3378 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) { 3379 // ----- Close the zip file 3380 $this->privCloseFd(); 3381 $this->privSwapBackMagicQuotes(); 3382 3383 return $v_result; 3384 } 3385 3386 // ----- Set the file content 3387 $p_file_list[$v_nb_extracted]['content'] = $v_string; 3388 3389 // ----- Next extracted file 3390 $v_nb_extracted++; 3391 3392 // ----- Look for user callback abort 3393 if ($v_result1 == 2) { 3394 break; 3395 } 3396 3397 // ----- Look for extraction in standard output 3398 } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { 3399 // ----- Extracting the file in standard output 3400 $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); 3401 if ($v_result1 < 1) { 3402 $this->privCloseFd(); 3403 $this->privSwapBackMagicQuotes(); 3404 3405 return $v_result1; 3406 } 3407 3408 // ----- Get the only interesting attributes 3409 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { 3410 $this->privCloseFd(); 3411 $this->privSwapBackMagicQuotes(); 3412 3413 return $v_result; 3414 } 3415 3416 // ----- Look for user callback abort 3417 if ($v_result1 == 2) { 3418 break; 3419 } 3420 3421 // ----- Look for normal extraction 3422 } else { 3423 // ----- Extracting the file 3424 $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options); 3425 if ($v_result1 < 1) { 3426 $this->privCloseFd(); 3427 $this->privSwapBackMagicQuotes(); 3428 3429 return $v_result1; 3430 } 3431 3432 // ----- Get the only interesting attributes 3433 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { 3434 // ----- Close the zip file 3435 $this->privCloseFd(); 3436 $this->privSwapBackMagicQuotes(); 3437 3438 return $v_result; 3439 } 3440 3441 // ----- Look for user callback abort 3442 if ($v_result1 == 2) { 3443 break; 3444 } 3445 } 3446 } 3447 } 3448 3449 // ----- Close the zip file 3450 $this->privCloseFd(); 3451 $this->privSwapBackMagicQuotes(); 3452 3453 // ----- Return 3454 return $v_result; 3455 } 3456 // -------------------------------------------------------------------------------- 3457 3458 // -------------------------------------------------------------------------------- 3459 // Function : privExtractFile() 3460 // Description : 3461 // Parameters : 3462 // Return Values : 3463 // 3464 // 1 : ... ? 3465 // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback 3466 // -------------------------------------------------------------------------------- 3467 public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) 3468 { 3469 $v_result = 1; 3470 3471 // ----- Read the file header 3472 if (($v_result = $this->privReadFileHeader($v_header)) != 1) { 3473 // ----- Return 3474 return $v_result; 3475 } 3476 3477 // ----- Check that the file header is coherent with $p_entry info 3478 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { 3479 // TBC 3480 } 3481 3482 // ----- Look for all path to remove 3483 if ($p_remove_all_path == true) { 3484 // ----- Look for folder entry that not need to be extracted 3485 if (($p_entry['external'] & 0x00000010) == 0x00000010) { 3486 3487 $p_entry['status'] = "filtered"; 3488 3489 return $v_result; 3490 } 3491 3492 // ----- Get the basename of the path 3493 $p_entry['filename'] = basename($p_entry['filename']); 3494 3495 // ----- Look for path to remove 3496 } elseif ($p_remove_path != "") { 3497 if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) { 3498 3499 // ----- Change the file status 3500 $p_entry['status'] = "filtered"; 3501 3502 // ----- Return 3503 return $v_result; 3504 } 3505 3506 $p_remove_path_size = strlen($p_remove_path); 3507 if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) { 3508 3509 // ----- Remove the path 3510 $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); 3511 3512 } 3513 } 3514 3515 // ----- Add the path 3516 if ($p_path != '') { 3517 $p_entry['filename'] = $p_path . "/" . $p_entry['filename']; 3518 } 3519 3520 // ----- Check a base_dir_restriction 3521 if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { 3522 $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']); 3523 if ($v_inclusion == 0) { 3524 3525 PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '" . $p_entry['filename'] . "' is " . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); 3526 3527 return PclZip::errorCode(); 3528 } 3529 } 3530 3531 // ----- Look for pre-extract callback 3532 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { 3533 3534 // ----- Generate a local information 3535 $v_local_header = array(); 3536 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3537 3538 // ----- Call the callback 3539 // Here I do not use call_user_func() because I need to send a reference to the 3540 // header. 3541 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); 3542 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); 3543 if ($v_result == 0) { 3544 // ----- Change the file status 3545 $p_entry['status'] = "skipped"; 3546 $v_result = 1; 3547 } 3548 3549 // ----- Look for abort result 3550 if ($v_result == 2) { 3551 // ----- This status is internal and will be changed in 'skipped' 3552 $p_entry['status'] = "aborted"; 3553 $v_result = PCLZIP_ERR_USER_ABORTED; 3554 } 3555 3556 // ----- Update the informations 3557 // Only some fields can be modified 3558 $p_entry['filename'] = $v_local_header['filename']; 3559 } 3560 3561 // ----- Look if extraction should be done 3562 if ($p_entry['status'] == 'ok') { 3563 3564 // ----- Look for specific actions while the file exist 3565 if (file_exists($p_entry['filename'])) { 3566 3567 // ----- Look if file is a directory 3568 if (is_dir($p_entry['filename'])) { 3569 3570 // ----- Change the file status 3571 $p_entry['status'] = "already_a_directory"; 3572 3573 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3574 // For historical reason first PclZip implementation does not stop 3575 // when this kind of error occurs. 3576 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3577 3578 PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '" . $p_entry['filename'] . "' is " . "already used by an existing directory"); 3579 3580 return PclZip::errorCode(); 3581 } 3582 3583 // ----- Look if file is write protected 3584 } elseif (!is_writeable($p_entry['filename'])) { 3585 3586 // ----- Change the file status 3587 $p_entry['status'] = "write_protected"; 3588 3589 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3590 // For historical reason first PclZip implementation does not stop 3591 // when this kind of error occurs. 3592 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3593 3594 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '" . $p_entry['filename'] . "' exists " . "and is write protected"); 3595 3596 return PclZip::errorCode(); 3597 } 3598 3599 // ----- Look if the extracted file is older 3600 } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) { 3601 // ----- Change the file status 3602 if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) { 3603 } else { 3604 $p_entry['status'] = "newer_exist"; 3605 3606 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3607 // For historical reason first PclZip implementation does not stop 3608 // when this kind of error occurs. 3609 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3610 3611 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '" . $p_entry['filename'] . "' exists " . "and option PCLZIP_OPT_REPLACE_NEWER is not selected"); 3612 3613 return PclZip::errorCode(); 3614 } 3615 } 3616 } else { 3617 } 3618 3619 // ----- Check the directory availability and create it if necessary 3620 } else { 3621 if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) { 3622 $v_dir_to_check = $p_entry['filename']; 3623 } elseif (!strstr($p_entry['filename'], "/")) { 3624 $v_dir_to_check = ""; 3625 } else { 3626 $v_dir_to_check = dirname($p_entry['filename']); 3627 } 3628 3629 if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) { 3630 3631 // ----- Change the file status 3632 $p_entry['status'] = "path_creation_fail"; 3633 3634 // ----- Return 3635 //return $v_result; 3636 $v_result = 1; 3637 } 3638 } 3639 } 3640 3641 // ----- Look if extraction should be done 3642 if ($p_entry['status'] == 'ok') { 3643 3644 // ----- Do the extraction (if not a folder) 3645 if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { 3646 // ----- Look for not compressed file 3647 if ($p_entry['compression'] == 0) { 3648 3649 // ----- Opening destination file 3650 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 3651 3652 // ----- Change the file status 3653 $p_entry['status'] = "write_error"; 3654 3655 // ----- Return 3656 return $v_result; 3657 } 3658 3659 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 3660 $v_size = $p_entry['compressed_size']; 3661 while ($v_size != 0) { 3662 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 3663 $v_buffer = @fread($this->zip_fd, $v_read_size); 3664 /* Try to speed up the code 3665 $v_binary_data = pack('a'.$v_read_size, $v_buffer); 3666 @fwrite($v_dest_file, $v_binary_data, $v_read_size); 3667 */ 3668 @fwrite($v_dest_file, $v_buffer, $v_read_size); 3669 $v_size -= $v_read_size; 3670 } 3671 3672 // ----- Closing the destination file 3673 fclose($v_dest_file); 3674 3675 // ----- Change the file mtime 3676 touch($p_entry['filename'], $p_entry['mtime']); 3677 3678 } else { 3679 // ----- TBC 3680 // Need to be finished 3681 if (($p_entry['flag'] & 1) == 1) { 3682 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.'); 3683 3684 return PclZip::errorCode(); 3685 } 3686 3687 // ----- Look for using temporary file to unzip 3688 if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) { 3689 $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); 3690 if ($v_result < PCLZIP_ERR_NO_ERROR) { 3691 return $v_result; 3692 } 3693 3694 // ----- Look for extract in memory 3695 } else { 3696 3697 // ----- Read the compressed file in a buffer (one shot) 3698 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); 3699 3700 // ----- Decompress the file 3701 $v_file_content = @gzinflate($v_buffer); 3702 unset($v_buffer); 3703 if ($v_file_content === false) { 3704 3705 // ----- Change the file status 3706 // TBC 3707 $p_entry['status'] = "error"; 3708 3709 return $v_result; 3710 } 3711 3712 // ----- Opening destination file 3713 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 3714 3715 // ----- Change the file status 3716 $p_entry['status'] = "write_error"; 3717 3718 return $v_result; 3719 } 3720 3721 // ----- Write the uncompressed data 3722 @fwrite($v_dest_file, $v_file_content, $p_entry['size']); 3723 unset($v_file_content); 3724 3725 // ----- Closing the destination file 3726 @fclose($v_dest_file); 3727 3728 } 3729 3730 // ----- Change the file mtime 3731 @touch($p_entry['filename'], $p_entry['mtime']); 3732 } 3733 3734 // ----- Look for chmod option 3735 if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { 3736 3737 // ----- Change the mode of the file 3738 @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); 3739 } 3740 3741 } 3742 } 3743 3744 // ----- Change abort status 3745 if ($p_entry['status'] == "aborted") { 3746 $p_entry['status'] = "skipped"; 3747 3748 // ----- Look for post-extract callback 3749 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { 3750 3751 // ----- Generate a local information 3752 $v_local_header = array(); 3753 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3754 3755 // ----- Call the callback 3756 // Here I do not use call_user_func() because I need to send a reference to the 3757 // header. 3758 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); 3759 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); 3760 3761 // ----- Look for abort result 3762 if ($v_result == 2) { 3763 $v_result = PCLZIP_ERR_USER_ABORTED; 3764 } 3765 } 3766 3767 // ----- Return 3768 return $v_result; 3769 } 3770 // -------------------------------------------------------------------------------- 3771 3772 // -------------------------------------------------------------------------------- 3773 // Function : privExtractFileUsingTempFile() 3774 // Description : 3775 // Parameters : 3776 // Return Values : 3777 // -------------------------------------------------------------------------------- 3778 public function privExtractFileUsingTempFile(&$p_entry, &$p_options) 3779 { 3780 $v_result = 1; 3781 3782 // ----- Creates a temporary file 3783 $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; 3784 if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { 3785 fclose($v_file); 3786 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); 3787 3788 return PclZip::errorCode(); 3789 } 3790 3791 // ----- Write gz file format header 3792 $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); 3793 @fwrite($v_dest_file, $v_binary_data, 10); 3794 3795 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 3796 $v_size = $p_entry['compressed_size']; 3797 while ($v_size != 0) { 3798 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 3799 $v_buffer = @fread($this->zip_fd, $v_read_size); 3800 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 3801 @fwrite($v_dest_file, $v_buffer, $v_read_size); 3802 $v_size -= $v_read_size; 3803 } 3804 3805 // ----- Write gz file format footer 3806 $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); 3807 @fwrite($v_dest_file, $v_binary_data, 8); 3808 3809 // ----- Close the temporary file 3810 @fclose($v_dest_file); 3811 3812 // ----- Opening destination file 3813 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 3814 $p_entry['status'] = "write_error"; 3815 3816 return $v_result; 3817 } 3818 3819 // ----- Open the temporary gz file 3820 if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { 3821 @fclose($v_dest_file); 3822 $p_entry['status'] = "read_error"; 3823 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); 3824 3825 return PclZip::errorCode(); 3826 } 3827 3828 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 3829 $v_size = $p_entry['size']; 3830 while ($v_size != 0) { 3831 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 3832 $v_buffer = @gzread($v_src_file, $v_read_size); 3833 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 3834 @fwrite($v_dest_file, $v_buffer, $v_read_size); 3835 $v_size -= $v_read_size; 3836 } 3837 @fclose($v_dest_file); 3838 @gzclose($v_src_file); 3839 3840 // ----- Delete the temporary file 3841 @unlink($v_gzip_temp_name); 3842 3843 // ----- Return 3844 return $v_result; 3845 } 3846 // -------------------------------------------------------------------------------- 3847 3848 // -------------------------------------------------------------------------------- 3849 // Function : privExtractFileInOutput() 3850 // Description : 3851 // Parameters : 3852 // Return Values : 3853 // -------------------------------------------------------------------------------- 3854 public function privExtractFileInOutput(&$p_entry, &$p_options) 3855 { 3856 $v_result = 1; 3857 3858 // ----- Read the file header 3859 if (($v_result = $this->privReadFileHeader($v_header)) != 1) { 3860 return $v_result; 3861 } 3862 3863 // ----- Check that the file header is coherent with $p_entry info 3864 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { 3865 // TBC 3866 } 3867 3868 // ----- Look for pre-extract callback 3869 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { 3870 3871 // ----- Generate a local information 3872 $v_local_header = array(); 3873 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3874 3875 // ----- Call the callback 3876 // Here I do not use call_user_func() because I need to send a reference to the 3877 // header. 3878 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); 3879 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); 3880 if ($v_result == 0) { 3881 // ----- Change the file status 3882 $p_entry['status'] = "skipped"; 3883 $v_result = 1; 3884 } 3885 3886 // ----- Look for abort result 3887 if ($v_result == 2) { 3888 // ----- This status is internal and will be changed in 'skipped' 3889 $p_entry['status'] = "aborted"; 3890 $v_result = PCLZIP_ERR_USER_ABORTED; 3891 } 3892 3893 // ----- Update the informations 3894 // Only some fields can be modified 3895 $p_entry['filename'] = $v_local_header['filename']; 3896 } 3897 3898 // ----- Trace 3899 3900 // ----- Look if extraction should be done 3901 if ($p_entry['status'] == 'ok') { 3902 3903 // ----- Do the extraction (if not a folder) 3904 if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { 3905 // ----- Look for not compressed file 3906 if ($p_entry['compressed_size'] == $p_entry['size']) { 3907 3908 // ----- Read the file in a buffer (one shot) 3909 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); 3910 3911 // ----- Send the file to the output 3912 echo $v_buffer; 3913 unset($v_buffer); 3914 } else { 3915 3916 // ----- Read the compressed file in a buffer (one shot) 3917 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); 3918 3919 // ----- Decompress the file 3920 $v_file_content = gzinflate($v_buffer); 3921 unset($v_buffer); 3922 3923 // ----- Send the file to the output 3924 echo $v_file_content; 3925 unset($v_file_content); 3926 } 3927 } 3928 } 3929 3930 // ----- Change abort status 3931 if ($p_entry['status'] == "aborted") { 3932 $p_entry['status'] = "skipped"; 3933 3934 // ----- Look for post-extract callback 3935 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { 3936 3937 // ----- Generate a local information 3938 $v_local_header = array(); 3939 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3940 3941 // ----- Call the callback 3942 // Here I do not use call_user_func() because I need to send a reference to the 3943 // header. 3944 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); 3945 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); 3946 3947 // ----- Look for abort result 3948 if ($v_result == 2) { 3949 $v_result = PCLZIP_ERR_USER_ABORTED; 3950 } 3951 } 3952 3953 return $v_result; 3954 } 3955 // -------------------------------------------------------------------------------- 3956 3957 // -------------------------------------------------------------------------------- 3958 // Function : privExtractFileAsString() 3959 // Description : 3960 // Parameters : 3961 // Return Values : 3962 // -------------------------------------------------------------------------------- 3963 public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) 3964 { 3965 $v_result = 1; 3966 3967 // ----- Read the file header 3968 $v_header = array(); 3969 if (($v_result = $this->privReadFileHeader($v_header)) != 1) { 3970 // ----- Return 3971 return $v_result; 3972 } 3973 3974 // ----- Check that the file header is coherent with $p_entry info 3975 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { 3976 // TBC 3977 } 3978 3979 // ----- Look for pre-extract callback 3980 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { 3981 3982 // ----- Generate a local information 3983 $v_local_header = array(); 3984 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3985 3986 // ----- Call the callback 3987 // Here I do not use call_user_func() because I need to send a reference to the 3988 // header. 3989 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); 3990 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); 3991 if ($v_result == 0) { 3992 // ----- Change the file status 3993 $p_entry['status'] = "skipped"; 3994 $v_result = 1; 3995 } 3996 3997 // ----- Look for abort result 3998 if ($v_result == 2) { 3999 // ----- This status is internal and will be changed in 'skipped' 4000 $p_entry['status'] = "aborted"; 4001 $v_result = PCLZIP_ERR_USER_ABORTED; 4002 } 4003 4004 // ----- Update the informations 4005 // Only some fields can be modified 4006 $p_entry['filename'] = $v_local_header['filename']; 4007 } 4008 4009 // ----- Look if extraction should be done 4010 if ($p_entry['status'] == 'ok') { 4011 4012 // ----- Do the extraction (if not a folder) 4013 if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { 4014 // ----- Look for not compressed file 4015 // if ($p_entry['compressed_size'] == $p_entry['size']) 4016 if ($p_entry['compression'] == 0) { 4017 4018 // ----- Reading the file 4019 $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); 4020 } else { 4021 4022 // ----- Reading the file 4023 $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); 4024 4025 // ----- Decompress the file 4026 if (($p_string = @gzinflate($v_data)) === false) { 4027 // TBC 4028 } 4029 } 4030 4031 // ----- Trace 4032 } else { 4033 // TBC : error : can not extract a folder in a string 4034 } 4035 4036 } 4037 4038 // ----- Change abort status 4039 if ($p_entry['status'] == "aborted") { 4040 $p_entry['status'] = "skipped"; 4041 4042 // ----- Look for post-extract callback 4043 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { 4044 4045 // ----- Generate a local information 4046 $v_local_header = array(); 4047 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 4048 4049 // ----- Swap the content to header 4050 $v_local_header['content'] = $p_string; 4051 $p_string = ''; 4052 4053 // ----- Call the callback 4054 // Here I do not use call_user_func() because I need to send a reference to the 4055 // header. 4056 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); 4057 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); 4058 4059 // ----- Swap back the content to header 4060 $p_string = $v_local_header['content']; 4061 unset($v_local_header['content']); 4062 4063 // ----- Look for abort result 4064 if ($v_result == 2) { 4065 $v_result = PCLZIP_ERR_USER_ABORTED; 4066 } 4067 } 4068 4069 // ----- Return 4070 return $v_result; 4071 } 4072 // -------------------------------------------------------------------------------- 4073 4074 // -------------------------------------------------------------------------------- 4075 // Function : privReadFileHeader() 4076 // Description : 4077 // Parameters : 4078 // Return Values : 4079 // -------------------------------------------------------------------------------- 4080 public function privReadFileHeader(&$p_header) 4081 { 4082 $v_result = 1; 4083 4084 // ----- Read the 4 bytes signature 4085 $v_binary_data = @fread($this->zip_fd, 4); 4086 $v_data = unpack('Vid', $v_binary_data); 4087 4088 // ----- Check signature 4089 if ($v_data['id'] != 0x04034b50) { 4090 4091 // ----- Error log 4092 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); 4093 4094 // ----- Return 4095 return PclZip::errorCode(); 4096 } 4097 4098 // ----- Read the first 42 bytes of the header 4099 $v_binary_data = fread($this->zip_fd, 26); 4100 4101 // ----- Look for invalid block size 4102 if (strlen($v_binary_data) != 26) { 4103 $p_header['filename'] = ""; 4104 $p_header['status'] = "invalid_header"; 4105 4106 // ----- Error log 4107 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); 4108 4109 // ----- Return 4110 return PclZip::errorCode(); 4111 } 4112 4113 // ----- Extract the values 4114 $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); 4115 4116 // ----- Get filename 4117 $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); 4118 4119 // ----- Get extra_fields 4120 if ($v_data['extra_len'] != 0) { 4121 $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); 4122 } else { 4123 $p_header['extra'] = ''; 4124 } 4125 4126 // ----- Extract properties 4127 $p_header['version_extracted'] = $v_data['version']; 4128 $p_header['compression'] = $v_data['compression']; 4129 $p_header['size'] = $v_data['size']; 4130 $p_header['compressed_size'] = $v_data['compressed_size']; 4131 $p_header['crc'] = $v_data['crc']; 4132 $p_header['flag'] = $v_data['flag']; 4133 $p_header['filename_len'] = $v_data['filename_len']; 4134 4135 // ----- Recuperate date in UNIX format 4136 $p_header['mdate'] = $v_data['mdate']; 4137 $p_header['mtime'] = $v_data['mtime']; 4138 if ($p_header['mdate'] && $p_header['mtime']) { 4139 // ----- Extract time 4140 $v_hour = ($p_header['mtime'] & 0xF800) >> 11; 4141 $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; 4142 $v_seconde = ($p_header['mtime'] & 0x001F) * 2; 4143 4144 // ----- Extract date 4145 $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; 4146 $v_month = ($p_header['mdate'] & 0x01E0) >> 5; 4147 $v_day = $p_header['mdate'] & 0x001F; 4148 4149 // ----- Get UNIX date format 4150 $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); 4151 4152 } else { 4153 $p_header['mtime'] = time(); 4154 } 4155 4156 // TBC 4157 //for (reset($v_data); $key = key($v_data); next($v_data)) { 4158 //} 4159 4160 // ----- Set the stored filename 4161 $p_header['stored_filename'] = $p_header['filename']; 4162 4163 // ----- Set the status field 4164 $p_header['status'] = "ok"; 4165 4166 // ----- Return 4167 return $v_result; 4168 } 4169 // -------------------------------------------------------------------------------- 4170 4171 // -------------------------------------------------------------------------------- 4172 // Function : privReadCentralFileHeader() 4173 // Description : 4174 // Parameters : 4175 // Return Values : 4176 // -------------------------------------------------------------------------------- 4177 public function privReadCentralFileHeader(&$p_header) 4178 { 4179 $v_result = 1; 4180 4181 // ----- Read the 4 bytes signature 4182 $v_binary_data = @fread($this->zip_fd, 4); 4183 $v_data = unpack('Vid', $v_binary_data); 4184 4185 // ----- Check signature 4186 if ($v_data['id'] != 0x02014b50) { 4187 4188 // ----- Error log 4189 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); 4190 4191 // ----- Return 4192 return PclZip::errorCode(); 4193 } 4194 4195 // ----- Read the first 42 bytes of the header 4196 $v_binary_data = fread($this->zip_fd, 42); 4197 4198 // ----- Look for invalid block size 4199 if (strlen($v_binary_data) != 42) { 4200 $p_header['filename'] = ""; 4201 $p_header['status'] = "invalid_header"; 4202 4203 // ----- Error log 4204 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); 4205 4206 // ----- Return 4207 return PclZip::errorCode(); 4208 } 4209 4210 // ----- Extract the values 4211 $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); 4212 4213 // ----- Get filename 4214 if ($p_header['filename_len'] != 0) { 4215 $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); 4216 } else { 4217 $p_header['filename'] = ''; 4218 } 4219 4220 // ----- Get extra 4221 if ($p_header['extra_len'] != 0) { 4222 $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); 4223 } else { 4224 $p_header['extra'] = ''; 4225 } 4226 4227 // ----- Get comment 4228 if ($p_header['comment_len'] != 0) { 4229 $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); 4230 } else { 4231 $p_header['comment'] = ''; 4232 } 4233 4234 // ----- Extract properties 4235 4236 // ----- Recuperate date in UNIX format 4237 //if ($p_header['mdate'] && $p_header['mtime']) 4238 // TBC : bug : this was ignoring time with 0/0/0 4239 if (1) { 4240 // ----- Extract time 4241 $v_hour = ($p_header['mtime'] & 0xF800) >> 11; 4242 $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; 4243 $v_seconde = ($p_header['mtime'] & 0x001F) * 2; 4244 4245 // ----- Extract date 4246 $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; 4247 $v_month = ($p_header['mdate'] & 0x01E0) >> 5; 4248 $v_day = $p_header['mdate'] & 0x001F; 4249 4250 // ----- Get UNIX date format 4251 $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); 4252 4253 } else { 4254 $p_header['mtime'] = time(); 4255 } 4256 4257 // ----- Set the stored filename 4258 $p_header['stored_filename'] = $p_header['filename']; 4259 4260 // ----- Set default status to ok 4261 $p_header['status'] = 'ok'; 4262 4263 // ----- Look if it is a directory 4264 if (substr($p_header['filename'], -1) == '/') { 4265 //$p_header['external'] = 0x41FF0010; 4266 $p_header['external'] = 0x00000010; 4267 } 4268 4269 // ----- Return 4270 return $v_result; 4271 } 4272 // -------------------------------------------------------------------------------- 4273 4274 // -------------------------------------------------------------------------------- 4275 // Function : privCheckFileHeaders() 4276 // Description : 4277 // Parameters : 4278 // Return Values : 4279 // 1 on success, 4280 // 0 on error; 4281 // -------------------------------------------------------------------------------- 4282 public function privCheckFileHeaders(&$p_local_header, &$p_central_header) 4283 { 4284 $v_result = 1; 4285 4286 // ----- Check the static values 4287 // TBC 4288 if ($p_local_header['filename'] != $p_central_header['filename']) { 4289 } 4290 if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { 4291 } 4292 if ($p_local_header['flag'] != $p_central_header['flag']) { 4293 } 4294 if ($p_local_header['compression'] != $p_central_header['compression']) { 4295 } 4296 if ($p_local_header['mtime'] != $p_central_header['mtime']) { 4297 } 4298 if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { 4299 } 4300 4301 // ----- Look for flag bit 3 4302 if (($p_local_header['flag'] & 8) == 8) { 4303 $p_local_header['size'] = $p_central_header['size']; 4304 $p_local_header['compressed_size'] = $p_central_header['compressed_size']; 4305 $p_local_header['crc'] = $p_central_header['crc']; 4306 } 4307 4308 // ----- Return 4309 return $v_result; 4310 } 4311 // -------------------------------------------------------------------------------- 4312 4313 // -------------------------------------------------------------------------------- 4314 // Function : privReadEndCentralDir() 4315 // Description : 4316 // Parameters : 4317 // Return Values : 4318 // -------------------------------------------------------------------------------- 4319 public function privReadEndCentralDir(&$p_central_dir) 4320 { 4321 $v_result = 1; 4322 4323 // ----- Go to the end of the zip file 4324 $v_size = filesize($this->zipname); 4325 @fseek($this->zip_fd, $v_size); 4326 if (@ftell($this->zip_fd) != $v_size) { 4327 // ----- Error log 4328 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\''); 4329 4330 // ----- Return 4331 return PclZip::errorCode(); 4332 } 4333 4334 // ----- First try : look if this is an archive with no commentaries (most of the time) 4335 // in this case the end of central dir is at 22 bytes of the file end 4336 $v_found = 0; 4337 if ($v_size > 26) { 4338 @fseek($this->zip_fd, $v_size - 22); 4339 if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) { 4340 // ----- Error log 4341 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); 4342 4343 // ----- Return 4344 return PclZip::errorCode(); 4345 } 4346 4347 // ----- Read for bytes 4348 $v_binary_data = @fread($this->zip_fd, 4); 4349 $v_data = @unpack('Vid', $v_binary_data); 4350 4351 // ----- Check signature 4352 if ($v_data['id'] == 0x06054b50) { 4353 $v_found = 1; 4354 } 4355 4356 $v_pos = ftell($this->zip_fd); 4357 } 4358 4359 // ----- Go back to the maximum possible size of the Central Dir End Record 4360 if (!$v_found) { 4361 $v_maximum_size = 65557; // 0xFFFF + 22; 4362 if ($v_maximum_size > $v_size) { 4363 $v_maximum_size = $v_size; 4364 } 4365 @fseek($this->zip_fd, $v_size - $v_maximum_size); 4366 if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) { 4367 // ----- Error log 4368 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); 4369 4370 // ----- Return 4371 return PclZip::errorCode(); 4372 } 4373 4374 // ----- Read byte per byte in order to find the signature 4375 $v_pos = ftell($this->zip_fd); 4376 $v_bytes = 0x00000000; 4377 while ($v_pos < $v_size) { 4378 // ----- Read a byte 4379 $v_byte = @fread($this->zip_fd, 1); 4380 4381 // ----- Add the byte 4382 //$v_bytes = ($v_bytes << 8) | Ord($v_byte); 4383 // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number 4384 // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. 4385 $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); 4386 4387 // ----- Compare the bytes 4388 if ($v_bytes == 0x504b0506) { 4389 $v_pos++; 4390 break; 4391 } 4392 4393 $v_pos++; 4394 } 4395 4396 // ----- Look if not found end of central dir 4397 if ($v_pos == $v_size) { 4398 4399 // ----- Error log 4400 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); 4401 4402 // ----- Return 4403 return PclZip::errorCode(); 4404 } 4405 } 4406 4407 // ----- Read the first 18 bytes of the header 4408 $v_binary_data = fread($this->zip_fd, 18); 4409 4410 // ----- Look for invalid block size 4411 if (strlen($v_binary_data) != 18) { 4412 4413 // ----- Error log 4414 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data)); 4415 4416 // ----- Return 4417 return PclZip::errorCode(); 4418 } 4419 4420 // ----- Extract the values 4421 $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); 4422 4423 // ----- Check the global size 4424 if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { 4425 4426 // ----- Removed in release 2.2 see readme file 4427 // The check of the file size is a little too strict. 4428 // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. 4429 // While decrypted, zip has training 0 bytes 4430 if (0) { 4431 // ----- Error log 4432 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.'); 4433 4434 // ----- Return 4435 return PclZip::errorCode(); 4436 } 4437 } 4438 4439 // ----- Get comment 4440 if ($v_data['comment_size'] != 0) { 4441 $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); 4442 } else { 4443 $p_central_dir['comment'] = ''; 4444 } 4445 4446 $p_central_dir['entries'] = $v_data['entries']; 4447 $p_central_dir['disk_entries'] = $v_data['disk_entries']; 4448 $p_central_dir['offset'] = $v_data['offset']; 4449 $p_central_dir['size'] = $v_data['size']; 4450 $p_central_dir['disk'] = $v_data['disk']; 4451 $p_central_dir['disk_start'] = $v_data['disk_start']; 4452 4453 // TBC 4454 //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { 4455 //} 4456 4457 // ----- Return 4458 return $v_result; 4459 } 4460 // -------------------------------------------------------------------------------- 4461 4462 // -------------------------------------------------------------------------------- 4463 // Function : privDeleteByRule() 4464 // Description : 4465 // Parameters : 4466 // Return Values : 4467 // -------------------------------------------------------------------------------- 4468 public function privDeleteByRule(&$p_result_list, &$p_options) 4469 { 4470 $v_result = 1; 4471 $v_list_detail = array(); 4472 4473 // ----- Open the zip file 4474 if (($v_result = $this->privOpenFd('rb')) != 1) { 4475 // ----- Return 4476 return $v_result; 4477 } 4478 4479 // ----- Read the central directory informations 4480 $v_central_dir = array(); 4481 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 4482 $this->privCloseFd(); 4483 4484 return $v_result; 4485 } 4486 4487 // ----- Go to beginning of File 4488 @rewind($this->zip_fd); 4489 4490 // ----- Scan all the files 4491 // ----- Start at beginning of Central Dir 4492 $v_pos_entry = $v_central_dir['offset']; 4493 @rewind($this->zip_fd); 4494 if (@fseek($this->zip_fd, $v_pos_entry)) { 4495 // ----- Close the zip file 4496 $this->privCloseFd(); 4497 4498 // ----- Error log 4499 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 4500 4501 // ----- Return 4502 return PclZip::errorCode(); 4503 } 4504 4505 // ----- Read each entry 4506 $v_header_list = array(); 4507 $j_start = 0; 4508 for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { 4509 4510 // ----- Read the file header 4511 $v_header_list[$v_nb_extracted] = array(); 4512 if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) { 4513 // ----- Close the zip file 4514 $this->privCloseFd(); 4515 4516 return $v_result; 4517 } 4518 4519 // ----- Store the index 4520 $v_header_list[$v_nb_extracted]['index'] = $i; 4521 4522 // ----- Look for the specific extract rules 4523 $v_found = false; 4524 4525 // ----- Look for extract by name rule 4526 if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { 4527 4528 // ----- Look if the filename is in the list 4529 for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { 4530 4531 // ----- Look for a directory 4532 if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { 4533 4534 // ----- Look if the directory is in the filename path 4535 if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { 4536 $v_found = true; 4537 } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { 4538 $v_found = true; 4539 } 4540 4541 // ----- Look for a filename 4542 } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { 4543 $v_found = true; 4544 } 4545 } 4546 4547 // ----- Look for extract by ereg rule 4548 // ereg() is deprecated with PHP 5.3 4549 /* 4550 elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) 4551 && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { 4552 4553 if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { 4554 $v_found = true; 4555 } 4556 } 4557 */ 4558 4559 // ----- Look for extract by preg rule 4560 } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { 4561 4562 if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { 4563 $v_found = true; 4564 } 4565 4566 // ----- Look for extract by index rule 4567 } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { 4568 4569 // ----- Look if the index is in the list 4570 for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { 4571 4572 if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { 4573 $v_found = true; 4574 } 4575 if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { 4576 $j_start = $j + 1; 4577 } 4578 4579 if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { 4580 break; 4581 } 4582 } 4583 } else { 4584 $v_found = true; 4585 } 4586 4587 // ----- Look for deletion 4588 if ($v_found) { 4589 unset($v_header_list[$v_nb_extracted]); 4590 } else { 4591 $v_nb_extracted++; 4592 } 4593 } 4594 4595 // ----- Look if something need to be deleted 4596 if ($v_nb_extracted > 0) { 4597 4598 // ----- Creates a temporay file 4599 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; 4600 4601 // ----- Creates a temporary zip archive 4602 $v_temp_zip = new PclZip($v_zip_temp_name); 4603 4604 // ----- Open the temporary zip file in write mode 4605 if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { 4606 $this->privCloseFd(); 4607 4608 // ----- Return 4609 return $v_result; 4610 } 4611 4612 // ----- Look which file need to be kept 4613 for ($i = 0; $i < sizeof($v_header_list); $i++) { 4614 4615 // ----- Calculate the position of the header 4616 @rewind($this->zip_fd); 4617 if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { 4618 // ----- Close the zip file 4619 $this->privCloseFd(); 4620 $v_temp_zip->privCloseFd(); 4621 @unlink($v_zip_temp_name); 4622 4623 // ----- Error log 4624 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 4625 4626 // ----- Return 4627 return PclZip::errorCode(); 4628 } 4629 4630 // ----- Read the file header 4631 $v_local_header = array(); 4632 if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { 4633 // ----- Close the zip file 4634 $this->privCloseFd(); 4635 $v_temp_zip->privCloseFd(); 4636 @unlink($v_zip_temp_name); 4637 4638 // ----- Return 4639 return $v_result; 4640 } 4641 4642 // ----- Check that local file header is same as central file header 4643 if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) { 4644 // TBC 4645 } 4646 unset($v_local_header); 4647 4648 // ----- Write the file header 4649 if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { 4650 // ----- Close the zip file 4651 $this->privCloseFd(); 4652 $v_temp_zip->privCloseFd(); 4653 @unlink($v_zip_temp_name); 4654 4655 // ----- Return 4656 return $v_result; 4657 } 4658 4659 // ----- Read/write the data block 4660 if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { 4661 // ----- Close the zip file 4662 $this->privCloseFd(); 4663 $v_temp_zip->privCloseFd(); 4664 @unlink($v_zip_temp_name); 4665 4666 // ----- Return 4667 return $v_result; 4668 } 4669 } 4670 4671 // ----- Store the offset of the central dir 4672 $v_offset = @ftell($v_temp_zip->zip_fd); 4673 4674 // ----- Re-Create the Central Dir files header 4675 for ($i = 0; $i < sizeof($v_header_list); $i++) { 4676 // ----- Create the file header 4677 if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) { 4678 $v_temp_zip->privCloseFd(); 4679 $this->privCloseFd(); 4680 @unlink($v_zip_temp_name); 4681 4682 // ----- Return 4683 return $v_result; 4684 } 4685 4686 // ----- Transform the header to a 'usable' info 4687 $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); 4688 } 4689 4690 // ----- Zip file comment 4691 $v_comment = ''; 4692 if (isset($p_options[PCLZIP_OPT_COMMENT])) { 4693 $v_comment = $p_options[PCLZIP_OPT_COMMENT]; 4694 } 4695 4696 // ----- Calculate the size of the central header 4697 $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset; 4698 4699 // ----- Create the central dir footer 4700 if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { 4701 // ----- Reset the file list 4702 unset($v_header_list); 4703 $v_temp_zip->privCloseFd(); 4704 $this->privCloseFd(); 4705 @unlink($v_zip_temp_name); 4706 4707 // ----- Return 4708 return $v_result; 4709 } 4710 4711 // ----- Close 4712 $v_temp_zip->privCloseFd(); 4713 $this->privCloseFd(); 4714 4715 // ----- Delete the zip file 4716 // TBC : I should test the result ... 4717 @unlink($this->zipname); 4718 4719 // ----- Rename the temporary file 4720 // TBC : I should test the result ... 4721 //@rename($v_zip_temp_name, $this->zipname); 4722 PclZipUtilRename($v_zip_temp_name, $this->zipname); 4723 4724 // ----- Destroy the temporary archive 4725 unset($v_temp_zip); 4726 4727 // ----- Remove every files : reset the file 4728 } elseif ($v_central_dir['entries'] != 0) { 4729 $this->privCloseFd(); 4730 4731 if (($v_result = $this->privOpenFd('wb')) != 1) { 4732 return $v_result; 4733 } 4734 4735 if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { 4736 return $v_result; 4737 } 4738 4739 $this->privCloseFd(); 4740 } 4741 4742 // ----- Return 4743 return $v_result; 4744 } 4745 // -------------------------------------------------------------------------------- 4746 4747 // -------------------------------------------------------------------------------- 4748 // Function : privDirCheck() 4749 // Description : 4750 // Check if a directory exists, if not it creates it and all the parents directory 4751 // which may be useful. 4752 // Parameters : 4753 // $p_dir : Directory path to check. 4754 // Return Values : 4755 // 1 : OK 4756 // -1 : Unable to create directory 4757 // -------------------------------------------------------------------------------- 4758 public function privDirCheck($p_dir, $p_is_dir = false) 4759 { 4760 $v_result = 1; 4761 4762 // ----- Remove the final '/' 4763 if (($p_is_dir) && (substr($p_dir, -1) == '/')) { 4764 $p_dir = substr($p_dir, 0, strlen($p_dir) - 1); 4765 } 4766 4767 // ----- Check the directory availability 4768 if ((is_dir($p_dir)) || ($p_dir == "")) { 4769 return 1; 4770 } 4771 4772 // ----- Extract parent directory 4773 $p_parent_dir = dirname($p_dir); 4774 4775 // ----- Just a check 4776 if ($p_parent_dir != $p_dir) { 4777 // ----- Look for parent directory 4778 if ($p_parent_dir != "") { 4779 if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) { 4780 return $v_result; 4781 } 4782 } 4783 } 4784 4785 // ----- Create the directory 4786 if (!@mkdir($p_dir, 0777)) { 4787 // ----- Error log 4788 PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); 4789 4790 // ----- Return 4791 return PclZip::errorCode(); 4792 } 4793 4794 // ----- Return 4795 return $v_result; 4796 } 4797 // -------------------------------------------------------------------------------- 4798 4799 // -------------------------------------------------------------------------------- 4800 // Function : privMerge() 4801 // Description : 4802 // If $p_archive_to_add does not exist, the function exit with a success result. 4803 // Parameters : 4804 // Return Values : 4805 // -------------------------------------------------------------------------------- 4806 public function privMerge(&$p_archive_to_add) 4807 { 4808 $v_result = 1; 4809 4810 // ----- Look if the archive_to_add exists 4811 if (!is_file($p_archive_to_add->zipname)) { 4812 4813 // ----- Nothing to merge, so merge is a success 4814 $v_result = 1; 4815 4816 // ----- Return 4817 return $v_result; 4818 } 4819 4820 // ----- Look if the archive exists 4821 if (!is_file($this->zipname)) { 4822 4823 // ----- Do a duplicate 4824 $v_result = $this->privDuplicate($p_archive_to_add->zipname); 4825 4826 // ----- Return 4827 return $v_result; 4828 } 4829 4830 // ----- Open the zip file 4831 if (($v_result = $this->privOpenFd('rb')) != 1) { 4832 // ----- Return 4833 return $v_result; 4834 } 4835 4836 // ----- Read the central directory informations 4837 $v_central_dir = array(); 4838 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 4839 $this->privCloseFd(); 4840 4841 return $v_result; 4842 } 4843 4844 // ----- Go to beginning of File 4845 @rewind($this->zip_fd); 4846 4847 // ----- Open the archive_to_add file 4848 if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) { 4849 $this->privCloseFd(); 4850 4851 // ----- Return 4852 return $v_result; 4853 } 4854 4855 // ----- Read the central directory informations 4856 $v_central_dir_to_add = array(); 4857 if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) { 4858 $this->privCloseFd(); 4859 $p_archive_to_add->privCloseFd(); 4860 4861 return $v_result; 4862 } 4863 4864 // ----- Go to beginning of File 4865 @rewind($p_archive_to_add->zip_fd); 4866 4867 // ----- Creates a temporay file 4868 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; 4869 4870 // ----- Open the temporary file in write mode 4871 if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { 4872 $this->privCloseFd(); 4873 $p_archive_to_add->privCloseFd(); 4874 4875 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); 4876 4877 // ----- Return 4878 return PclZip::errorCode(); 4879 } 4880 4881 // ----- Copy the files from the archive to the temporary file 4882 // TBC : Here I should better append the file and go back to erase the central dir 4883 $v_size = $v_central_dir['offset']; 4884 while ($v_size != 0) { 4885 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4886 $v_buffer = fread($this->zip_fd, $v_read_size); 4887 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4888 $v_size -= $v_read_size; 4889 } 4890 4891 // ----- Copy the files from the archive_to_add into the temporary file 4892 $v_size = $v_central_dir_to_add['offset']; 4893 while ($v_size != 0) { 4894 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4895 $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); 4896 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4897 $v_size -= $v_read_size; 4898 } 4899 4900 // ----- Store the offset of the central dir 4901 $v_offset = @ftell($v_zip_temp_fd); 4902 4903 // ----- Copy the block of file headers from the old archive 4904 $v_size = $v_central_dir['size']; 4905 while ($v_size != 0) { 4906 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4907 $v_buffer = @fread($this->zip_fd, $v_read_size); 4908 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4909 $v_size -= $v_read_size; 4910 } 4911 4912 // ----- Copy the block of file headers from the archive_to_add 4913 $v_size = $v_central_dir_to_add['size']; 4914 while ($v_size != 0) { 4915 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4916 $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); 4917 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4918 $v_size -= $v_read_size; 4919 } 4920 4921 // ----- Merge the file comments 4922 $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment']; 4923 4924 // ----- Calculate the size of the (new) central header 4925 $v_size = @ftell($v_zip_temp_fd) - $v_offset; 4926 4927 // ----- Swap the file descriptor 4928 // Here is a trick : I swap the temporary fd with the zip fd, in order to use 4929 // the following methods on the temporary fil and not the real archive fd 4930 $v_swap = $this->zip_fd; 4931 $this->zip_fd = $v_zip_temp_fd; 4932 $v_zip_temp_fd = $v_swap; 4933 4934 // ----- Create the central dir footer 4935 if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) { 4936 $this->privCloseFd(); 4937 $p_archive_to_add->privCloseFd(); 4938 @fclose($v_zip_temp_fd); 4939 $this->zip_fd = null; 4940 4941 // ----- Reset the file list 4942 unset($v_header_list); 4943 4944 // ----- Return 4945 return $v_result; 4946 } 4947 4948 // ----- Swap back the file descriptor 4949 $v_swap = $this->zip_fd; 4950 $this->zip_fd = $v_zip_temp_fd; 4951 $v_zip_temp_fd = $v_swap; 4952 4953 // ----- Close 4954 $this->privCloseFd(); 4955 $p_archive_to_add->privCloseFd(); 4956 4957 // ----- Close the temporary file 4958 @fclose($v_zip_temp_fd); 4959 4960 // ----- Delete the zip file 4961 // TBC : I should test the result ... 4962 @unlink($this->zipname); 4963 4964 // ----- Rename the temporary file 4965 // TBC : I should test the result ... 4966 //@rename($v_zip_temp_name, $this->zipname); 4967 PclZipUtilRename($v_zip_temp_name, $this->zipname); 4968 4969 // ----- Return 4970 return $v_result; 4971 } 4972 // -------------------------------------------------------------------------------- 4973 4974 // -------------------------------------------------------------------------------- 4975 // Function : privDuplicate() 4976 // Description : 4977 // Parameters : 4978 // Return Values : 4979 // -------------------------------------------------------------------------------- 4980 public function privDuplicate($p_archive_filename) 4981 { 4982 $v_result = 1; 4983 4984 // ----- Look if the $p_archive_filename exists 4985 if (!is_file($p_archive_filename)) { 4986 4987 // ----- Nothing to duplicate, so duplicate is a success. 4988 $v_result = 1; 4989 4990 // ----- Return 4991 return $v_result; 4992 } 4993 4994 // ----- Open the zip file 4995 if (($v_result = $this->privOpenFd('wb')) != 1) { 4996 // ----- Return 4997 return $v_result; 4998 } 4999 5000 // ----- Open the temporary file in write mode 5001 if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { 5002 $this->privCloseFd(); 5003 5004 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode'); 5005 5006 // ----- Return 5007 return PclZip::errorCode(); 5008 } 5009 5010 // ----- Copy the files from the archive to the temporary file 5011 // TBC : Here I should better append the file and go back to erase the central dir 5012 $v_size = filesize($p_archive_filename); 5013 while ($v_size != 0) { 5014 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 5015 $v_buffer = fread($v_zip_temp_fd, $v_read_size); 5016 @fwrite($this->zip_fd, $v_buffer, $v_read_size); 5017 $v_size -= $v_read_size; 5018 } 5019 5020 // ----- Close 5021 $this->privCloseFd(); 5022 5023 // ----- Close the temporary file 5024 @fclose($v_zip_temp_fd); 5025 5026 // ----- Return 5027 return $v_result; 5028 } 5029 // -------------------------------------------------------------------------------- 5030 5031 // -------------------------------------------------------------------------------- 5032 // Function : privErrorLog() 5033 // Description : 5034 // Parameters : 5035 // -------------------------------------------------------------------------------- 5036 public function privErrorLog($p_error_code = 0, $p_error_string = '') 5037 { 5038 if (PCLZIP_ERROR_EXTERNAL == 1) { 5039 PclError($p_error_code, $p_error_string); 5040 } else { 5041 $this->error_code = $p_error_code; 5042 $this->error_string = $p_error_string; 5043 } 5044 } 5045 // -------------------------------------------------------------------------------- 5046 5047 // -------------------------------------------------------------------------------- 5048 // Function : privErrorReset() 5049 // Description : 5050 // Parameters : 5051 // -------------------------------------------------------------------------------- 5052 public function privErrorReset() 5053 { 5054 if (PCLZIP_ERROR_EXTERNAL == 1) { 5055 PclErrorReset(); 5056 } else { 5057 $this->error_code = 0; 5058 $this->error_string = ''; 5059 } 5060 } 5061 // -------------------------------------------------------------------------------- 5062 5063 // -------------------------------------------------------------------------------- 5064 // Function : privDisableMagicQuotes() 5065 // Description : 5066 // Parameters : 5067 // Return Values : 5068 // -------------------------------------------------------------------------------- 5069 public function privDisableMagicQuotes() 5070 { 5071 $v_result = 1; 5072 5073 // ----- Look if function exists 5074 if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { 5075 return $v_result; 5076 } 5077 5078 // ----- Look if already done 5079 if ($this->magic_quotes_status != -1) { 5080 return $v_result; 5081 } 5082 5083 // ----- Get and memorize the magic_quote value 5084 $this->magic_quotes_status = @get_magic_quotes_runtime(); 5085 5086 // ----- Disable magic_quotes 5087 if ($this->magic_quotes_status == 1) { 5088 @set_magic_quotes_runtime(0); 5089 } 5090 5091 // ----- Return 5092 return $v_result; 5093 } 5094 // -------------------------------------------------------------------------------- 5095 5096 // -------------------------------------------------------------------------------- 5097 // Function : privSwapBackMagicQuotes() 5098 // Description : 5099 // Parameters : 5100 // Return Values : 5101 // -------------------------------------------------------------------------------- 5102 public function privSwapBackMagicQuotes() 5103 { 5104 $v_result = 1; 5105 5106 // ----- Look if function exists 5107 if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { 5108 return $v_result; 5109 } 5110 5111 // ----- Look if something to do 5112 if ($this->magic_quotes_status != -1) { 5113 return $v_result; 5114 } 5115 5116 // ----- Swap back magic_quotes 5117 if ($this->magic_quotes_status == 1) { 5118 @set_magic_quotes_runtime($this->magic_quotes_status); 5119 } 5120 5121 // ----- Return 5122 return $v_result; 5123 } 5124 // -------------------------------------------------------------------------------- 5125} 5126 5127// End of class 5128// -------------------------------------------------------------------------------- 5129 5130// -------------------------------------------------------------------------------- 5131// Function : PclZipUtilPathReduction() 5132// Description : 5133// Parameters : 5134// Return Values : 5135// -------------------------------------------------------------------------------- 5136function PclZipUtilPathReduction($p_dir) 5137{ 5138 $v_result = ""; 5139 5140 // ----- Look for not empty path 5141 if ($p_dir != "") { 5142 // ----- Explode path by directory names 5143 $v_list = explode("/", $p_dir); 5144 5145 // ----- Study directories from last to first 5146 $v_skip = 0; 5147 for ($i = sizeof($v_list) - 1; $i >= 0; $i--) { 5148 // ----- Look for current path 5149 if ($v_list[$i] == ".") { 5150 // ----- Ignore this directory 5151 // Should be the first $i=0, but no check is done 5152 } elseif ($v_list[$i] == "..") { 5153 $v_skip++; 5154 } elseif ($v_list[$i] == "") { 5155 // ----- First '/' i.e. root slash 5156 if ($i == 0) { 5157 $v_result = "/" . $v_result; 5158 if ($v_skip > 0) { 5159 // ----- It is an invalid path, so the path is not modified 5160 // TBC 5161 $v_result = $p_dir; 5162 $v_skip = 0; 5163 } 5164 5165 // ----- Last '/' i.e. indicates a directory 5166 } elseif ($i == (sizeof($v_list) - 1)) { 5167 $v_result = $v_list[$i]; 5168 5169 // ----- Double '/' inside the path 5170 } else { 5171 // ----- Ignore only the double '//' in path, 5172 // but not the first and last '/' 5173 } 5174 } else { 5175 // ----- Look for item to skip 5176 if ($v_skip > 0) { 5177 $v_skip--; 5178 } else { 5179 $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? "/" . $v_result : ""); 5180 } 5181 } 5182 } 5183 5184 // ----- Look for skip 5185 if ($v_skip > 0) { 5186 while ($v_skip > 0) { 5187 $v_result = '../' . $v_result; 5188 $v_skip--; 5189 } 5190 } 5191 } 5192 5193 // ----- Return 5194 return $v_result; 5195} 5196// -------------------------------------------------------------------------------- 5197 5198// -------------------------------------------------------------------------------- 5199// Function : PclZipUtilPathInclusion() 5200// Description : 5201// This function indicates if the path $p_path is under the $p_dir tree. Or, 5202// said in an other way, if the file or sub-dir $p_path is inside the dir 5203// $p_dir. 5204// The function indicates also if the path is exactly the same as the dir. 5205// This function supports path with duplicated '/' like '//', but does not 5206// support '.' or '..' statements. 5207// Parameters : 5208// Return Values : 5209// 0 if $p_path is not inside directory $p_dir 5210// 1 if $p_path is inside directory $p_dir 5211// 2 if $p_path is exactly the same as $p_dir 5212// -------------------------------------------------------------------------------- 5213function PclZipUtilPathInclusion($p_dir, $p_path) 5214{ 5215 $v_result = 1; 5216 5217 // ----- Look for path beginning by ./ 5218 if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) { 5219 $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1); 5220 } 5221 if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) { 5222 $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1); 5223 } 5224 5225 // ----- Explode dir and path by directory separator 5226 $v_list_dir = explode("/", $p_dir); 5227 $v_list_dir_size = sizeof($v_list_dir); 5228 $v_list_path = explode("/", $p_path); 5229 $v_list_path_size = sizeof($v_list_path); 5230 5231 // ----- Study directories paths 5232 $i = 0; 5233 $j = 0; 5234 while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { 5235 5236 // ----- Look for empty dir (path reduction) 5237 if ($v_list_dir[$i] == '') { 5238 $i++; 5239 continue; 5240 } 5241 if ($v_list_path[$j] == '') { 5242 $j++; 5243 continue; 5244 } 5245 5246 // ----- Compare the items 5247 if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) { 5248 $v_result = 0; 5249 } 5250 5251 // ----- Next items 5252 $i++; 5253 $j++; 5254 } 5255 5256 // ----- Look if everything seems to be the same 5257 if ($v_result) { 5258 // ----- Skip all the empty items 5259 while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) { 5260 $j++; 5261 } 5262 while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) { 5263 $i++; 5264 } 5265 5266 if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { 5267 // ----- There are exactly the same 5268 $v_result = 2; 5269 } elseif ($i < $v_list_dir_size) { 5270 // ----- The path is shorter than the dir 5271 $v_result = 0; 5272 } 5273 } 5274 5275 // ----- Return 5276 return $v_result; 5277} 5278// -------------------------------------------------------------------------------- 5279 5280// -------------------------------------------------------------------------------- 5281// Function : PclZipUtilCopyBlock() 5282// Description : 5283// Parameters : 5284// $p_mode : read/write compression mode 5285// 0 : src & dest normal 5286// 1 : src gzip, dest normal 5287// 2 : src normal, dest gzip 5288// 3 : src & dest gzip 5289// Return Values : 5290// -------------------------------------------------------------------------------- 5291function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0) 5292{ 5293 $v_result = 1; 5294 5295 if ($p_mode == 0) { 5296 while ($p_size != 0) { 5297 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5298 $v_buffer = @fread($p_src, $v_read_size); 5299 @fwrite($p_dest, $v_buffer, $v_read_size); 5300 $p_size -= $v_read_size; 5301 } 5302 } elseif ($p_mode == 1) { 5303 while ($p_size != 0) { 5304 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5305 $v_buffer = @gzread($p_src, $v_read_size); 5306 @fwrite($p_dest, $v_buffer, $v_read_size); 5307 $p_size -= $v_read_size; 5308 } 5309 } elseif ($p_mode == 2) { 5310 while ($p_size != 0) { 5311 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5312 $v_buffer = @fread($p_src, $v_read_size); 5313 @gzwrite($p_dest, $v_buffer, $v_read_size); 5314 $p_size -= $v_read_size; 5315 } 5316 } elseif ($p_mode == 3) { 5317 while ($p_size != 0) { 5318 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5319 $v_buffer = @gzread($p_src, $v_read_size); 5320 @gzwrite($p_dest, $v_buffer, $v_read_size); 5321 $p_size -= $v_read_size; 5322 } 5323 } 5324 5325 // ----- Return 5326 return $v_result; 5327} 5328// -------------------------------------------------------------------------------- 5329 5330// -------------------------------------------------------------------------------- 5331// Function : PclZipUtilRename() 5332// Description : 5333// This function tries to do a simple rename() function. If it fails, it 5334// tries to copy the $p_src file in a new $p_dest file and then unlink the 5335// first one. 5336// Parameters : 5337// $p_src : Old filename 5338// $p_dest : New filename 5339// Return Values : 5340// 1 on success, 0 on failure. 5341// -------------------------------------------------------------------------------- 5342function PclZipUtilRename($p_src, $p_dest) 5343{ 5344 $v_result = 1; 5345 5346 // ----- Try to rename the files 5347 if (!@rename($p_src, $p_dest)) { 5348 5349 // ----- Try to copy & unlink the src 5350 if (!@copy($p_src, $p_dest)) { 5351 $v_result = 0; 5352 } elseif (!@unlink($p_src)) { 5353 $v_result = 0; 5354 } 5355 } 5356 5357 // ----- Return 5358 return $v_result; 5359} 5360// -------------------------------------------------------------------------------- 5361 5362// -------------------------------------------------------------------------------- 5363// Function : PclZipUtilOptionText() 5364// Description : 5365// Translate option value in text. Mainly for debug purpose. 5366// Parameters : 5367// $p_option : the option value. 5368// Return Values : 5369// The option text value. 5370// -------------------------------------------------------------------------------- 5371function PclZipUtilOptionText($p_option) 5372{ 5373 5374 $v_list = get_defined_constants(); 5375 for (reset($v_list); $v_key = key($v_list); next($v_list)) { 5376 $v_prefix = substr($v_key, 0, 10); 5377 if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) { 5378 return $v_key; 5379 } 5380 } 5381 5382 $v_result = 'Unknown'; 5383 5384 return $v_result; 5385} 5386// -------------------------------------------------------------------------------- 5387 5388// -------------------------------------------------------------------------------- 5389// Function : PclZipUtilTranslateWinPath() 5390// Description : 5391// Translate windows path by replacing '\' by '/' and optionally removing 5392// drive letter. 5393// Parameters : 5394// $p_path : path to translate. 5395// $p_remove_disk_letter : true | false 5396// Return Values : 5397// The path translated. 5398// -------------------------------------------------------------------------------- 5399function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true) 5400{ 5401 if (stristr(php_uname(), 'windows')) { 5402 // ----- Look for potential disk letter 5403 if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { 5404 $p_path = substr($p_path, $v_position + 1); 5405 } 5406 // ----- Change potential windows directory separator 5407 if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) { 5408 $p_path = strtr($p_path, '\\', '/'); 5409 } 5410 } 5411 5412 return $p_path; 5413} 5414// -------------------------------------------------------------------------------- 5415