159b616ccSAndreas Gohr<?php 259b616ccSAndreas Gohr/** 359b616ccSAndreas Gohr * SimplePie 459b616ccSAndreas Gohr * 559b616ccSAndreas Gohr * A PHP-Based RSS and Atom Feed Framework. 659b616ccSAndreas Gohr * Takes the hard work out of managing a complete RSS/Atom solution. 759b616ccSAndreas Gohr * 859b616ccSAndreas Gohr * Copyright (c) 2004-2016, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors 959b616ccSAndreas Gohr * All rights reserved. 1059b616ccSAndreas Gohr * 1159b616ccSAndreas Gohr * Redistribution and use in source and binary forms, with or without modification, are 1259b616ccSAndreas Gohr * permitted provided that the following conditions are met: 1359b616ccSAndreas Gohr * 1459b616ccSAndreas Gohr * * Redistributions of source code must retain the above copyright notice, this list of 1559b616ccSAndreas Gohr * conditions and the following disclaimer. 1659b616ccSAndreas Gohr * 1759b616ccSAndreas Gohr * * Redistributions in binary form must reproduce the above copyright notice, this list 1859b616ccSAndreas Gohr * of conditions and the following disclaimer in the documentation and/or other materials 1959b616ccSAndreas Gohr * provided with the distribution. 2059b616ccSAndreas Gohr * 2159b616ccSAndreas Gohr * * Neither the name of the SimplePie Team nor the names of its contributors may be used 2259b616ccSAndreas Gohr * to endorse or promote products derived from this software without specific prior 2359b616ccSAndreas Gohr * written permission. 2459b616ccSAndreas Gohr * 2559b616ccSAndreas Gohr * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 2659b616ccSAndreas Gohr * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 2759b616ccSAndreas Gohr * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 2859b616ccSAndreas Gohr * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2959b616ccSAndreas Gohr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 3059b616ccSAndreas Gohr * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3159b616ccSAndreas Gohr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3259b616ccSAndreas Gohr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3359b616ccSAndreas Gohr * POSSIBILITY OF SUCH DAMAGE. 3459b616ccSAndreas Gohr * 3559b616ccSAndreas Gohr * @package SimplePie 3659b616ccSAndreas Gohr * @copyright 2004-2016 Ryan Parman, Geoffrey Sneddon, Ryan McCue 3759b616ccSAndreas Gohr * @author Ryan Parman 3859b616ccSAndreas Gohr * @author Geoffrey Sneddon 3959b616ccSAndreas Gohr * @author Ryan McCue 4059b616ccSAndreas Gohr * @link http://simplepie.org/ SimplePie 4159b616ccSAndreas Gohr * @license http://www.opensource.org/licenses/bsd-license.php BSD License 4259b616ccSAndreas Gohr */ 4359b616ccSAndreas Gohr 4459b616ccSAndreas Gohr 4559b616ccSAndreas Gohr/** 4659b616ccSAndreas Gohr * Decode 'gzip' encoded HTTP data 4759b616ccSAndreas Gohr * 4859b616ccSAndreas Gohr * @package SimplePie 4959b616ccSAndreas Gohr * @subpackage HTTP 5059b616ccSAndreas Gohr * @link http://www.gzip.org/format.txt 5159b616ccSAndreas Gohr */ 5259b616ccSAndreas Gohrclass SimplePie_gzdecode 5359b616ccSAndreas Gohr{ 5459b616ccSAndreas Gohr /** 5559b616ccSAndreas Gohr * Compressed data 5659b616ccSAndreas Gohr * 5759b616ccSAndreas Gohr * @access private 5859b616ccSAndreas Gohr * @var string 5959b616ccSAndreas Gohr * @see gzdecode::$data 6059b616ccSAndreas Gohr */ 6159b616ccSAndreas Gohr var $compressed_data; 6259b616ccSAndreas Gohr 6359b616ccSAndreas Gohr /** 6459b616ccSAndreas Gohr * Size of compressed data 6559b616ccSAndreas Gohr * 6659b616ccSAndreas Gohr * @access private 6759b616ccSAndreas Gohr * @var int 6859b616ccSAndreas Gohr */ 6959b616ccSAndreas Gohr var $compressed_size; 7059b616ccSAndreas Gohr 7159b616ccSAndreas Gohr /** 7259b616ccSAndreas Gohr * Minimum size of a valid gzip string 7359b616ccSAndreas Gohr * 7459b616ccSAndreas Gohr * @access private 7559b616ccSAndreas Gohr * @var int 7659b616ccSAndreas Gohr */ 7759b616ccSAndreas Gohr var $min_compressed_size = 18; 7859b616ccSAndreas Gohr 7959b616ccSAndreas Gohr /** 8059b616ccSAndreas Gohr * Current position of pointer 8159b616ccSAndreas Gohr * 8259b616ccSAndreas Gohr * @access private 8359b616ccSAndreas Gohr * @var int 8459b616ccSAndreas Gohr */ 8559b616ccSAndreas Gohr var $position = 0; 8659b616ccSAndreas Gohr 8759b616ccSAndreas Gohr /** 8859b616ccSAndreas Gohr * Flags (FLG) 8959b616ccSAndreas Gohr * 9059b616ccSAndreas Gohr * @access private 9159b616ccSAndreas Gohr * @var int 9259b616ccSAndreas Gohr */ 9359b616ccSAndreas Gohr var $flags; 9459b616ccSAndreas Gohr 9559b616ccSAndreas Gohr /** 9659b616ccSAndreas Gohr * Uncompressed data 9759b616ccSAndreas Gohr * 9859b616ccSAndreas Gohr * @access public 9959b616ccSAndreas Gohr * @see gzdecode::$compressed_data 10059b616ccSAndreas Gohr * @var string 10159b616ccSAndreas Gohr */ 10259b616ccSAndreas Gohr var $data; 10359b616ccSAndreas Gohr 10459b616ccSAndreas Gohr /** 10559b616ccSAndreas Gohr * Modified time 10659b616ccSAndreas Gohr * 10759b616ccSAndreas Gohr * @access public 10859b616ccSAndreas Gohr * @var int 10959b616ccSAndreas Gohr */ 11059b616ccSAndreas Gohr var $MTIME; 11159b616ccSAndreas Gohr 11259b616ccSAndreas Gohr /** 11359b616ccSAndreas Gohr * Extra Flags 11459b616ccSAndreas Gohr * 11559b616ccSAndreas Gohr * @access public 11659b616ccSAndreas Gohr * @var int 11759b616ccSAndreas Gohr */ 11859b616ccSAndreas Gohr var $XFL; 11959b616ccSAndreas Gohr 12059b616ccSAndreas Gohr /** 12159b616ccSAndreas Gohr * Operating System 12259b616ccSAndreas Gohr * 12359b616ccSAndreas Gohr * @access public 12459b616ccSAndreas Gohr * @var int 12559b616ccSAndreas Gohr */ 12659b616ccSAndreas Gohr var $OS; 12759b616ccSAndreas Gohr 12859b616ccSAndreas Gohr /** 12959b616ccSAndreas Gohr * Subfield ID 1 13059b616ccSAndreas Gohr * 13159b616ccSAndreas Gohr * @access public 13259b616ccSAndreas Gohr * @see gzdecode::$extra_field 13359b616ccSAndreas Gohr * @see gzdecode::$SI2 13459b616ccSAndreas Gohr * @var string 13559b616ccSAndreas Gohr */ 13659b616ccSAndreas Gohr var $SI1; 13759b616ccSAndreas Gohr 13859b616ccSAndreas Gohr /** 13959b616ccSAndreas Gohr * Subfield ID 2 14059b616ccSAndreas Gohr * 14159b616ccSAndreas Gohr * @access public 14259b616ccSAndreas Gohr * @see gzdecode::$extra_field 14359b616ccSAndreas Gohr * @see gzdecode::$SI1 14459b616ccSAndreas Gohr * @var string 14559b616ccSAndreas Gohr */ 14659b616ccSAndreas Gohr var $SI2; 14759b616ccSAndreas Gohr 14859b616ccSAndreas Gohr /** 14959b616ccSAndreas Gohr * Extra field content 15059b616ccSAndreas Gohr * 15159b616ccSAndreas Gohr * @access public 15259b616ccSAndreas Gohr * @see gzdecode::$SI1 15359b616ccSAndreas Gohr * @see gzdecode::$SI2 15459b616ccSAndreas Gohr * @var string 15559b616ccSAndreas Gohr */ 15659b616ccSAndreas Gohr var $extra_field; 15759b616ccSAndreas Gohr 15859b616ccSAndreas Gohr /** 15959b616ccSAndreas Gohr * Original filename 16059b616ccSAndreas Gohr * 16159b616ccSAndreas Gohr * @access public 16259b616ccSAndreas Gohr * @var string 16359b616ccSAndreas Gohr */ 16459b616ccSAndreas Gohr var $filename; 16559b616ccSAndreas Gohr 16659b616ccSAndreas Gohr /** 16759b616ccSAndreas Gohr * Human readable comment 16859b616ccSAndreas Gohr * 16959b616ccSAndreas Gohr * @access public 17059b616ccSAndreas Gohr * @var string 17159b616ccSAndreas Gohr */ 17259b616ccSAndreas Gohr var $comment; 17359b616ccSAndreas Gohr 17459b616ccSAndreas Gohr /** 17559b616ccSAndreas Gohr * Don't allow anything to be set 17659b616ccSAndreas Gohr * 17759b616ccSAndreas Gohr * @param string $name 17859b616ccSAndreas Gohr * @param mixed $value 17959b616ccSAndreas Gohr */ 18059b616ccSAndreas Gohr public function __set($name, $value) 18159b616ccSAndreas Gohr { 18259b616ccSAndreas Gohr trigger_error("Cannot write property $name", E_USER_ERROR); 18359b616ccSAndreas Gohr } 18459b616ccSAndreas Gohr 18559b616ccSAndreas Gohr /** 18659b616ccSAndreas Gohr * Set the compressed string and related properties 18759b616ccSAndreas Gohr * 18859b616ccSAndreas Gohr * @param string $data 18959b616ccSAndreas Gohr */ 19059b616ccSAndreas Gohr public function __construct($data) 19159b616ccSAndreas Gohr { 19259b616ccSAndreas Gohr $this->compressed_data = $data; 19359b616ccSAndreas Gohr $this->compressed_size = strlen($data); 19459b616ccSAndreas Gohr } 19559b616ccSAndreas Gohr 19659b616ccSAndreas Gohr /** 19759b616ccSAndreas Gohr * Decode the GZIP stream 19859b616ccSAndreas Gohr * 19959b616ccSAndreas Gohr * @return bool Successfulness 20059b616ccSAndreas Gohr */ 20159b616ccSAndreas Gohr public function parse() 20259b616ccSAndreas Gohr { 20359b616ccSAndreas Gohr if ($this->compressed_size >= $this->min_compressed_size) 20459b616ccSAndreas Gohr { 20559b616ccSAndreas Gohr // Check ID1, ID2, and CM 20659b616ccSAndreas Gohr if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") 20759b616ccSAndreas Gohr { 20859b616ccSAndreas Gohr return false; 20959b616ccSAndreas Gohr } 21059b616ccSAndreas Gohr 21159b616ccSAndreas Gohr // Get the FLG (FLaGs) 21259b616ccSAndreas Gohr $this->flags = ord($this->compressed_data[3]); 21359b616ccSAndreas Gohr 21459b616ccSAndreas Gohr // FLG bits above (1 << 4) are reserved 21559b616ccSAndreas Gohr if ($this->flags > 0x1F) 21659b616ccSAndreas Gohr { 21759b616ccSAndreas Gohr return false; 21859b616ccSAndreas Gohr } 21959b616ccSAndreas Gohr 22059b616ccSAndreas Gohr // Advance the pointer after the above 22159b616ccSAndreas Gohr $this->position += 4; 22259b616ccSAndreas Gohr 22359b616ccSAndreas Gohr // MTIME 22459b616ccSAndreas Gohr $mtime = substr($this->compressed_data, $this->position, 4); 22559b616ccSAndreas Gohr // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness 22659b616ccSAndreas Gohr if (current(unpack('S', "\x00\x01")) === 1) 22759b616ccSAndreas Gohr { 22859b616ccSAndreas Gohr $mtime = strrev($mtime); 22959b616ccSAndreas Gohr } 23059b616ccSAndreas Gohr $this->MTIME = current(unpack('l', $mtime)); 23159b616ccSAndreas Gohr $this->position += 4; 23259b616ccSAndreas Gohr 23359b616ccSAndreas Gohr // Get the XFL (eXtra FLags) 23459b616ccSAndreas Gohr $this->XFL = ord($this->compressed_data[$this->position++]); 23559b616ccSAndreas Gohr 23659b616ccSAndreas Gohr // Get the OS (Operating System) 23759b616ccSAndreas Gohr $this->OS = ord($this->compressed_data[$this->position++]); 23859b616ccSAndreas Gohr 23959b616ccSAndreas Gohr // Parse the FEXTRA 24059b616ccSAndreas Gohr if ($this->flags & 4) 24159b616ccSAndreas Gohr { 24259b616ccSAndreas Gohr // Read subfield IDs 24359b616ccSAndreas Gohr $this->SI1 = $this->compressed_data[$this->position++]; 24459b616ccSAndreas Gohr $this->SI2 = $this->compressed_data[$this->position++]; 24559b616ccSAndreas Gohr 24659b616ccSAndreas Gohr // SI2 set to zero is reserved for future use 24759b616ccSAndreas Gohr if ($this->SI2 === "\x00") 24859b616ccSAndreas Gohr { 24959b616ccSAndreas Gohr return false; 25059b616ccSAndreas Gohr } 25159b616ccSAndreas Gohr 25259b616ccSAndreas Gohr // Get the length of the extra field 25359b616ccSAndreas Gohr $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); 25459b616ccSAndreas Gohr $this->position += 2; 25559b616ccSAndreas Gohr 25659b616ccSAndreas Gohr // Check the length of the string is still valid 25759b616ccSAndreas Gohr $this->min_compressed_size += $len + 4; 25859b616ccSAndreas Gohr if ($this->compressed_size >= $this->min_compressed_size) 25959b616ccSAndreas Gohr { 26059b616ccSAndreas Gohr // Set the extra field to the given data 26159b616ccSAndreas Gohr $this->extra_field = substr($this->compressed_data, $this->position, $len); 26259b616ccSAndreas Gohr $this->position += $len; 26359b616ccSAndreas Gohr } 26459b616ccSAndreas Gohr else 26559b616ccSAndreas Gohr { 26659b616ccSAndreas Gohr return false; 26759b616ccSAndreas Gohr } 26859b616ccSAndreas Gohr } 26959b616ccSAndreas Gohr 27059b616ccSAndreas Gohr // Parse the FNAME 27159b616ccSAndreas Gohr if ($this->flags & 8) 27259b616ccSAndreas Gohr { 27359b616ccSAndreas Gohr // Get the length of the filename 27459b616ccSAndreas Gohr $len = strcspn($this->compressed_data, "\x00", $this->position); 27559b616ccSAndreas Gohr 27659b616ccSAndreas Gohr // Check the length of the string is still valid 27759b616ccSAndreas Gohr $this->min_compressed_size += $len + 1; 27859b616ccSAndreas Gohr if ($this->compressed_size >= $this->min_compressed_size) 27959b616ccSAndreas Gohr { 28059b616ccSAndreas Gohr // Set the original filename to the given string 28159b616ccSAndreas Gohr $this->filename = substr($this->compressed_data, $this->position, $len); 28259b616ccSAndreas Gohr $this->position += $len + 1; 28359b616ccSAndreas Gohr } 28459b616ccSAndreas Gohr else 28559b616ccSAndreas Gohr { 28659b616ccSAndreas Gohr return false; 28759b616ccSAndreas Gohr } 28859b616ccSAndreas Gohr } 28959b616ccSAndreas Gohr 29059b616ccSAndreas Gohr // Parse the FCOMMENT 29159b616ccSAndreas Gohr if ($this->flags & 16) 29259b616ccSAndreas Gohr { 29359b616ccSAndreas Gohr // Get the length of the comment 29459b616ccSAndreas Gohr $len = strcspn($this->compressed_data, "\x00", $this->position); 29559b616ccSAndreas Gohr 29659b616ccSAndreas Gohr // Check the length of the string is still valid 29759b616ccSAndreas Gohr $this->min_compressed_size += $len + 1; 29859b616ccSAndreas Gohr if ($this->compressed_size >= $this->min_compressed_size) 29959b616ccSAndreas Gohr { 30059b616ccSAndreas Gohr // Set the original comment to the given string 30159b616ccSAndreas Gohr $this->comment = substr($this->compressed_data, $this->position, $len); 30259b616ccSAndreas Gohr $this->position += $len + 1; 30359b616ccSAndreas Gohr } 30459b616ccSAndreas Gohr else 30559b616ccSAndreas Gohr { 30659b616ccSAndreas Gohr return false; 30759b616ccSAndreas Gohr } 30859b616ccSAndreas Gohr } 30959b616ccSAndreas Gohr 31059b616ccSAndreas Gohr // Parse the FHCRC 31159b616ccSAndreas Gohr if ($this->flags & 2) 31259b616ccSAndreas Gohr { 31359b616ccSAndreas Gohr // Check the length of the string is still valid 31459b616ccSAndreas Gohr $this->min_compressed_size += $len + 2; 31559b616ccSAndreas Gohr if ($this->compressed_size >= $this->min_compressed_size) 31659b616ccSAndreas Gohr { 31759b616ccSAndreas Gohr // Read the CRC 31859b616ccSAndreas Gohr $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); 31959b616ccSAndreas Gohr 32059b616ccSAndreas Gohr // Check the CRC matches 32159b616ccSAndreas Gohr if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) 32259b616ccSAndreas Gohr { 32359b616ccSAndreas Gohr $this->position += 2; 32459b616ccSAndreas Gohr } 32559b616ccSAndreas Gohr else 32659b616ccSAndreas Gohr { 32759b616ccSAndreas Gohr return false; 32859b616ccSAndreas Gohr } 32959b616ccSAndreas Gohr } 33059b616ccSAndreas Gohr else 33159b616ccSAndreas Gohr { 33259b616ccSAndreas Gohr return false; 33359b616ccSAndreas Gohr } 33459b616ccSAndreas Gohr } 33559b616ccSAndreas Gohr 33659b616ccSAndreas Gohr // Decompress the actual data 33759b616ccSAndreas Gohr if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) 33859b616ccSAndreas Gohr { 33959b616ccSAndreas Gohr return false; 34059b616ccSAndreas Gohr } 341*e43cd7e1SAndreas Gohr 34259b616ccSAndreas Gohr $this->position = $this->compressed_size - 8; 34359b616ccSAndreas Gohr 34459b616ccSAndreas Gohr // Check CRC of data 34559b616ccSAndreas Gohr $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); 34659b616ccSAndreas Gohr $this->position += 4; 34759b616ccSAndreas Gohr /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) 34859b616ccSAndreas Gohr { 34959b616ccSAndreas Gohr return false; 35059b616ccSAndreas Gohr }*/ 35159b616ccSAndreas Gohr 35259b616ccSAndreas Gohr // Check ISIZE of data 35359b616ccSAndreas Gohr $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); 35459b616ccSAndreas Gohr $this->position += 4; 35559b616ccSAndreas Gohr if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) 35659b616ccSAndreas Gohr { 35759b616ccSAndreas Gohr return false; 35859b616ccSAndreas Gohr } 35959b616ccSAndreas Gohr 36059b616ccSAndreas Gohr // Wow, against all odds, we've actually got a valid gzip string 36159b616ccSAndreas Gohr return true; 36259b616ccSAndreas Gohr } 363*e43cd7e1SAndreas Gohr 36459b616ccSAndreas Gohr return false; 36559b616ccSAndreas Gohr } 36659b616ccSAndreas Gohr} 367