Beispiel #1
0
 function testInt32HashingSanity()
 {
     /* Max value for a signed 32-bit integer. */
     $integerMax = 2147483647;
     $maxValue = $integerMax - HashUtility::HASH_OFFSET;
     $integersToTest = array(0, 1, 2, 3, 4, 5, 10, 21, 30, 43, 50, 101, 211, 300, 461, 500, 1011, 2000, 3000, 4051, 4096, 1000000000, 2000000000, $maxValue);
     $integersToTestNegative = array(1, 2, 3, 4, 5, 10, 21, 30, 43, 50, 101, 211, 300, 461, 500, 1011, 2000, 3000, 4051, 4096, 1000000000, 2000000000, $maxValue, $integerMax, $integerMax + HashUtility::HASH_OFFSET);
     foreach ($integersToTest as $integer) {
         $hash = HashUtility::hashInt32($integer);
         $unhashed = HashUtility::unhashInt32($hash);
         $this->assertEqual($integer, $unhashed, sprintf("HashUtility::hashInt32(%s) should equal HashUtility::unhashInt32(%s), equals %s", $integer, $hash, $unhashed));
     }
     foreach ($integersToTestNegative as $integer) {
         $integer *= -1;
         $hash = HashUtility::hashInt32($integer);
         $unhashed = HashUtility::unhashInt32($hash);
         $this->assertEqual($integer, $unhashed, sprintf("HashUtility::hashInt32(%s) should equal HashUtility::unhashInt32(%s), equals %s", $integer, $hash, $unhashed));
     }
 }
 /**
  * Adds a file to the archive.
  *
  * @param string Name of file as to be stored inside the archive,
  *               optionally including the path.
  * @param string File data.
  * @param integer Last modified timestamp, or false for current time.
  * @return void
  */
 function addFileFromDisk($name, $filename, $timestamp = false)
 {
     /* Normally, we would split this into several methods, but this must be
      * optimized for minimal RAM usage, which presents a design challenge.
      */
     $data = @file_get_contents($filename);
     /* Do we still have a valid file handle? */
     if (!$this->_fileHandle) {
         $this->_errorMessage = 'Unexpected end of file.';
         return false;
     }
     /* Convert DOS / Windows paths to UNIX paths. */
     $name = str_replace('\\', '/', $name);
     /* If a timestamp wasn't specified, use the current time. */
     if ($timestamp === false) {
         $timestamp = time();
     }
     /* Convert our UNIX timestamp to DOS format. */
     $DOSTime = FileCompressorUtility::UNIXToDOSTime($timestamp);
     /* Calculate the length of the file data before compression. */
     $uncompressedLength = filesize($filename);
     /* Calculate the CRC32 checksum of the file data to be compressed. */
     $CRC32 = HashUtility::crc32File($filename);
     /* Version needed to extract.
      *
      * Store Only: 10
      * DEFLATE:    20
      * BZIP2:      46
      *
      * From the ZIP format specification:
      *
      * Current minimum feature versions are as defined below:
      *
      * 1.0 - Default value
      * 1.1 - File is a volume label
      * 2.0 - File is a folder (directory)
      * 2.0 - File is compressed using Deflate compression
      * 2.0 - File is encrypted using traditional PKWARE encryption
      * 2.1 - File is compressed using Deflate64(tm)
      * 2.5 - File is compressed using PKWARE DCL Implode 
      * 2.7 - File is a patch data set 
      * 4.5 - File uses ZIP64 format extensions
      * 4.6 - File is compressed using BZIP2 compression*
      * 5.0 - File is encrypted using DES
      * 5.0 - File is encrypted using 3DES
      * 5.0 - File is encrypted using original RC2 encryption
      * 5.0 - File is encrypted using RC4 encryption
      * 5.1 - File is encrypted using AES encryption
      * 5.1 - File is encrypted using corrected RC2 encryption**
      * 5.2 - File is encrypted using corrected RC2-64 encryption**
      * 6.1 - File is encrypted using non-OAEP key wrapping***
      * 6.2 - Central directory encryption
      * 6.3 - File is compressed using LZMA
      * 6.3 - File is compressed using PPMd+
      * 6.3 - File is encrypted using Blowfish
      * 6.3 - File is encrypted using Twofish
      */
     $versionNeededToExtract = 20;
     /* General purpose bit-flag.
      *
      * From the ZIP format specification:
      *
      * Bit 0: If set, indicates that the file is encrypted.
      *
      * <cut, irrelevant>
      *
      * (For Methods 8 and 9 - Deflating)
      * Bit 2  Bit 1
      *   0      0    Normal (-en) compression option was used.
      *   0      1    Maximum (-exx/-ex) compression option was used.
      *   1      0    Fast (-ef) compression option was used.
      *   1      1    Super Fast (-es) compression option was used.
      *
      * <cut, irrelevant>
      *
      * Bit 3: If this bit is set, the fields crc-32, compressed 
      *        size and uncompressed size are set to zero in the 
      *        local header.  The correct values are put in the 
      *        data descriptor immediately following the compressed
      *        data.  (Note: PKZIP version 2.04g for DOS only 
      *        recognizes this bit for method 8 compression, newer 
      *        versions of PKZIP recognize this bit for any 
      *        compression method.)
      *
      * Bit 4: Reserved for use with method 8, for enhanced
      *        deflating. 
      *
      * Bit 5: If this bit is set, this indicates that the file is 
      *        compressed patched data.  (Note: Requires PKZIP 
      *        version 2.70 or greater)
      *
      * Bit 6: Strong encryption.  If this bit is set, you should
      *        set the version needed to extract value to at least
      *        50 and you must also set bit 0.  If AES encryption
      *        is used, the version needed to extract value must 
      *        be at least 51.
      *
      * Bit [7-10]: Currently unused.
      *
      * Bit 11: Language encoding flag (EFS).  If this bit is set,
      *         the filename and comment fields for this file
      *         must be encoded using UTF-8. (see APPENDIX D)
      *
      * Bit 12: Reserved by PKWARE for enhanced compression.
      *
      * Bit 13: Used when encrypting the Central Directory to indicate 
      *         selected data values in the Local Header are masked to
      *         hide their actual values.  See the section describing 
      *         the Strong Encryption Specification for details.
      *
      * Bit [14-15]: Reserved by PKWARE.
      */
     $generalPurposeBitFlag = 0;
     /* Compression method.
      *
      * 0:  STORE
      * 8:  DEFLATE
      * 12: BZIP2
      */
     $compressionMethod = 8;
     /* Extra field length. */
     $extraFieldLength = 0;
     /* Format:
      *
      * [4B] [Start of File Record Marker]
      * [2B] [Version Needed to Extract]
      * [2B] [General Purpose Bit Flag (See Above)]
      * [2B] [Compression Method (See Above)]
      *
      * [4B] [Last-Modified Timestamp in DOS Format]
      * [4B] [CRC32 Checksum of Compressed Data]
      * [4B] [Compressed Data Length]
      * [4B] [Uncompressed Data Length]
      *
      * [2B] [Filename Length]
      * [2B] [Extra Field Length]
      */
     $fileRecord = pack('VvvvVVVVvv', START_FILE_RECORD, $versionNeededToExtract, $generalPurposeBitFlag, $compressionMethod, $DOSTime, $CRC32, 0, $uncompressedLength, strlen($name), $extraFieldLength);
     /* Filename. */
     $fileRecord .= $name;
     /* This is the "data descriptor" section, however, apparently this
      * causes problems and is optional anyway.
      *
      * From the ZIP format specification:
      * C.  Data descriptor:
      *
      * crc-32                          4 bytes
      * compressed size                 4 bytes
      * uncompressed size               4 bytes
      *
      * This descriptor exists only if bit 3 of the general
      * purpose bit flag is set (see below).  It is byte aligned
      * and immediately follows the last byte of compressed data.
      * This descriptor is used only when it was not possible to
      * seek in the output .ZIP file, e.g., when the output .ZIP file
      * was standard output or a non-seekable device.  For ZIP64(tm) format
      * archives, the compressed and uncompressed sizes are 8 bytes each.
      *
      * When compressing files, compressed and uncompressed sizes 
      * should be stored in ZIP64 format (as 8 byte values) when a 
      * files size exceeds 0xFFFFFFFF.   However ZIP64 format may be 
      * used regardless of the size of a file.  When extracting, if 
      * the zip64 extended information extra field is present for 
      * the file the compressed and uncompressed sizes will be 8
      * byte values.  
      *
      * Although not originally assigned a signature, the value 
      * 0x08074b50 has commonly been adopted as a signature value 
      * for the data descriptor record.  Implementers should be 
      * aware that ZIP files may be encountered with or without this 
      * signature marking data descriptors and should account for
      * either case when reading ZIP files to ensure compatibility.
      * When writing ZIP files, it is recommended to include the
      * signature value marking the data descriptor record.  When
      * the signature is used, the fields currently defined for
      * the data descriptor record will immediately follow the
      * signature.
      *
      * <cut, irrlevent>
      *
      * When the Central Directory Encryption method is used, the data
      * descriptor record is not required, but may be used.  If present,
      * and bit 3 of the general purpose bit field is set to indicate
      * its presence, the values in fields of the data descriptor
      * record should be set to binary zeros.
      *
      * $fileRecord .= pack('V', START_DATA_DESCRIPTOR);
      * $fileRecord .= pack('V', $CRC32);
      * $fileRecord .= pack('V', $compressedLength);
      * $fileRecord .= pack('V', $uncompressedLength);
      */
     /* Get the length of this file record for use later on. */
     $fileRecordLength = strlen($fileRecord);
     /* Add this file record to the zip file. */
     if (fwrite($this->_fileHandle, $fileRecord) === false) {
         return false;
     }
     unset($fileRecord);
     $tempFilename = FileUtility::makeRandomTemporaryFilePath();
     $compressedLength = 0;
     $fhSource = fopen(realpath($filename), 'rb');
     $fhCompressor = gzopen($tempFilename, 'wb');
     if (!$fhSource or !$fhCompressor) {
         $this->_errorMessage = 'Unexpected end of file.';
         return false;
     }
     while (!feof($fhSource)) {
         $temp = fread($fhSource, 32767);
         gzwrite($fhCompressor, $temp);
     }
     gzclose($fhCompressor);
     fclose($fhSource);
     $fhCompressed = fopen($tempFilename, 'rb');
     if (!$fhCompressed) {
         $this->_errorMessage = 'Unexpected end of file.';
         return false;
     }
     /* Strip off the headers and footers. */
     $gzipHeaderLength = 10;
     $gzipFooterLength = 8;
     if (fseek($fhCompressed, $gzipHeaderLength, SEEK_SET) === -1) {
         $this->_errorMessage = 'Unexpected end of file.';
         return false;
     }
     while (!feof($fhCompressed)) {
         $temp = fread($fhCompressed, 8192);
         $compressedLength += strlen($temp);
         fwrite($this->_fileHandle, $temp);
     }
     fclose($fhCompressed);
     @unlink($tempFilename);
     /* Ignore last 8 bytes of compressed data. */
     $compressedLength -= $gzipFooterLength;
     /* We need to seek back into the file and correct the 4B representation
        of how large the compressed data is. It is stored at 
        pointer - $compressedSize - 12 bytes. */
     if (fseek($this->_fileHandle, 0 - $compressedLength - strlen($name) - $gzipFooterLength - 12, SEEK_CUR) === -1) {
         $this->_errorMessage = 'Unexpected end of file.';
         return false;
     }
     $compressedLengthPacked = pack('V', $compressedLength);
     fwrite($this->_fileHandle, $compressedLengthPacked);
     /* Seek to the end of the file, but seek back 4 bytes to recover CRC bug for gzcompress. */
     if (fseek($this->_fileHandle, 0 - $gzipFooterLength, SEEK_END) === -1) {
         $this->_errorMessage = 'Unexpected end of file.';
         return false;
     }
     /* Increment total compressed data length and file record count. */
     $fileRecordLength += $compressedLength;
     $this->_fileRecordsLength += $fileRecordLength;
     ++$this->_fileRecordCount;
     /* Create the Central Directory entry for this file and append it
      * to the Central Directory (stored in memory for now until all file
      * records have been written).
      */
     $this->createCentralDirectoryEntry($name, $DOSTime, $CRC32, $compressedLength, $uncompressedLength, $fileRecordLength);
     return true;
 }