Search moodle.org's
Developer Documentation

See Release Notes

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