Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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, Geoffrey 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, Geoffrey Sneddon, Ryan McCue
  37   * @author Ryan Parman
  38   * @author Geoffrey 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   * Used for fetching remote files and reading local files
  46   *
  47   * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
  48   *
  49   * This class can be overloaded with {@see SimplePie::set_file_class()}
  50   *
  51   * @package SimplePie
  52   * @subpackage HTTP
  53   * @todo Move to properly supporting RFC2616 (HTTP/1.1)
  54   */
  55  class SimplePie_File
  56  {
  57  	 var $url;
  58  	 var $useragent;
  59  	 var $success = true;
  60  	 var $headers = array();
  61  	 var $body;
  62  	 var $status_code;
  63  	 var $redirects = 0;
  64  	 var $error;
  65  	 var $method = SIMPLEPIE_FILE_SOURCE_NONE;
  66  	 var $permanent_url;
  67  
  68  	public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false, $curl_options = array())
  69  	 {
  70  	 	 if (class_exists('idna_convert'))
  71  	 	 {
  72  	 	 	 $idn = new idna_convert();
  73  	 	 	 $parsed = SimplePie_Misc::parse_url($url);
  74  	 	 	 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], NULL);
  75  	 	 }
  76  	 	 $this->url = $url;
  77  	 	 $this->permanent_url = $url;
  78  	 	 $this->useragent = $useragent;
  79  	 	 if (preg_match('/^http(s)?:\/\//i', $url))
  80  	 	 {
  81  	 	 	 if ($useragent === null)
  82  	 	 	 {
  83  	 	 	 	 $useragent = ini_get('user_agent');
  84  	 	 	 	 $this->useragent = $useragent;
  85  	 	 	 }
  86  	 	 	 if (!is_array($headers))
  87  	 	 	 {
  88  	 	 	 	 $headers = array();
  89  	 	 	 }
  90  	 	 	 if (!$force_fsockopen && function_exists('curl_exec'))
  91  	 	 	 {
  92  	 	 	 	 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
  93  	 	 	 	 $fp = curl_init();
  94  	 	 	 	 $headers2 = array();
  95  	 	 	 	 foreach ($headers as $key => $value)
  96  	 	 	 	 {
  97  	 	 	 	 	 $headers2[] = "$key: $value";
  98  	 	 	 	 }
  99  	 	 	 	 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
 100  	 	 	 	 {
 101  	 	 	 	 	 curl_setopt($fp, CURLOPT_ENCODING, '');
 102  	 	 	 	 }
 103  	 	 	 	 curl_setopt($fp, CURLOPT_URL, $url);
 104  	 	 	 	 curl_setopt($fp, CURLOPT_HEADER, 1);
 105  	 	 	 	 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
 106  	 	 	 	 curl_setopt($fp, CURLOPT_FAILONERROR, 1);
 107  	 	 	 	 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
 108  	 	 	 	 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
 109  	 	 	 	 curl_setopt($fp, CURLOPT_REFERER, $url);
 110  	 	 	 	 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
 111  	 	 	 	 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
 112  	 	 	 	 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
 113  	 	 	 	 {
 114  	 	 	 	 	 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
 115  	 	 	 	 	 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
 116  	 	 	 	 }
 117  	 	 	 	 foreach ($curl_options as $curl_param => $curl_value) {
 118  	 	 	 	 	 curl_setopt($fp, $curl_param, $curl_value);
 119  	 	 	 	 }
 120  
 121  	 	 	 	 $this->headers = curl_exec($fp);
 122  	 	 	 	 if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
 123  	 	 	 	 {
 124  	 	 	 	 	 curl_setopt($fp, CURLOPT_ENCODING, 'none');
 125  	 	 	 	 	 $this->headers = curl_exec($fp);
 126  	 	 	 	 }
 127  	 	 	 	 if (curl_errno($fp))
 128  	 	 	 	 {
 129  	 	 	 	 	 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
 130  	 	 	 	 	 $this->success = false;
 131  	 	 	 	 }
 132  	 	 	 	 else
 133  	 	 	 	 {
 134  	 	 	 	 	 // Use the updated url provided by curl_getinfo after any redirects.
 135  	 	 	 	 	 if ($info = curl_getinfo($fp)) {
 136  	 	 	 	 	 	 $this->url = $info['url'];
 137  	 	 	 	 	 }
 138  	 	 	 	 	 curl_close($fp);
 139  	 	 	 	 	 $this->headers = SimplePie_HTTP_Parser::prepareHeaders($this->headers, $info['redirect_count'] + 1);
 140  	 	 	 	 	 $parser = new SimplePie_HTTP_Parser($this->headers);
 141  	 	 	 	 	 if ($parser->parse())
 142  	 	 	 	 	 {
 143  	 	 	 	 	 	 $this->headers = $parser->headers;
 144  	 	 	 	 	 	 $this->body = trim($parser->body);
 145  	 	 	 	 	 	 $this->status_code = $parser->status_code;
 146  	 	 	 	 	 	 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
 147  	 	 	 	 	 	 {
 148  	 	 	 	 	 	 	 $this->redirects++;
 149  	 	 	 	 	 	 	 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
 150  	 	 	 	 	 	 	 $previousStatusCode = $this->status_code;
 151  	 	 	 	 	 	 	 $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
 152  	 	 	 	 	 	 	 $this->permanent_url = ($previousStatusCode == 301) ? $location : $url;
 153  	 	 	 	 	 	 	 return;
 154  	 	 	 	 	 	 }
 155  	 	 	 	 	 }
 156  	 	 	 	 }
 157  	 	 	 }
 158  	 	 	 else
 159  	 	 	 {
 160  	 	 	 	 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
 161  	 	 	 	 $url_parts = parse_url($url);
 162  	 	 	 	 $socket_host = $url_parts['host'];
 163  	 	 	 	 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
 164  	 	 	 	 {
 165  	 	 	 	 	 $socket_host = "ssl://$url_parts[host]";
 166  	 	 	 	 	 $url_parts['port'] = 443;
 167  	 	 	 	 }
 168  	 	 	 	 if (!isset($url_parts['port']))
 169  	 	 	 	 {
 170  	 	 	 	 	 $url_parts['port'] = 80;
 171  	 	 	 	 }
 172  	 	 	 	 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
 173  	 	 	 	 if (!$fp)
 174  	 	 	 	 {
 175  	 	 	 	 	 $this->error = 'fsockopen error: ' . $errstr;
 176  	 	 	 	 	 $this->success = false;
 177  	 	 	 	 }
 178  	 	 	 	 else
 179  	 	 	 	 {
 180  	 	 	 	 	 stream_set_timeout($fp, $timeout);
 181  	 	 	 	 	 if (isset($url_parts['path']))
 182  	 	 	 	 	 {
 183  	 	 	 	 	 	 if (isset($url_parts['query']))
 184  	 	 	 	 	 	 {
 185  	 	 	 	 	 	 	 $get = "$url_parts[path]?$url_parts[query]";
 186  	 	 	 	 	 	 }
 187  	 	 	 	 	 	 else
 188  	 	 	 	 	 	 {
 189  	 	 	 	 	 	 	 $get = $url_parts['path'];
 190  	 	 	 	 	 	 }
 191  	 	 	 	 	 }
 192  	 	 	 	 	 else
 193  	 	 	 	 	 {
 194  	 	 	 	 	 	 $get = '/';
 195  	 	 	 	 	 }
 196  	 	 	 	 	 $out = "GET $get HTTP/1.1\r\n";
 197  	 	 	 	 	 $out .= "Host: $url_parts[host]\r\n";
 198  	 	 	 	 	 $out .= "User-Agent: $useragent\r\n";
 199  	 	 	 	 	 if (extension_loaded('zlib'))
 200  	 	 	 	 	 {
 201  	 	 	 	 	 	 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
 202  	 	 	 	 	 }
 203  
 204  	 	 	 	 	 if (isset($url_parts['user']) && isset($url_parts['pass']))
 205  	 	 	 	 	 {
 206  	 	 	 	 	 	 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
 207  	 	 	 	 	 }
 208  	 	 	 	 	 foreach ($headers as $key => $value)
 209  	 	 	 	 	 {
 210  	 	 	 	 	 	 $out .= "$key: $value\r\n";
 211  	 	 	 	 	 }
 212  	 	 	 	 	 $out .= "Connection: Close\r\n\r\n";
 213  	 	 	 	 	 fwrite($fp, $out);
 214  
 215  	 	 	 	 	 $info = stream_get_meta_data($fp);
 216  
 217  	 	 	 	 	 $this->headers = '';
 218  	 	 	 	 	 while (!$info['eof'] && !$info['timed_out'])
 219  	 	 	 	 	 {
 220  	 	 	 	 	 	 $this->headers .= fread($fp, 1160);
 221  	 	 	 	 	 	 $info = stream_get_meta_data($fp);
 222  	 	 	 	 	 }
 223  	 	 	 	 	 if (!$info['timed_out'])
 224  	 	 	 	 	 {
 225  	 	 	 	 	 	 $parser = new SimplePie_HTTP_Parser($this->headers);
 226  	 	 	 	 	 	 if ($parser->parse())
 227  	 	 	 	 	 	 {
 228  	 	 	 	 	 	 	 $this->headers = $parser->headers;
 229  	 	 	 	 	 	 	 $this->body = $parser->body;
 230  	 	 	 	 	 	 	 $this->status_code = $parser->status_code;
 231  	 	 	 	 	 	 	 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
 232  	 	 	 	 	 	 	 {
 233  	 	 	 	 	 	 	 	 $this->redirects++;
 234  	 	 	 	 	 	 	 	 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
 235  	 	 	 	 	 	 	 	 $previousStatusCode = $this->status_code;
 236  	 	 	 	 	 	 	 	 $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
 237  	 	 	 	 	 	 	 	 $this->permanent_url = ($previousStatusCode == 301) ? $location : $url;
 238  	 	 	 	 	 	 	 	 return;
 239  	 	 	 	 	 	 	 }
 240  	 	 	 	 	 	 	 if (isset($this->headers['content-encoding']))
 241  	 	 	 	 	 	 	 {
 242  	 	 	 	 	 	 	 	 // Hey, we act dumb elsewhere, so let's do that here too
 243  	 	 	 	 	 	 	 	 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
 244  	 	 	 	 	 	 	 	 {
 245  	 	 	 	 	 	 	 	 	 case 'gzip':
 246  	 	 	 	 	 	 	 	 	 case 'x-gzip':
 247  	 	 	 	 	 	 	 	 	 	 $decoder = new SimplePie_gzdecode($this->body);
 248  	 	 	 	 	 	 	 	 	 	 if (!$decoder->parse())
 249  	 	 	 	 	 	 	 	 	 	 {
 250  	 	 	 	 	 	 	 	 	 	 	 $this->error = 'Unable to decode HTTP "gzip" stream';
 251  	 	 	 	 	 	 	 	 	 	 	 $this->success = false;
 252  	 	 	 	 	 	 	 	 	 	 }
 253  	 	 	 	 	 	 	 	 	 	 else
 254  	 	 	 	 	 	 	 	 	 	 {
 255  	 	 	 	 	 	 	 	 	 	 	 $this->body = trim($decoder->data);
 256  	 	 	 	 	 	 	 	 	 	 }
 257  	 	 	 	 	 	 	 	 	 	 break;
 258  
 259  	 	 	 	 	 	 	 	 	 case 'deflate':
 260  	 	 	 	 	 	 	 	 	 	 if (($decompressed = gzinflate($this->body)) !== false)
 261  	 	 	 	 	 	 	 	 	 	 {
 262  	 	 	 	 	 	 	 	 	 	 	 $this->body = $decompressed;
 263  	 	 	 	 	 	 	 	 	 	 }
 264  	 	 	 	 	 	 	 	 	 	 else if (($decompressed = gzuncompress($this->body)) !== false)
 265  	 	 	 	 	 	 	 	 	 	 {
 266  	 	 	 	 	 	 	 	 	 	 	 $this->body = $decompressed;
 267  	 	 	 	 	 	 	 	 	 	 }
 268  	 	 	 	 	 	 	 	 	 	 else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
 269  	 	 	 	 	 	 	 	 	 	 {
 270  	 	 	 	 	 	 	 	 	 	 	 $this->body = $decompressed;
 271  	 	 	 	 	 	 	 	 	 	 }
 272  	 	 	 	 	 	 	 	 	 	 else
 273  	 	 	 	 	 	 	 	 	 	 {
 274  	 	 	 	 	 	 	 	 	 	 	 $this->error = 'Unable to decode HTTP "deflate" stream';
 275  	 	 	 	 	 	 	 	 	 	 	 $this->success = false;
 276  	 	 	 	 	 	 	 	 	 	 }
 277  	 	 	 	 	 	 	 	 	 	 break;
 278  
 279  	 	 	 	 	 	 	 	 	 default:
 280  	 	 	 	 	 	 	 	 	 	 $this->error = 'Unknown content coding';
 281  	 	 	 	 	 	 	 	 	 	 $this->success = false;
 282  	 	 	 	 	 	 	 	 }
 283  	 	 	 	 	 	 	 }
 284  	 	 	 	 	 	 }
 285  	 	 	 	 	 }
 286  	 	 	 	 	 else
 287  	 	 	 	 	 {
 288  	 	 	 	 	 	 $this->error = 'fsocket timed out';
 289  	 	 	 	 	 	 $this->success = false;
 290  	 	 	 	 	 }
 291  	 	 	 	 	 fclose($fp);
 292  	 	 	 	 }
 293  	 	 	 }
 294  	 	 }
 295  	 	 else
 296  	 	 {
 297  	 	 	 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
 298  	 	 	 if (empty($url) || !($this->body = trim(file_get_contents($url))))
 299  	 	 	 {
 300  	 	 	 	 $this->error = 'file_get_contents could not read the file';
 301  	 	 	 	 $this->success = false;
 302  	 	 	 }
 303  	 	 }
 304  	 }
 305  }