"TYPO3 4.0.1: typo3_src-4.0.1/typo3/mod/tools/em/class.em_unzip.php Source File", "datetime" => "Sat Dec 2 19:22:21 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) Vincent Blavet <vincent@phpconcept.net> 00006 * (c) 2005-2006 Karsten Dambekalns <karsten@typo3.org> 00007 * All rights reserved 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00022 * MA 02110-1301 USA 00023 * 00024 * This copyright notice MUST APPEAR in all copies of the script! 00025 ***************************************************************/ 00036 // Constants 00037 define( 'ARCHIVE_ZIP_READ_BLOCK_SIZE', 2048 ); 00038 00039 // File list separator 00040 define( 'ARCHIVE_ZIP_SEPARATOR', ',' ); 00041 00042 define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '' ); 00043 00044 // Error codes 00045 define( 'ARCHIVE_ZIP_ERR_NO_ERROR', 0 ); 00046 define( 'ARCHIVE_ZIP_ERR_WRITE_OPEN_FAIL', -1 ); 00047 define( 'ARCHIVE_ZIP_ERR_READ_OPEN_FAIL', -2 ); 00048 define( 'ARCHIVE_ZIP_ERR_INVALID_PARAMETER', -3 ); 00049 define( 'ARCHIVE_ZIP_ERR_MISSING_FILE', -4 ); 00050 define( 'ARCHIVE_ZIP_ERR_FILENAME_TOO_LONG', -5 ); 00051 define( 'ARCHIVE_ZIP_ERR_INVALID_ZIP', -6 ); 00052 define( 'ARCHIVE_ZIP_ERR_BAD_EXTRACTED_FILE', -7 ); 00053 define( 'ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL', -8 ); 00054 define( 'ARCHIVE_ZIP_ERR_BAD_EXTENSION', -9 ); 00055 define( 'ARCHIVE_ZIP_ERR_BAD_FORMAT', -10 ); 00056 define( 'ARCHIVE_ZIP_ERR_DELETE_FILE_FAIL', -11 ); 00057 define( 'ARCHIVE_ZIP_ERR_RENAME_FILE_FAIL', -12 ); 00058 define( 'ARCHIVE_ZIP_ERR_BAD_CHECKSUM', -13 ); 00059 define( 'ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); 00060 define( 'ARCHIVE_ZIP_ERR_MISSING_OPTION_VALUE', -15 ); 00061 define( 'ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE', -16 ); 00062 00063 // Warning codes 00064 define( 'ARCHIVE_ZIP_WARN_NO_WARNING', 0 ); 00065 define( 'ARCHIVE_ZIP_WARN_FILE_EXIST', 1 ); 00066 00067 // Methods parameters 00068 define( 'ARCHIVE_ZIP_PARAM_PATH', 'path' ); 00069 define( 'ARCHIVE_ZIP_PARAM_ADD_PATH', 'add_path' ); 00070 define( 'ARCHIVE_ZIP_PARAM_REMOVE_PATH', 'remove_path' ); 00071 define( 'ARCHIVE_ZIP_PARAM_REMOVE_ALL_PATH', 'remove_all_path' ); 00072 define( 'ARCHIVE_ZIP_PARAM_SET_CHMOD', 'set_chmod' ); 00073 define( 'ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING', 'extract_as_string' ); 00074 define( 'ARCHIVE_ZIP_PARAM_NO_COMPRESSION', 'no_compression' ); 00075 00076 define( 'ARCHIVE_ZIP_PARAM_PRE_EXTRACT', 'callback_pre_extract' ); 00077 define( 'ARCHIVE_ZIP_PARAM_POST_EXTRACT', 'callback_post_extract' ); 00078 define( 'ARCHIVE_ZIP_PARAM_PRE_ADD', 'callback_pre_add' ); 00079 define( 'ARCHIVE_ZIP_PARAM_POST_ADD', 'callback_post_add' ); 00080 00081 00082 00089 class em_unzip { 00095 var $_zipname=''; 00096 00102 var $_zip_fd=0; 00103 00107 var $_error_code=1; 00108 00112 var $_error_string=''; 00113 00122 function em_unzip($p_zipname) { 00123 00124 // Check the zlib 00125 if (!extension_loaded('zlib')) { 00126 die("The extension 'zlib' couldn't be found.\n". 00127 "Please make sure your version of PHP was built ". 00128 "with 'zlib' support.\n"); 00129 } 00130 00131 // Set the attributes 00132 $this->_zipname = $p_zipname; 00133 $this->_zip_fd = 0; 00134 00135 return; 00136 } 00137 00138 00139 00159 function extract($p_params=0) { 00160 $this->_errorReset(); 00161 00162 // Check archive 00163 if (!$this->_checkFormat()) { 00164 return(0); 00165 } 00166 00167 // Set default values 00168 if ($p_params === 0) { 00169 $p_params = array(); 00170 } 00171 if ($this->_check_parameters($p_params, 00172 array ('extract_as_string' => false, 00173 'add_path' => '', 00174 'remove_path' => '', 00175 'remove_all_path' => false, 00176 'callback_pre_extract' => '', 00177 'callback_post_extract' => '', 00178 'set_chmod' => 0) ) != 1) { 00179 return 0; 00180 } 00181 00182 // Call the extracting fct 00183 $v_list = array(); 00184 if ($this->_extractByRule($v_list, $p_params) != 1) { 00185 unset($v_list); 00186 return(0); 00187 } 00188 00189 return $v_list; 00190 } 00191 00198 function errorCode() { 00199 return($this->_error_code); 00200 } 00201 00209 function errorName($p_with_code=false) { 00210 $v_const_list = get_defined_constants(); 00211 00212 // Extract error constants from all const. 00213 for (reset($v_const_list); 00214 list($v_key, $v_value) = each($v_const_list);) { 00215 if (substr($v_key, 0, strlen('ARCHIVE_ZIP_ERR_')) =='ARCHIVE_ZIP_ERR_') { 00216 $v_error_list[$v_key] = $v_value; 00217 } 00218 } 00219 00220 // Search the name form the code value 00221 $v_key=array_search($this->_error_code, $v_error_list, true); 00222 if ($v_key!=false) { 00223 $v_value = $v_key; 00224 } else { 00225 $v_value = 'NoName'; 00226 } 00227 00228 if ($p_with_code) { 00229 return($v_value.' ('.$this->_error_code.')'); 00230 } else { 00231 return($v_value); 00232 } 00233 } 00234 00245 function errorInfo($p_full=false) { 00246 if ($p_full) { 00247 return($this->errorName(true)." : ".$this->_error_string); 00248 } else { 00249 return($this->_error_string." [code ".$this->_error_code."]"); 00250 } 00251 } 00252 00253 00261 function _checkFormat($p_level=0) { 00262 $v_result = true; 00263 00264 // Reset the error handler 00265 $this->_errorReset(); 00266 00267 // Look if the file exits 00268 if (!is_file($this->_zipname)) { 00269 // Error log 00270 $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, 00271 "Missing archive file '".$this->_zipname."'"); 00272 return(false); 00273 } 00274 00275 // Check that the file is readeable 00276 if (!is_readable($this->_zipname)) { 00277 // Error log 00278 $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 00279 "Unable to read archive '".$this->_zipname."'"); 00280 return(false); 00281 } 00282 00283 // Check the magic code 00284 // TBC 00285 00286 // Check the central header 00287 // TBC 00288 00289 // Check each file header 00290 // TBC 00291 00292 // Return 00293 return $v_result; 00294 } 00295 00296 00303 function _openFd($p_mode) { 00304 $v_result=1; 00305 00306 // Look if already open 00307 if ($this->_zip_fd != 0) { 00308 $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 00309 'Zip file \''.$this->_zipname.'\' already open'); 00310 return em_unzip::errorCode(); 00311 } 00312 00313 // Open the zip file 00314 if (($this->_zip_fd = @fopen($this->_zipname, $p_mode)) == 0) { 00315 $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 00316 'Unable to open archive \''.$this->_zipname 00317 .'\' in '.$p_mode.' mode'); 00318 return em_unzip::errorCode(); 00319 } 00320 00321 // Return 00322 return $v_result; 00323 } 00324 00331 function _closeFd() { 00332 $v_result=1; 00333 00334 if ($this->_zip_fd != 0) 00335 @fclose($this->_zip_fd); 00336 $this->_zip_fd = 0; 00337 00338 // Return 00339 return $v_result; 00340 } 00341 00342 00343 00350 function _convertHeader2FileInfo($p_header, &$p_info) { 00351 $v_result=1; 00352 00353 // Get the interesting attributes 00354 $p_info['filename'] = $p_header['filename']; 00355 $p_info['stored_filename'] = $p_header['stored_filename']; 00356 $p_info['size'] = $p_header['size']; 00357 $p_info['compressed_size'] = $p_header['compressed_size']; 00358 $p_info['mtime'] = $p_header['mtime']; 00359 $p_info['comment'] = $p_header['comment']; 00360 $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); 00361 $p_info['index'] = $p_header['index']; 00362 $p_info['status'] = $p_header['status']; 00363 00364 // Return 00365 return $v_result; 00366 } 00367 00368 00369 // Function : _extractByRule() 00370 // Description : 00371 // Extract a file or directory depending of rules (by index, by name, ...) 00372 // Parameters : 00373 // $p_file_list : An array where will be placed the properties of each 00374 // extracted file 00375 // $p_path : Path to add while writing the extracted files 00376 // $p_remove_path : Path to remove (from the file memorized path) while writing the 00377 // extracted files. If the path does not match the file path, 00378 // the file is extracted with its memorized path. 00379 // $p_remove_path does not apply to 'list' mode. 00380 // $p_path and $p_remove_path are commulative. 00381 // Return Values : 00382 // 1 on success,0 or less on error (see error code list) 00383 00390 function _extractByRule(&$p_file_list, &$p_params) 00391 { 00392 $v_result=1; 00393 00394 $p_path = $p_params['add_path']; 00395 $p_remove_path = $p_params['remove_path']; 00396 $p_remove_all_path = $p_params['remove_all_path']; 00397 00398 // Check the path 00399 if (($p_path == "") 00400 || ((substr($p_path, 0, 1) != "/") 00401 && (substr($p_path, 0, 3) != "../") && (substr($p_path,1,2)!=":/"))) 00402 $p_path = "./".$p_path; 00403 00404 // Reduce the path last (and duplicated) '/' 00405 if (($p_path != "./") && ($p_path != "/")) { 00406 // Look for the path end '/' 00407 while (substr($p_path, -1) == "/") { 00408 $p_path = substr($p_path, 0, strlen($p_path)-1); 00409 } 00410 } 00411 00412 // Open the zip file 00413 if (($v_result = $this->_openFd('rb')) != 1) 00414 { 00415 return $v_result; 00416 } 00417 00418 // Read the central directory informations 00419 $v_central_dir = array(); 00420 if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) 00421 { 00422 // Close the zip file 00423 $this->_closeFd(); 00424 00425 return $v_result; 00426 } 00427 00428 // Start at beginning of Central Dir 00429 $v_pos_entry = $v_central_dir['offset']; 00430 00431 // Read each entry 00432 $j_start = 0; 00433 for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { 00434 // Read next Central dir entry 00435 @rewind($this->_zip_fd); 00436 if (@fseek($this->_zip_fd, $v_pos_entry)) { 00437 $this->_closeFd(); 00438 00439 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 00440 'Invalid archive size'); 00441 00442 return em_unzip::errorCode(); 00443 } 00444 00445 // Read the file header 00446 $v_header = array(); 00447 if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) { 00448 $this->_closeFd(); 00449 00450 return $v_result; 00451 } 00452 00453 // Store the index 00454 $v_header['index'] = $i; 00455 00456 // Store the file position 00457 $v_pos_entry = ftell($this->_zip_fd); 00458 00459 00460 // Go to the file position 00461 @rewind($this->_zip_fd); 00462 if (@fseek($this->_zip_fd, $v_header['offset'])) 00463 { 00464 // Close the zip file 00465 $this->_closeFd(); 00466 00467 // Error log 00468 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); 00469 00470 // Return 00471 return em_unzip::errorCode(); 00472 } 00473 00474 // Extracting the file 00475 if (($v_result = $this->_extractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_params)) != 1) 00476 { 00477 // Close the zip file 00478 $this->_closeFd(); 00479 00480 return $v_result; 00481 } 00482 00483 // Get the only interesting attributes 00484 if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) 00485 { 00486 // Close the zip file 00487 $this->_closeFd(); 00488 00489 return $v_result; 00490 } 00491 } 00492 00493 // Close the zip file 00494 $this->_closeFd(); 00495 00496 // Return 00497 return $v_result; 00498 } 00499 00506 function _extractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_params) { 00507 $v_result=1; 00508 00509 // Read the file header 00510 if (($v_result = $this->_readFileHeader($v_header)) != 1) 00511 { 00512 // Return 00513 return $v_result; 00514 } 00515 00516 00517 // Check that the file header is coherent with $p_entry info 00518 // TBC 00519 00520 // Look for all path to remove 00521 if ($p_remove_all_path == true) { 00522 // Get the basename of the path 00523 $p_entry['filename'] = basename($p_entry['filename']); 00524 } 00525 00526 // Look for path to remove 00527 else if ($p_remove_path != "") 00528 { 00529 //if (strcmp($p_remove_path, $p_entry['filename'])==0) 00530 if ($this->_tool_PathInclusion($p_remove_path, $p_entry['filename']) == 2) 00531 { 00532 00533 // Change the file status 00534 $p_entry['status'] = "filtered"; 00535 00536 // Return 00537 return $v_result; 00538 } 00539 00540 $p_remove_path_size = strlen($p_remove_path); 00541 if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) 00542 { 00543 00544 // Remove the path 00545 $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); 00546 00547 } 00548 } 00549 00550 // Add the path 00551 if ($p_path != '') 00552 { 00553 $p_entry['filename'] = $p_path."/".$p_entry['filename']; 00554 } 00555 00556 // Look for pre-extract callback 00557 if ( (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT])) 00558 && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] != '')) { 00559 00560 // Generate a local information 00561 $v_local_header = array(); 00562 $this->_convertHeader2FileInfo($p_entry, $v_local_header); 00563 00564 // Call the callback 00565 // Here I do not use call_user_func() because I need to send a reference to the 00566 // header. 00567 eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT].'(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);'); 00568 if ($v_result == 0) { 00569 // Change the file status 00570 $p_entry['status'] = "skipped"; 00571 $v_result = 1; 00572 } 00573 00574 // Update the informations 00575 // Only some fields can be modified 00576 $p_entry['filename'] = $v_local_header['filename']; 00577 } 00578 00579 // Trace 00580 00581 // Look if extraction should be done 00582 if ($p_entry['status'] == 'ok') { 00583 00584 // Look for specific actions while the file exist 00585 if (file_exists($p_entry['filename'])) { 00586 // Look if file is a directory 00587 if (is_dir($p_entry['filename'])) { 00588 // Change the file status 00589 $p_entry['status'] = "already_a_directory"; 00590 00591 // Return 00592 //return $v_result; 00593 } 00594 // Look if file is write protected 00595 else if (!is_writeable($p_entry['filename'])) { 00596 // Change the file status 00597 $p_entry['status'] = "write_protected"; 00598 00599 // Return 00600 //return $v_result; 00601 } 00602 00603 // Look if the extracted file is older 00604 else if (filemtime($p_entry['filename']) > $p_entry['mtime']) { 00605 // Change the file status 00606 $p_entry['status'] = "newer_exist"; 00607 00608 // Return 00609 //return $v_result; 00610 } 00611 } 00612 00613 // Check the directory availability and create it if necessary 00614 else { 00615 if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) 00616 $v_dir_to_check = $p_entry['filename']; 00617 else if (!strstr($p_entry['filename'], "/")) 00618 $v_dir_to_check = ""; 00619 else 00620 $v_dir_to_check = dirname($p_entry['filename']); 00621 00622 if (($v_result = $this->_dirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { 00623 // Change the file status 00624 $p_entry['status'] = "path_creation_fail"; 00625 00626 // Return 00627 //return $v_result; 00628 $v_result = 1; 00629 } 00630 } 00631 } 00632 00633 // Look if extraction should be done 00634 if ($p_entry['status'] == 'ok') { 00635 // Do the extraction (if not a folder) 00636 if (!(($p_entry['external']&0x00000010)==0x00000010)) { 00637 // Look for not compressed file 00638 if ($p_entry['compressed_size'] == $p_entry['size']) { 00639 // Opening destination file 00640 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 00641 // Change the file status 00642 $p_entry['status'] = "write_error"; 00643 00644 // Return 00645 return $v_result; 00646 } 00647 00648 00649 // Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks 00650 $v_size = $p_entry['compressed_size']; 00651 while ($v_size != 0) { 00652 $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); 00653 $v_buffer = fread($this->_zip_fd, $v_read_size); 00654 $v_binary_data = pack('a'.$v_read_size, $v_buffer); 00655 @fwrite($v_dest_file, $v_binary_data, $v_read_size); 00656 $v_size -= $v_read_size; 00657 } 00658 00659 // Closing the destination file 00660 fclose($v_dest_file); 00661 00662 // Change the file mtime 00663 touch($p_entry['filename'], $p_entry['mtime']); 00664 } else { 00665 // Trace 00666 00667 // Opening destination file 00668 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { 00669 00670 // Change the file status 00671 $p_entry['status'] = "write_error"; 00672 00673 return $v_result; 00674 } 00675 00676 00677 // Read the compressed file in a buffer (one shot) 00678 $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']); 00679 00680 // Decompress the file 00681 $v_file_content = gzinflate($v_buffer); 00682 unset($v_buffer); 00683 00684 // Write the uncompressed data 00685 @fwrite($v_dest_file, $v_file_content, $p_entry['size']); 00686 unset($v_file_content); 00687 00688 // Closing the destination file 00689 @fclose($v_dest_file); 00690 00691 // Change the file mtime 00692 @touch($p_entry['filename'], $p_entry['mtime']); 00693 } 00694 00695 // Look for chmod option 00696 if ( (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD])) 00697 && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD] != 0)) { 00698 00699 // Change the mode of the file 00700 chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]); 00701 } 00702 00703 } 00704 } 00705 00706 // Look for post-extract callback 00707 if ( (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT])) 00708 && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] != '')) { 00709 00710 // Generate a local information 00711 $v_local_header = array(); 00712 $this->_convertHeader2FileInfo($p_entry, $v_local_header); 00713 00714 // Call the callback 00715 // Here I do not use call_user_func() because I need to send a reference to the 00716 // header. 00717 eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT].'(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);'); 00718 } 00719 00720 // Return 00721 return $v_result; 00722 } 00723 00730 function _readFileHeader(&$p_header) { 00731 $v_result=1; 00732 00733 // Read the 4 bytes signature 00734 $v_binary_data = @fread($this->_zip_fd, 4); 00735 $v_data = unpack('Vid', $v_binary_data); 00736 00737 // Check signature 00738 if ($v_data['id'] != 0x04034b50) { 00739 00740 // Error log 00741 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); 00742 00743 // Return 00744 return em_unzip::errorCode(); 00745 } 00746 00747 // Read the first 42 bytes of the header 00748 $v_binary_data = fread($this->_zip_fd, 26); 00749 00750 // Look for invalid block size 00751 if (strlen($v_binary_data) != 26) { 00752 $p_header['filename'] = ""; 00753 $p_header['status'] = "invalid_header"; 00754 00755 // Error log 00756 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); 00757 00758 // Return 00759 return em_unzip::errorCode(); 00760 } 00761 00762 // Extract the values 00763 $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); 00764 00765 // Get filename 00766 $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']); 00767 00768 // Get extra_fields 00769 if ($v_data['extra_len'] != 0) { 00770 $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']); 00771 } 00772 else { 00773 $p_header['extra'] = ''; 00774 } 00775 00776 // Extract properties 00777 $p_header['compression'] = $v_data['compression']; 00778 $p_header['size'] = $v_data['size']; 00779 $p_header['compressed_size'] = $v_data['compressed_size']; 00780 $p_header['crc'] = $v_data['crc']; 00781 $p_header['flag'] = $v_data['flag']; 00782 00783 // Recuperate date in UNIX format 00784 $p_header['mdate'] = $v_data['mdate']; 00785 $p_header['mtime'] = $v_data['mtime']; 00786 if ($p_header['mdate'] && $p_header['mtime']) { 00787 // Extract time 00788 $v_hour = ($p_header['mtime'] & 0xF800) >> 11; 00789 $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; 00790 $v_seconde = ($p_header['mtime'] & 0x001F)*2; 00791 00792 // Extract date 00793 $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; 00794 $v_month = ($p_header['mdate'] & 0x01E0) >> 5; 00795 $v_day = $p_header['mdate'] & 0x001F; 00796 00797 // Get UNIX date format 00798 $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); 00799 00800 } else { 00801 $p_header['mtime'] = time(); 00802 } 00803 00804 // Other informations 00805 00806 // TBC 00807 //for(reset($v_data); $key = key($v_data); next($v_data)) { 00808 //} 00809 00810 // Set the stored filename 00811 $p_header['stored_filename'] = $p_header['filename']; 00812 00813 // Set the status field 00814 $p_header['status'] = "ok"; 00815 00816 // Return 00817 return $v_result; 00818 } 00819 00826 function _readCentralFileHeader(&$p_header) { 00827 $v_result=1; 00828 00829 // Read the 4 bytes signature 00830 $v_binary_data = @fread($this->_zip_fd, 4); 00831 $v_data = unpack('Vid', $v_binary_data); 00832 00833 // Check signature 00834 if ($v_data['id'] != 0x02014b50) { 00835 00836 // Error log 00837 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); 00838 00839 // Return 00840 return em_unzip::errorCode(); 00841 } 00842 00843 // Read the first 42 bytes of the header 00844 $v_binary_data = fread($this->_zip_fd, 42); 00845 00846 // Look for invalid block size 00847 if (strlen($v_binary_data) != 42) { 00848 $p_header['filename'] = ""; 00849 $p_header['status'] = "invalid_header"; 00850 00851 // Error log 00852 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); 00853 00854 // Return 00855 return em_unzip::errorCode(); 00856 } 00857 00858 // Extract the values 00859 $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); 00860 00861 // Get filename 00862 if ($p_header['filename_len'] != 0) 00863 $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']); 00864 else 00865 $p_header['filename'] = ''; 00866 00867 // Get extra 00868 if ($p_header['extra_len'] != 0) 00869 $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']); 00870 else 00871 $p_header['extra'] = ''; 00872 00873 // Get comment 00874 if ($p_header['comment_len'] != 0) 00875 $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']); 00876 else 00877 $p_header['comment'] = ''; 00878 00879 // Extract properties 00880 00881 // Recuperate date in UNIX format 00882 if ($p_header['mdate'] && $p_header['mtime']) { 00883 // Extract time 00884 $v_hour = ($p_header['mtime'] & 0xF800) >> 11; 00885 $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; 00886 $v_seconde = ($p_header['mtime'] & 0x001F)*2; 00887 00888 // Extract date 00889 $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; 00890 $v_month = ($p_header['mdate'] & 0x01E0) >> 5; 00891 $v_day = $p_header['mdate'] & 0x001F; 00892 00893 // Get UNIX date format 00894 $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); 00895 00896 } else { 00897 $p_header['mtime'] = time(); 00898 } 00899 00900 // Set the stored filename 00901 $p_header['stored_filename'] = $p_header['filename']; 00902 00903 // Set default status to ok 00904 $p_header['status'] = 'ok'; 00905 00906 // Look if it is a directory 00907 if (substr($p_header['filename'], -1) == '/') { 00908 $p_header['external'] = 0x41FF0010; 00909 } 00910 00911 00912 // Return 00913 return $v_result; 00914 } 00915 00922 function _readEndCentralDir(&$p_central_dir) { 00923 $v_result=1; 00924 00925 // Go to the end of the zip file 00926 $v_size = filesize($this->_zipname); 00927 @fseek($this->_zip_fd, $v_size); 00928 if (@ftell($this->_zip_fd) != $v_size) { 00929 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 00930 'Unable to go to the end of the archive \'' 00931 .$this->_zipname.'\''); 00932 return em_unzip::errorCode(); 00933 } 00934 00935 // First try : look if this is an archive with no commentaries 00936 // (most of the time) 00937 // in this case the end of central dir is at 22 bytes of the file end 00938 $v_found = 0; 00939 if ($v_size > 26) { 00940 @fseek($this->_zip_fd, $v_size-22); 00941 if (($v_pos = @ftell($this->_zip_fd)) != ($v_size-22)) { 00942 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 00943 'Unable to seek back to the middle of the archive \'' 00944 .$this->_zipname.'\''); 00945 return em_unzip::errorCode(); 00946 } 00947 00948 // Read for bytes 00949 $v_binary_data = @fread($this->_zip_fd, 4); 00950 $v_data = unpack('Vid', $v_binary_data); 00951 00952 // Check signature 00953 if ($v_data['id'] == 0x06054b50) { 00954 $v_found = 1; 00955 } 00956 00957 $v_pos = ftell($this->_zip_fd); 00958 } 00959 00960 // Go back to the maximum possible size of the Central Dir End Record 00961 if (!$v_found) { 00962 $v_maximum_size = 65557; // 0xFFFF + 22; 00963 if ($v_maximum_size > $v_size) 00964 $v_maximum_size = $v_size; 00965 @fseek($this->_zip_fd, $v_size-$v_maximum_size); 00966 if (@ftell($this->_zip_fd) != ($v_size-$v_maximum_size)) { 00967 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 00968 'Unable to seek back to the middle of the archive \'' 00969 .$this->_zipname.'\''); 00970 return em_unzip::errorCode(); 00971 } 00972 00973 // Read byte per byte in order to find the signature 00974 $v_pos = ftell($this->_zip_fd); 00975 $v_bytes = 0x00000000; 00976 while ($v_pos < $v_size) { 00977 // Read a byte 00978 $v_byte = @fread($this->_zip_fd, 1); 00979 00980 // Add the byte 00981 $v_bytes = ($v_bytes << 8) | Ord($v_byte); 00982 00983 // Compare the bytes 00984 if ($v_bytes == 0x504b0506) { 00985 $v_pos++; 00986 break; 00987 } 00988 00989 $v_pos++; 00990 } 00991 00992 // Look if not found end of central dir 00993 if ($v_pos == $v_size) { 00994 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 00995 "Unable to find End of Central Dir Record signature"); 00996 return em_unzip::errorCode(); 00997 } 00998 } 00999 01000 // Read the first 18 bytes of the header 01001 $v_binary_data = fread($this->_zip_fd, 18); 01002 01003 // Look for invalid block size 01004 if (strlen($v_binary_data) != 18) { 01005 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 01006 "Invalid End of Central Dir Record size : " 01007 .strlen($v_binary_data)); 01008 return em_unzip::errorCode(); 01009 } 01010 01011 // Extract the values 01012 $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); 01013 01014 // Check the global size 01015 if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { 01016 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 01017 "Fail to find the right signature"); 01018 return em_unzip::errorCode(); 01019 } 01020 01021 // Get comment 01022 if ($v_data['comment_size'] != 0) 01023 $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']); 01024 else 01025 $p_central_dir['comment'] = ''; 01026 01027 $p_central_dir['entries'] = $v_data['entries']; 01028 $p_central_dir['disk_entries'] = $v_data['disk_entries']; 01029 $p_central_dir['offset'] = $v_data['offset']; 01030 $p_central_dir['size'] = $v_data['size']; 01031 $p_central_dir['disk'] = $v_data['disk']; 01032 $p_central_dir['disk_start'] = $v_data['disk_start']; 01033 01034 // Return 01035 return $v_result; 01036 } 01037 01045 function _dirCheck($p_dir, $p_is_dir=false) { 01046 $v_result = 1; 01047 01048 // Remove the final '/' 01049 if (($p_is_dir) && (substr($p_dir, -1)=='/')) { 01050 $p_dir = substr($p_dir, 0, strlen($p_dir)-1); 01051 } 01052 01053 // Check the directory availability 01054 if ((is_dir($p_dir)) || ($p_dir == "")) { 01055 return 1; 01056 } 01057 01058 // Extract parent directory 01059 $p_parent_dir = dirname($p_dir); 01060 01061 // Just a check 01062 if ($p_parent_dir != $p_dir) { 01063 // Look for parent directory 01064 if ($p_parent_dir != "") { 01065 if (($v_result = $this->_dirCheck($p_parent_dir)) != 1) { 01066 return $v_result; 01067 } 01068 } 01069 } 01070 01071 // Create the directory 01072 if (!@mkdir($p_dir, 0777)) { 01073 $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL, 01074 "Unable to create directory '$p_dir'"); 01075 return em_unzip::errorCode(); 01076 } 01077 01078 // Return 01079 return $v_result; 01080 } 01081 01090 function _check_parameters(&$p_params, $p_default) { 01091 01092 // Check that param is an array 01093 if (!is_array($p_params)) { 01094 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 01095 'Unsupported parameter, waiting for an array'); 01096 return em_unzip::errorCode(); 01097 } 01098 01099 // Check that all the params are valid 01100 for (reset($p_params); list($v_key, $v_value) = each($p_params); ) { 01101 if (!isset($p_default[$v_key])) { 01102 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 01103 'Unsupported parameter with key \''.$v_key.'\''); 01104 01105 return em_unzip::errorCode(); 01106 } 01107 } 01108 01109 // Set the default values 01110 for (reset($p_default); list($v_key, $v_value) = each($p_default); ) { 01111 if (!isset($p_params[$v_key])) { 01112 $p_params[$v_key] = $p_default[$v_key]; 01113 } 01114 } 01115 01116 // Check specific parameters 01117 $v_callback_list = array ('callback_pre_add','callback_post_add', 01118 'callback_pre_extract','callback_post_extract'); 01119 for ($i=0; $i<sizeof($v_callback_list); $i++) { 01120 $v_key=$v_callback_list[$i]; 01121 if ( (isset($p_params[$v_key])) && ($p_params[$v_key] != '')) { 01122 if (!function_exists($p_params[$v_key])) { 01123 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE, 01124 "Callback '".$p_params[$v_key] 01125 ."()' is not an existing function for " 01126 ."parameter '".$v_key."'"); 01127 return em_unzip::errorCode(); 01128 } 01129 } 01130 } 01131 01132 return(1); 01133 } 01134 01143 function _errorLog($p_error_code=0, $p_error_string='') { 01144 $this->_error_code = $p_error_code; 01145 $this->_error_string = $p_error_string; 01146 } 01147 01154 function _errorReset() { 01155 $this->_error_code = 1; 01156 $this->_error_string = ''; 01157 } 01158 01165 function _tool_PathReduction($p_dir) { 01166 $v_result = ""; 01167 01168 // Look for not empty path 01169 if ($p_dir != "") { 01170 // Explode path by directory names 01171 $v_list = explode("/", $p_dir); 01172 01173 // Study directories from last to first 01174 for ($i=sizeof($v_list)-1; $i>=0; $i--) { 01175 // Look for current path 01176 if ($v_list[$i] == ".") { 01177 // Ignore this directory 01178 // Should be the first $i=0, but no check is done 01179 } else if ($v_list[$i] == "..") { 01180 // Ignore it and ignore the $i-1 01181 $i--; 01182 } else if (($v_list[$i] == "") && ($i!=(sizeof($v_list)-1)) && ($i!=0)) { 01183 // Ignore only the double '//' in path, 01184 // but not the first and last '/' 01185 } else { 01186 $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); 01187 } 01188 } 01189 } 01190 01191 // Return 01192 return $v_result; 01193 } 01194 01201 function _tool_PathInclusion($p_dir, $p_path) { 01202 $v_result = 1; 01203 01204 // Explode dir and path by directory separator 01205 $v_list_dir = explode("/", $p_dir); 01206 $v_list_dir_size = sizeof($v_list_dir); 01207 $v_list_path = explode("/", $p_path); 01208 $v_list_path_size = sizeof($v_list_path); 01209 01210 // Study directories paths 01211 $i = 0; 01212 $j = 0; 01213 while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { 01214 // Look for empty dir (path reduction) 01215 if ($v_list_dir[$i] == '') { 01216 $i++; 01217 continue; 01218 } 01219 if ($v_list_path[$j] == '') { 01220 $j++; 01221 continue; 01222 } 01223 01224 // Compare the items 01225 if ( ($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { 01226 $v_result = 0; 01227 } 01228 01229 // Next items 01230 $i++; 01231 $j++; 01232 } 01233 01234 // Look if everything seems to be the same 01235 if ($v_result) { 01236 // Skip all the empty items 01237 while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; 01238 while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; 01239 01240 if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { 01241 // There are exactly the same 01242 $v_result = 2; 01243 } else if ($i < $v_list_dir_size) { 01244 // The path is shorter than the dir 01245 $v_result = 0; 01246 } 01247 } 01248 01249 // Return 01250 return $v_result; 01251 } 01252 01260 function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode=0) { 01261 $v_result = 1; 01262 01263 if ($p_mode==0) { 01264 while ($p_size != 0) { 01265 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE 01266 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); 01267 $v_buffer = @fread($p_src, $v_read_size); 01268 @fwrite($p_dest, $v_buffer, $v_read_size); 01269 $p_size -= $v_read_size; 01270 } 01271 } else if ($p_mode==1) { 01272 while ($p_size != 0) { 01273 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE 01274 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); 01275 $v_buffer = @gzread($p_src, $v_read_size); 01276 @fwrite($p_dest, $v_buffer, $v_read_size); 01277 $p_size -= $v_read_size; 01278 } 01279 } else if ($p_mode==2) { 01280 while ($p_size != 0) { 01281 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE 01282 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); 01283 $v_buffer = @fread($p_src, $v_read_size); 01284 @gzwrite($p_dest, $v_buffer, $v_read_size); 01285 $p_size -= $v_read_size; 01286 } 01287 } 01288 else if ($p_mode==3) { 01289 while ($p_size != 0) { 01290 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE 01291 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); 01292 $v_buffer = @gzread($p_src, $v_read_size); 01293 @gzwrite($p_dest, $v_buffer, $v_read_size); 01294 $p_size -= $v_read_size; 01295 } 01296 } 01297 01298 // Return 01299 return $v_result; 01300 } 01301 01308 function _tool_Rename($p_src, $p_dest) { 01309 $v_result = 1; 01310 01311 // Try to rename the files 01312 if (!@rename($p_src, $p_dest)) { 01313 01314 // Try to copy & unlink the src 01315 if (!@copy($p_src, $p_dest)) { 01316 $v_result = 0; 01317 } else if (!@unlink($p_src)) { 01318 $v_result = 0; 01319 } 01320 } 01321 01322 // Return 01323 return $v_result; 01324 } 01325 01333 function _tool_TranslateWinPath($p_path, $p_remove_disk_letter=true) { 01334 if (stristr(php_uname(), 'windows')) { 01335 // Look for potential disk letter 01336 if ( ($p_remove_disk_letter) 01337 && (($v_position = strpos($p_path, ':')) != false)) { 01338 $p_path = substr($p_path, $v_position+1); 01339 } 01340 // Change potential windows directory separator 01341 if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { 01342 $p_path = strtr($p_path, '\\', '/'); 01343 } 01344 } 01345 return $p_path; 01346 } 01347 01348 } 01349 01350 ?>