Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 310 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]

   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  }