1<?php 2// -------------------------------------------------------------------------------- 3// PhpConcept Library - Zip Module 2.8.4 4// -------------------------------------------------------------------------------- 5// License GNU/LGPL - Vincent Blavet - August 2009 6// Originaly http://www.phpconcept.net 7// Now https://github.com/chamilo/pclzip 8// -------------------------------------------------------------------------------- 9// 10// Presentation : 11// PclZip is a PHP library that manage ZIP archives. 12// So far tests show that archives generated by PclZip are readable by 13// WinZip application and other tools. 14// 15// Description : 16// See readme.txt and http://www.phpconcept.net 17// 18// Warning : 19// This library and the associated files are non commercial, non professional 20// work. 21// It should not have unexpected results. However if any damage is caused by 22// this software the author can not be responsible. 23// The use of this software is at the risk of the user. 24// 25// -------------------------------------------------------------------------------- 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 $v_memory_limit = preg_replace('/\s*[KkMmGg]$/', '', $v_memory_limit); 1791 1792 if ($last == 'g') { 1793 //$v_memory_limit = $v_memory_limit*1024*1024*1024; 1794 $v_memory_limit = $v_memory_limit * 1073741824; 1795 } 1796 if ($last == 'm') { 1797 //$v_memory_limit = $v_memory_limit*1024*1024; 1798 $v_memory_limit = $v_memory_limit * 1048576; 1799 } 1800 if ($last == 'k') { 1801 $v_memory_limit = $v_memory_limit * 1024; 1802 } 1803 1804 $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO); 1805 1806 // ----- Sanity check : No threshold if value lower than 1M 1807 if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { 1808 unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); 1809 } 1810 1811 // ----- Return 1812 return $v_result; 1813 } 1814 // -------------------------------------------------------------------------------- 1815 1816 // -------------------------------------------------------------------------------- 1817 // Function : privFileDescrParseAtt() 1818 // Description : 1819 // Parameters : 1820 // Return Values : 1821 // 1 on success. 1822 // 0 on failure. 1823 // -------------------------------------------------------------------------------- 1824 public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false) 1825 { 1826 $v_result = 1; 1827 1828 // ----- For each file in the list check the attributes 1829 foreach ($p_file_list as $v_key => $v_value) { 1830 1831 // ----- Check if the option is supported 1832 if (!isset($v_requested_options[$v_key])) { 1833 // ----- Error log 1834 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file"); 1835 1836 // ----- Return 1837 return PclZip::errorCode(); 1838 } 1839 1840 // ----- Look for attribute 1841 switch ($v_key) { 1842 case PCLZIP_ATT_FILE_NAME: 1843 if (!is_string($v_value)) { 1844 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1845 1846 return PclZip::errorCode(); 1847 } 1848 1849 $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); 1850 1851 if ($p_filedescr['filename'] == '') { 1852 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1853 1854 return PclZip::errorCode(); 1855 } 1856 1857 break; 1858 1859 case PCLZIP_ATT_FILE_NEW_SHORT_NAME: 1860 if (!is_string($v_value)) { 1861 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1862 1863 return PclZip::errorCode(); 1864 } 1865 1866 $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); 1867 1868 if ($p_filedescr['new_short_name'] == '') { 1869 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1870 1871 return PclZip::errorCode(); 1872 } 1873 break; 1874 1875 case PCLZIP_ATT_FILE_NEW_FULL_NAME: 1876 if (!is_string($v_value)) { 1877 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1878 1879 return PclZip::errorCode(); 1880 } 1881 1882 $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); 1883 1884 if ($p_filedescr['new_full_name'] == '') { 1885 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1886 1887 return PclZip::errorCode(); 1888 } 1889 break; 1890 1891 // ----- Look for options that takes a string 1892 case PCLZIP_ATT_FILE_COMMENT: 1893 if (!is_string($v_value)) { 1894 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1895 1896 return PclZip::errorCode(); 1897 } 1898 1899 $p_filedescr['comment'] = $v_value; 1900 break; 1901 1902 case PCLZIP_ATT_FILE_MTIME: 1903 if (!is_integer($v_value)) { 1904 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'"); 1905 1906 return PclZip::errorCode(); 1907 } 1908 1909 $p_filedescr['mtime'] = $v_value; 1910 break; 1911 1912 case PCLZIP_ATT_FILE_CONTENT: 1913 $p_filedescr['content'] = $v_value; 1914 break; 1915 1916 default: 1917 // ----- Error log 1918 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" . $v_key . "'"); 1919 1920 // ----- Return 1921 return PclZip::errorCode(); 1922 } 1923 1924 // ----- Look for mandatory options 1925 if ($v_requested_options !== false) { 1926 for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) { 1927 // ----- Look for mandatory option 1928 if ($v_requested_options[$key] == 'mandatory') { 1929 // ----- Look if present 1930 if (!isset($p_file_list[$key])) { 1931 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")"); 1932 1933 return PclZip::errorCode(); 1934 } 1935 } 1936 } 1937 } 1938 1939 // end foreach 1940 } 1941 1942 // ----- Return 1943 return $v_result; 1944 } 1945 // -------------------------------------------------------------------------------- 1946 1947 // -------------------------------------------------------------------------------- 1948 // Function : privFileDescrExpand() 1949 // Description : 1950 // This method look for each item of the list to see if its a file, a folder 1951 // or a string to be added as file. For any other type of files (link, other) 1952 // just ignore the item. 1953 // Then prepare the information that will be stored for that file. 1954 // When its a folder, expand the folder with all the files that are in that 1955 // folder (recursively). 1956 // Parameters : 1957 // Return Values : 1958 // 1 on success. 1959 // 0 on failure. 1960 // -------------------------------------------------------------------------------- 1961 public function privFileDescrExpand(&$p_filedescr_list, &$p_options) 1962 { 1963 $v_result = 1; 1964 1965 // ----- Create a result list 1966 $v_result_list = array(); 1967 1968 // ----- Look each entry 1969 for ($i = 0; $i < sizeof($p_filedescr_list); $i++) { 1970 1971 // ----- Get filedescr 1972 $v_descr = $p_filedescr_list[$i]; 1973 1974 // ----- Reduce the filename 1975 $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false); 1976 $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']); 1977 1978 // ----- Look for real file or folder 1979 if (file_exists($v_descr['filename'])) { 1980 if (@is_file($v_descr['filename'])) { 1981 $v_descr['type'] = 'file'; 1982 } elseif (@is_dir($v_descr['filename'])) { 1983 $v_descr['type'] = 'folder'; 1984 } elseif (@is_link($v_descr['filename'])) { 1985 // skip 1986 continue; 1987 } else { 1988 // skip 1989 continue; 1990 } 1991 1992 // ----- Look for string added as file 1993 } elseif (isset($v_descr['content'])) { 1994 $v_descr['type'] = 'virtual_file'; 1995 1996 // ----- Missing file 1997 } else { 1998 // ----- Error log 1999 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist"); 2000 2001 // ----- Return 2002 return PclZip::errorCode(); 2003 } 2004 2005 // ----- Calculate the stored filename 2006 $this->privCalculateStoredFilename($v_descr, $p_options); 2007 2008 // ----- Add the descriptor in result list 2009 $v_result_list[sizeof($v_result_list)] = $v_descr; 2010 2011 // ----- Look for folder 2012 if ($v_descr['type'] == 'folder') { 2013 // ----- List of items in folder 2014 $v_dirlist_descr = array(); 2015 $v_dirlist_nb = 0; 2016 if ($v_folder_handler = @opendir($v_descr['filename'])) { 2017 while (($v_item_handler = @readdir($v_folder_handler)) !== false) { 2018 2019 // ----- Skip '.' and '..' 2020 if (($v_item_handler == '.') || ($v_item_handler == '..')) { 2021 continue; 2022 } 2023 2024 // ----- Compose the full filename 2025 $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler; 2026 2027 // ----- Look for different stored filename 2028 // Because the name of the folder was changed, the name of the 2029 // files/sub-folders also change 2030 if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { 2031 if ($v_descr['stored_filename'] != '') { 2032 $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler; 2033 } else { 2034 $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; 2035 } 2036 } 2037 2038 $v_dirlist_nb++; 2039 } 2040 2041 @closedir($v_folder_handler); 2042 } else { 2043 // TBC : unable to open folder in read mode 2044 } 2045 2046 // ----- Expand each element of the list 2047 if ($v_dirlist_nb != 0) { 2048 // ----- Expand 2049 if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { 2050 return $v_result; 2051 } 2052 2053 // ----- Concat the resulting list 2054 $v_result_list = array_merge($v_result_list, $v_dirlist_descr); 2055 } else { 2056 } 2057 2058 // ----- Free local array 2059 unset($v_dirlist_descr); 2060 } 2061 } 2062 2063 // ----- Get the result list 2064 $p_filedescr_list = $v_result_list; 2065 2066 // ----- Return 2067 return $v_result; 2068 } 2069 // -------------------------------------------------------------------------------- 2070 2071 // -------------------------------------------------------------------------------- 2072 // Function : privCreate() 2073 // Description : 2074 // Parameters : 2075 // Return Values : 2076 // -------------------------------------------------------------------------------- 2077 public function privCreate($p_filedescr_list, &$p_result_list, &$p_options) 2078 { 2079 $v_result = 1; 2080 $v_list_detail = array(); 2081 2082 // ----- Magic quotes trick 2083 $this->privDisableMagicQuotes(); 2084 2085 // ----- Open the file in write mode 2086 if (($v_result = $this->privOpenFd('wb')) != 1) { 2087 // ----- Return 2088 return $v_result; 2089 } 2090 2091 // ----- Add the list of files 2092 $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); 2093 2094 // ----- Close 2095 $this->privCloseFd(); 2096 2097 // ----- Magic quotes trick 2098 $this->privSwapBackMagicQuotes(); 2099 2100 // ----- Return 2101 return $v_result; 2102 } 2103 // -------------------------------------------------------------------------------- 2104 2105 // -------------------------------------------------------------------------------- 2106 // Function : privAdd() 2107 // Description : 2108 // Parameters : 2109 // Return Values : 2110 // -------------------------------------------------------------------------------- 2111 public function privAdd($p_filedescr_list, &$p_result_list, &$p_options) 2112 { 2113 $v_result = 1; 2114 $v_list_detail = array(); 2115 2116 // ----- Look if the archive exists or is empty 2117 if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) { 2118 2119 // ----- Do a create 2120 $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); 2121 2122 // ----- Return 2123 return $v_result; 2124 } 2125 // ----- Magic quotes trick 2126 $this->privDisableMagicQuotes(); 2127 2128 // ----- Open the zip file 2129 if (($v_result = $this->privOpenFd('rb')) != 1) { 2130 // ----- Magic quotes trick 2131 $this->privSwapBackMagicQuotes(); 2132 2133 // ----- Return 2134 return $v_result; 2135 } 2136 2137 // ----- Read the central directory informations 2138 $v_central_dir = array(); 2139 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 2140 $this->privCloseFd(); 2141 $this->privSwapBackMagicQuotes(); 2142 2143 return $v_result; 2144 } 2145 2146 // ----- Go to beginning of File 2147 @rewind($this->zip_fd); 2148 2149 // ----- Creates a temporay file 2150 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; 2151 2152 // ----- Open the temporary file in write mode 2153 if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { 2154 $this->privCloseFd(); 2155 $this->privSwapBackMagicQuotes(); 2156 2157 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); 2158 2159 // ----- Return 2160 return PclZip::errorCode(); 2161 } 2162 2163 // ----- Copy the files from the archive to the temporary file 2164 // TBC : Here I should better append the file and go back to erase the central dir 2165 $v_size = $v_central_dir['offset']; 2166 while ($v_size != 0) { 2167 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2168 $v_buffer = fread($this->zip_fd, $v_read_size); 2169 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 2170 $v_size -= $v_read_size; 2171 } 2172 2173 // ----- Swap the file descriptor 2174 // Here is a trick : I swap the temporary fd with the zip fd, in order to use 2175 // the following methods on the temporary fil and not the real archive 2176 $v_swap = $this->zip_fd; 2177 $this->zip_fd = $v_zip_temp_fd; 2178 $v_zip_temp_fd = $v_swap; 2179 2180 // ----- Add the files 2181 $v_header_list = array(); 2182 if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { 2183 fclose($v_zip_temp_fd); 2184 $this->privCloseFd(); 2185 @unlink($v_zip_temp_name); 2186 $this->privSwapBackMagicQuotes(); 2187 2188 // ----- Return 2189 return $v_result; 2190 } 2191 2192 // ----- Store the offset of the central dir 2193 $v_offset = @ftell($this->zip_fd); 2194 2195 // ----- Copy the block of file headers from the old archive 2196 $v_size = $v_central_dir['size']; 2197 while ($v_size != 0) { 2198 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2199 $v_buffer = @fread($v_zip_temp_fd, $v_read_size); 2200 @fwrite($this->zip_fd, $v_buffer, $v_read_size); 2201 $v_size -= $v_read_size; 2202 } 2203 2204 // ----- Create the Central Dir files header 2205 for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { 2206 // ----- Create the file header 2207 if ($v_header_list[$i]['status'] == 'ok') { 2208 if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { 2209 fclose($v_zip_temp_fd); 2210 $this->privCloseFd(); 2211 @unlink($v_zip_temp_name); 2212 $this->privSwapBackMagicQuotes(); 2213 2214 // ----- Return 2215 return $v_result; 2216 } 2217 $v_count++; 2218 } 2219 2220 // ----- Transform the header to a 'usable' info 2221 $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); 2222 } 2223 2224 // ----- Zip file comment 2225 $v_comment = $v_central_dir['comment']; 2226 if (isset($p_options[PCLZIP_OPT_COMMENT])) { 2227 $v_comment = $p_options[PCLZIP_OPT_COMMENT]; 2228 } 2229 if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { 2230 $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT]; 2231 } 2232 if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { 2233 $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment; 2234 } 2235 2236 // ----- Calculate the size of the central header 2237 $v_size = @ftell($this->zip_fd) - $v_offset; 2238 2239 // ----- Create the central dir footer 2240 if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) { 2241 // ----- Reset the file list 2242 unset($v_header_list); 2243 $this->privSwapBackMagicQuotes(); 2244 2245 // ----- Return 2246 return $v_result; 2247 } 2248 2249 // ----- Swap back the file descriptor 2250 $v_swap = $this->zip_fd; 2251 $this->zip_fd = $v_zip_temp_fd; 2252 $v_zip_temp_fd = $v_swap; 2253 2254 // ----- Close 2255 $this->privCloseFd(); 2256 2257 // ----- Close the temporary file 2258 @fclose($v_zip_temp_fd); 2259 2260 // ----- Magic quotes trick 2261 $this->privSwapBackMagicQuotes(); 2262 2263 // ----- Delete the zip file 2264 // TBC : I should test the result ... 2265 @unlink($this->zipname); 2266 2267 // ----- Rename the temporary file 2268 // TBC : I should test the result ... 2269 //@rename($v_zip_temp_name, $this->zipname); 2270 PclZipUtilRename($v_zip_temp_name, $this->zipname); 2271 2272 // ----- Return 2273 return $v_result; 2274 } 2275 // -------------------------------------------------------------------------------- 2276 2277 // -------------------------------------------------------------------------------- 2278 // Function : privOpenFd() 2279 // Description : 2280 // Parameters : 2281 // -------------------------------------------------------------------------------- 2282 public function privOpenFd($p_mode) 2283 { 2284 $v_result = 1; 2285 2286 // ----- Look if already open 2287 if ($this->zip_fd != 0) { 2288 // ----- Error log 2289 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open'); 2290 2291 // ----- Return 2292 return PclZip::errorCode(); 2293 } 2294 2295 // ----- Open the zip file 2296 if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) { 2297 // ----- Error log 2298 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode'); 2299 2300 // ----- Return 2301 return PclZip::errorCode(); 2302 } 2303 2304 // ----- Return 2305 return $v_result; 2306 } 2307 // -------------------------------------------------------------------------------- 2308 2309 // -------------------------------------------------------------------------------- 2310 // Function : privCloseFd() 2311 // Description : 2312 // Parameters : 2313 // -------------------------------------------------------------------------------- 2314 public function privCloseFd() 2315 { 2316 $v_result = 1; 2317 2318 if ($this->zip_fd != 0) { 2319 @fclose($this->zip_fd); 2320 } 2321 $this->zip_fd = 0; 2322 2323 // ----- Return 2324 return $v_result; 2325 } 2326 // -------------------------------------------------------------------------------- 2327 2328 // -------------------------------------------------------------------------------- 2329 // Function : privAddList() 2330 // Description : 2331 // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is 2332 // different from the real path of the file. This is usefull if you want to have PclTar 2333 // running in any directory, and memorize relative path from an other directory. 2334 // Parameters : 2335 // $p_list : An array containing the file or directory names to add in the tar 2336 // $p_result_list : list of added files with their properties (specially the status field) 2337 // $p_add_dir : Path to add in the filename path archived 2338 // $p_remove_dir : Path to remove in the filename path archived 2339 // Return Values : 2340 // -------------------------------------------------------------------------------- 2341 // function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) 2342 public function privAddList($p_filedescr_list, &$p_result_list, &$p_options) 2343 { 2344 $v_result = 1; 2345 2346 // ----- Add the files 2347 $v_header_list = array(); 2348 if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) { 2349 // ----- Return 2350 return $v_result; 2351 } 2352 2353 // ----- Store the offset of the central dir 2354 $v_offset = @ftell($this->zip_fd); 2355 2356 // ----- Create the Central Dir files header 2357 for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) { 2358 // ----- Create the file header 2359 if ($v_header_list[$i]['status'] == 'ok') { 2360 if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) { 2361 // ----- Return 2362 return $v_result; 2363 } 2364 $v_count++; 2365 } 2366 2367 // ----- Transform the header to a 'usable' info 2368 $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); 2369 } 2370 2371 // ----- Zip file comment 2372 $v_comment = ''; 2373 if (isset($p_options[PCLZIP_OPT_COMMENT])) { 2374 $v_comment = $p_options[PCLZIP_OPT_COMMENT]; 2375 } 2376 2377 // ----- Calculate the size of the central header 2378 $v_size = @ftell($this->zip_fd) - $v_offset; 2379 2380 // ----- Create the central dir footer 2381 if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) { 2382 // ----- Reset the file list 2383 unset($v_header_list); 2384 2385 // ----- Return 2386 return $v_result; 2387 } 2388 2389 // ----- Return 2390 return $v_result; 2391 } 2392 // -------------------------------------------------------------------------------- 2393 2394 // -------------------------------------------------------------------------------- 2395 // Function : privAddFileList() 2396 // Description : 2397 // Parameters : 2398 // $p_filedescr_list : An array containing the file description 2399 // or directory names to add in the zip 2400 // $p_result_list : list of added files with their properties (specially the status field) 2401 // Return Values : 2402 // -------------------------------------------------------------------------------- 2403 public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) 2404 { 2405 $v_result = 1; 2406 $v_header = array(); 2407 2408 // ----- Recuperate the current number of elt in list 2409 $v_nb = sizeof($p_result_list); 2410 2411 // ----- Loop on the files 2412 for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) { 2413 // ----- Format the filename 2414 $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false); 2415 2416 // ----- Skip empty file names 2417 // TBC : Can this be possible ? not checked in DescrParseAtt ? 2418 if ($p_filedescr_list[$j]['filename'] == "") { 2419 continue; 2420 } 2421 2422 // ----- Check the filename 2423 if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) { 2424 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist"); 2425 2426 return PclZip::errorCode(); 2427 } 2428 2429 // ----- Look if it is a file or a dir with no all path remove option 2430 // or a dir with all its path removed 2431 // if ( (is_file($p_filedescr_list[$j]['filename'])) 2432 // || ( is_dir($p_filedescr_list[$j]['filename']) 2433 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]))) { 2434 2435 // ----- Add the file 2436 $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options); 2437 if ($v_result != 1) { 2438 return $v_result; 2439 } 2440 2441 // ----- Store the file infos 2442 $p_result_list[$v_nb++] = $v_header; 2443 } 2444 } 2445 2446 // ----- Return 2447 return $v_result; 2448 } 2449 // -------------------------------------------------------------------------------- 2450 2451 // -------------------------------------------------------------------------------- 2452 // Function : privAddFile() 2453 // Description : 2454 // Parameters : 2455 // Return Values : 2456 // -------------------------------------------------------------------------------- 2457 public function privAddFile($p_filedescr, &$p_header, &$p_options) 2458 { 2459 $v_result = 1; 2460 2461 // ----- Working variable 2462 $p_filename = $p_filedescr['filename']; 2463 2464 // TBC : Already done in the fileAtt check ... ? 2465 if ($p_filename == "") { 2466 // ----- Error log 2467 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); 2468 2469 // ----- Return 2470 return PclZip::errorCode(); 2471 } 2472 2473 // ----- Look for a stored different filename 2474 /* TBC : Removed 2475 if (isset($p_filedescr['stored_filename'])) { 2476 $v_stored_filename = $p_filedescr['stored_filename']; 2477 } else { 2478 $v_stored_filename = $p_filedescr['stored_filename']; 2479 } 2480 */ 2481 2482 // ----- Set the file properties 2483 clearstatcache(); 2484 $p_header['version'] = 20; 2485 $p_header['version_extracted'] = 10; 2486 $p_header['flag'] = 0; 2487 $p_header['compression'] = 0; 2488 $p_header['crc'] = 0; 2489 $p_header['compressed_size'] = 0; 2490 $p_header['filename_len'] = strlen($p_filename); 2491 $p_header['extra_len'] = 0; 2492 $p_header['disk'] = 0; 2493 $p_header['internal'] = 0; 2494 $p_header['offset'] = 0; 2495 $p_header['filename'] = $p_filename; 2496 // TBC : Removed $p_header['stored_filename'] = $v_stored_filename; 2497 $p_header['stored_filename'] = $p_filedescr['stored_filename']; 2498 $p_header['extra'] = ''; 2499 $p_header['status'] = 'ok'; 2500 $p_header['index'] = -1; 2501 2502 // ----- Look for regular file 2503 if ($p_filedescr['type'] == 'file') { 2504 $p_header['external'] = 0x00000000; 2505 $p_header['size'] = filesize($p_filename); 2506 2507 // ----- Look for regular folder 2508 } elseif ($p_filedescr['type'] == 'folder') { 2509 $p_header['external'] = 0x00000010; 2510 $p_header['mtime'] = filemtime($p_filename); 2511 $p_header['size'] = filesize($p_filename); 2512 2513 // ----- Look for virtual file 2514 } elseif ($p_filedescr['type'] == 'virtual_file') { 2515 $p_header['external'] = 0x00000000; 2516 $p_header['size'] = strlen($p_filedescr['content']); 2517 } 2518 2519 // ----- Look for filetime 2520 if (isset($p_filedescr['mtime'])) { 2521 $p_header['mtime'] = $p_filedescr['mtime']; 2522 } elseif ($p_filedescr['type'] == 'virtual_file') { 2523 $p_header['mtime'] = time(); 2524 } else { 2525 $p_header['mtime'] = filemtime($p_filename); 2526 } 2527 2528 // ------ Look for file comment 2529 if (isset($p_filedescr['comment'])) { 2530 $p_header['comment_len'] = strlen($p_filedescr['comment']); 2531 $p_header['comment'] = $p_filedescr['comment']; 2532 } else { 2533 $p_header['comment_len'] = 0; 2534 $p_header['comment'] = ''; 2535 } 2536 2537 // ----- Look for pre-add callback 2538 if (isset($p_options[PCLZIP_CB_PRE_ADD])) { 2539 2540 // ----- Generate a local information 2541 $v_local_header = array(); 2542 $this->privConvertHeader2FileInfo($p_header, $v_local_header); 2543 2544 // ----- Call the callback 2545 // Here I do not use call_user_func() because I need to send a reference to the 2546 // header. 2547 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); 2548 $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); 2549 if ($v_result == 0) { 2550 // ----- Change the file status 2551 $p_header['status'] = "skipped"; 2552 $v_result = 1; 2553 } 2554 2555 // ----- Update the informations 2556 // Only some fields can be modified 2557 if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { 2558 $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); 2559 } 2560 } 2561 2562 // ----- Look for empty stored filename 2563 if ($p_header['stored_filename'] == "") { 2564 $p_header['status'] = "filtered"; 2565 } 2566 2567 // ----- Check the path length 2568 if (strlen($p_header['stored_filename']) > 0xFF) { 2569 $p_header['status'] = 'filename_too_long'; 2570 } 2571 2572 // ----- Look if no error, or file not skipped 2573 if ($p_header['status'] == 'ok') { 2574 2575 // ----- Look for a file 2576 if ($p_filedescr['type'] == 'file') { 2577 // ----- Look for using temporary file to zip 2578 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'])))) { 2579 $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); 2580 if ($v_result < PCLZIP_ERR_NO_ERROR) { 2581 return $v_result; 2582 } 2583 2584 // ----- Use "in memory" zip algo 2585 } else { 2586 2587 // ----- Open the source file 2588 if (($v_file = @fopen($p_filename, "rb")) == 0) { 2589 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); 2590 2591 return PclZip::errorCode(); 2592 } 2593 2594 // ----- Read the file content 2595 $v_content = @fread($v_file, $p_header['size']); 2596 2597 // ----- Close the file 2598 @fclose($v_file); 2599 2600 // ----- Calculate the CRC 2601 $p_header['crc'] = @crc32($v_content); 2602 2603 // ----- Look for no compression 2604 if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { 2605 // ----- Set header parameters 2606 $p_header['compressed_size'] = $p_header['size']; 2607 $p_header['compression'] = 0; 2608 2609 // ----- Look for normal compression 2610 } else { 2611 // ----- Compress the content 2612 $v_content = @gzdeflate($v_content); 2613 2614 // ----- Set header parameters 2615 $p_header['compressed_size'] = strlen($v_content); 2616 $p_header['compression'] = 8; 2617 } 2618 2619 // ----- Call the header generation 2620 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2621 @fclose($v_file); 2622 2623 return $v_result; 2624 } 2625 2626 // ----- Write the compressed (or not) content 2627 @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); 2628 2629 } 2630 2631 // ----- Look for a virtual file (a file from string) 2632 } elseif ($p_filedescr['type'] == 'virtual_file') { 2633 2634 $v_content = $p_filedescr['content']; 2635 2636 // ----- Calculate the CRC 2637 $p_header['crc'] = @crc32($v_content); 2638 2639 // ----- Look for no compression 2640 if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { 2641 // ----- Set header parameters 2642 $p_header['compressed_size'] = $p_header['size']; 2643 $p_header['compression'] = 0; 2644 2645 // ----- Look for normal compression 2646 } else { 2647 // ----- Compress the content 2648 $v_content = @gzdeflate($v_content); 2649 2650 // ----- Set header parameters 2651 $p_header['compressed_size'] = strlen($v_content); 2652 $p_header['compression'] = 8; 2653 } 2654 2655 // ----- Call the header generation 2656 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2657 @fclose($v_file); 2658 2659 return $v_result; 2660 } 2661 2662 // ----- Write the compressed (or not) content 2663 @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); 2664 2665 // ----- Look for a directory 2666 } elseif ($p_filedescr['type'] == 'folder') { 2667 // ----- Look for directory last '/' 2668 if (@substr($p_header['stored_filename'], -1) != '/') { 2669 $p_header['stored_filename'] .= '/'; 2670 } 2671 2672 // ----- Set the file properties 2673 $p_header['size'] = 0; 2674 //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked 2675 $p_header['external'] = 0x00000010; // Value for a folder : to be checked 2676 2677 // ----- Call the header generation 2678 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2679 return $v_result; 2680 } 2681 } 2682 } 2683 2684 // ----- Look for post-add callback 2685 if (isset($p_options[PCLZIP_CB_POST_ADD])) { 2686 2687 // ----- Generate a local information 2688 $v_local_header = array(); 2689 $this->privConvertHeader2FileInfo($p_header, $v_local_header); 2690 2691 // ----- Call the callback 2692 // Here I do not use call_user_func() because I need to send a reference to the 2693 // header. 2694 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); 2695 $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); 2696 if ($v_result == 0) { 2697 // ----- Ignored 2698 $v_result = 1; 2699 } 2700 2701 // ----- Update the informations 2702 // Nothing can be modified 2703 } 2704 2705 // ----- Return 2706 return $v_result; 2707 } 2708 // -------------------------------------------------------------------------------- 2709 2710 // -------------------------------------------------------------------------------- 2711 // Function : privAddFileUsingTempFile() 2712 // Description : 2713 // Parameters : 2714 // Return Values : 2715 // -------------------------------------------------------------------------------- 2716 public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) 2717 { 2718 $v_result = PCLZIP_ERR_NO_ERROR; 2719 2720 // ----- Working variable 2721 $p_filename = $p_filedescr['filename']; 2722 2723 // ----- Open the source file 2724 if (($v_file = @fopen($p_filename, "rb")) == 0) { 2725 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); 2726 2727 return PclZip::errorCode(); 2728 } 2729 2730 // ----- Creates a compressed temporary file 2731 $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; 2732 if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { 2733 fclose($v_file); 2734 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); 2735 2736 return PclZip::errorCode(); 2737 } 2738 2739 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 2740 $v_size = filesize($p_filename); 2741 while ($v_size != 0) { 2742 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2743 $v_buffer = @fread($v_file, $v_read_size); 2744 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 2745 @gzputs($v_file_compressed, $v_buffer, $v_read_size); 2746 $v_size -= $v_read_size; 2747 } 2748 2749 // ----- Close the file 2750 @fclose($v_file); 2751 @gzclose($v_file_compressed); 2752 2753 // ----- Check the minimum file size 2754 if (filesize($v_gzip_temp_name) < 18) { 2755 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes'); 2756 2757 return PclZip::errorCode(); 2758 } 2759 2760 // ----- Extract the compressed attributes 2761 if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { 2762 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); 2763 2764 return PclZip::errorCode(); 2765 } 2766 2767 // ----- Read the gzip file header 2768 $v_binary_data = @fread($v_file_compressed, 10); 2769 $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); 2770 2771 // ----- Check some parameters 2772 $v_data_header['os'] = bin2hex($v_data_header['os']); 2773 2774 // ----- Read the gzip file footer 2775 @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8); 2776 $v_binary_data = @fread($v_file_compressed, 8); 2777 $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); 2778 2779 // ----- Set the attributes 2780 $p_header['compression'] = ord($v_data_header['cm']); 2781 //$p_header['mtime'] = $v_data_header['mtime']; 2782 $p_header['crc'] = $v_data_footer['crc']; 2783 $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18; 2784 2785 // ----- Close the file 2786 @fclose($v_file_compressed); 2787 2788 // ----- Call the header generation 2789 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { 2790 return $v_result; 2791 } 2792 2793 // ----- Add the compressed data 2794 if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { 2795 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); 2796 2797 return PclZip::errorCode(); 2798 } 2799 2800 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 2801 fseek($v_file_compressed, 10); 2802 $v_size = $p_header['compressed_size']; 2803 while ($v_size != 0) { 2804 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 2805 $v_buffer = @fread($v_file_compressed, $v_read_size); 2806 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 2807 @fwrite($this->zip_fd, $v_buffer, $v_read_size); 2808 $v_size -= $v_read_size; 2809 } 2810 2811 // ----- Close the file 2812 @fclose($v_file_compressed); 2813 2814 // ----- Unlink the temporary file 2815 @unlink($v_gzip_temp_name); 2816 2817 // ----- Return 2818 return $v_result; 2819 } 2820 // -------------------------------------------------------------------------------- 2821 2822 // -------------------------------------------------------------------------------- 2823 // Function : privCalculateStoredFilename() 2824 // Description : 2825 // Based on file descriptor properties and global options, this method 2826 // calculate the filename that will be stored in the archive. 2827 // Parameters : 2828 // Return Values : 2829 // -------------------------------------------------------------------------------- 2830 public function privCalculateStoredFilename(&$p_filedescr, &$p_options) 2831 { 2832 $v_result = 1; 2833 2834 // ----- Working variables 2835 $p_filename = $p_filedescr['filename']; 2836 if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { 2837 $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; 2838 } else { 2839 $p_add_dir = ''; 2840 } 2841 if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { 2842 $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; 2843 } else { 2844 $p_remove_dir = ''; 2845 } 2846 if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { 2847 $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; 2848 } else { 2849 $p_remove_all_dir = 0; 2850 } 2851 2852 // ----- Look for full name change 2853 if (isset($p_filedescr['new_full_name'])) { 2854 // ----- Remove drive letter if any 2855 $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); 2856 2857 // ----- Look for path and/or short name change 2858 } else { 2859 2860 // ----- Look for short name change 2861 // Its when we cahnge just the filename but not the path 2862 if (isset($p_filedescr['new_short_name'])) { 2863 $v_path_info = pathinfo($p_filename); 2864 $v_dir = ''; 2865 if ($v_path_info['dirname'] != '') { 2866 $v_dir = $v_path_info['dirname'] . '/'; 2867 } 2868 $v_stored_filename = $v_dir . $p_filedescr['new_short_name']; 2869 } else { 2870 // ----- Calculate the stored filename 2871 $v_stored_filename = $p_filename; 2872 } 2873 2874 // ----- Look for all path to remove 2875 if ($p_remove_all_dir) { 2876 $v_stored_filename = basename($p_filename); 2877 2878 // ----- Look for partial path remove 2879 } elseif ($p_remove_dir != "") { 2880 if (substr($p_remove_dir, -1) != '/') { 2881 $p_remove_dir .= "/"; 2882 } 2883 2884 if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) { 2885 2886 if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) { 2887 $p_remove_dir = "./" . $p_remove_dir; 2888 } 2889 if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) { 2890 $p_remove_dir = substr($p_remove_dir, 2); 2891 } 2892 } 2893 2894 $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename); 2895 if ($v_compare > 0) { 2896 if ($v_compare == 2) { 2897 $v_stored_filename = ""; 2898 } else { 2899 $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir)); 2900 } 2901 } 2902 } 2903 2904 // ----- Remove drive letter if any 2905 $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); 2906 2907 // ----- Look for path to add 2908 if ($p_add_dir != "") { 2909 if (substr($p_add_dir, -1) == "/") { 2910 $v_stored_filename = $p_add_dir . $v_stored_filename; 2911 } else { 2912 $v_stored_filename = $p_add_dir . "/" . $v_stored_filename; 2913 } 2914 } 2915 } 2916 2917 // ----- Filename (reduce the path of stored name) 2918 $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); 2919 $p_filedescr['stored_filename'] = $v_stored_filename; 2920 2921 // ----- Return 2922 return $v_result; 2923 } 2924 // -------------------------------------------------------------------------------- 2925 2926 // -------------------------------------------------------------------------------- 2927 // Function : privWriteFileHeader() 2928 // Description : 2929 // Parameters : 2930 // Return Values : 2931 // -------------------------------------------------------------------------------- 2932 public function privWriteFileHeader(&$p_header) 2933 { 2934 $v_result = 1; 2935 2936 // ----- Store the offset position of the file 2937 $p_header['offset'] = ftell($this->zip_fd); 2938 2939 // ----- Transform UNIX mtime to DOS format mdate/mtime 2940 $v_date = getdate($p_header['mtime']); 2941 $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; 2942 $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; 2943 2944 // ----- Packed data 2945 $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']); 2946 2947 // ----- Write the first 148 bytes of the header in the archive 2948 fputs($this->zip_fd, $v_binary_data, 30); 2949 2950 // ----- Write the variable fields 2951 if (strlen($p_header['stored_filename']) != 0) { 2952 fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); 2953 } 2954 if ($p_header['extra_len'] != 0) { 2955 fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); 2956 } 2957 2958 // ----- Return 2959 return $v_result; 2960 } 2961 // -------------------------------------------------------------------------------- 2962 2963 // -------------------------------------------------------------------------------- 2964 // Function : privWriteCentralFileHeader() 2965 // Description : 2966 // Parameters : 2967 // Return Values : 2968 // -------------------------------------------------------------------------------- 2969 public function privWriteCentralFileHeader(&$p_header) 2970 { 2971 $v_result = 1; 2972 2973 // TBC 2974 //for (reset($p_header); $key = key($p_header); next($p_header)) { 2975 //} 2976 2977 // ----- Transform UNIX mtime to DOS format mdate/mtime 2978 $v_date = getdate($p_header['mtime']); 2979 $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2; 2980 $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday']; 2981 2982 // ----- Packed data 2983 $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']); 2984 2985 // ----- Write the 42 bytes of the header in the zip file 2986 fputs($this->zip_fd, $v_binary_data, 46); 2987 2988 // ----- Write the variable fields 2989 if (strlen($p_header['stored_filename']) != 0) { 2990 fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); 2991 } 2992 if ($p_header['extra_len'] != 0) { 2993 fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); 2994 } 2995 if ($p_header['comment_len'] != 0) { 2996 fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); 2997 } 2998 2999 // ----- Return 3000 return $v_result; 3001 } 3002 // -------------------------------------------------------------------------------- 3003 3004 // -------------------------------------------------------------------------------- 3005 // Function : privWriteCentralHeader() 3006 // Description : 3007 // Parameters : 3008 // Return Values : 3009 // -------------------------------------------------------------------------------- 3010 public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) 3011 { 3012 $v_result = 1; 3013 3014 // ----- Packed data 3015 $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); 3016 3017 // ----- Write the 22 bytes of the header in the zip file 3018 fputs($this->zip_fd, $v_binary_data, 22); 3019 3020 // ----- Write the variable fields 3021 if (strlen($p_comment) != 0) { 3022 fputs($this->zip_fd, $p_comment, strlen($p_comment)); 3023 } 3024 3025 // ----- Return 3026 return $v_result; 3027 } 3028 // -------------------------------------------------------------------------------- 3029 3030 // -------------------------------------------------------------------------------- 3031 // Function : privList() 3032 // Description : 3033 // Parameters : 3034 // Return Values : 3035 // -------------------------------------------------------------------------------- 3036 public function privList(&$p_list) 3037 { 3038 $v_result = 1; 3039 3040 // ----- Magic quotes trick 3041 $this->privDisableMagicQuotes(); 3042 3043 // ----- Open the zip file 3044 if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) { 3045 // ----- Magic quotes trick 3046 $this->privSwapBackMagicQuotes(); 3047 3048 // ----- Error log 3049 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->zipname . '\' in binary read mode'); 3050 3051 // ----- Return 3052 return PclZip::errorCode(); 3053 } 3054 3055 // ----- Read the central directory informations 3056 $v_central_dir = array(); 3057 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 3058 $this->privSwapBackMagicQuotes(); 3059 3060 return $v_result; 3061 } 3062 3063 // ----- Go to beginning of Central Dir 3064 @rewind($this->zip_fd); 3065 if (@fseek($this->zip_fd, $v_central_dir['offset'])) { 3066 $this->privSwapBackMagicQuotes(); 3067 3068 // ----- Error log 3069 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 3070 3071 // ----- Return 3072 return PclZip::errorCode(); 3073 } 3074 3075 // ----- Read each entry 3076 for ($i = 0; $i < $v_central_dir['entries']; $i++) { 3077 // ----- Read the file header 3078 if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { 3079 $this->privSwapBackMagicQuotes(); 3080 3081 return $v_result; 3082 } 3083 $v_header['index'] = $i; 3084 3085 // ----- Get the only interesting attributes 3086 $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); 3087 unset($v_header); 3088 } 3089 3090 // ----- Close the zip file 3091 $this->privCloseFd(); 3092 3093 // ----- Magic quotes trick 3094 $this->privSwapBackMagicQuotes(); 3095 3096 // ----- Return 3097 return $v_result; 3098 } 3099 // -------------------------------------------------------------------------------- 3100 3101 // -------------------------------------------------------------------------------- 3102 // Function : privConvertHeader2FileInfo() 3103 // Description : 3104 // This function takes the file informations from the central directory 3105 // entries and extract the interesting parameters that will be given back. 3106 // The resulting file infos are set in the array $p_info 3107 // $p_info['filename'] : Filename with full path. Given by user (add), 3108 // extracted in the filesystem (extract). 3109 // $p_info['stored_filename'] : Stored filename in the archive. 3110 // $p_info['size'] = Size of the file. 3111 // $p_info['compressed_size'] = Compressed size of the file. 3112 // $p_info['mtime'] = Last modification date of the file. 3113 // $p_info['comment'] = Comment associated with the file. 3114 // $p_info['folder'] = true/false : indicates if the entry is a folder or not. 3115 // $p_info['status'] = status of the action on the file. 3116 // $p_info['crc'] = CRC of the file content. 3117 // Parameters : 3118 // Return Values : 3119 // -------------------------------------------------------------------------------- 3120 public function privConvertHeader2FileInfo($p_header, &$p_info) 3121 { 3122 $v_result = 1; 3123 3124 // ----- Get the interesting attributes 3125 $v_temp_path = PclZipUtilPathReduction($p_header['filename']); 3126 $p_info['filename'] = $v_temp_path; 3127 $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); 3128 $p_info['stored_filename'] = $v_temp_path; 3129 $p_info['size'] = $p_header['size']; 3130 $p_info['compressed_size'] = $p_header['compressed_size']; 3131 $p_info['mtime'] = $p_header['mtime']; 3132 $p_info['comment'] = $p_header['comment']; 3133 $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010); 3134 $p_info['index'] = $p_header['index']; 3135 $p_info['status'] = $p_header['status']; 3136 $p_info['crc'] = $p_header['crc']; 3137 3138 // ----- Return 3139 return $v_result; 3140 } 3141 // -------------------------------------------------------------------------------- 3142 3143 // -------------------------------------------------------------------------------- 3144 // Function : privExtractByRule() 3145 // Description : 3146 // Extract a file or directory depending of rules (by index, by name, ...) 3147 // Parameters : 3148 // $p_file_list : An array where will be placed the properties of each 3149 // extracted file 3150 // $p_path : Path to add while writing the extracted files 3151 // $p_remove_path : Path to remove (from the file memorized path) while writing the 3152 // extracted files. If the path does not match the file path, 3153 // the file is extracted with its memorized path. 3154 // $p_remove_path does not apply to 'list' mode. 3155 // $p_path and $p_remove_path are commulative. 3156 // Return Values : 3157 // 1 on success,0 or less on error (see error code list) 3158 // -------------------------------------------------------------------------------- 3159 public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) 3160 { 3161 $v_result = 1; 3162 3163 // ----- Magic quotes trick 3164 $this->privDisableMagicQuotes(); 3165 3166 // ----- Check the path 3167 if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2) != ":/"))) { 3168 $p_path = "./" . $p_path; 3169 } 3170 3171 // ----- Reduce the path last (and duplicated) '/' 3172 if (($p_path != "./") && ($p_path != "/")) { 3173 // ----- Look for the path end '/' 3174 while (substr($p_path, -1) == "/") { 3175 $p_path = substr($p_path, 0, strlen($p_path) - 1); 3176 } 3177 } 3178 3179 // ----- Look for path to remove format (should end by /) 3180 if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { 3181 $p_remove_path .= '/'; 3182 } 3183 $p_remove_path_size = strlen($p_remove_path); 3184 3185 // ----- Open the zip file 3186 if (($v_result = $this->privOpenFd('rb')) != 1) { 3187 $this->privSwapBackMagicQuotes(); 3188 3189 return $v_result; 3190 } 3191 3192 // ----- Read the central directory informations 3193 $v_central_dir = array(); 3194 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 3195 // ----- Close the zip file 3196 $this->privCloseFd(); 3197 $this->privSwapBackMagicQuotes(); 3198 3199 return $v_result; 3200 } 3201 3202 // ----- Start at beginning of Central Dir 3203 $v_pos_entry = $v_central_dir['offset']; 3204 3205 // ----- Read each entry 3206 $j_start = 0; 3207 for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { 3208 3209 // ----- Read next Central dir entry 3210 @rewind($this->zip_fd); 3211 if (@fseek($this->zip_fd, $v_pos_entry)) { 3212 // ----- Close the zip file 3213 $this->privCloseFd(); 3214 $this->privSwapBackMagicQuotes(); 3215 3216 // ----- Error log 3217 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 3218 3219 // ----- Return 3220 return PclZip::errorCode(); 3221 } 3222 3223 // ----- Read the file header 3224 $v_header = array(); 3225 if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) { 3226 // ----- Close the zip file 3227 $this->privCloseFd(); 3228 $this->privSwapBackMagicQuotes(); 3229 3230 return $v_result; 3231 } 3232 3233 // ----- Store the index 3234 $v_header['index'] = $i; 3235 3236 // ----- Store the file position 3237 $v_pos_entry = ftell($this->zip_fd); 3238 3239 // ----- Look for the specific extract rules 3240 $v_extract = false; 3241 3242 // ----- Look for extract by name rule 3243 if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { 3244 3245 // ----- Look if the filename is in the list 3246 for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) { 3247 3248 // ----- Look for a directory 3249 if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { 3250 3251 // ----- Look if the directory is in the filename path 3252 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])) { 3253 $v_extract = true; 3254 } 3255 3256 // ----- Look for a filename 3257 } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { 3258 $v_extract = true; 3259 } 3260 } 3261 // ----- Look for extract by ereg rule 3262 // ereg() is deprecated with PHP 5.3 3263 /* 3264 elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) 3265 && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { 3266 3267 if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { 3268 $v_extract = true; 3269 } 3270 } 3271 */ 3272 3273 // ----- Look for extract by preg rule 3274 } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { 3275 3276 if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { 3277 $v_extract = true; 3278 } 3279 3280 // ----- Look for extract by index rule 3281 } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { 3282 3283 // ----- Look if the index is in the list 3284 for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) { 3285 3286 if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { 3287 $v_extract = true; 3288 } 3289 if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { 3290 $j_start = $j + 1; 3291 } 3292 3293 if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { 3294 break; 3295 } 3296 } 3297 3298 // ----- Look for no rule, which means extract all the archive 3299 } else { 3300 $v_extract = true; 3301 } 3302 3303 // ----- Check compression method 3304 if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) { 3305 $v_header['status'] = 'unsupported_compression'; 3306 3307 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3308 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3309 3310 $this->privSwapBackMagicQuotes(); 3311 3312 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '" . $v_header['stored_filename'] . "' is " . "compressed by an unsupported compression " . "method (" . $v_header['compression'] . ") "); 3313 3314 return PclZip::errorCode(); 3315 } 3316 } 3317 3318 // ----- Check encrypted files 3319 if (($v_extract) && (($v_header['flag'] & 1) == 1)) { 3320 $v_header['status'] = 'unsupported_encryption'; 3321 3322 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3323 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3324 3325 $this->privSwapBackMagicQuotes(); 3326 3327 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for " . " filename '" . $v_header['stored_filename'] . "'"); 3328 3329 return PclZip::errorCode(); 3330 } 3331 } 3332 3333 // ----- Look for real extraction 3334 if (($v_extract) && ($v_header['status'] != 'ok')) { 3335 $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]); 3336 if ($v_result != 1) { 3337 $this->privCloseFd(); 3338 $this->privSwapBackMagicQuotes(); 3339 3340 return $v_result; 3341 } 3342 3343 $v_extract = false; 3344 } 3345 3346 // ----- Look for real extraction 3347 if ($v_extract) { 3348 3349 // ----- Go to the file position 3350 @rewind($this->zip_fd); 3351 if (@fseek($this->zip_fd, $v_header['offset'])) { 3352 // ----- Close the zip file 3353 $this->privCloseFd(); 3354 3355 $this->privSwapBackMagicQuotes(); 3356 3357 // ----- Error log 3358 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 3359 3360 // ----- Return 3361 return PclZip::errorCode(); 3362 } 3363 3364 // ----- Look for extraction as string 3365 if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { 3366 3367 $v_string = ''; 3368 3369 // ----- Extracting the file 3370 $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); 3371 if ($v_result1 < 1) { 3372 $this->privCloseFd(); 3373 $this->privSwapBackMagicQuotes(); 3374 3375 return $v_result1; 3376 } 3377 3378 // ----- Get the only interesting attributes 3379 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) { 3380 // ----- Close the zip file 3381 $this->privCloseFd(); 3382 $this->privSwapBackMagicQuotes(); 3383 3384 return $v_result; 3385 } 3386 3387 // ----- Set the file content 3388 $p_file_list[$v_nb_extracted]['content'] = $v_string; 3389 3390 // ----- Next extracted file 3391 $v_nb_extracted++; 3392 3393 // ----- Look for user callback abort 3394 if ($v_result1 == 2) { 3395 break; 3396 } 3397 3398 // ----- Look for extraction in standard output 3399 } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { 3400 // ----- Extracting the file in standard output 3401 $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); 3402 if ($v_result1 < 1) { 3403 $this->privCloseFd(); 3404 $this->privSwapBackMagicQuotes(); 3405 3406 return $v_result1; 3407 } 3408 3409 // ----- Get the only interesting attributes 3410 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { 3411 $this->privCloseFd(); 3412 $this->privSwapBackMagicQuotes(); 3413 3414 return $v_result; 3415 } 3416 3417 // ----- Look for user callback abort 3418 if ($v_result1 == 2) { 3419 break; 3420 } 3421 3422 // ----- Look for normal extraction 3423 } else { 3424 // ----- Extracting the file 3425 $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options); 3426 if ($v_result1 < 1) { 3427 $this->privCloseFd(); 3428 $this->privSwapBackMagicQuotes(); 3429 3430 return $v_result1; 3431 } 3432 3433 // ----- Get the only interesting attributes 3434 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { 3435 // ----- Close the zip file 3436 $this->privCloseFd(); 3437 $this->privSwapBackMagicQuotes(); 3438 3439 return $v_result; 3440 } 3441 3442 // ----- Look for user callback abort 3443 if ($v_result1 == 2) { 3444 break; 3445 } 3446 } 3447 } 3448 } 3449 3450 // ----- Close the zip file 3451 $this->privCloseFd(); 3452 $this->privSwapBackMagicQuotes(); 3453 3454 // ----- Return 3455 return $v_result; 3456 } 3457 // -------------------------------------------------------------------------------- 3458 3459 // -------------------------------------------------------------------------------- 3460 // Function : privExtractFile() 3461 // Description : 3462 // Parameters : 3463 // Return Values : 3464 // 3465 // 1 : ... ? 3466 // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback 3467 // -------------------------------------------------------------------------------- 3468 public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) 3469 { 3470 $v_result = 1; 3471 3472 // ----- Read the file header 3473 if (($v_result = $this->privReadFileHeader($v_header)) != 1) { 3474 // ----- Return 3475 return $v_result; 3476 } 3477 3478 // ----- Check that the file header is coherent with $p_entry info 3479 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { 3480 // TBC 3481 } 3482 3483 // ----- Look for all path to remove 3484 if ($p_remove_all_path == true) { 3485 // ----- Look for folder entry that not need to be extracted 3486 if (($p_entry['external'] & 0x00000010) == 0x00000010) { 3487 3488 $p_entry['status'] = "filtered"; 3489 3490 return $v_result; 3491 } 3492 3493 // ----- Get the basename of the path 3494 $p_entry['filename'] = basename($p_entry['filename']); 3495 3496 // ----- Look for path to remove 3497 } elseif ($p_remove_path != "") { 3498 if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) { 3499 3500 // ----- Change the file status 3501 $p_entry['status'] = "filtered"; 3502 3503 // ----- Return 3504 return $v_result; 3505 } 3506 3507 $p_remove_path_size = strlen($p_remove_path); 3508 if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) { 3509 3510 // ----- Remove the path 3511 $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); 3512 3513 } 3514 } 3515 3516 // ----- Add the path 3517 if ($p_path != '') { 3518 $p_entry['filename'] = $p_path . "/" . $p_entry['filename']; 3519 } 3520 3521 // ----- Check a base_dir_restriction 3522 if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { 3523 $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']); 3524 if ($v_inclusion == 0) { 3525 3526 PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '" . $p_entry['filename'] . "' is " . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); 3527 3528 return PclZip::errorCode(); 3529 } 3530 } 3531 3532 // ----- Look for pre-extract callback 3533 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { 3534 3535 // ----- Generate a local information 3536 $v_local_header = array(); 3537 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3538 3539 // ----- Call the callback 3540 // Here I do not use call_user_func() because I need to send a reference to the 3541 // header. 3542 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); 3543 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); 3544 if ($v_result == 0) { 3545 // ----- Change the file status 3546 $p_entry['status'] = "skipped"; 3547 $v_result = 1; 3548 } 3549 3550 // ----- Look for abort result 3551 if ($v_result == 2) { 3552 // ----- This status is internal and will be changed in 'skipped' 3553 $p_entry['status'] = "aborted"; 3554 $v_result = PCLZIP_ERR_USER_ABORTED; 3555 } 3556 3557 // ----- Update the informations 3558 // Only some fields can be modified 3559 $p_entry['filename'] = $v_local_header['filename']; 3560 } 3561 3562 // ----- Look if extraction should be done 3563 if ($p_entry['status'] == 'ok') { 3564 3565 // ----- Look for specific actions while the file exist 3566 if (file_exists($p_entry['filename'])) { 3567 3568 // ----- Look if file is a directory 3569 if (is_dir($p_entry['filename'])) { 3570 3571 // ----- Change the file status 3572 $p_entry['status'] = "already_a_directory"; 3573 3574 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3575 // For historical reason first PclZip implementation does not stop 3576 // when this kind of error occurs. 3577 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3578 3579 PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '" . $p_entry['filename'] . "' is " . "already used by an existing directory"); 3580 3581 return PclZip::errorCode(); 3582 } 3583 3584 // ----- Look if file is write protected 3585 } elseif (!is_writeable($p_entry['filename'])) { 3586 3587 // ----- Change the file status 3588 $p_entry['status'] = "write_protected"; 3589 3590 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3591 // For historical reason first PclZip implementation does not stop 3592 // when this kind of error occurs. 3593 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3594 3595 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '" . $p_entry['filename'] . "' exists " . "and is write protected"); 3596 3597 return PclZip::errorCode(); 3598 } 3599 3600 // ----- Look if the extracted file is older 3601 } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) { 3602 // ----- Change the file status 3603 if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) { 3604 } else { 3605 $p_entry['status'] = "newer_exist"; 3606 3607 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR 3608 // For historical reason first PclZip implementation does not stop 3609 // when this kind of error occurs. 3610 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) { 3611 3612 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '" . $p_entry['filename'] . "' exists " . "and option PCLZIP_OPT_REPLACE_NEWER is not selected"); 3613 3614 return PclZip::errorCode(); 3615 } 3616 } 3617 } else { 3618 } 3619 3620 // ----- Check the directory availability and create it if necessary 3621 } else { 3622 if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) { 3623 $v_dir_to_check = $p_entry['filename']; 3624 } elseif (!strstr($p_entry['filename'], "/")) { 3625 $v_dir_to_check = ""; 3626 } else { 3627 $v_dir_to_check = dirname($p_entry['filename']); 3628 } 3629 3630 if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) { 3631 3632 // ----- Change the file status 3633 $p_entry['status'] = "path_creation_fail"; 3634 3635 // ----- Return 3636 //return $v_result; 3637 $v_result = 1; 3638 } 3639 } 3640 } 3641 3642 // ----- Look if extraction should be done 3643 if ($p_entry['status'] == 'ok') { 3644 3645 // ----- Do the extraction (if not a folder) 3646 if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { 3647 // ----- Look for not compressed file 3648 if ($p_entry['compression'] == 0) { 3649 3650 // ----- Opening destination file 3651 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 3652 3653 // ----- Change the file status 3654 $p_entry['status'] = "write_error"; 3655 3656 // ----- Return 3657 return $v_result; 3658 } 3659 3660 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 3661 $v_size = $p_entry['compressed_size']; 3662 while ($v_size != 0) { 3663 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 3664 $v_buffer = @fread($this->zip_fd, $v_read_size); 3665 /* Try to speed up the code 3666 $v_binary_data = pack('a'.$v_read_size, $v_buffer); 3667 @fwrite($v_dest_file, $v_binary_data, $v_read_size); 3668 */ 3669 @fwrite($v_dest_file, $v_buffer, $v_read_size); 3670 $v_size -= $v_read_size; 3671 } 3672 3673 // ----- Closing the destination file 3674 fclose($v_dest_file); 3675 3676 // ----- Change the file mtime 3677 touch($p_entry['filename'], $p_entry['mtime']); 3678 3679 } else { 3680 // ----- TBC 3681 // Need to be finished 3682 if (($p_entry['flag'] & 1) == 1) { 3683 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.'); 3684 3685 return PclZip::errorCode(); 3686 } 3687 3688 // ----- Look for using temporary file to unzip 3689 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'])))) { 3690 $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); 3691 if ($v_result < PCLZIP_ERR_NO_ERROR) { 3692 return $v_result; 3693 } 3694 3695 // ----- Look for extract in memory 3696 } else { 3697 3698 // ----- Read the compressed file in a buffer (one shot) 3699 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); 3700 3701 // ----- Decompress the file 3702 $v_file_content = @gzinflate($v_buffer); 3703 unset($v_buffer); 3704 if ($v_file_content === false) { 3705 3706 // ----- Change the file status 3707 // TBC 3708 $p_entry['status'] = "error"; 3709 3710 return $v_result; 3711 } 3712 3713 // ----- Opening destination file 3714 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 3715 3716 // ----- Change the file status 3717 $p_entry['status'] = "write_error"; 3718 3719 return $v_result; 3720 } 3721 3722 // ----- Write the uncompressed data 3723 @fwrite($v_dest_file, $v_file_content, $p_entry['size']); 3724 unset($v_file_content); 3725 3726 // ----- Closing the destination file 3727 @fclose($v_dest_file); 3728 3729 } 3730 3731 // ----- Change the file mtime 3732 @touch($p_entry['filename'], $p_entry['mtime']); 3733 } 3734 3735 // ----- Look for chmod option 3736 if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { 3737 3738 // ----- Change the mode of the file 3739 @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); 3740 } 3741 3742 } 3743 } 3744 3745 // ----- Change abort status 3746 if ($p_entry['status'] == "aborted") { 3747 $p_entry['status'] = "skipped"; 3748 3749 // ----- Look for post-extract callback 3750 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { 3751 3752 // ----- Generate a local information 3753 $v_local_header = array(); 3754 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3755 3756 // ----- Call the callback 3757 // Here I do not use call_user_func() because I need to send a reference to the 3758 // header. 3759 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); 3760 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); 3761 3762 // ----- Look for abort result 3763 if ($v_result == 2) { 3764 $v_result = PCLZIP_ERR_USER_ABORTED; 3765 } 3766 } 3767 3768 // ----- Return 3769 return $v_result; 3770 } 3771 // -------------------------------------------------------------------------------- 3772 3773 // -------------------------------------------------------------------------------- 3774 // Function : privExtractFileUsingTempFile() 3775 // Description : 3776 // Parameters : 3777 // Return Values : 3778 // -------------------------------------------------------------------------------- 3779 public function privExtractFileUsingTempFile(&$p_entry, &$p_options) 3780 { 3781 $v_result = 1; 3782 3783 // ----- Creates a temporary file 3784 $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz'; 3785 if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { 3786 fclose($v_file); 3787 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode'); 3788 3789 return PclZip::errorCode(); 3790 } 3791 3792 // ----- Write gz file format header 3793 $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); 3794 @fwrite($v_dest_file, $v_binary_data, 10); 3795 3796 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 3797 $v_size = $p_entry['compressed_size']; 3798 while ($v_size != 0) { 3799 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 3800 $v_buffer = @fread($this->zip_fd, $v_read_size); 3801 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 3802 @fwrite($v_dest_file, $v_buffer, $v_read_size); 3803 $v_size -= $v_read_size; 3804 } 3805 3806 // ----- Write gz file format footer 3807 $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); 3808 @fwrite($v_dest_file, $v_binary_data, 8); 3809 3810 // ----- Close the temporary file 3811 @fclose($v_dest_file); 3812 3813 // ----- Opening destination file 3814 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 3815 $p_entry['status'] = "write_error"; 3816 3817 return $v_result; 3818 } 3819 3820 // ----- Open the temporary gz file 3821 if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { 3822 @fclose($v_dest_file); 3823 $p_entry['status'] = "read_error"; 3824 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode'); 3825 3826 return PclZip::errorCode(); 3827 } 3828 3829 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks 3830 $v_size = $p_entry['size']; 3831 while ($v_size != 0) { 3832 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 3833 $v_buffer = @gzread($v_src_file, $v_read_size); 3834 //$v_binary_data = pack('a'.$v_read_size, $v_buffer); 3835 @fwrite($v_dest_file, $v_buffer, $v_read_size); 3836 $v_size -= $v_read_size; 3837 } 3838 @fclose($v_dest_file); 3839 @gzclose($v_src_file); 3840 3841 // ----- Delete the temporary file 3842 @unlink($v_gzip_temp_name); 3843 3844 // ----- Return 3845 return $v_result; 3846 } 3847 // -------------------------------------------------------------------------------- 3848 3849 // -------------------------------------------------------------------------------- 3850 // Function : privExtractFileInOutput() 3851 // Description : 3852 // Parameters : 3853 // Return Values : 3854 // -------------------------------------------------------------------------------- 3855 public function privExtractFileInOutput(&$p_entry, &$p_options) 3856 { 3857 $v_result = 1; 3858 3859 // ----- Read the file header 3860 if (($v_result = $this->privReadFileHeader($v_header)) != 1) { 3861 return $v_result; 3862 } 3863 3864 // ----- Check that the file header is coherent with $p_entry info 3865 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { 3866 // TBC 3867 } 3868 3869 // ----- Look for pre-extract callback 3870 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { 3871 3872 // ----- Generate a local information 3873 $v_local_header = array(); 3874 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3875 3876 // ----- Call the callback 3877 // Here I do not use call_user_func() because I need to send a reference to the 3878 // header. 3879 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); 3880 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); 3881 if ($v_result == 0) { 3882 // ----- Change the file status 3883 $p_entry['status'] = "skipped"; 3884 $v_result = 1; 3885 } 3886 3887 // ----- Look for abort result 3888 if ($v_result == 2) { 3889 // ----- This status is internal and will be changed in 'skipped' 3890 $p_entry['status'] = "aborted"; 3891 $v_result = PCLZIP_ERR_USER_ABORTED; 3892 } 3893 3894 // ----- Update the informations 3895 // Only some fields can be modified 3896 $p_entry['filename'] = $v_local_header['filename']; 3897 } 3898 3899 // ----- Trace 3900 3901 // ----- Look if extraction should be done 3902 if ($p_entry['status'] == 'ok') { 3903 3904 // ----- Do the extraction (if not a folder) 3905 if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { 3906 // ----- Look for not compressed file 3907 if ($p_entry['compressed_size'] == $p_entry['size']) { 3908 3909 // ----- Read the file in a buffer (one shot) 3910 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); 3911 3912 // ----- Send the file to the output 3913 echo $v_buffer; 3914 unset($v_buffer); 3915 } else { 3916 3917 // ----- Read the compressed file in a buffer (one shot) 3918 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); 3919 3920 // ----- Decompress the file 3921 $v_file_content = gzinflate($v_buffer); 3922 unset($v_buffer); 3923 3924 // ----- Send the file to the output 3925 echo $v_file_content; 3926 unset($v_file_content); 3927 } 3928 } 3929 } 3930 3931 // ----- Change abort status 3932 if ($p_entry['status'] == "aborted") { 3933 $p_entry['status'] = "skipped"; 3934 3935 // ----- Look for post-extract callback 3936 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { 3937 3938 // ----- Generate a local information 3939 $v_local_header = array(); 3940 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3941 3942 // ----- Call the callback 3943 // Here I do not use call_user_func() because I need to send a reference to the 3944 // header. 3945 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); 3946 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); 3947 3948 // ----- Look for abort result 3949 if ($v_result == 2) { 3950 $v_result = PCLZIP_ERR_USER_ABORTED; 3951 } 3952 } 3953 3954 return $v_result; 3955 } 3956 // -------------------------------------------------------------------------------- 3957 3958 // -------------------------------------------------------------------------------- 3959 // Function : privExtractFileAsString() 3960 // Description : 3961 // Parameters : 3962 // Return Values : 3963 // -------------------------------------------------------------------------------- 3964 public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) 3965 { 3966 $v_result = 1; 3967 3968 // ----- Read the file header 3969 $v_header = array(); 3970 if (($v_result = $this->privReadFileHeader($v_header)) != 1) { 3971 // ----- Return 3972 return $v_result; 3973 } 3974 3975 // ----- Check that the file header is coherent with $p_entry info 3976 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { 3977 // TBC 3978 } 3979 3980 // ----- Look for pre-extract callback 3981 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { 3982 3983 // ----- Generate a local information 3984 $v_local_header = array(); 3985 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 3986 3987 // ----- Call the callback 3988 // Here I do not use call_user_func() because I need to send a reference to the 3989 // header. 3990 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); 3991 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); 3992 if ($v_result == 0) { 3993 // ----- Change the file status 3994 $p_entry['status'] = "skipped"; 3995 $v_result = 1; 3996 } 3997 3998 // ----- Look for abort result 3999 if ($v_result == 2) { 4000 // ----- This status is internal and will be changed in 'skipped' 4001 $p_entry['status'] = "aborted"; 4002 $v_result = PCLZIP_ERR_USER_ABORTED; 4003 } 4004 4005 // ----- Update the informations 4006 // Only some fields can be modified 4007 $p_entry['filename'] = $v_local_header['filename']; 4008 } 4009 4010 // ----- Look if extraction should be done 4011 if ($p_entry['status'] == 'ok') { 4012 4013 // ----- Do the extraction (if not a folder) 4014 if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) { 4015 // ----- Look for not compressed file 4016 // if ($p_entry['compressed_size'] == $p_entry['size']) 4017 if ($p_entry['compression'] == 0) { 4018 4019 // ----- Reading the file 4020 $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); 4021 } else { 4022 4023 // ----- Reading the file 4024 $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); 4025 4026 // ----- Decompress the file 4027 if (($p_string = @gzinflate($v_data)) === false) { 4028 // TBC 4029 } 4030 } 4031 4032 // ----- Trace 4033 } else { 4034 // TBC : error : can not extract a folder in a string 4035 } 4036 4037 } 4038 4039 // ----- Change abort status 4040 if ($p_entry['status'] == "aborted") { 4041 $p_entry['status'] = "skipped"; 4042 4043 // ----- Look for post-extract callback 4044 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { 4045 4046 // ----- Generate a local information 4047 $v_local_header = array(); 4048 $this->privConvertHeader2FileInfo($p_entry, $v_local_header); 4049 4050 // ----- Swap the content to header 4051 $v_local_header['content'] = $p_string; 4052 $p_string = ''; 4053 4054 // ----- Call the callback 4055 // Here I do not use call_user_func() because I need to send a reference to the 4056 // header. 4057 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); 4058 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); 4059 4060 // ----- Swap back the content to header 4061 $p_string = $v_local_header['content']; 4062 unset($v_local_header['content']); 4063 4064 // ----- Look for abort result 4065 if ($v_result == 2) { 4066 $v_result = PCLZIP_ERR_USER_ABORTED; 4067 } 4068 } 4069 4070 // ----- Return 4071 return $v_result; 4072 } 4073 // -------------------------------------------------------------------------------- 4074 4075 // -------------------------------------------------------------------------------- 4076 // Function : privReadFileHeader() 4077 // Description : 4078 // Parameters : 4079 // Return Values : 4080 // -------------------------------------------------------------------------------- 4081 public function privReadFileHeader(&$p_header) 4082 { 4083 $v_result = 1; 4084 4085 // ----- Read the 4 bytes signature 4086 $v_binary_data = @fread($this->zip_fd, 4); 4087 $v_data = unpack('Vid', $v_binary_data); 4088 4089 // ----- Check signature 4090 if ($v_data['id'] != 0x04034b50) { 4091 4092 // ----- Error log 4093 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); 4094 4095 // ----- Return 4096 return PclZip::errorCode(); 4097 } 4098 4099 // ----- Read the first 42 bytes of the header 4100 $v_binary_data = fread($this->zip_fd, 26); 4101 4102 // ----- Look for invalid block size 4103 if (strlen($v_binary_data) != 26) { 4104 $p_header['filename'] = ""; 4105 $p_header['status'] = "invalid_header"; 4106 4107 // ----- Error log 4108 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); 4109 4110 // ----- Return 4111 return PclZip::errorCode(); 4112 } 4113 4114 // ----- Extract the values 4115 $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); 4116 4117 // ----- Get filename 4118 $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); 4119 4120 // ----- Get extra_fields 4121 if ($v_data['extra_len'] != 0) { 4122 $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); 4123 } else { 4124 $p_header['extra'] = ''; 4125 } 4126 4127 // ----- Extract properties 4128 $p_header['version_extracted'] = $v_data['version']; 4129 $p_header['compression'] = $v_data['compression']; 4130 $p_header['size'] = $v_data['size']; 4131 $p_header['compressed_size'] = $v_data['compressed_size']; 4132 $p_header['crc'] = $v_data['crc']; 4133 $p_header['flag'] = $v_data['flag']; 4134 $p_header['filename_len'] = $v_data['filename_len']; 4135 4136 // ----- Recuperate date in UNIX format 4137 $p_header['mdate'] = $v_data['mdate']; 4138 $p_header['mtime'] = $v_data['mtime']; 4139 if ($p_header['mdate'] && $p_header['mtime']) { 4140 // ----- Extract time 4141 $v_hour = ($p_header['mtime'] & 0xF800) >> 11; 4142 $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; 4143 $v_seconde = ($p_header['mtime'] & 0x001F) * 2; 4144 4145 // ----- Extract date 4146 $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; 4147 $v_month = ($p_header['mdate'] & 0x01E0) >> 5; 4148 $v_day = $p_header['mdate'] & 0x001F; 4149 4150 // ----- Get UNIX date format 4151 $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); 4152 4153 } else { 4154 $p_header['mtime'] = time(); 4155 } 4156 4157 // TBC 4158 //for (reset($v_data); $key = key($v_data); next($v_data)) { 4159 //} 4160 4161 // ----- Set the stored filename 4162 $p_header['stored_filename'] = $p_header['filename']; 4163 4164 // ----- Set the status field 4165 $p_header['status'] = "ok"; 4166 4167 // ----- Return 4168 return $v_result; 4169 } 4170 // -------------------------------------------------------------------------------- 4171 4172 // -------------------------------------------------------------------------------- 4173 // Function : privReadCentralFileHeader() 4174 // Description : 4175 // Parameters : 4176 // Return Values : 4177 // -------------------------------------------------------------------------------- 4178 public function privReadCentralFileHeader(&$p_header) 4179 { 4180 $v_result = 1; 4181 4182 // ----- Read the 4 bytes signature 4183 $v_binary_data = @fread($this->zip_fd, 4); 4184 $v_data = unpack('Vid', $v_binary_data); 4185 4186 // ----- Check signature 4187 if ($v_data['id'] != 0x02014b50) { 4188 4189 // ----- Error log 4190 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); 4191 4192 // ----- Return 4193 return PclZip::errorCode(); 4194 } 4195 4196 // ----- Read the first 42 bytes of the header 4197 $v_binary_data = fread($this->zip_fd, 42); 4198 4199 // ----- Look for invalid block size 4200 if (strlen($v_binary_data) != 42) { 4201 $p_header['filename'] = ""; 4202 $p_header['status'] = "invalid_header"; 4203 4204 // ----- Error log 4205 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data)); 4206 4207 // ----- Return 4208 return PclZip::errorCode(); 4209 } 4210 4211 // ----- Extract the values 4212 $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); 4213 4214 // ----- Get filename 4215 if ($p_header['filename_len'] != 0) { 4216 $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); 4217 } else { 4218 $p_header['filename'] = ''; 4219 } 4220 4221 // ----- Get extra 4222 if ($p_header['extra_len'] != 0) { 4223 $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); 4224 } else { 4225 $p_header['extra'] = ''; 4226 } 4227 4228 // ----- Get comment 4229 if ($p_header['comment_len'] != 0) { 4230 $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); 4231 } else { 4232 $p_header['comment'] = ''; 4233 } 4234 4235 // ----- Extract properties 4236 4237 // ----- Recuperate date in UNIX format 4238 //if ($p_header['mdate'] && $p_header['mtime']) 4239 // TBC : bug : this was ignoring time with 0/0/0 4240 if (1) { 4241 // ----- Extract time 4242 $v_hour = ($p_header['mtime'] & 0xF800) >> 11; 4243 $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; 4244 $v_seconde = ($p_header['mtime'] & 0x001F) * 2; 4245 4246 // ----- Extract date 4247 $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; 4248 $v_month = ($p_header['mdate'] & 0x01E0) >> 5; 4249 $v_day = $p_header['mdate'] & 0x001F; 4250 4251 // ----- Get UNIX date format 4252 $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); 4253 4254 } else { 4255 $p_header['mtime'] = time(); 4256 } 4257 4258 // ----- Set the stored filename 4259 $p_header['stored_filename'] = $p_header['filename']; 4260 4261 // ----- Set default status to ok 4262 $p_header['status'] = 'ok'; 4263 4264 // ----- Look if it is a directory 4265 if (substr($p_header['filename'], -1) == '/') { 4266 //$p_header['external'] = 0x41FF0010; 4267 $p_header['external'] = 0x00000010; 4268 } 4269 4270 // ----- Return 4271 return $v_result; 4272 } 4273 // -------------------------------------------------------------------------------- 4274 4275 // -------------------------------------------------------------------------------- 4276 // Function : privCheckFileHeaders() 4277 // Description : 4278 // Parameters : 4279 // Return Values : 4280 // 1 on success, 4281 // 0 on error; 4282 // -------------------------------------------------------------------------------- 4283 public function privCheckFileHeaders(&$p_local_header, &$p_central_header) 4284 { 4285 $v_result = 1; 4286 4287 // ----- Check the static values 4288 // TBC 4289 if ($p_local_header['filename'] != $p_central_header['filename']) { 4290 } 4291 if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { 4292 } 4293 if ($p_local_header['flag'] != $p_central_header['flag']) { 4294 } 4295 if ($p_local_header['compression'] != $p_central_header['compression']) { 4296 } 4297 if ($p_local_header['mtime'] != $p_central_header['mtime']) { 4298 } 4299 if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { 4300 } 4301 4302 // ----- Look for flag bit 3 4303 if (($p_local_header['flag'] & 8) == 8) { 4304 $p_local_header['size'] = $p_central_header['size']; 4305 $p_local_header['compressed_size'] = $p_central_header['compressed_size']; 4306 $p_local_header['crc'] = $p_central_header['crc']; 4307 } 4308 4309 // ----- Return 4310 return $v_result; 4311 } 4312 // -------------------------------------------------------------------------------- 4313 4314 // -------------------------------------------------------------------------------- 4315 // Function : privReadEndCentralDir() 4316 // Description : 4317 // Parameters : 4318 // Return Values : 4319 // -------------------------------------------------------------------------------- 4320 public function privReadEndCentralDir(&$p_central_dir) 4321 { 4322 $v_result = 1; 4323 4324 // ----- Go to the end of the zip file 4325 $v_size = filesize($this->zipname); 4326 @fseek($this->zip_fd, $v_size); 4327 if (@ftell($this->zip_fd) != $v_size) { 4328 // ----- Error log 4329 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\''); 4330 4331 // ----- Return 4332 return PclZip::errorCode(); 4333 } 4334 4335 // ----- First try : look if this is an archive with no commentaries (most of the time) 4336 // in this case the end of central dir is at 22 bytes of the file end 4337 $v_found = 0; 4338 if ($v_size > 26) { 4339 @fseek($this->zip_fd, $v_size - 22); 4340 if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) { 4341 // ----- Error log 4342 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); 4343 4344 // ----- Return 4345 return PclZip::errorCode(); 4346 } 4347 4348 // ----- Read for bytes 4349 $v_binary_data = @fread($this->zip_fd, 4); 4350 $v_data = @unpack('Vid', $v_binary_data); 4351 4352 // ----- Check signature 4353 if ($v_data['id'] == 0x06054b50) { 4354 $v_found = 1; 4355 } 4356 4357 $v_pos = ftell($this->zip_fd); 4358 } 4359 4360 // ----- Go back to the maximum possible size of the Central Dir End Record 4361 if (!$v_found) { 4362 $v_maximum_size = 65557; // 0xFFFF + 22; 4363 if ($v_maximum_size > $v_size) { 4364 $v_maximum_size = $v_size; 4365 } 4366 @fseek($this->zip_fd, $v_size - $v_maximum_size); 4367 if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) { 4368 // ----- Error log 4369 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->zipname . '\''); 4370 4371 // ----- Return 4372 return PclZip::errorCode(); 4373 } 4374 4375 // ----- Read byte per byte in order to find the signature 4376 $v_pos = ftell($this->zip_fd); 4377 $v_bytes = 0x00000000; 4378 while ($v_pos < $v_size) { 4379 // ----- Read a byte 4380 $v_byte = @fread($this->zip_fd, 1); 4381 4382 // ----- Add the byte 4383 //$v_bytes = ($v_bytes << 8) | Ord($v_byte); 4384 // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number 4385 // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. 4386 $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); 4387 4388 // ----- Compare the bytes 4389 if ($v_bytes == 0x504b0506) { 4390 $v_pos++; 4391 break; 4392 } 4393 4394 $v_pos++; 4395 } 4396 4397 // ----- Look if not found end of central dir 4398 if ($v_pos == $v_size) { 4399 4400 // ----- Error log 4401 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); 4402 4403 // ----- Return 4404 return PclZip::errorCode(); 4405 } 4406 } 4407 4408 // ----- Read the first 18 bytes of the header 4409 $v_binary_data = fread($this->zip_fd, 18); 4410 4411 // ----- Look for invalid block size 4412 if (strlen($v_binary_data) != 18) { 4413 4414 // ----- Error log 4415 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data)); 4416 4417 // ----- Return 4418 return PclZip::errorCode(); 4419 } 4420 4421 // ----- Extract the values 4422 $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); 4423 4424 // ----- Check the global size 4425 if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { 4426 4427 // ----- Removed in release 2.2 see readme file 4428 // The check of the file size is a little too strict. 4429 // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. 4430 // While decrypted, zip has training 0 bytes 4431 if (0) { 4432 // ----- Error log 4433 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.'); 4434 4435 // ----- Return 4436 return PclZip::errorCode(); 4437 } 4438 } 4439 4440 // ----- Get comment 4441 if ($v_data['comment_size'] != 0) { 4442 $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); 4443 } else { 4444 $p_central_dir['comment'] = ''; 4445 } 4446 4447 $p_central_dir['entries'] = $v_data['entries']; 4448 $p_central_dir['disk_entries'] = $v_data['disk_entries']; 4449 $p_central_dir['offset'] = $v_data['offset']; 4450 $p_central_dir['size'] = $v_data['size']; 4451 $p_central_dir['disk'] = $v_data['disk']; 4452 $p_central_dir['disk_start'] = $v_data['disk_start']; 4453 4454 // TBC 4455 //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { 4456 //} 4457 4458 // ----- Return 4459 return $v_result; 4460 } 4461 // -------------------------------------------------------------------------------- 4462 4463 // -------------------------------------------------------------------------------- 4464 // Function : privDeleteByRule() 4465 // Description : 4466 // Parameters : 4467 // Return Values : 4468 // -------------------------------------------------------------------------------- 4469 public function privDeleteByRule(&$p_result_list, &$p_options) 4470 { 4471 $v_result = 1; 4472 $v_list_detail = array(); 4473 4474 // ----- Open the zip file 4475 if (($v_result = $this->privOpenFd('rb')) != 1) { 4476 // ----- Return 4477 return $v_result; 4478 } 4479 4480 // ----- Read the central directory informations 4481 $v_central_dir = array(); 4482 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 4483 $this->privCloseFd(); 4484 4485 return $v_result; 4486 } 4487 4488 // ----- Go to beginning of File 4489 @rewind($this->zip_fd); 4490 4491 // ----- Scan all the files 4492 // ----- Start at beginning of Central Dir 4493 $v_pos_entry = $v_central_dir['offset']; 4494 @rewind($this->zip_fd); 4495 if (@fseek($this->zip_fd, $v_pos_entry)) { 4496 // ----- Close the zip file 4497 $this->privCloseFd(); 4498 4499 // ----- Error log 4500 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 4501 4502 // ----- Return 4503 return PclZip::errorCode(); 4504 } 4505 4506 // ----- Read each entry 4507 $v_header_list = array(); 4508 $j_start = 0; 4509 for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) { 4510 4511 // ----- Read the file header 4512 $v_header_list[$v_nb_extracted] = array(); 4513 if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) { 4514 // ----- Close the zip file 4515 $this->privCloseFd(); 4516 4517 return $v_result; 4518 } 4519 4520 // ----- Store the index 4521 $v_header_list[$v_nb_extracted]['index'] = $i; 4522 4523 // ----- Look for the specific extract rules 4524 $v_found = false; 4525 4526 // ----- Look for extract by name rule 4527 if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { 4528 4529 // ----- Look if the filename is in the list 4530 for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) { 4531 4532 // ----- Look for a directory 4533 if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") { 4534 4535 // ----- Look if the directory is in the filename path 4536 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])) { 4537 $v_found = true; 4538 } 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])) { 4539 $v_found = true; 4540 } 4541 4542 // ----- Look for a filename 4543 } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { 4544 $v_found = true; 4545 } 4546 } 4547 4548 // ----- Look for extract by ereg rule 4549 // ereg() is deprecated with PHP 5.3 4550 /* 4551 elseif ( (isset($p_options[PCLZIP_OPT_BY_EREG])) 4552 && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { 4553 4554 if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { 4555 $v_found = true; 4556 } 4557 } 4558 */ 4559 4560 // ----- Look for extract by preg rule 4561 } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { 4562 4563 if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { 4564 $v_found = true; 4565 } 4566 4567 // ----- Look for extract by index rule 4568 } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { 4569 4570 // ----- Look if the index is in the list 4571 for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) { 4572 4573 if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { 4574 $v_found = true; 4575 } 4576 if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { 4577 $j_start = $j + 1; 4578 } 4579 4580 if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) { 4581 break; 4582 } 4583 } 4584 } else { 4585 $v_found = true; 4586 } 4587 4588 // ----- Look for deletion 4589 if ($v_found) { 4590 unset($v_header_list[$v_nb_extracted]); 4591 } else { 4592 $v_nb_extracted++; 4593 } 4594 } 4595 4596 // ----- Look if something need to be deleted 4597 if ($v_nb_extracted > 0) { 4598 4599 // ----- Creates a temporay file 4600 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; 4601 4602 // ----- Creates a temporary zip archive 4603 $v_temp_zip = new PclZip($v_zip_temp_name); 4604 4605 // ----- Open the temporary zip file in write mode 4606 if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { 4607 $this->privCloseFd(); 4608 4609 // ----- Return 4610 return $v_result; 4611 } 4612 4613 // ----- Look which file need to be kept 4614 for ($i = 0; $i < sizeof($v_header_list); $i++) { 4615 4616 // ----- Calculate the position of the header 4617 @rewind($this->zip_fd); 4618 if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { 4619 // ----- Close the zip file 4620 $this->privCloseFd(); 4621 $v_temp_zip->privCloseFd(); 4622 @unlink($v_zip_temp_name); 4623 4624 // ----- Error log 4625 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 4626 4627 // ----- Return 4628 return PclZip::errorCode(); 4629 } 4630 4631 // ----- Read the file header 4632 $v_local_header = array(); 4633 if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { 4634 // ----- Close the zip file 4635 $this->privCloseFd(); 4636 $v_temp_zip->privCloseFd(); 4637 @unlink($v_zip_temp_name); 4638 4639 // ----- Return 4640 return $v_result; 4641 } 4642 4643 // ----- Check that local file header is same as central file header 4644 if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) { 4645 // TBC 4646 } 4647 unset($v_local_header); 4648 4649 // ----- Write the file header 4650 if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { 4651 // ----- Close the zip file 4652 $this->privCloseFd(); 4653 $v_temp_zip->privCloseFd(); 4654 @unlink($v_zip_temp_name); 4655 4656 // ----- Return 4657 return $v_result; 4658 } 4659 4660 // ----- Read/write the data block 4661 if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { 4662 // ----- Close the zip file 4663 $this->privCloseFd(); 4664 $v_temp_zip->privCloseFd(); 4665 @unlink($v_zip_temp_name); 4666 4667 // ----- Return 4668 return $v_result; 4669 } 4670 } 4671 4672 // ----- Store the offset of the central dir 4673 $v_offset = @ftell($v_temp_zip->zip_fd); 4674 4675 // ----- Re-Create the Central Dir files header 4676 for ($i = 0; $i < sizeof($v_header_list); $i++) { 4677 // ----- Create the file header 4678 if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) { 4679 $v_temp_zip->privCloseFd(); 4680 $this->privCloseFd(); 4681 @unlink($v_zip_temp_name); 4682 4683 // ----- Return 4684 return $v_result; 4685 } 4686 4687 // ----- Transform the header to a 'usable' info 4688 $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); 4689 } 4690 4691 // ----- Zip file comment 4692 $v_comment = ''; 4693 if (isset($p_options[PCLZIP_OPT_COMMENT])) { 4694 $v_comment = $p_options[PCLZIP_OPT_COMMENT]; 4695 } 4696 4697 // ----- Calculate the size of the central header 4698 $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset; 4699 4700 // ----- Create the central dir footer 4701 if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { 4702 // ----- Reset the file list 4703 unset($v_header_list); 4704 $v_temp_zip->privCloseFd(); 4705 $this->privCloseFd(); 4706 @unlink($v_zip_temp_name); 4707 4708 // ----- Return 4709 return $v_result; 4710 } 4711 4712 // ----- Close 4713 $v_temp_zip->privCloseFd(); 4714 $this->privCloseFd(); 4715 4716 // ----- Delete the zip file 4717 // TBC : I should test the result ... 4718 @unlink($this->zipname); 4719 4720 // ----- Rename the temporary file 4721 // TBC : I should test the result ... 4722 //@rename($v_zip_temp_name, $this->zipname); 4723 PclZipUtilRename($v_zip_temp_name, $this->zipname); 4724 4725 // ----- Destroy the temporary archive 4726 unset($v_temp_zip); 4727 4728 // ----- Remove every files : reset the file 4729 } elseif ($v_central_dir['entries'] != 0) { 4730 $this->privCloseFd(); 4731 4732 if (($v_result = $this->privOpenFd('wb')) != 1) { 4733 return $v_result; 4734 } 4735 4736 if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { 4737 return $v_result; 4738 } 4739 4740 $this->privCloseFd(); 4741 } 4742 4743 // ----- Return 4744 return $v_result; 4745 } 4746 // -------------------------------------------------------------------------------- 4747 4748 // -------------------------------------------------------------------------------- 4749 // Function : privDirCheck() 4750 // Description : 4751 // Check if a directory exists, if not it creates it and all the parents directory 4752 // which may be useful. 4753 // Parameters : 4754 // $p_dir : Directory path to check. 4755 // Return Values : 4756 // 1 : OK 4757 // -1 : Unable to create directory 4758 // -------------------------------------------------------------------------------- 4759 public function privDirCheck($p_dir, $p_is_dir = false) 4760 { 4761 $v_result = 1; 4762 4763 // ----- Remove the final '/' 4764 if (($p_is_dir) && (substr($p_dir, -1) == '/')) { 4765 $p_dir = substr($p_dir, 0, strlen($p_dir) - 1); 4766 } 4767 4768 // ----- Check the directory availability 4769 if ((is_dir($p_dir)) || ($p_dir == "")) { 4770 return 1; 4771 } 4772 4773 // ----- Extract parent directory 4774 $p_parent_dir = dirname($p_dir); 4775 4776 // ----- Just a check 4777 if ($p_parent_dir != $p_dir) { 4778 // ----- Look for parent directory 4779 if ($p_parent_dir != "") { 4780 if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) { 4781 return $v_result; 4782 } 4783 } 4784 } 4785 4786 // ----- Create the directory 4787 if (!@mkdir($p_dir, 0777)) { 4788 // ----- Error log 4789 PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); 4790 4791 // ----- Return 4792 return PclZip::errorCode(); 4793 } 4794 4795 // ----- Return 4796 return $v_result; 4797 } 4798 // -------------------------------------------------------------------------------- 4799 4800 // -------------------------------------------------------------------------------- 4801 // Function : privMerge() 4802 // Description : 4803 // If $p_archive_to_add does not exist, the function exit with a success result. 4804 // Parameters : 4805 // Return Values : 4806 // -------------------------------------------------------------------------------- 4807 public function privMerge(&$p_archive_to_add) 4808 { 4809 $v_result = 1; 4810 4811 // ----- Look if the archive_to_add exists 4812 if (!is_file($p_archive_to_add->zipname)) { 4813 4814 // ----- Nothing to merge, so merge is a success 4815 $v_result = 1; 4816 4817 // ----- Return 4818 return $v_result; 4819 } 4820 4821 // ----- Look if the archive exists 4822 if (!is_file($this->zipname)) { 4823 4824 // ----- Do a duplicate 4825 $v_result = $this->privDuplicate($p_archive_to_add->zipname); 4826 4827 // ----- Return 4828 return $v_result; 4829 } 4830 4831 // ----- Open the zip file 4832 if (($v_result = $this->privOpenFd('rb')) != 1) { 4833 // ----- Return 4834 return $v_result; 4835 } 4836 4837 // ----- Read the central directory informations 4838 $v_central_dir = array(); 4839 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) { 4840 $this->privCloseFd(); 4841 4842 return $v_result; 4843 } 4844 4845 // ----- Go to beginning of File 4846 @rewind($this->zip_fd); 4847 4848 // ----- Open the archive_to_add file 4849 if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) { 4850 $this->privCloseFd(); 4851 4852 // ----- Return 4853 return $v_result; 4854 } 4855 4856 // ----- Read the central directory informations 4857 $v_central_dir_to_add = array(); 4858 if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) { 4859 $this->privCloseFd(); 4860 $p_archive_to_add->privCloseFd(); 4861 4862 return $v_result; 4863 } 4864 4865 // ----- Go to beginning of File 4866 @rewind($p_archive_to_add->zip_fd); 4867 4868 // ----- Creates a temporay file 4869 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp'; 4870 4871 // ----- Open the temporary file in write mode 4872 if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { 4873 $this->privCloseFd(); 4874 $p_archive_to_add->privCloseFd(); 4875 4876 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode'); 4877 4878 // ----- Return 4879 return PclZip::errorCode(); 4880 } 4881 4882 // ----- Copy the files from the archive to the temporary file 4883 // TBC : Here I should better append the file and go back to erase the central dir 4884 $v_size = $v_central_dir['offset']; 4885 while ($v_size != 0) { 4886 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4887 $v_buffer = fread($this->zip_fd, $v_read_size); 4888 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4889 $v_size -= $v_read_size; 4890 } 4891 4892 // ----- Copy the files from the archive_to_add into the temporary file 4893 $v_size = $v_central_dir_to_add['offset']; 4894 while ($v_size != 0) { 4895 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4896 $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); 4897 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4898 $v_size -= $v_read_size; 4899 } 4900 4901 // ----- Store the offset of the central dir 4902 $v_offset = @ftell($v_zip_temp_fd); 4903 4904 // ----- Copy the block of file headers from the old archive 4905 $v_size = $v_central_dir['size']; 4906 while ($v_size != 0) { 4907 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4908 $v_buffer = @fread($this->zip_fd, $v_read_size); 4909 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4910 $v_size -= $v_read_size; 4911 } 4912 4913 // ----- Copy the block of file headers from the archive_to_add 4914 $v_size = $v_central_dir_to_add['size']; 4915 while ($v_size != 0) { 4916 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 4917 $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); 4918 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); 4919 $v_size -= $v_read_size; 4920 } 4921 4922 // ----- Merge the file comments 4923 $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment']; 4924 4925 // ----- Calculate the size of the (new) central header 4926 $v_size = @ftell($v_zip_temp_fd) - $v_offset; 4927 4928 // ----- Swap the file descriptor 4929 // Here is a trick : I swap the temporary fd with the zip fd, in order to use 4930 // the following methods on the temporary fil and not the real archive fd 4931 $v_swap = $this->zip_fd; 4932 $this->zip_fd = $v_zip_temp_fd; 4933 $v_zip_temp_fd = $v_swap; 4934 4935 // ----- Create the central dir footer 4936 if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) { 4937 $this->privCloseFd(); 4938 $p_archive_to_add->privCloseFd(); 4939 @fclose($v_zip_temp_fd); 4940 $this->zip_fd = null; 4941 4942 // ----- Reset the file list 4943 unset($v_header_list); 4944 4945 // ----- Return 4946 return $v_result; 4947 } 4948 4949 // ----- Swap back the file descriptor 4950 $v_swap = $this->zip_fd; 4951 $this->zip_fd = $v_zip_temp_fd; 4952 $v_zip_temp_fd = $v_swap; 4953 4954 // ----- Close 4955 $this->privCloseFd(); 4956 $p_archive_to_add->privCloseFd(); 4957 4958 // ----- Close the temporary file 4959 @fclose($v_zip_temp_fd); 4960 4961 // ----- Delete the zip file 4962 // TBC : I should test the result ... 4963 @unlink($this->zipname); 4964 4965 // ----- Rename the temporary file 4966 // TBC : I should test the result ... 4967 //@rename($v_zip_temp_name, $this->zipname); 4968 PclZipUtilRename($v_zip_temp_name, $this->zipname); 4969 4970 // ----- Return 4971 return $v_result; 4972 } 4973 // -------------------------------------------------------------------------------- 4974 4975 // -------------------------------------------------------------------------------- 4976 // Function : privDuplicate() 4977 // Description : 4978 // Parameters : 4979 // Return Values : 4980 // -------------------------------------------------------------------------------- 4981 public function privDuplicate($p_archive_filename) 4982 { 4983 $v_result = 1; 4984 4985 // ----- Look if the $p_archive_filename exists 4986 if (!is_file($p_archive_filename)) { 4987 4988 // ----- Nothing to duplicate, so duplicate is a success. 4989 $v_result = 1; 4990 4991 // ----- Return 4992 return $v_result; 4993 } 4994 4995 // ----- Open the zip file 4996 if (($v_result = $this->privOpenFd('wb')) != 1) { 4997 // ----- Return 4998 return $v_result; 4999 } 5000 5001 // ----- Open the temporary file in write mode 5002 if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { 5003 $this->privCloseFd(); 5004 5005 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode'); 5006 5007 // ----- Return 5008 return PclZip::errorCode(); 5009 } 5010 5011 // ----- Copy the files from the archive to the temporary file 5012 // TBC : Here I should better append the file and go back to erase the central dir 5013 $v_size = filesize($p_archive_filename); 5014 while ($v_size != 0) { 5015 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); 5016 $v_buffer = fread($v_zip_temp_fd, $v_read_size); 5017 @fwrite($this->zip_fd, $v_buffer, $v_read_size); 5018 $v_size -= $v_read_size; 5019 } 5020 5021 // ----- Close 5022 $this->privCloseFd(); 5023 5024 // ----- Close the temporary file 5025 @fclose($v_zip_temp_fd); 5026 5027 // ----- Return 5028 return $v_result; 5029 } 5030 // -------------------------------------------------------------------------------- 5031 5032 // -------------------------------------------------------------------------------- 5033 // Function : privErrorLog() 5034 // Description : 5035 // Parameters : 5036 // -------------------------------------------------------------------------------- 5037 public function privErrorLog($p_error_code = 0, $p_error_string = '') 5038 { 5039 if (PCLZIP_ERROR_EXTERNAL == 1) { 5040 PclError($p_error_code, $p_error_string); 5041 } else { 5042 $this->error_code = $p_error_code; 5043 $this->error_string = $p_error_string; 5044 } 5045 } 5046 // -------------------------------------------------------------------------------- 5047 5048 // -------------------------------------------------------------------------------- 5049 // Function : privErrorReset() 5050 // Description : 5051 // Parameters : 5052 // -------------------------------------------------------------------------------- 5053 public function privErrorReset() 5054 { 5055 if (PCLZIP_ERROR_EXTERNAL == 1) { 5056 PclErrorReset(); 5057 } else { 5058 $this->error_code = 0; 5059 $this->error_string = ''; 5060 } 5061 } 5062 // -------------------------------------------------------------------------------- 5063 5064 // -------------------------------------------------------------------------------- 5065 // Function : privDisableMagicQuotes() 5066 // Description : 5067 // Parameters : 5068 // Return Values : 5069 // -------------------------------------------------------------------------------- 5070 public function privDisableMagicQuotes() 5071 { 5072 $v_result = 1; 5073 5074 // ----- Look if function exists 5075 if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { 5076 return $v_result; 5077 } 5078 5079 // ----- Look if already done 5080 if ($this->magic_quotes_status != -1) { 5081 return $v_result; 5082 } 5083 5084 // ----- Get and memorize the magic_quote value 5085 $this->magic_quotes_status = @get_magic_quotes_runtime(); 5086 5087 // ----- Disable magic_quotes 5088 if ($this->magic_quotes_status == 1) { 5089 @set_magic_quotes_runtime(0); 5090 } 5091 5092 // ----- Return 5093 return $v_result; 5094 } 5095 // -------------------------------------------------------------------------------- 5096 5097 // -------------------------------------------------------------------------------- 5098 // Function : privSwapBackMagicQuotes() 5099 // Description : 5100 // Parameters : 5101 // Return Values : 5102 // -------------------------------------------------------------------------------- 5103 public function privSwapBackMagicQuotes() 5104 { 5105 $v_result = 1; 5106 5107 // ----- Look if function exists 5108 if ((!function_exists("get_magic_quotes_runtime")) || (!function_exists("set_magic_quotes_runtime"))) { 5109 return $v_result; 5110 } 5111 5112 // ----- Look if something to do 5113 if ($this->magic_quotes_status != -1) { 5114 return $v_result; 5115 } 5116 5117 // ----- Swap back magic_quotes 5118 if ($this->magic_quotes_status == 1) { 5119 @set_magic_quotes_runtime($this->magic_quotes_status); 5120 } 5121 5122 // ----- Return 5123 return $v_result; 5124 } 5125 // -------------------------------------------------------------------------------- 5126} 5127 5128// End of class 5129// -------------------------------------------------------------------------------- 5130 5131// -------------------------------------------------------------------------------- 5132// Function : PclZipUtilPathReduction() 5133// Description : 5134// Parameters : 5135// Return Values : 5136// -------------------------------------------------------------------------------- 5137function PclZipUtilPathReduction($p_dir) 5138{ 5139 $v_result = ""; 5140 5141 // ----- Look for not empty path 5142 if ($p_dir != "") { 5143 // ----- Explode path by directory names 5144 $v_list = explode("/", $p_dir); 5145 5146 // ----- Study directories from last to first 5147 $v_skip = 0; 5148 for ($i = sizeof($v_list) - 1; $i >= 0; $i--) { 5149 // ----- Look for current path 5150 if ($v_list[$i] == ".") { 5151 // ----- Ignore this directory 5152 // Should be the first $i=0, but no check is done 5153 } elseif ($v_list[$i] == "..") { 5154 $v_skip++; 5155 } elseif ($v_list[$i] == "") { 5156 // ----- First '/' i.e. root slash 5157 if ($i == 0) { 5158 $v_result = "/" . $v_result; 5159 if ($v_skip > 0) { 5160 // ----- It is an invalid path, so the path is not modified 5161 // TBC 5162 $v_result = $p_dir; 5163 $v_skip = 0; 5164 } 5165 5166 // ----- Last '/' i.e. indicates a directory 5167 } elseif ($i == (sizeof($v_list) - 1)) { 5168 $v_result = $v_list[$i]; 5169 5170 // ----- Double '/' inside the path 5171 } else { 5172 // ----- Ignore only the double '//' in path, 5173 // but not the first and last '/' 5174 } 5175 } else { 5176 // ----- Look for item to skip 5177 if ($v_skip > 0) { 5178 $v_skip--; 5179 } else { 5180 $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? "/" . $v_result : ""); 5181 } 5182 } 5183 } 5184 5185 // ----- Look for skip 5186 if ($v_skip > 0) { 5187 while ($v_skip > 0) { 5188 $v_result = '../' . $v_result; 5189 $v_skip--; 5190 } 5191 } 5192 } 5193 5194 // ----- Return 5195 return $v_result; 5196} 5197// -------------------------------------------------------------------------------- 5198 5199// -------------------------------------------------------------------------------- 5200// Function : PclZipUtilPathInclusion() 5201// Description : 5202// This function indicates if the path $p_path is under the $p_dir tree. Or, 5203// said in an other way, if the file or sub-dir $p_path is inside the dir 5204// $p_dir. 5205// The function indicates also if the path is exactly the same as the dir. 5206// This function supports path with duplicated '/' like '//', but does not 5207// support '.' or '..' statements. 5208// Parameters : 5209// Return Values : 5210// 0 if $p_path is not inside directory $p_dir 5211// 1 if $p_path is inside directory $p_dir 5212// 2 if $p_path is exactly the same as $p_dir 5213// -------------------------------------------------------------------------------- 5214function PclZipUtilPathInclusion($p_dir, $p_path) 5215{ 5216 $v_result = 1; 5217 5218 // ----- Look for path beginning by ./ 5219 if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) { 5220 $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1); 5221 } 5222 if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) { 5223 $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1); 5224 } 5225 5226 // ----- Explode dir and path by directory separator 5227 $v_list_dir = explode("/", $p_dir); 5228 $v_list_dir_size = sizeof($v_list_dir); 5229 $v_list_path = explode("/", $p_path); 5230 $v_list_path_size = sizeof($v_list_path); 5231 5232 // ----- Study directories paths 5233 $i = 0; 5234 $j = 0; 5235 while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { 5236 5237 // ----- Look for empty dir (path reduction) 5238 if ($v_list_dir[$i] == '') { 5239 $i++; 5240 continue; 5241 } 5242 if ($v_list_path[$j] == '') { 5243 $j++; 5244 continue; 5245 } 5246 5247 // ----- Compare the items 5248 if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) { 5249 $v_result = 0; 5250 } 5251 5252 // ----- Next items 5253 $i++; 5254 $j++; 5255 } 5256 5257 // ----- Look if everything seems to be the same 5258 if ($v_result) { 5259 // ----- Skip all the empty items 5260 while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) { 5261 $j++; 5262 } 5263 while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) { 5264 $i++; 5265 } 5266 5267 if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { 5268 // ----- There are exactly the same 5269 $v_result = 2; 5270 } elseif ($i < $v_list_dir_size) { 5271 // ----- The path is shorter than the dir 5272 $v_result = 0; 5273 } 5274 } 5275 5276 // ----- Return 5277 return $v_result; 5278} 5279// -------------------------------------------------------------------------------- 5280 5281// -------------------------------------------------------------------------------- 5282// Function : PclZipUtilCopyBlock() 5283// Description : 5284// Parameters : 5285// $p_mode : read/write compression mode 5286// 0 : src & dest normal 5287// 1 : src gzip, dest normal 5288// 2 : src normal, dest gzip 5289// 3 : src & dest gzip 5290// Return Values : 5291// -------------------------------------------------------------------------------- 5292function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0) 5293{ 5294 $v_result = 1; 5295 5296 if ($p_mode == 0) { 5297 while ($p_size != 0) { 5298 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5299 $v_buffer = @fread($p_src, $v_read_size); 5300 @fwrite($p_dest, $v_buffer, $v_read_size); 5301 $p_size -= $v_read_size; 5302 } 5303 } elseif ($p_mode == 1) { 5304 while ($p_size != 0) { 5305 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5306 $v_buffer = @gzread($p_src, $v_read_size); 5307 @fwrite($p_dest, $v_buffer, $v_read_size); 5308 $p_size -= $v_read_size; 5309 } 5310 } elseif ($p_mode == 2) { 5311 while ($p_size != 0) { 5312 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5313 $v_buffer = @fread($p_src, $v_read_size); 5314 @gzwrite($p_dest, $v_buffer, $v_read_size); 5315 $p_size -= $v_read_size; 5316 } 5317 } elseif ($p_mode == 3) { 5318 while ($p_size != 0) { 5319 $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); 5320 $v_buffer = @gzread($p_src, $v_read_size); 5321 @gzwrite($p_dest, $v_buffer, $v_read_size); 5322 $p_size -= $v_read_size; 5323 } 5324 } 5325 5326 // ----- Return 5327 return $v_result; 5328} 5329// -------------------------------------------------------------------------------- 5330 5331// -------------------------------------------------------------------------------- 5332// Function : PclZipUtilRename() 5333// Description : 5334// This function tries to do a simple rename() function. If it fails, it 5335// tries to copy the $p_src file in a new $p_dest file and then unlink the 5336// first one. 5337// Parameters : 5338// $p_src : Old filename 5339// $p_dest : New filename 5340// Return Values : 5341// 1 on success, 0 on failure. 5342// -------------------------------------------------------------------------------- 5343function PclZipUtilRename($p_src, $p_dest) 5344{ 5345 $v_result = 1; 5346 5347 // ----- Try to rename the files 5348 if (!@rename($p_src, $p_dest)) { 5349 5350 // ----- Try to copy & unlink the src 5351 if (!@copy($p_src, $p_dest)) { 5352 $v_result = 0; 5353 } elseif (!@unlink($p_src)) { 5354 $v_result = 0; 5355 } 5356 } 5357 5358 // ----- Return 5359 return $v_result; 5360} 5361// -------------------------------------------------------------------------------- 5362 5363// -------------------------------------------------------------------------------- 5364// Function : PclZipUtilOptionText() 5365// Description : 5366// Translate option value in text. Mainly for debug purpose. 5367// Parameters : 5368// $p_option : the option value. 5369// Return Values : 5370// The option text value. 5371// -------------------------------------------------------------------------------- 5372function PclZipUtilOptionText($p_option) 5373{ 5374 5375 $v_list = get_defined_constants(); 5376 for (reset($v_list); $v_key = key($v_list); next($v_list)) { 5377 $v_prefix = substr($v_key, 0, 10); 5378 if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) { 5379 return $v_key; 5380 } 5381 } 5382 5383 $v_result = 'Unknown'; 5384 5385 return $v_result; 5386} 5387// -------------------------------------------------------------------------------- 5388 5389// -------------------------------------------------------------------------------- 5390// Function : PclZipUtilTranslateWinPath() 5391// Description : 5392// Translate windows path by replacing '\' by '/' and optionally removing 5393// drive letter. 5394// Parameters : 5395// $p_path : path to translate. 5396// $p_remove_disk_letter : true | false 5397// Return Values : 5398// The path translated. 5399// -------------------------------------------------------------------------------- 5400function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true) 5401{ 5402 if (stristr(php_uname(), 'windows')) { 5403 // ----- Look for potential disk letter 5404 if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { 5405 $p_path = substr($p_path, $v_position + 1); 5406 } 5407 // ----- Change potential windows directory separator 5408 if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) { 5409 $p_path = strtr($p_path, '\\', '/'); 5410 } 5411 } 5412 5413 return $p_path; 5414} 5415// -------------------------------------------------------------------------------- 5416