"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); ?>

class.em_unzip.php

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 ?>