Documentation TYPO3 par Ameos

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                 $v_header = '';
00511                 if (($v_result = $this->_readFileHeader($v_header)) != 1)
00512                 {
00513                         // Return
00514                         return $v_result;
00515                 }
00516 
00517 
00518                 // Check that the file header is coherent with $p_entry info
00519                 // TBC
00520 
00521                 // Look for all path to remove
00522                 if ($p_remove_all_path == true) {
00523                         // Get the basename of the path
00524                         $p_entry['filename'] = basename($p_entry['filename']);
00525                 }
00526 
00527                 // Look for path to remove
00528                 else if ($p_remove_path != "")
00529                 {
00530                         //if (strcmp($p_remove_path, $p_entry['filename'])==0)
00531                         if ($this->_tool_PathInclusion($p_remove_path, $p_entry['filename']) == 2)
00532                         {
00533 
00534                                 // Change the file status
00535                                 $p_entry['status'] = "filtered";
00536 
00537                                 // Return
00538                                 return $v_result;
00539                         }
00540 
00541                         $p_remove_path_size = strlen($p_remove_path);
00542                         if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
00543                         {
00544 
00545                                 // Remove the path
00546                                 $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
00547 
00548                         }
00549                 }
00550 
00551                 // Add the path
00552                 if ($p_path != '')
00553                 {
00554                         $p_entry['filename'] = $p_path."/".$p_entry['filename'];
00555                 }
00556 
00557                 // Look for pre-extract callback
00558                 if (   (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT]))
00559                 && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] != '')) {
00560 
00561                         // Generate a local information
00562                         $v_local_header = array();
00563                         $this->_convertHeader2FileInfo($p_entry, $v_local_header);
00564 
00565                         // Call the callback
00566                         // Here I do not use call_user_func() because I need to send a reference to the
00567                         // header.
00568                         eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT].'(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);');
00569                         if ($v_result == 0) {
00570                                 // Change the file status
00571                                 $p_entry['status'] = "skipped";
00572                                 $v_result = 1;
00573                         }
00574 
00575                         // Update the informations
00576                         // Only some fields can be modified
00577                         $p_entry['filename'] = $v_local_header['filename'];
00578                 }
00579 
00580                 // Trace
00581 
00582                 // Look if extraction should be done
00583                 if ($p_entry['status'] == 'ok') {
00584 
00585                         // Look for specific actions while the file exist
00586                         if (file_exists($p_entry['filename'])) {
00587                                 // Look if file is a directory
00588                                 if (is_dir($p_entry['filename'])) {
00589                                         // Change the file status
00590                                         $p_entry['status'] = "already_a_directory";
00591 
00592                                         // Return
00593                                         //return $v_result;
00594                                 }
00595                                 // Look if file is write protected
00596                                 else if (!is_writeable($p_entry['filename'])) {
00597                                         // Change the file status
00598                                         $p_entry['status'] = "write_protected";
00599 
00600                                         // Return
00601                                         //return $v_result;
00602                                 }
00603 
00604                                 // Look if the extracted file is older
00605                                 else if (filemtime($p_entry['filename']) > $p_entry['mtime']) {
00606                                         // Change the file status
00607                                         $p_entry['status'] = "newer_exist";
00608 
00609                                         // Return
00610                                         //return $v_result;
00611                                 }
00612                         }
00613 
00614                         // Check the directory availability and create it if necessary
00615                         else {
00616                                 if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
00617                                 $v_dir_to_check = $p_entry['filename'];
00618                                 else if (!strstr($p_entry['filename'], "/"))
00619                                 $v_dir_to_check = "";
00620                                 else
00621                                 $v_dir_to_check = dirname($p_entry['filename']);
00622 
00623                                 if (($v_result = $this->_dirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
00624                                         // Change the file status
00625                                         $p_entry['status'] = "path_creation_fail";
00626 
00627                                         // Return
00628                                         //return $v_result;
00629                                         $v_result = 1;
00630                                 }
00631                         }
00632                 }
00633 
00634                 // Look if extraction should be done
00635                 if ($p_entry['status'] == 'ok') {
00636                         // Do the extraction (if not a folder)
00637                         if (!(($p_entry['external']&0x00000010)==0x00000010)) {
00638                                 // Look for not compressed file
00639                                 if ($p_entry['compressed_size'] == $p_entry['size']) {
00640                                         // Opening destination file
00641                                         if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
00642                                                 // Change the file status
00643                                                 $p_entry['status'] = "write_error";
00644 
00645                                                 // Return
00646                                                 return $v_result;
00647                                         }
00648 
00649 
00650                                         // Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks
00651                                         $v_size = $p_entry['compressed_size'];
00652                                         while ($v_size != 0) {
00653                                                 $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
00654                                                 $v_buffer = fread($this->_zip_fd, $v_read_size);
00655                                                 $v_binary_data = pack('a'.$v_read_size, $v_buffer);
00656                                                 @fwrite($v_dest_file, $v_binary_data, $v_read_size);
00657                                                 $v_size -= $v_read_size;
00658                                         }
00659 
00660                                         // Closing the destination file
00661                                         fclose($v_dest_file);
00662 
00663                                         // Change the file mtime
00664                                         touch($p_entry['filename'], $p_entry['mtime']);
00665                                 } else {
00666                                         // Trace
00667 
00668                                         // Opening destination file
00669                                         if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
00670 
00671                                                 // Change the file status
00672                                                 $p_entry['status'] = "write_error";
00673 
00674                                                 return $v_result;
00675                                         }
00676 
00677 
00678                                         // Read the compressed file in a buffer (one shot)
00679                                         $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']);
00680 
00681                                         // Decompress the file
00682                                         $v_file_content = gzinflate($v_buffer);
00683                                         unset($v_buffer);
00684 
00685                                         // Write the uncompressed data
00686                                         @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
00687                                         unset($v_file_content);
00688 
00689                                         // Closing the destination file
00690                                         @fclose($v_dest_file);
00691 
00692                                         // Change the file mtime
00693                                         @touch($p_entry['filename'], $p_entry['mtime']);
00694                                 }
00695 
00696                                 // Look for chmod option
00697                                 if (   (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]))
00698                                 && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD] != 0)) {
00699 
00700                                         // Change the mode of the file
00701                                         chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]);
00702                                 }
00703 
00704                         }
00705                 }
00706 
00707                 // Look for post-extract callback
00708                 if (   (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT]))
00709                 && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] != '')) {
00710 
00711                         // Generate a local information
00712                         $v_local_header = array();
00713                         $this->_convertHeader2FileInfo($p_entry, $v_local_header);
00714 
00715                         // Call the callback
00716                         // Here I do not use call_user_func() because I need to send a reference to the
00717                         // header.
00718                         eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT].'(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);');
00719                 }
00720 
00721                 // Return
00722                 return $v_result;
00723         }
00724 
00731         function _readFileHeader(&$p_header) {
00732                 $v_result=1;
00733 
00734                 // Read the 4 bytes signature
00735                 $v_binary_data = @fread($this->_zip_fd, 4);
00736                 $v_data = unpack('Vid', $v_binary_data);
00737 
00738                 // Check signature
00739                 if ($v_data['id'] != 0x04034b50) {
00740 
00741                         // Error log
00742                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
00743 
00744                         // Return
00745                         return em_unzip::errorCode();
00746                 }
00747 
00748                 // Read the first 42 bytes of the header
00749                 $v_binary_data = fread($this->_zip_fd, 26);
00750 
00751                 // Look for invalid block size
00752                 if (strlen($v_binary_data) != 26) {
00753                         $p_header['filename'] = "";
00754                         $p_header['status'] = "invalid_header";
00755 
00756                         // Error log
00757                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
00758 
00759                         // Return
00760                         return em_unzip::errorCode();
00761                 }
00762 
00763                 // Extract the values
00764                 $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
00765 
00766                 // Get filename
00767                 $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']);
00768 
00769                 // Get extra_fields
00770                 if ($v_data['extra_len'] != 0) {
00771                         $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']);
00772                 }
00773                 else {
00774                         $p_header['extra'] = '';
00775                 }
00776 
00777                 // Extract properties
00778                 $p_header['compression'] = $v_data['compression'];
00779                 $p_header['size'] = $v_data['size'];
00780                 $p_header['compressed_size'] = $v_data['compressed_size'];
00781                 $p_header['crc'] = $v_data['crc'];
00782                 $p_header['flag'] = $v_data['flag'];
00783 
00784                 // Recuperate date in UNIX format
00785                 $p_header['mdate'] = $v_data['mdate'];
00786                 $p_header['mtime'] = $v_data['mtime'];
00787                 if ($p_header['mdate'] && $p_header['mtime']) {
00788                         // Extract time
00789                         $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
00790                         $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
00791                         $v_seconde = ($p_header['mtime'] & 0x001F)*2;
00792 
00793                         // Extract date
00794                         $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
00795                         $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
00796                         $v_day = $p_header['mdate'] & 0x001F;
00797 
00798                         // Get UNIX date format
00799                         $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
00800 
00801                 } else {
00802                         $p_header['mtime'] = time();
00803                 }
00804 
00805                 // Other informations
00806 
00807                 // TBC
00808                 //for(reset($v_data); $key = key($v_data); next($v_data)) {
00809                 //}
00810 
00811                 // Set the stored filename
00812                 $p_header['stored_filename'] = $p_header['filename'];
00813 
00814                 // Set the status field
00815                 $p_header['status'] = "ok";
00816 
00817                 // Return
00818                 return $v_result;
00819         }
00820 
00827         function _readCentralFileHeader(&$p_header) {
00828                 $v_result=1;
00829 
00830                 // Read the 4 bytes signature
00831                 $v_binary_data = @fread($this->_zip_fd, 4);
00832                 $v_data = unpack('Vid', $v_binary_data);
00833 
00834                 // Check signature
00835                 if ($v_data['id'] != 0x02014b50) {
00836 
00837                         // Error log
00838                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
00839 
00840                         // Return
00841                         return em_unzip::errorCode();
00842                 }
00843 
00844                 // Read the first 42 bytes of the header
00845                 $v_binary_data = fread($this->_zip_fd, 42);
00846 
00847                 // Look for invalid block size
00848                 if (strlen($v_binary_data) != 42) {
00849                         $p_header['filename'] = "";
00850                         $p_header['status'] = "invalid_header";
00851 
00852                         // Error log
00853                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
00854 
00855                         // Return
00856                         return em_unzip::errorCode();
00857                 }
00858 
00859                 // Extract the values
00860                 $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);
00861 
00862                 // Get filename
00863                 if ($p_header['filename_len'] != 0)
00864                 $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']);
00865                 else
00866                 $p_header['filename'] = '';
00867 
00868                 // Get extra
00869                 if ($p_header['extra_len'] != 0)
00870                 $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']);
00871                 else
00872                 $p_header['extra'] = '';
00873 
00874                 // Get comment
00875                 if ($p_header['comment_len'] != 0)
00876                 $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']);
00877                 else
00878                 $p_header['comment'] = '';
00879 
00880                 // Extract properties
00881 
00882                 // Recuperate date in UNIX format
00883                 if ($p_header['mdate'] && $p_header['mtime']) {
00884                         // Extract time
00885                         $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
00886                         $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
00887                         $v_seconde = ($p_header['mtime'] & 0x001F)*2;
00888 
00889                         // Extract date
00890                         $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
00891                         $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
00892                         $v_day = $p_header['mdate'] & 0x001F;
00893 
00894                         // Get UNIX date format
00895                         $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
00896 
00897                 } else {
00898                         $p_header['mtime'] = time();
00899                 }
00900 
00901                 // Set the stored filename
00902                 $p_header['stored_filename'] = $p_header['filename'];
00903 
00904                 // Set default status to ok
00905                 $p_header['status'] = 'ok';
00906 
00907                 // Look if it is a directory
00908                 if (substr($p_header['filename'], -1) == '/') {
00909                         $p_header['external'] = 0x41FF0010;
00910                 }
00911 
00912 
00913                 // Return
00914                 return $v_result;
00915         }
00916 
00923         function _readEndCentralDir(&$p_central_dir) {
00924                 $v_result=1;
00925 
00926                 // Go to the end of the zip file
00927                 $v_size = filesize($this->_zipname);
00928                 @fseek($this->_zip_fd, $v_size);
00929                 if (@ftell($this->_zip_fd) != $v_size) {
00930                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
00931                         'Unable to go to the end of the archive \''
00932                         .$this->_zipname.'\'');
00933                         return em_unzip::errorCode();
00934                 }
00935 
00936                 // First try : look if this is an archive with no commentaries
00937                 // (most of the time)
00938                 // in this case the end of central dir is at 22 bytes of the file end
00939                 $v_found = 0;
00940                 if ($v_size > 26) {
00941                         @fseek($this->_zip_fd, $v_size-22);
00942                         if (($v_pos = @ftell($this->_zip_fd)) != ($v_size-22)) {
00943                                 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
00944                                 'Unable to seek back to the middle of the archive \''
00945                                 .$this->_zipname.'\'');
00946                                 return em_unzip::errorCode();
00947                         }
00948 
00949                         // Read for bytes
00950                         $v_binary_data = @fread($this->_zip_fd, 4);
00951                         $v_data = unpack('Vid', $v_binary_data);
00952 
00953                         // Check signature
00954                         if ($v_data['id'] == 0x06054b50) {
00955                                 $v_found = 1;
00956                         }
00957 
00958                         $v_pos = ftell($this->_zip_fd);
00959                 }
00960 
00961                 // Go back to the maximum possible size of the Central Dir End Record
00962                 if (!$v_found) {
00963                         $v_maximum_size = 65557; // 0xFFFF + 22;
00964                         if ($v_maximum_size > $v_size)
00965                         $v_maximum_size = $v_size;
00966                         @fseek($this->_zip_fd, $v_size-$v_maximum_size);
00967                         if (@ftell($this->_zip_fd) != ($v_size-$v_maximum_size)) {
00968                                 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
00969                                 'Unable to seek back to the middle of the archive \''
00970                                 .$this->_zipname.'\'');
00971                                 return em_unzip::errorCode();
00972                         }
00973 
00974                         // Read byte per byte in order to find the signature
00975                         $v_pos = ftell($this->_zip_fd);
00976                         $v_bytes = 0x00000000;
00977                         while ($v_pos < $v_size) {
00978                                 // Read a byte
00979                                 $v_byte = @fread($this->_zip_fd, 1);
00980 
00981                                 //  Add the byte
00982                                 $v_bytes = ($v_bytes << 8) | Ord($v_byte);
00983 
00984                                 // Compare the bytes
00985                                 if ($v_bytes == 0x504b0506) {
00986                                         $v_pos++;
00987                                         break;
00988                                 }
00989 
00990                                 $v_pos++;
00991                         }
00992 
00993                         // Look if not found end of central dir
00994                         if ($v_pos == $v_size) {
00995                                 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
00996                                 "Unable to find End of Central Dir Record signature");
00997                                 return em_unzip::errorCode();
00998                         }
00999                 }
01000 
01001                 // Read the first 18 bytes of the header
01002                 $v_binary_data = fread($this->_zip_fd, 18);
01003 
01004                 // Look for invalid block size
01005                 if (strlen($v_binary_data) != 18) {
01006                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
01007                         "Invalid End of Central Dir Record size : "
01008                         .strlen($v_binary_data));
01009                         return em_unzip::errorCode();
01010                 }
01011 
01012                 // Extract the values
01013                 $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
01014 
01015                 // Check the global size
01016                 if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
01017                         $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
01018                         "Fail to find the right signature");
01019                         return em_unzip::errorCode();
01020                 }
01021 
01022                 // Get comment
01023                 if ($v_data['comment_size'] != 0)
01024                 $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']);
01025                 else
01026                 $p_central_dir['comment'] = '';
01027 
01028                 $p_central_dir['entries'] = $v_data['entries'];
01029                 $p_central_dir['disk_entries'] = $v_data['disk_entries'];
01030                 $p_central_dir['offset'] = $v_data['offset'];
01031                 $p_central_dir['size'] = $v_data['size'];
01032                 $p_central_dir['disk'] = $v_data['disk'];
01033                 $p_central_dir['disk_start'] = $v_data['disk_start'];
01034 
01035                 // Return
01036                 return $v_result;
01037         }
01038 
01046         function _dirCheck($p_dir, $p_is_dir=false) {
01047                 $v_result = 1;
01048 
01049                 // Remove the final '/'
01050                 if (($p_is_dir) && (substr($p_dir, -1)=='/')) {
01051                         $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
01052                 }
01053 
01054                 // Check the directory availability
01055                 if ((is_dir($p_dir)) || ($p_dir == "")) {
01056                         return 1;
01057                 }
01058 
01059                 // Extract parent directory
01060                 $p_parent_dir = dirname($p_dir);
01061 
01062                 // Just a check
01063                 if ($p_parent_dir != $p_dir) {
01064                         // Look for parent directory
01065                         if ($p_parent_dir != "") {
01066                                 if (($v_result = $this->_dirCheck($p_parent_dir)) != 1) {
01067                                         return $v_result;
01068                                 }
01069                         }
01070                 }
01071 
01072                 // Create the directory
01073                 if (!@mkdir($p_dir, 0777)) {
01074                         $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL,
01075                         "Unable to create directory '$p_dir'");
01076                         return em_unzip::errorCode();
01077                 }
01078 
01079                 // Return
01080                 return $v_result;
01081         }
01082 
01091         function _check_parameters(&$p_params, $p_default) {
01092 
01093                 // Check that param is an array
01094                 if (!is_array($p_params)) {
01095                         $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
01096                         'Unsupported parameter, waiting for an array');
01097                         return em_unzip::errorCode();
01098                 }
01099 
01100                 // Check that all the params are valid
01101                 for (reset($p_params); list($v_key, $v_value) = each($p_params); ) {
01102                         if (!isset($p_default[$v_key])) {
01103                                 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
01104                                 'Unsupported parameter with key \''.$v_key.'\'');
01105 
01106                                 return em_unzip::errorCode();
01107                         }
01108                 }
01109 
01110                 // Set the default values
01111                 for (reset($p_default); list($v_key, $v_value) = each($p_default); ) {
01112                         if (!isset($p_params[$v_key])) {
01113                                 $p_params[$v_key] = $p_default[$v_key];
01114                         }
01115                 }
01116 
01117                 // Check specific parameters
01118                 $v_callback_list = array ('callback_pre_add','callback_post_add',
01119                 'callback_pre_extract','callback_post_extract');
01120                 for ($i=0; $i<sizeof($v_callback_list); $i++) {
01121                         $v_key=$v_callback_list[$i];
01122                         if (   (isset($p_params[$v_key])) && ($p_params[$v_key] != '')) {
01123                                 if (!function_exists($p_params[$v_key])) {
01124                                         $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE,
01125                                         "Callback '".$p_params[$v_key]
01126                                         ."()' is not an existing function for "
01127                                         ."parameter '".$v_key."'");
01128                                         return em_unzip::errorCode();
01129                                 }
01130                         }
01131                 }
01132 
01133                 return(1);
01134         }
01135 
01144         function _errorLog($p_error_code=0, $p_error_string='') {
01145                 $this->_error_code = $p_error_code;
01146                 $this->_error_string = $p_error_string;
01147         }
01148 
01155         function _errorReset() {
01156                 $this->_error_code = 1;
01157                 $this->_error_string = '';
01158         }
01159 
01166         function _tool_PathReduction($p_dir) {
01167                 $v_result = "";
01168 
01169                 // Look for not empty path
01170                 if ($p_dir != "") {
01171                         // Explode path by directory names
01172                         $v_list = explode("/", $p_dir);
01173 
01174                         // Study directories from last to first
01175                         for ($i=sizeof($v_list)-1; $i>=0; $i--) {
01176                                 // Look for current path
01177                                 if ($v_list[$i] == ".") {
01178                                         // Ignore this directory
01179                                         // Should be the first $i=0, but no check is done
01180                                 } else if ($v_list[$i] == "..") {
01181                                         // Ignore it and ignore the $i-1
01182                                         $i--;
01183                                 } else if (($v_list[$i] == "") && ($i!=(sizeof($v_list)-1)) && ($i!=0)) {
01184                                         // Ignore only the double '//' in path,
01185                                         // but not the first and last '/'
01186                                 } else {
01187                                         $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
01188                                 }
01189                         }
01190                 }
01191 
01192                 // Return
01193                 return $v_result;
01194         }
01195 
01202         function _tool_PathInclusion($p_dir, $p_path) {
01203                 $v_result = 1;
01204 
01205                 // Explode dir and path by directory separator
01206                 $v_list_dir = explode("/", $p_dir);
01207                 $v_list_dir_size = sizeof($v_list_dir);
01208                 $v_list_path = explode("/", $p_path);
01209                 $v_list_path_size = sizeof($v_list_path);
01210 
01211                 // Study directories paths
01212                 $i = 0;
01213                 $j = 0;
01214                 while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
01215                         // Look for empty dir (path reduction)
01216                         if ($v_list_dir[$i] == '') {
01217                                 $i++;
01218                                 continue;
01219                         }
01220                         if ($v_list_path[$j] == '') {
01221                                 $j++;
01222                                 continue;
01223                         }
01224 
01225                         // Compare the items
01226                         if (   ($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != ''))  {
01227                                 $v_result = 0;
01228                         }
01229 
01230                         // Next items
01231                         $i++;
01232                         $j++;
01233                 }
01234 
01235                 // Look if everything seems to be the same
01236                 if ($v_result) {
01237                         // Skip all the empty items
01238                         while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
01239                         while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
01240 
01241                         if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
01242                                 // There are exactly the same
01243                                 $v_result = 2;
01244                         } else if ($i < $v_list_dir_size) {
01245                                 // The path is shorter than the dir
01246                                 $v_result = 0;
01247                         }
01248                 }
01249 
01250                 // Return
01251                 return $v_result;
01252         }
01253 
01261         function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode=0) {
01262                 $v_result = 1;
01263 
01264                 if ($p_mode==0) {
01265                         while ($p_size != 0) {
01266                                 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
01267                                 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
01268                                 $v_buffer = @fread($p_src, $v_read_size);
01269                                 @fwrite($p_dest, $v_buffer, $v_read_size);
01270                                 $p_size -= $v_read_size;
01271                         }
01272                 } else if ($p_mode==1) {
01273                         while ($p_size != 0) {
01274                                 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
01275                                 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
01276                                 $v_buffer = @gzread($p_src, $v_read_size);
01277                                 @fwrite($p_dest, $v_buffer, $v_read_size);
01278                                 $p_size -= $v_read_size;
01279                         }
01280                 } else if ($p_mode==2) {
01281                         while ($p_size != 0) {
01282                                 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
01283                                 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
01284                                 $v_buffer = @fread($p_src, $v_read_size);
01285                                 @gzwrite($p_dest, $v_buffer, $v_read_size);
01286                                 $p_size -= $v_read_size;
01287                         }
01288                 }
01289                 else if ($p_mode==3) {
01290                         while ($p_size != 0) {
01291                                 $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
01292                                 ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
01293                                 $v_buffer = @gzread($p_src, $v_read_size);
01294                                 @gzwrite($p_dest, $v_buffer, $v_read_size);
01295                                 $p_size -= $v_read_size;
01296                         }
01297                 }
01298 
01299                 // Return
01300                 return $v_result;
01301         }
01302 
01309         function _tool_Rename($p_src, $p_dest) {
01310                 $v_result = 1;
01311 
01312                 // Try to rename the files
01313                 if (!@rename($p_src, $p_dest)) {
01314 
01315                         // Try to copy & unlink the src
01316                         if (!@copy($p_src, $p_dest)) {
01317                                 $v_result = 0;
01318                         } else if (!@unlink($p_src)) {
01319                                 $v_result = 0;
01320                         }
01321                 }
01322 
01323                 // Return
01324                 return $v_result;
01325         }
01326 
01334         function _tool_TranslateWinPath($p_path, $p_remove_disk_letter=true) {
01335                 if (stristr(php_uname(), 'windows')) {
01336                         // Look for potential disk letter
01337                         if (   ($p_remove_disk_letter)
01338                         && (($v_position = strpos($p_path, ':')) != false)) {
01339                                 $p_path = substr($p_path, $v_position+1);
01340                         }
01341                         // Change potential windows directory separator
01342                         if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
01343                                 $p_path = strtr($p_path, '\\', '/');
01344                         }
01345                 }
01346                 return $p_path;
01347         }
01348 
01349 }
01350 
01351 ?>


Généré par Les experts TYPO3 avec  doxygen 1.4.6