2092 | 2092 | * then the RFC 1951 standard deflate will be attempted. Finally, the RFC |
2093 | 2093 | * 1952 standard gzip decode will be attempted. If all fail, then the |
2094 | 2094 | * original compressed string will be returned. |
2095 | 2095 | * |
2096 | 2096 | * @since 2.8.0 |
2097 | 2097 | * |
2098 | 2098 | * @param string $compressed String to decompress. |
2099 | 2099 | * @param int $length The optional length of the compressed data. |
2100 | 2100 | * @return string|bool False on failure. |
2101 | 2101 | */ |
2102 | 2102 | public static function decompress( $compressed, $length = null ) { |
2103 | 2103 | |
2104 | 2104 | if ( empty($compressed) ) |
2105 | 2105 | return $compressed; |
2106 | 2106 | |
2149 | 2146 | if ( substr($gzData, 0, 3) == "\x1f\x8b\x08" ) { |
2150 | 2147 | $i = 10; |
2151 | 2148 | $flg = ord( substr($gzData, 3, 1) ); |
2152 | 2149 | if ( $flg > 0 ) { |
2153 | 2150 | if ( $flg & 4 ) { |
2154 | 2151 | list($xlen) = unpack('v', substr($gzData, $i, 2) ); |
2155 | 2152 | $i = $i + 2 + $xlen; |
2156 | 2153 | } |
2157 | 2154 | if ( $flg & 8 ) |
2158 | 2155 | $i = strpos($gzData, "\0", $i) + 1; |
2159 | 2156 | if ( $flg & 16 ) |
2160 | 2157 | $i = strpos($gzData, "\0", $i) + 1; |
2161 | 2158 | if ( $flg & 2 ) |
2162 | 2159 | $i = $i + 2; |
2163 | 2160 | } |
2169 | | // Compressed data from java.util.zip.Deflater amongst others. |
2170 | | $decompressed = @gzinflate( substr($gzData, 2) ); |
2171 | | if ( false !== $decompressed ) |
| 2168 | // If the data is Huffman Encoded, we must first strip the leading 2 byte Huffman marker for gzinflate() |
| 2169 | // The Response is Huffman coded by many compressors such as java.util.zip.Deflater, |
| 2170 | // Ruby’s Zlib::Deflate, and .NET's System.IO.Compression.DeflateStream. |
| 2171 | // See http://decompres.blogspot.com/ for a quick explanation of this data type |
| 2172 | $huffman_encoded = false; |
| 2173 | list( , $first_nibble ) = unpack( 'h', $gzData ); // low nibble of first byte should be 0x08 |
| 2174 | list( , $first_two_bytes ) = unpack( 'n', $gzData ); // First 2 bytes should be divisible by 0x1F |
| 2175 | if ( 0x08 == $first_nibble && 0 == ( $first_two_bytes % 0x1F ) ) |
| 2176 | $huffman_encoded = true; |
| 2177 | |
| 2178 | if ( $huffman_encoded ) { |
| 2179 | if ( false !== ( $decompressed = @gzinflate( substr( $gzData, 2 ) ) ) ) |
| 2180 | return $decompressed; |
| 2181 | } |
| 2182 | |
| 2183 | if ( "\x50\x4b\x03\x04" == substr( $gzData, 0, 4 ) ) { |
| 2184 | // ZIP file format header |
| 2185 | // Offset 6: 2 bytes, General-purpose field |
| 2186 | // Offset 26: 2 bytes, filename length |
| 2187 | // Offset 28: 2 bytes, optional field length |
| 2188 | // Offset 30: Filename field, followed by optional field, followed immediately by data |
| 2189 | list( , $general_purpose_flag ) = unpack( 'v', substr( $gzData, 6, 2 ) ); |
| 2190 | |
| 2191 | // If the file has been compressed on the fly, 0x08 bit is set of the general purpose field |
| 2192 | // We can use this to differentiate between a compressed document, and a ZIP file |
| 2193 | $zip_compressed_on_the_fly = ( 0x08 == (0x08 & $general_purpose_flag ) ); |
| 2194 | |
| 2195 | if ( ! $zip_compressed_on_the_fly ) { |
| 2196 | return $gzData; // Don't attempt to decode a compressed zip file from the server |
| 2197 | } |
| 2198 | |
| 2199 | // Determine the first byte of data, based on the above ZIP header offsets: |
| 2200 | $first_file_start = array_sum( unpack( 'v2', substr( $gzData, 26, 4 ) ) ); |
| 2201 | if ( false !== ( $decompressed = @gzinflate( substr( $gzData, 30 + $first_file_start ) ) ) ) { |
| 2202 | return $decompressed; |
| 2203 | } |
| 2204 | |
| 2205 | return false; |
| 2206 | } |
| 2207 | |
| 2208 | // Finally fall back to straight gzinflate |
| 2209 | if ( false !== ( $decompressed = @gzinflate( $gzData ) ) ) { |