ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

gzdecode.php (8506B)


      1 <?php
      2 /**
      3  * SimplePie
      4  *
      5  * A PHP-Based RSS and Atom Feed Framework.
      6  * Takes the hard work out of managing a complete RSS/Atom solution.
      7  *
      8  * Copyright (c) 2004-2016, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without modification, are
     12  * permitted provided that the following conditions are met:
     13  *
     14  * 	* Redistributions of source code must retain the above copyright notice, this list of
     15  * 	  conditions and the following disclaimer.
     16  *
     17  * 	* Redistributions in binary form must reproduce the above copyright notice, this list
     18  * 	  of conditions and the following disclaimer in the documentation and/or other materials
     19  * 	  provided with the distribution.
     20  *
     21  * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
     22  * 	  to endorse or promote products derived from this software without specific prior
     23  * 	  written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
     26  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     27  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
     28  * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     33  * POSSIBILITY OF SUCH DAMAGE.
     34  *
     35  * @package SimplePie
     36  * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue
     37  * @author Ryan Parman
     38  * @author Sam Sneddon
     39  * @author Ryan McCue
     40  * @link http://simplepie.org/ SimplePie
     41  * @license http://www.opensource.org/licenses/bsd-license.php BSD License
     42  */
     43 
     44 
     45 /**
     46  * Decode 'gzip' encoded HTTP data
     47  *
     48  * @package SimplePie
     49  * @subpackage HTTP
     50  * @link http://www.gzip.org/format.txt
     51  */
     52 class SimplePie_gzdecode
     53 {
     54 	/**
     55 	 * Compressed data
     56 	 *
     57 	 * @access private
     58 	 * @var string
     59 	 * @see gzdecode::$data
     60 	 */
     61 	var $compressed_data;
     62 
     63 	/**
     64 	 * Size of compressed data
     65 	 *
     66 	 * @access private
     67 	 * @var int
     68 	 */
     69 	var $compressed_size;
     70 
     71 	/**
     72 	 * Minimum size of a valid gzip string
     73 	 *
     74 	 * @access private
     75 	 * @var int
     76 	 */
     77 	var $min_compressed_size = 18;
     78 
     79 	/**
     80 	 * Current position of pointer
     81 	 *
     82 	 * @access private
     83 	 * @var int
     84 	 */
     85 	var $position = 0;
     86 
     87 	/**
     88 	 * Flags (FLG)
     89 	 *
     90 	 * @access private
     91 	 * @var int
     92 	 */
     93 	var $flags;
     94 
     95 	/**
     96 	 * Uncompressed data
     97 	 *
     98 	 * @access public
     99 	 * @see gzdecode::$compressed_data
    100 	 * @var string
    101 	 */
    102 	var $data;
    103 
    104 	/**
    105 	 * Modified time
    106 	 *
    107 	 * @access public
    108 	 * @var int
    109 	 */
    110 	var $MTIME;
    111 
    112 	/**
    113 	 * Extra Flags
    114 	 *
    115 	 * @access public
    116 	 * @var int
    117 	 */
    118 	var $XFL;
    119 
    120 	/**
    121 	 * Operating System
    122 	 *
    123 	 * @access public
    124 	 * @var int
    125 	 */
    126 	var $OS;
    127 
    128 	/**
    129 	 * Subfield ID 1
    130 	 *
    131 	 * @access public
    132 	 * @see gzdecode::$extra_field
    133 	 * @see gzdecode::$SI2
    134 	 * @var string
    135 	 */
    136 	var $SI1;
    137 
    138 	/**
    139 	 * Subfield ID 2
    140 	 *
    141 	 * @access public
    142 	 * @see gzdecode::$extra_field
    143 	 * @see gzdecode::$SI1
    144 	 * @var string
    145 	 */
    146 	var $SI2;
    147 
    148 	/**
    149 	 * Extra field content
    150 	 *
    151 	 * @access public
    152 	 * @see gzdecode::$SI1
    153 	 * @see gzdecode::$SI2
    154 	 * @var string
    155 	 */
    156 	var $extra_field;
    157 
    158 	/**
    159 	 * Original filename
    160 	 *
    161 	 * @access public
    162 	 * @var string
    163 	 */
    164 	var $filename;
    165 
    166 	/**
    167 	 * Human readable comment
    168 	 *
    169 	 * @access public
    170 	 * @var string
    171 	 */
    172 	var $comment;
    173 
    174 	/**
    175 	 * Don't allow anything to be set
    176 	 *
    177 	 * @param string $name
    178 	 * @param mixed $value
    179 	 */
    180 	public function __set($name, $value)
    181 	{
    182 		trigger_error("Cannot write property $name", E_USER_ERROR);
    183 	}
    184 
    185 	/**
    186 	 * Set the compressed string and related properties
    187 	 *
    188 	 * @param string $data
    189 	 */
    190 	public function __construct($data)
    191 	{
    192 		$this->compressed_data = $data;
    193 		$this->compressed_size = strlen($data);
    194 	}
    195 
    196 	/**
    197 	 * Decode the GZIP stream
    198 	 *
    199 	 * @return bool Successfulness
    200 	 */
    201 	public function parse()
    202 	{
    203 		if ($this->compressed_size >= $this->min_compressed_size)
    204 		{
    205 			// Check ID1, ID2, and CM
    206 			if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
    207 			{
    208 				return false;
    209 			}
    210 
    211 			// Get the FLG (FLaGs)
    212 			$this->flags = ord($this->compressed_data[3]);
    213 
    214 			// FLG bits above (1 << 4) are reserved
    215 			if ($this->flags > 0x1F)
    216 			{
    217 				return false;
    218 			}
    219 
    220 			// Advance the pointer after the above
    221 			$this->position += 4;
    222 
    223 			// MTIME
    224 			$mtime = substr($this->compressed_data, $this->position, 4);
    225 			// Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
    226 			if (current(unpack('S', "\x00\x01")) === 1)
    227 			{
    228 				$mtime = strrev($mtime);
    229 			}
    230 			$this->MTIME = current(unpack('l', $mtime));
    231 			$this->position += 4;
    232 
    233 			// Get the XFL (eXtra FLags)
    234 			$this->XFL = ord($this->compressed_data[$this->position++]);
    235 
    236 			// Get the OS (Operating System)
    237 			$this->OS = ord($this->compressed_data[$this->position++]);
    238 
    239 			// Parse the FEXTRA
    240 			if ($this->flags & 4)
    241 			{
    242 				// Read subfield IDs
    243 				$this->SI1 = $this->compressed_data[$this->position++];
    244 				$this->SI2 = $this->compressed_data[$this->position++];
    245 
    246 				// SI2 set to zero is reserved for future use
    247 				if ($this->SI2 === "\x00")
    248 				{
    249 					return false;
    250 				}
    251 
    252 				// Get the length of the extra field
    253 				$len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
    254 				$this->position += 2;
    255 
    256 				// Check the length of the string is still valid
    257 				$this->min_compressed_size += $len + 4;
    258 				if ($this->compressed_size >= $this->min_compressed_size)
    259 				{
    260 					// Set the extra field to the given data
    261 					$this->extra_field = substr($this->compressed_data, $this->position, $len);
    262 					$this->position += $len;
    263 				}
    264 				else
    265 				{
    266 					return false;
    267 				}
    268 			}
    269 
    270 			// Parse the FNAME
    271 			if ($this->flags & 8)
    272 			{
    273 				// Get the length of the filename
    274 				$len = strcspn($this->compressed_data, "\x00", $this->position);
    275 
    276 				// Check the length of the string is still valid
    277 				$this->min_compressed_size += $len + 1;
    278 				if ($this->compressed_size >= $this->min_compressed_size)
    279 				{
    280 					// Set the original filename to the given string
    281 					$this->filename = substr($this->compressed_data, $this->position, $len);
    282 					$this->position += $len + 1;
    283 				}
    284 				else
    285 				{
    286 					return false;
    287 				}
    288 			}
    289 
    290 			// Parse the FCOMMENT
    291 			if ($this->flags & 16)
    292 			{
    293 				// Get the length of the comment
    294 				$len = strcspn($this->compressed_data, "\x00", $this->position);
    295 
    296 				// Check the length of the string is still valid
    297 				$this->min_compressed_size += $len + 1;
    298 				if ($this->compressed_size >= $this->min_compressed_size)
    299 				{
    300 					// Set the original comment to the given string
    301 					$this->comment = substr($this->compressed_data, $this->position, $len);
    302 					$this->position += $len + 1;
    303 				}
    304 				else
    305 				{
    306 					return false;
    307 				}
    308 			}
    309 
    310 			// Parse the FHCRC
    311 			if ($this->flags & 2)
    312 			{
    313 				// Check the length of the string is still valid
    314 				$this->min_compressed_size += $len + 2;
    315 				if ($this->compressed_size >= $this->min_compressed_size)
    316 				{
    317 					// Read the CRC
    318 					$crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
    319 
    320 					// Check the CRC matches
    321 					if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
    322 					{
    323 						$this->position += 2;
    324 					}
    325 					else
    326 					{
    327 						return false;
    328 					}
    329 				}
    330 				else
    331 				{
    332 					return false;
    333 				}
    334 			}
    335 
    336 			// Decompress the actual data
    337 			if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
    338 			{
    339 				return false;
    340 			}
    341 
    342 			$this->position = $this->compressed_size - 8;
    343 
    344 			// Check CRC of data
    345 			$crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
    346 			$this->position += 4;
    347 			/*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
    348 			{
    349 				return false;
    350 			}*/
    351 
    352 			// Check ISIZE of data
    353 			$isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
    354 			$this->position += 4;
    355 			if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
    356 			{
    357 				return false;
    358 			}
    359 
    360 			// Wow, against all odds, we've actually got a valid gzip string
    361 			return true;
    362 		}
    363 
    364 		return false;
    365 	}
    366 }