[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/simplepie/simplepie/library/ -> SimplePie.php (source)

   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-2017, 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   * @version 1.5.5
  37   * @copyright 2004-2017 Ryan Parman, Sam Sneddon, Ryan McCue
  38   * @author Ryan Parman
  39   * @author Sam Sneddon
  40   * @author Ryan McCue
  41   * @link http://simplepie.org/ SimplePie
  42   * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  43   */
  44  
  45  /**
  46   * SimplePie Name
  47   */
  48  define('SIMPLEPIE_NAME', 'SimplePie');
  49  
  50  /**
  51   * SimplePie Version
  52   */
  53  define('SIMPLEPIE_VERSION', '1.5.5');
  54  
  55  /**
  56   * SimplePie Build
  57   * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
  58   */
  59  define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::get_build()));
  60  
  61  /**
  62   * SimplePie Website URL
  63   */
  64  define('SIMPLEPIE_URL', 'http://simplepie.org');
  65  
  66  /**
  67   * SimplePie Useragent
  68   * @see SimplePie::set_useragent()
  69   */
  70  define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
  71  
  72  /**
  73   * SimplePie Linkback
  74   */
  75  define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
  76  
  77  /**
  78   * No Autodiscovery
  79   * @see SimplePie::set_autodiscovery_level()
  80   */
  81  define('SIMPLEPIE_LOCATOR_NONE', 0);
  82  
  83  /**
  84   * Feed Link Element Autodiscovery
  85   * @see SimplePie::set_autodiscovery_level()
  86   */
  87  define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
  88  
  89  /**
  90   * Local Feed Extension Autodiscovery
  91   * @see SimplePie::set_autodiscovery_level()
  92   */
  93  define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
  94  
  95  /**
  96   * Local Feed Body Autodiscovery
  97   * @see SimplePie::set_autodiscovery_level()
  98   */
  99  define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
 100  
 101  /**
 102   * Remote Feed Extension Autodiscovery
 103   * @see SimplePie::set_autodiscovery_level()
 104   */
 105  define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
 106  
 107  /**
 108   * Remote Feed Body Autodiscovery
 109   * @see SimplePie::set_autodiscovery_level()
 110   */
 111  define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
 112  
 113  /**
 114   * All Feed Autodiscovery
 115   * @see SimplePie::set_autodiscovery_level()
 116   */
 117  define('SIMPLEPIE_LOCATOR_ALL', 31);
 118  
 119  /**
 120   * No known feed type
 121   */
 122  define('SIMPLEPIE_TYPE_NONE', 0);
 123  
 124  /**
 125   * RSS 0.90
 126   */
 127  define('SIMPLEPIE_TYPE_RSS_090', 1);
 128  
 129  /**
 130   * RSS 0.91 (Netscape)
 131   */
 132  define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
 133  
 134  /**
 135   * RSS 0.91 (Userland)
 136   */
 137  define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
 138  
 139  /**
 140   * RSS 0.91 (both Netscape and Userland)
 141   */
 142  define('SIMPLEPIE_TYPE_RSS_091', 6);
 143  
 144  /**
 145   * RSS 0.92
 146   */
 147  define('SIMPLEPIE_TYPE_RSS_092', 8);
 148  
 149  /**
 150   * RSS 0.93
 151   */
 152  define('SIMPLEPIE_TYPE_RSS_093', 16);
 153  
 154  /**
 155   * RSS 0.94
 156   */
 157  define('SIMPLEPIE_TYPE_RSS_094', 32);
 158  
 159  /**
 160   * RSS 1.0
 161   */
 162  define('SIMPLEPIE_TYPE_RSS_10', 64);
 163  
 164  /**
 165   * RSS 2.0
 166   */
 167  define('SIMPLEPIE_TYPE_RSS_20', 128);
 168  
 169  /**
 170   * RDF-based RSS
 171   */
 172  define('SIMPLEPIE_TYPE_RSS_RDF', 65);
 173  
 174  /**
 175   * Non-RDF-based RSS (truly intended as syndication format)
 176   */
 177  define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
 178  
 179  /**
 180   * All RSS
 181   */
 182  define('SIMPLEPIE_TYPE_RSS_ALL', 255);
 183  
 184  /**
 185   * Atom 0.3
 186   */
 187  define('SIMPLEPIE_TYPE_ATOM_03', 256);
 188  
 189  /**
 190   * Atom 1.0
 191   */
 192  define('SIMPLEPIE_TYPE_ATOM_10', 512);
 193  
 194  /**
 195   * All Atom
 196   */
 197  define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
 198  
 199  /**
 200   * All feed types
 201   */
 202  define('SIMPLEPIE_TYPE_ALL', 1023);
 203  
 204  /**
 205   * No construct
 206   */
 207  define('SIMPLEPIE_CONSTRUCT_NONE', 0);
 208  
 209  /**
 210   * Text construct
 211   */
 212  define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
 213  
 214  /**
 215   * HTML construct
 216   */
 217  define('SIMPLEPIE_CONSTRUCT_HTML', 2);
 218  
 219  /**
 220   * XHTML construct
 221   */
 222  define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
 223  
 224  /**
 225   * base64-encoded construct
 226   */
 227  define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
 228  
 229  /**
 230   * IRI construct
 231   */
 232  define('SIMPLEPIE_CONSTRUCT_IRI', 16);
 233  
 234  /**
 235   * A construct that might be HTML
 236   */
 237  define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
 238  
 239  /**
 240   * All constructs
 241   */
 242  define('SIMPLEPIE_CONSTRUCT_ALL', 63);
 243  
 244  /**
 245   * Don't change case
 246   */
 247  define('SIMPLEPIE_SAME_CASE', 1);
 248  
 249  /**
 250   * Change to lowercase
 251   */
 252  define('SIMPLEPIE_LOWERCASE', 2);
 253  
 254  /**
 255   * Change to uppercase
 256   */
 257  define('SIMPLEPIE_UPPERCASE', 4);
 258  
 259  /**
 260   * PCRE for HTML attributes
 261   */
 262  define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
 263  
 264  /**
 265   * PCRE for XML attributes
 266   */
 267  define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
 268  
 269  /**
 270   * XML Namespace
 271   */
 272  define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
 273  
 274  /**
 275   * Atom 1.0 Namespace
 276   */
 277  define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
 278  
 279  /**
 280   * Atom 0.3 Namespace
 281   */
 282  define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
 283  
 284  /**
 285   * RDF Namespace
 286   */
 287  define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
 288  
 289  /**
 290   * RSS 0.90 Namespace
 291   */
 292  define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
 293  
 294  /**
 295   * RSS 1.0 Namespace
 296   */
 297  define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
 298  
 299  /**
 300   * RSS 1.0 Content Module Namespace
 301   */
 302  define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
 303  
 304  /**
 305   * RSS 2.0 Namespace
 306   * (Stupid, I know, but I'm certain it will confuse people less with support.)
 307   */
 308  define('SIMPLEPIE_NAMESPACE_RSS_20', '');
 309  
 310  /**
 311   * DC 1.0 Namespace
 312   */
 313  define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
 314  
 315  /**
 316   * DC 1.1 Namespace
 317   */
 318  define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
 319  
 320  /**
 321   * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
 322   */
 323  define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
 324  
 325  /**
 326   * GeoRSS Namespace
 327   */
 328  define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
 329  
 330  /**
 331   * Media RSS Namespace
 332   */
 333  define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
 334  
 335  /**
 336   * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
 337   */
 338  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
 339  
 340  /**
 341   * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
 342   */
 343  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
 344  
 345  /**
 346   * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
 347   */
 348  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
 349  
 350  /**
 351   * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
 352   */
 353  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
 354  
 355  /**
 356   * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
 357   */
 358  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
 359  
 360  /**
 361   * iTunes RSS Namespace
 362   */
 363  define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
 364  
 365  /**
 366   * XHTML Namespace
 367   */
 368  define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
 369  
 370  /**
 371   * IANA Link Relations Registry
 372   */
 373  define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
 374  
 375  /**
 376   * No file source
 377   */
 378  define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
 379  
 380  /**
 381   * Remote file source
 382   */
 383  define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
 384  
 385  /**
 386   * Local file source
 387   */
 388  define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
 389  
 390  /**
 391   * fsockopen() file source
 392   */
 393  define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
 394  
 395  /**
 396   * cURL file source
 397   */
 398  define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
 399  
 400  /**
 401   * file_get_contents() file source
 402   */
 403  define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
 404  
 405  
 406  
 407  /**
 408   * SimplePie
 409   *
 410   * @package SimplePie
 411   * @subpackage API
 412   */
 413  class SimplePie
 414  {
 415      /**
 416       * @var array Raw data
 417       * @access private
 418       */
 419      public $data = array();
 420  
 421      /**
 422       * @var mixed Error string
 423       * @access private
 424       */
 425      public $error;
 426  
 427      /**
 428       * @var object Instance of SimplePie_Sanitize (or other class)
 429       * @see SimplePie::set_sanitize_class()
 430       * @access private
 431       */
 432      public $sanitize;
 433  
 434      /**
 435       * @var string SimplePie Useragent
 436       * @see SimplePie::set_useragent()
 437       * @access private
 438       */
 439      public $useragent = SIMPLEPIE_USERAGENT;
 440  
 441      /**
 442       * @var string Feed URL
 443       * @see SimplePie::set_feed_url()
 444       * @access private
 445       */
 446      public $feed_url;
 447  
 448      /**
 449       * @var string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently
 450       * @see SimplePie::subscribe_url()
 451       * @access private
 452       */
 453      public $permanent_url = null;
 454  
 455      /**
 456       * @var object Instance of SimplePie_File to use as a feed
 457       * @see SimplePie::set_file()
 458       * @access private
 459       */
 460      public $file;
 461  
 462      /**
 463       * @var string Raw feed data
 464       * @see SimplePie::set_raw_data()
 465       * @access private
 466       */
 467      public $raw_data;
 468  
 469      /**
 470       * @var int Timeout for fetching remote files
 471       * @see SimplePie::set_timeout()
 472       * @access private
 473       */
 474      public $timeout = 10;
 475  
 476      /**
 477       * @var array Custom curl options
 478       * @see SimplePie::set_curl_options()
 479       * @access private
 480       */
 481      public $curl_options = array();
 482  
 483      /**
 484       * @var bool Forces fsockopen() to be used for remote files instead
 485       * of cURL, even if a new enough version is installed
 486       * @see SimplePie::force_fsockopen()
 487       * @access private
 488       */
 489      public $force_fsockopen = false;
 490  
 491      /**
 492       * @var bool Force the given data/URL to be treated as a feed no matter what
 493       * it appears like
 494       * @see SimplePie::force_feed()
 495       * @access private
 496       */
 497      public $force_feed = false;
 498  
 499      /**
 500       * @var bool Enable/Disable Caching
 501       * @see SimplePie::enable_cache()
 502       * @access private
 503       */
 504      public $cache = true;
 505  
 506      /**
 507       * @var bool Force SimplePie to fallback to expired cache, if enabled,
 508       * when feed is unavailable.
 509       * @see SimplePie::force_cache_fallback()
 510       * @access private
 511       */
 512      public $force_cache_fallback = false;
 513  
 514      /**
 515       * @var int Cache duration (in seconds)
 516       * @see SimplePie::set_cache_duration()
 517       * @access private
 518       */
 519      public $cache_duration = 3600;
 520  
 521      /**
 522       * @var int Auto-discovery cache duration (in seconds)
 523       * @see SimplePie::set_autodiscovery_cache_duration()
 524       * @access private
 525       */
 526      public $autodiscovery_cache_duration = 604800; // 7 Days.
 527  
 528      /**
 529       * @var string Cache location (relative to executing script)
 530       * @see SimplePie::set_cache_location()
 531       * @access private
 532       */
 533      public $cache_location = './cache';
 534  
 535      /**
 536       * @var string Function that creates the cache filename
 537       * @see SimplePie::set_cache_name_function()
 538       * @access private
 539       */
 540      public $cache_name_function = 'md5';
 541  
 542      /**
 543       * @var bool Reorder feed by date descending
 544       * @see SimplePie::enable_order_by_date()
 545       * @access private
 546       */
 547      public $order_by_date = true;
 548  
 549      /**
 550       * @var mixed Force input encoding to be set to the follow value
 551       * (false, or anything type-cast to false, disables this feature)
 552       * @see SimplePie::set_input_encoding()
 553       * @access private
 554       */
 555      public $input_encoding = false;
 556  
 557      /**
 558       * @var int Feed Autodiscovery Level
 559       * @see SimplePie::set_autodiscovery_level()
 560       * @access private
 561       */
 562      public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
 563  
 564      /**
 565       * Class registry object
 566       *
 567       * @var SimplePie_Registry
 568       */
 569      public $registry;
 570  
 571      /**
 572       * @var int Maximum number of feeds to check with autodiscovery
 573       * @see SimplePie::set_max_checked_feeds()
 574       * @access private
 575       */
 576      public $max_checked_feeds = 10;
 577  
 578      /**
 579       * @var array All the feeds found during the autodiscovery process
 580       * @see SimplePie::get_all_discovered_feeds()
 581       * @access private
 582       */
 583      public $all_discovered_feeds = array();
 584  
 585      /**
 586       * @var string Web-accessible path to the handler_image.php file.
 587       * @see SimplePie::set_image_handler()
 588       * @access private
 589       */
 590      public $image_handler = '';
 591  
 592      /**
 593       * @var array Stores the URLs when multiple feeds are being initialized.
 594       * @see SimplePie::set_feed_url()
 595       * @access private
 596       */
 597      public $multifeed_url = array();
 598  
 599      /**
 600       * @var array Stores SimplePie objects when multiple feeds initialized.
 601       * @access private
 602       */
 603      public $multifeed_objects = array();
 604  
 605      /**
 606       * @var array Stores the get_object_vars() array for use with multifeeds.
 607       * @see SimplePie::set_feed_url()
 608       * @access private
 609       */
 610      public $config_settings = null;
 611  
 612      /**
 613       * @var integer Stores the number of items to return per-feed with multifeeds.
 614       * @see SimplePie::set_item_limit()
 615       * @access private
 616       */
 617      public $item_limit = 0;
 618  
 619      /**
 620       * @var bool Stores if last-modified and/or etag headers were sent with the
 621       * request when checking a feed.
 622       */
 623      public $check_modified = false;
 624  
 625      /**
 626       * @var array Stores the default attributes to be stripped by strip_attributes().
 627       * @see SimplePie::strip_attributes()
 628       * @access private
 629       */
 630      public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
 631  
 632      /**
 633       * @var array Stores the default attributes to add to different tags by add_attributes().
 634       * @see SimplePie::add_attributes()
 635       * @access private
 636       */
 637      public $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none'));
 638  
 639      /**
 640       * @var array Stores the default tags to be stripped by strip_htmltags().
 641       * @see SimplePie::strip_htmltags()
 642       * @access private
 643       */
 644      public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
 645  
 646      /**
 647       * @var bool Should we throw exceptions, or use the old-style error property?
 648       * @access private
 649       */
 650      public $enable_exceptions = false;
 651  
 652      /**
 653       * The SimplePie class contains feed level data and options
 654       *
 655       * To use SimplePie, create the SimplePie object with no parameters. You can
 656       * then set configuration options using the provided methods. After setting
 657       * them, you must initialise the feed using $feed->init(). At that point the
 658       * object's methods and properties will be available to you.
 659       *
 660       * Previously, it was possible to pass in the feed URL along with cache
 661       * options directly into the constructor. This has been removed as of 1.3 as
 662       * it caused a lot of confusion.
 663       *
 664       * @since 1.0 Preview Release
 665       */
 666  	public function __construct()
 667      {
 668          if (version_compare(PHP_VERSION, '5.6', '<'))
 669          {
 670              trigger_error('Please upgrade to PHP 5.6 or newer.');
 671              die();
 672          }
 673  
 674          // Other objects, instances created here so we can set options on them
 675          $this->sanitize = new SimplePie_Sanitize();
 676          $this->registry = new SimplePie_Registry();
 677  
 678          if (func_num_args() > 0)
 679          {
 680              $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
 681              trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_duration() directly.', $level);
 682  
 683              $args = func_get_args();
 684              switch (count($args)) {
 685                  case 3:
 686                      $this->set_cache_duration($args[2]);
 687                  case 2:
 688                      $this->set_cache_location($args[1]);
 689                  case 1:
 690                      $this->set_feed_url($args[0]);
 691                      $this->init();
 692              }
 693          }
 694      }
 695  
 696      /**
 697       * Used for converting object to a string
 698       */
 699  	public function __toString()
 700      {
 701          return md5(serialize($this->data));
 702      }
 703  
 704      /**
 705       * Remove items that link back to this before destroying this object
 706       */
 707  	public function __destruct()
 708      {
 709          if (!gc_enabled())
 710          {
 711              if (!empty($this->data['items']))
 712              {
 713                  foreach ($this->data['items'] as $item)
 714                  {
 715                      $item->__destruct();
 716                  }
 717                  unset($item, $this->data['items']);
 718              }
 719              if (!empty($this->data['ordered_items']))
 720              {
 721                  foreach ($this->data['ordered_items'] as $item)
 722                  {
 723                      $item->__destruct();
 724                  }
 725                  unset($item, $this->data['ordered_items']);
 726              }
 727          }
 728      }
 729  
 730      /**
 731       * Force the given data/URL to be treated as a feed
 732       *
 733       * This tells SimplePie to ignore the content-type provided by the server.
 734       * Be careful when using this option, as it will also disable autodiscovery.
 735       *
 736       * @since 1.1
 737       * @param bool $enable Force the given data/URL to be treated as a feed
 738       */
 739  	public function force_feed($enable = false)
 740      {
 741          $this->force_feed = (bool) $enable;
 742      }
 743  
 744      /**
 745       * Set the URL of the feed you want to parse
 746       *
 747       * This allows you to enter the URL of the feed you want to parse, or the
 748       * website you want to try to use auto-discovery on. This takes priority
 749       * over any set raw data.
 750       *
 751       * You can set multiple feeds to mash together by passing an array instead
 752       * of a string for the $url. Remember that with each additional feed comes
 753       * additional processing and resources.
 754       *
 755       * @since 1.0 Preview Release
 756       * @see set_raw_data()
 757       * @param string|array $url This is the URL (or array of URLs) that you want to parse.
 758       */
 759  	public function set_feed_url($url)
 760      {
 761          $this->multifeed_url = array();
 762          if (is_array($url))
 763          {
 764              foreach ($url as $value)
 765              {
 766                  $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
 767              }
 768          }
 769          else
 770          {
 771              $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
 772              $this->permanent_url = $this->feed_url;
 773          }
 774      }
 775  
 776      /**
 777       * Set an instance of {@see SimplePie_File} to use as a feed
 778       *
 779       * @param SimplePie_File &$file
 780       * @return bool True on success, false on failure
 781       */
 782  	public function set_file(&$file)
 783      {
 784          if ($file instanceof SimplePie_File)
 785          {
 786              $this->feed_url = $file->url;
 787              $this->permanent_url = $this->feed_url;
 788              $this->file =& $file;
 789              return true;
 790          }
 791          return false;
 792      }
 793  
 794      /**
 795       * Set the raw XML data to parse
 796       *
 797       * Allows you to use a string of RSS/Atom data instead of a remote feed.
 798       *
 799       * If you have a feed available as a string in PHP, you can tell SimplePie
 800       * to parse that data string instead of a remote feed. Any set feed URL
 801       * takes precedence.
 802       *
 803       * @since 1.0 Beta 3
 804       * @param string $data RSS or Atom data as a string.
 805       * @see set_feed_url()
 806       */
 807  	public function set_raw_data($data)
 808      {
 809          $this->raw_data = $data;
 810      }
 811  
 812      /**
 813       * Set the default timeout for fetching remote feeds
 814       *
 815       * This allows you to change the maximum time the feed's server to respond
 816       * and send the feed back.
 817       *
 818       * @since 1.0 Beta 3
 819       * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
 820       */
 821  	public function set_timeout($timeout = 10)
 822      {
 823          $this->timeout = (int) $timeout;
 824      }
 825  
 826      /**
 827       * Set custom curl options
 828       *
 829       * This allows you to change default curl options
 830       *
 831       * @since 1.0 Beta 3
 832       * @param array $curl_options Curl options to add to default settings
 833       */
 834  	public function set_curl_options(array $curl_options = array())
 835      {
 836          $this->curl_options = $curl_options;
 837      }
 838  
 839      /**
 840       * Force SimplePie to use fsockopen() instead of cURL
 841       *
 842       * @since 1.0 Beta 3
 843       * @param bool $enable Force fsockopen() to be used
 844       */
 845  	public function force_fsockopen($enable = false)
 846      {
 847          $this->force_fsockopen = (bool) $enable;
 848      }
 849  
 850      /**
 851       * Enable/disable caching in SimplePie.
 852       *
 853       * This option allows you to disable caching all-together in SimplePie.
 854       * However, disabling the cache can lead to longer load times.
 855       *
 856       * @since 1.0 Preview Release
 857       * @param bool $enable Enable caching
 858       */
 859  	public function enable_cache($enable = true)
 860      {
 861          $this->cache = (bool) $enable;
 862      }
 863  
 864      /**
 865       * SimplePie to continue to fall back to expired cache, if enabled, when
 866       * feed is unavailable.
 867       *
 868       * This tells SimplePie to ignore any file errors and fall back to cache
 869       * instead. This only works if caching is enabled and cached content
 870       * still exists.
 871  
 872       * @param bool $enable Force use of cache on fail.
 873       */
 874  	public function force_cache_fallback($enable = false)
 875      {
 876          $this->force_cache_fallback= (bool) $enable;
 877      }
 878  
 879      /**
 880       * Set the length of time (in seconds) that the contents of a feed will be
 881       * cached
 882       *
 883       * @param int $seconds The feed content cache duration
 884       */
 885  	public function set_cache_duration($seconds = 3600)
 886      {
 887          $this->cache_duration = (int) $seconds;
 888      }
 889  
 890      /**
 891       * Set the length of time (in seconds) that the autodiscovered feed URL will
 892       * be cached
 893       *
 894       * @param int $seconds The autodiscovered feed URL cache duration.
 895       */
 896  	public function set_autodiscovery_cache_duration($seconds = 604800)
 897      {
 898          $this->autodiscovery_cache_duration = (int) $seconds;
 899      }
 900  
 901      /**
 902       * Set the file system location where the cached files should be stored
 903       *
 904       * @param string $location The file system location.
 905       */
 906  	public function set_cache_location($location = './cache')
 907      {
 908          $this->cache_location = (string) $location;
 909      }
 910  
 911      /**
 912       * Set whether feed items should be sorted into reverse chronological order
 913       *
 914       * @param bool $enable Sort as reverse chronological order.
 915       */
 916  	public function enable_order_by_date($enable = true)
 917      {
 918          $this->order_by_date = (bool) $enable;
 919      }
 920  
 921      /**
 922       * Set the character encoding used to parse the feed
 923       *
 924       * This overrides the encoding reported by the feed, however it will fall
 925       * back to the normal encoding detection if the override fails
 926       *
 927       * @param string $encoding Character encoding
 928       */
 929  	public function set_input_encoding($encoding = false)
 930      {
 931          if ($encoding)
 932          {
 933              $this->input_encoding = (string) $encoding;
 934          }
 935          else
 936          {
 937              $this->input_encoding = false;
 938          }
 939      }
 940  
 941      /**
 942       * Set how much feed autodiscovery to do
 943       *
 944       * @see SIMPLEPIE_LOCATOR_NONE
 945       * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
 946       * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
 947       * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
 948       * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
 949       * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
 950       * @see SIMPLEPIE_LOCATOR_ALL
 951       * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
 952       */
 953  	public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
 954      {
 955          $this->autodiscovery = (int) $level;
 956      }
 957  
 958      /**
 959       * Get the class registry
 960       *
 961       * Use this to override SimplePie's default classes
 962       * @see SimplePie_Registry
 963       * @return SimplePie_Registry
 964       */
 965      public function &get_registry()
 966      {
 967          return $this->registry;
 968      }
 969  
 970      /**#@+
 971       * Useful when you are overloading or extending SimplePie's default classes.
 972       *
 973       * @deprecated Use {@see get_registry()} instead
 974       * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
 975       * @param string $class Name of custom class
 976       * @return boolean True on success, false otherwise
 977       */
 978      /**
 979       * Set which class SimplePie uses for caching
 980       */
 981  	public function set_cache_class($class = 'SimplePie_Cache')
 982      {
 983          return $this->registry->register('Cache', $class, true);
 984      }
 985  
 986      /**
 987       * Set which class SimplePie uses for auto-discovery
 988       */
 989  	public function set_locator_class($class = 'SimplePie_Locator')
 990      {
 991          return $this->registry->register('Locator', $class, true);
 992      }
 993  
 994      /**
 995       * Set which class SimplePie uses for XML parsing
 996       */
 997  	public function set_parser_class($class = 'SimplePie_Parser')
 998      {
 999          return $this->registry->register('Parser', $class, true);
1000      }
1001  
1002      /**
1003       * Set which class SimplePie uses for remote file fetching
1004       */
1005  	public function set_file_class($class = 'SimplePie_File')
1006      {
1007          return $this->registry->register('File', $class, true);
1008      }
1009  
1010      /**
1011       * Set which class SimplePie uses for data sanitization
1012       */
1013  	public function set_sanitize_class($class = 'SimplePie_Sanitize')
1014      {
1015          return $this->registry->register('Sanitize', $class, true);
1016      }
1017  
1018      /**
1019       * Set which class SimplePie uses for handling feed items
1020       */
1021  	public function set_item_class($class = 'SimplePie_Item')
1022      {
1023          return $this->registry->register('Item', $class, true);
1024      }
1025  
1026      /**
1027       * Set which class SimplePie uses for handling author data
1028       */
1029  	public function set_author_class($class = 'SimplePie_Author')
1030      {
1031          return $this->registry->register('Author', $class, true);
1032      }
1033  
1034      /**
1035       * Set which class SimplePie uses for handling category data
1036       */
1037  	public function set_category_class($class = 'SimplePie_Category')
1038      {
1039          return $this->registry->register('Category', $class, true);
1040      }
1041  
1042      /**
1043       * Set which class SimplePie uses for feed enclosures
1044       */
1045  	public function set_enclosure_class($class = 'SimplePie_Enclosure')
1046      {
1047          return $this->registry->register('Enclosure', $class, true);
1048      }
1049  
1050      /**
1051       * Set which class SimplePie uses for `<media:text>` captions
1052       */
1053  	public function set_caption_class($class = 'SimplePie_Caption')
1054      {
1055          return $this->registry->register('Caption', $class, true);
1056      }
1057  
1058      /**
1059       * Set which class SimplePie uses for `<media:copyright>`
1060       */
1061  	public function set_copyright_class($class = 'SimplePie_Copyright')
1062      {
1063          return $this->registry->register('Copyright', $class, true);
1064      }
1065  
1066      /**
1067       * Set which class SimplePie uses for `<media:credit>`
1068       */
1069  	public function set_credit_class($class = 'SimplePie_Credit')
1070      {
1071          return $this->registry->register('Credit', $class, true);
1072      }
1073  
1074      /**
1075       * Set which class SimplePie uses for `<media:rating>`
1076       */
1077  	public function set_rating_class($class = 'SimplePie_Rating')
1078      {
1079          return $this->registry->register('Rating', $class, true);
1080      }
1081  
1082      /**
1083       * Set which class SimplePie uses for `<media:restriction>`
1084       */
1085  	public function set_restriction_class($class = 'SimplePie_Restriction')
1086      {
1087          return $this->registry->register('Restriction', $class, true);
1088      }
1089  
1090      /**
1091       * Set which class SimplePie uses for content-type sniffing
1092       */
1093  	public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1094      {
1095          return $this->registry->register('Content_Type_Sniffer', $class, true);
1096      }
1097  
1098      /**
1099       * Set which class SimplePie uses item sources
1100       */
1101  	public function set_source_class($class = 'SimplePie_Source')
1102      {
1103          return $this->registry->register('Source', $class, true);
1104      }
1105      /**#@-*/
1106  
1107      /**
1108       * Set the user agent string
1109       *
1110       * @param string $ua New user agent string.
1111       */
1112  	public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1113      {
1114          $this->useragent = (string) $ua;
1115      }
1116  
1117      /**
1118       * Set callback function to create cache filename with
1119       *
1120       * @param mixed $function Callback function
1121       */
1122  	public function set_cache_name_function($function = 'md5')
1123      {
1124          if (is_callable($function))
1125          {
1126              $this->cache_name_function = $function;
1127          }
1128      }
1129  
1130      /**
1131       * Set options to make SP as fast as possible
1132       *
1133       * Forgoes a substantial amount of data sanitization in favor of speed. This
1134       * turns SimplePie into a dumb parser of feeds.
1135       *
1136       * @param bool $set Whether to set them or not
1137       */
1138  	public function set_stupidly_fast($set = false)
1139      {
1140          if ($set)
1141          {
1142              $this->enable_order_by_date(false);
1143              $this->remove_div(false);
1144              $this->strip_comments(false);
1145              $this->strip_htmltags(false);
1146              $this->strip_attributes(false);
1147              $this->add_attributes(false);
1148              $this->set_image_handler(false);
1149          }
1150      }
1151  
1152      /**
1153       * Set maximum number of feeds to check with autodiscovery
1154       *
1155       * @param int $max Maximum number of feeds to check
1156       */
1157  	public function set_max_checked_feeds($max = 10)
1158      {
1159          $this->max_checked_feeds = (int) $max;
1160      }
1161  
1162  	public function remove_div($enable = true)
1163      {
1164          $this->sanitize->remove_div($enable);
1165      }
1166  
1167  	public function strip_htmltags($tags = '', $encode = null)
1168      {
1169          if ($tags === '')
1170          {
1171              $tags = $this->strip_htmltags;
1172          }
1173          $this->sanitize->strip_htmltags($tags);
1174          if ($encode !== null)
1175          {
1176              $this->sanitize->encode_instead_of_strip($tags);
1177          }
1178      }
1179  
1180  	public function encode_instead_of_strip($enable = true)
1181      {
1182          $this->sanitize->encode_instead_of_strip($enable);
1183      }
1184  
1185  	public function strip_attributes($attribs = '')
1186      {
1187          if ($attribs === '')
1188          {
1189              $attribs = $this->strip_attributes;
1190          }
1191          $this->sanitize->strip_attributes($attribs);
1192      }
1193  
1194  	public function add_attributes($attribs = '')
1195      {
1196          if ($attribs === '')
1197          {
1198              $attribs = $this->add_attributes;
1199          }
1200          $this->sanitize->add_attributes($attribs);
1201      }
1202  
1203      /**
1204       * Set the output encoding
1205       *
1206       * Allows you to override SimplePie's output to match that of your webpage.
1207       * This is useful for times when your webpages are not being served as
1208       * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
1209       * is similar to {@see set_input_encoding()}.
1210       *
1211       * It should be noted, however, that not all character encodings can support
1212       * all characters. If your page is being served as ISO-8859-1 and you try
1213       * to display a Japanese feed, you'll likely see garbled characters.
1214       * Because of this, it is highly recommended to ensure that your webpages
1215       * are served as UTF-8.
1216       *
1217       * The number of supported character encodings depends on whether your web
1218       * host supports {@link http://php.net/mbstring mbstring},
1219       * {@link http://php.net/iconv iconv}, or both. See
1220       * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
1221       * more information.
1222       *
1223       * @param string $encoding
1224       */
1225  	public function set_output_encoding($encoding = 'UTF-8')
1226      {
1227          $this->sanitize->set_output_encoding($encoding);
1228      }
1229  
1230  	public function strip_comments($strip = false)
1231      {
1232          $this->sanitize->strip_comments($strip);
1233      }
1234  
1235      /**
1236       * Set element/attribute key/value pairs of HTML attributes
1237       * containing URLs that need to be resolved relative to the feed
1238       *
1239       * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1240       * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1241       * |q|@cite
1242       *
1243       * @since 1.0
1244       * @param array|null $element_attribute Element/attribute key/value pairs, null for default
1245       */
1246  	public function set_url_replacements($element_attribute = null)
1247      {
1248          $this->sanitize->set_url_replacements($element_attribute);
1249      }
1250  
1251      /**
1252       * Set the handler to enable the display of cached images.
1253       *
1254       * @param string $page Web-accessible path to the handler_image.php file.
1255       * @param string $qs The query string that the value should be passed to.
1256       */
1257  	public function set_image_handler($page = false, $qs = 'i')
1258      {
1259          if ($page !== false)
1260          {
1261              $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1262          }
1263          else
1264          {
1265              $this->image_handler = '';
1266          }
1267      }
1268  
1269      /**
1270       * Set the limit for items returned per-feed with multifeeds
1271       *
1272       * @param integer $limit The maximum number of items to return.
1273       */
1274  	public function set_item_limit($limit = 0)
1275      {
1276          $this->item_limit = (int) $limit;
1277      }
1278  
1279      /**
1280       * Enable throwing exceptions
1281       *
1282       * @param boolean $enable Should we throw exceptions, or use the old-style error property?
1283       */
1284  	public function enable_exceptions($enable = true)
1285      {
1286          $this->enable_exceptions = $enable;
1287      }
1288  
1289      /**
1290       * Initialize the feed object
1291       *
1292       * This is what makes everything happen. Period. This is where all of the
1293       * configuration options get processed, feeds are fetched, cached, and
1294       * parsed, and all of that other good stuff.
1295       *
1296       * @return boolean True if successful, false otherwise
1297       */
1298  	public function init()
1299      {
1300          // Check absolute bare minimum requirements.
1301          if (!extension_loaded('xml') || !extension_loaded('pcre'))
1302          {
1303              $this->error = 'XML or PCRE extensions not loaded!';
1304              return false;
1305          }
1306          // Then check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader.
1307          elseif (!extension_loaded('xmlreader'))
1308          {
1309              static $xml_is_sane = null;
1310              if ($xml_is_sane === null)
1311              {
1312                  $parser_check = xml_parser_create();
1313                  xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1314                  xml_parser_free($parser_check);
1315                  $xml_is_sane = isset($values[0]['value']);
1316              }
1317              if (!$xml_is_sane)
1318              {
1319                  return false;
1320              }
1321          }
1322  
1323          // The default sanitize class gets set in the constructor, check if it has
1324          // changed.
1325          if ($this->registry->get_class('Sanitize') !== 'SimplePie_Sanitize') {
1326              $this->sanitize = $this->registry->create('Sanitize');
1327          }
1328          if (method_exists($this->sanitize, 'set_registry'))
1329          {
1330              $this->sanitize->set_registry($this->registry);
1331          }
1332  
1333          // Pass whatever was set with config options over to the sanitizer.
1334          // Pass the classes in for legacy support; new classes should use the registry instead
1335          $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
1336          $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen, $this->curl_options);
1337  
1338          if (!empty($this->multifeed_url))
1339          {
1340              $i = 0;
1341              $success = 0;
1342              $this->multifeed_objects = array();
1343              $this->error = array();
1344              foreach ($this->multifeed_url as $url)
1345              {
1346                  $this->multifeed_objects[$i] = clone $this;
1347                  $this->multifeed_objects[$i]->set_feed_url($url);
1348                  $single_success = $this->multifeed_objects[$i]->init();
1349                  $success |= $single_success;
1350                  if (!$single_success)
1351                  {
1352                      $this->error[$i] = $this->multifeed_objects[$i]->error();
1353                  }
1354                  $i++;
1355              }
1356              return (bool) $success;
1357          }
1358          elseif ($this->feed_url === null && $this->raw_data === null)
1359          {
1360              return false;
1361          }
1362  
1363          $this->error = null;
1364          $this->data = array();
1365          $this->check_modified = false;
1366          $this->multifeed_objects = array();
1367          $cache = false;
1368  
1369          if ($this->feed_url !== null)
1370          {
1371              $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
1372  
1373              // Decide whether to enable caching
1374              if ($this->cache && $parsed_feed_url['scheme'] !== '')
1375              {
1376                  $url = $this->feed_url . ($this->force_feed ? '#force_feed' : '');
1377                  $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $url), 'spc'));
1378              }
1379  
1380              // Fetch the data via SimplePie_File into $this->raw_data
1381              if (($fetched = $this->fetch_data($cache)) === true)
1382              {
1383                  return true;
1384              }
1385              elseif ($fetched === false) {
1386                  return false;
1387              }
1388  
1389              list($headers, $sniffed) = $fetched;
1390          }
1391  
1392          // Empty response check
1393          if(empty($this->raw_data)){
1394              $this->error = "A feed could not be found at `$this->feed_url`. Empty body.";
1395              $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1396              return false;
1397          }
1398  
1399          // Set up array of possible encodings
1400          $encodings = array();
1401  
1402          // First check to see if input has been overridden.
1403          if ($this->input_encoding !== false)
1404          {
1405              $encodings[] = strtoupper($this->input_encoding);
1406          }
1407  
1408          $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1409          $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1410  
1411          // RFC 3023 (only applies to sniffed content)
1412          if (isset($sniffed))
1413          {
1414              if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1415              {
1416                  if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1417                  {
1418                      $encodings[] = strtoupper($charset[1]);
1419                  }
1420                  $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1421                  $encodings[] = 'UTF-8';
1422              }
1423              elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1424              {
1425                  if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1426                  {
1427                      $encodings[] = strtoupper($charset[1]);
1428                  }
1429                  $encodings[] = 'US-ASCII';
1430              }
1431              // Text MIME-type default
1432              elseif (substr($sniffed, 0, 5) === 'text/')
1433              {
1434                  $encodings[] = 'UTF-8';
1435              }
1436          }
1437  
1438          // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1439          $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1440          $encodings[] = 'UTF-8';
1441          $encodings[] = 'ISO-8859-1';
1442  
1443          // There's no point in trying an encoding twice
1444          $encodings = array_unique($encodings);
1445  
1446          // Loop through each possible encoding, till we return something, or run out of possibilities
1447          foreach ($encodings as $encoding)
1448          {
1449              // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1450              if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
1451              {
1452                  // Create new parser
1453                  $parser = $this->registry->create('Parser');
1454  
1455                  // If it's parsed fine
1456                  if ($parser->parse($utf8_data, 'UTF-8', $this->permanent_url))
1457                  {
1458                      $this->data = $parser->get_data();
1459                      if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
1460                      {
1461                          $this->error = "A feed could not be found at `$this->feed_url`. This does not appear to be a valid RSS or Atom feed.";
1462                          $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1463                          return false;
1464                      }
1465  
1466                      if (isset($headers))
1467                      {
1468                          $this->data['headers'] = $headers;
1469                      }
1470                      $this->data['build'] = SIMPLEPIE_BUILD;
1471  
1472                      // Cache the file if caching is enabled
1473                      if ($cache && !$cache->save($this))
1474                      {
1475                          trigger_error("$this->cache_location is not writable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1476                      }
1477                      return true;
1478                  }
1479              }
1480          }
1481  
1482          if (isset($parser))
1483          {
1484              // We have an error, just set SimplePie_Misc::error to it and quit
1485              $this->error = $this->feed_url;
1486              $this->error .= sprintf(' is invalid XML, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
1487          }
1488          else
1489          {
1490              $this->error = 'The data could not be converted to UTF-8.';
1491              if (!extension_loaded('mbstring') && !extension_loaded('iconv') && !class_exists('\UConverter')) {
1492                  $this->error .= ' You MUST have either the iconv, mbstring or intl (PHP 5.5+) extension installed and enabled.';
1493              } else {
1494                  $missingExtensions = array();
1495                  if (!extension_loaded('iconv')) {
1496                      $missingExtensions[] = 'iconv';
1497                  }
1498                  if (!extension_loaded('mbstring')) {
1499                      $missingExtensions[] = 'mbstring';
1500                  }
1501                  if (!class_exists('\UConverter')) {
1502                      $missingExtensions[] = 'intl (PHP 5.5+)';
1503                  }
1504                  $this->error .= ' Try installing/enabling the ' . implode(' or ', $missingExtensions) . ' extension.';
1505              }
1506          }
1507  
1508          $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1509  
1510          return false;
1511      }
1512  
1513      /**
1514       * Fetch the data via SimplePie_File
1515       *
1516       * If the data is already cached, attempt to fetch it from there instead
1517       * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
1518       * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
1519       */
1520  	protected function fetch_data(&$cache)
1521      {
1522          // If it's enabled, use the cache
1523          if ($cache)
1524          {
1525              // Load the Cache
1526              $this->data = $cache->load();
1527              if (!empty($this->data))
1528              {
1529                  // If the cache is for an outdated build of SimplePie
1530                  if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1531                  {
1532                      $cache->unlink();
1533                      $this->data = array();
1534                  }
1535                  // If we've hit a collision just rerun it with caching disabled
1536                  elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1537                  {
1538                      $cache = false;
1539                      $this->data = array();
1540                  }
1541                  // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1542                  elseif (isset($this->data['feed_url']))
1543                  {
1544                      // If the autodiscovery cache is still valid use it.
1545                      if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1546                      {
1547                          // Do not need to do feed autodiscovery yet.
1548                          if ($this->data['feed_url'] !== $this->data['url'])
1549                          {
1550                              $this->set_feed_url($this->data['feed_url']);
1551                              return $this->init();
1552                          }
1553  
1554                          $cache->unlink();
1555                          $this->data = array();
1556                      }
1557                  }
1558                  // Check if the cache has been updated
1559                  elseif ($cache->mtime() + $this->cache_duration < time())
1560                  {
1561                      // Want to know if we tried to send last-modified and/or etag headers
1562                      // when requesting this file. (Note that it's up to the file to
1563                      // support this, but we don't always send the headers either.)
1564                      $this->check_modified = true;
1565                      if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1566                      {
1567                          $headers = array(
1568                              'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1569                          );
1570                          if (isset($this->data['headers']['last-modified']))
1571                          {
1572                              $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1573                          }
1574                          if (isset($this->data['headers']['etag']))
1575                          {
1576                              $headers['if-none-match'] = $this->data['headers']['etag'];
1577                          }
1578  
1579                          $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options));
1580  
1581                          if ($file->success)
1582                          {
1583                              if ($file->status_code === 304)
1584                              {
1585                                  // Set raw_data to false here too, to signify that the cache
1586                                  // is still valid.
1587                                  $this->raw_data = false;
1588                                  $cache->touch();
1589                                  return true;
1590                              }
1591                          }
1592                          else
1593                          {
1594                              $this->check_modified = false;
1595                              if($this->force_cache_fallback)
1596                              {
1597                                  $cache->touch();
1598                                  return true;
1599                              }
1600  
1601                              unset($file);
1602                          }
1603                      }
1604                  }
1605                  // If the cache is still valid, just return true
1606                  else
1607                  {
1608                      $this->raw_data = false;
1609                      return true;
1610                  }
1611              }
1612              // If the cache is empty, delete it
1613              else
1614              {
1615                  $cache->unlink();
1616                  $this->data = array();
1617              }
1618          }
1619          // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
1620          if (!isset($file))
1621          {
1622              if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
1623              {
1624                  $file =& $this->file;
1625              }
1626              else
1627              {
1628                  $headers = array(
1629                      'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
1630                  );
1631                  $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen, $this->curl_options));
1632              }
1633          }
1634          // If the file connection has an error, set SimplePie::error to that and quit
1635          if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1636          {
1637              $this->error = $file->error;
1638              return !empty($this->data);
1639          }
1640  
1641          if (!$this->force_feed)
1642          {
1643              // Check if the supplied URL is a feed, if it isn't, look for it.
1644              $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds, $this->force_fsockopen, $this->curl_options));
1645  
1646              if (!$locate->is_feed($file))
1647              {
1648                  $copyStatusCode = $file->status_code;
1649                  $copyContentType = $file->headers['content-type'];
1650                  try
1651                  {
1652                      $microformats = false;
1653                      if (class_exists('DOMXpath') && function_exists('Mf2\parse')) {
1654                          $doc = new DOMDocument();
1655                          @$doc->loadHTML($file->body);
1656                          $xpath = new DOMXpath($doc);
1657                          // Check for both h-feed and h-entry, as both a feed with no entries
1658                          // and a list of entries without an h-feed wrapper are both valid.
1659                          $query = '//*[contains(concat(" ", @class, " "), " h-feed ") or '.
1660                              'contains(concat(" ", @class, " "), " h-entry ")]';
1661                          $result = $xpath->query($query);
1662                          $microformats = $result->length !== 0;
1663                      }
1664                      // Now also do feed discovery, but if microformats were found don't
1665                      // overwrite the current value of file.
1666                      $discovered = $locate->find($this->autodiscovery,
1667                                                  $this->all_discovered_feeds);
1668                      if ($microformats)
1669                      {
1670                          if ($hub = $locate->get_rel_link('hub'))
1671                          {
1672                              $self = $locate->get_rel_link('self');
1673                              $this->store_links($file, $hub, $self);
1674                          }
1675                          // Push the current file onto all_discovered feeds so the user can
1676                          // be shown this as one of the options.
1677                          if (isset($this->all_discovered_feeds)) {
1678                              $this->all_discovered_feeds[] = $file;
1679                          }
1680                      }
1681                      else
1682                      {
1683                          if ($discovered)
1684                          {
1685                              $file = $discovered;
1686                          }
1687                          else
1688                          {
1689                              // We need to unset this so that if SimplePie::set_file() has
1690                              // been called that object is untouched
1691                              unset($file);
1692                              $this->error = "A feed could not be found at `$this->feed_url`; the status code is `$copyStatusCode` and content-type is `$copyContentType`";
1693                              $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1694                              return false;
1695                          }
1696                      }
1697                  }
1698                  catch (SimplePie_Exception $e)
1699                  {
1700                      // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1701                      unset($file);
1702                      // This is usually because DOMDocument doesn't exist
1703                      $this->error = $e->getMessage();
1704                      $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
1705                      return false;
1706                  }
1707                  if ($cache)
1708                  {
1709                      $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1710                      if (!$cache->save($this))
1711                      {
1712                          trigger_error("$this->cache_location is not writable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
1713                      }
1714                      $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
1715                  }
1716              }
1717              $this->feed_url = $file->url;
1718              $locate = null;
1719          }
1720  
1721          $this->raw_data = $file->body;
1722          $this->permanent_url = $file->permanent_url;
1723          $headers = $file->headers;
1724          $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1725          $sniffed = $sniffer->get_type();
1726  
1727          return array($headers, $sniffed);
1728      }
1729  
1730      /**
1731       * Get the error message for the occured error
1732       *
1733       * @return string|array Error message, or array of messages for multifeeds
1734       */
1735  	public function error()
1736      {
1737          return $this->error;
1738      }
1739  
1740      /**
1741       * Get the raw XML
1742       *
1743       * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1744       * the data instead of printing it.
1745       *
1746       * @return string|boolean Raw XML data, false if the cache is used
1747       */
1748  	public function get_raw_data()
1749      {
1750          return $this->raw_data;
1751      }
1752  
1753      /**
1754       * Get the character encoding used for output
1755       *
1756       * @since Preview Release
1757       * @return string
1758       */
1759  	public function get_encoding()
1760      {
1761          return $this->sanitize->output_encoding;
1762      }
1763  
1764      /**
1765       * Send the content-type header with correct encoding
1766       *
1767       * This method ensures that the SimplePie-enabled page is being served with
1768       * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
1769       * and character encoding HTTP headers (character encoding determined by the
1770       * {@see set_output_encoding} config option).
1771       *
1772       * This won't work properly if any content or whitespace has already been
1773       * sent to the browser, because it relies on PHP's
1774       * {@link http://php.net/header header()} function, and these are the
1775       * circumstances under which the function works.
1776       *
1777       * Because it's setting these settings for the entire page (as is the nature
1778       * of HTTP headers), this should only be used once per page (again, at the
1779       * top).
1780       *
1781       * @param string $mime MIME type to serve the page as
1782       */
1783  	public function handle_content_type($mime = 'text/html')
1784      {
1785          if (!headers_sent())
1786          {
1787              $header = "Content-type: $mime;";
1788              if ($this->get_encoding())
1789              {
1790                  $header .= ' charset=' . $this->get_encoding();
1791              }
1792              else
1793              {
1794                  $header .= ' charset=UTF-8';
1795              }
1796              header($header);
1797          }
1798      }
1799  
1800      /**
1801       * Get the type of the feed
1802       *
1803       * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1804       * using {@link http://php.net/language.operators.bitwise bitwise operators}
1805       *
1806       * @since 0.8 (usage changed to using constants in 1.0)
1807       * @see SIMPLEPIE_TYPE_NONE Unknown.
1808       * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
1809       * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
1810       * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
1811       * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
1812       * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
1813       * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
1814       * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
1815       * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
1816       * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
1817       * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
1818       * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
1819       * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
1820       * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
1821       * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
1822       * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
1823       * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
1824       * @return int SIMPLEPIE_TYPE_* constant
1825       */
1826  	public function get_type()
1827      {
1828          if (!isset($this->data['type']))
1829          {
1830              $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1831              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1832              {
1833                  $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1834              }
1835              elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1836              {
1837                  $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1838              }
1839              elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1840              {
1841                  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1842                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1843                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1844                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1845                  {
1846                      $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1847                  }
1848                  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1849                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1850                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1851                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1852                  {
1853                      $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1854                  }
1855              }
1856              elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1857              {
1858                  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1859                  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1860                  {
1861                      switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1862                      {
1863                          case '0.91':
1864                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1865                              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1866                              {
1867                                  switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1868                                  {
1869                                      case '0':
1870                                          $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1871                                          break;
1872  
1873                                      case '24':
1874                                          $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1875                                          break;
1876                                  }
1877                              }
1878                              break;
1879  
1880                          case '0.92':
1881                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1882                              break;
1883  
1884                          case '0.93':
1885                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1886                              break;
1887  
1888                          case '0.94':
1889                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1890                              break;
1891  
1892                          case '2.0':
1893                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1894                              break;
1895                      }
1896                  }
1897              }
1898              else
1899              {
1900                  $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1901              }
1902          }
1903          return $this->data['type'];
1904      }
1905  
1906      /**
1907       * Get the URL for the feed
1908       *
1909       * When the 'permanent' mode is enabled, returns the original feed URL,
1910       * except in the case of an `HTTP 301 Moved Permanently` status response,
1911       * in which case the location of the first redirection is returned.
1912       *
1913       * When the 'permanent' mode is disabled (default),
1914       * may or may not be different from the URL passed to {@see set_feed_url()},
1915       * depending on whether auto-discovery was used, and whether there were
1916       * any redirects along the way.
1917       *
1918       * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
1919       * @todo Support <itunes:new-feed-url>
1920       * @todo Also, |atom:link|@rel=self
1921       * @param bool $permanent Permanent mode to return only the original URL or the first redirection
1922       * iff it is a 301 redirection
1923       * @return string|null
1924       */
1925  	public function subscribe_url($permanent = false)
1926      {
1927          if ($permanent)
1928          {
1929              if ($this->permanent_url !== null)
1930              {
1931                  // sanitize encodes ampersands which are required when used in a url.
1932                  return str_replace('&amp;', '&',
1933                                     $this->sanitize($this->permanent_url,
1934                                                     SIMPLEPIE_CONSTRUCT_IRI));
1935              }
1936          }
1937          else
1938          {
1939              if ($this->feed_url !== null)
1940              {
1941                  return str_replace('&amp;', '&',
1942                                     $this->sanitize($this->feed_url,
1943                                                     SIMPLEPIE_CONSTRUCT_IRI));
1944              }
1945          }
1946          return null;
1947      }
1948  
1949      /**
1950       * Get data for an feed-level element
1951       *
1952       * This method allows you to get access to ANY element/attribute that is a
1953       * sub-element of the opening feed tag.
1954       *
1955       * The return value is an indexed array of elements matching the given
1956       * namespace and tag name. Each element has `attribs`, `data` and `child`
1957       * subkeys. For `attribs` and `child`, these contain namespace subkeys.
1958       * `attribs` then has one level of associative name => value data (where
1959       * `value` is a string) after the namespace. `child` has tag-indexed keys
1960       * after the namespace, each member of which is an indexed array matching
1961       * this same format.
1962       *
1963       * For example:
1964       * <pre>
1965       * // This is probably a bad example because we already support
1966       * // <media:content> natively, but it shows you how to parse through
1967       * // the nodes.
1968       * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
1969       * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
1970       * $file = $content[0]['attribs']['']['url'];
1971       * echo $file;
1972       * </pre>
1973       *
1974       * @since 1.0
1975       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1976       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1977       * @param string $tag Tag name
1978       * @return array
1979       */
1980  	public function get_feed_tags($namespace, $tag)
1981      {
1982          $type = $this->get_type();
1983          if ($type & SIMPLEPIE_TYPE_ATOM_10)
1984          {
1985              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1986              {
1987                  return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1988              }
1989          }
1990          if ($type & SIMPLEPIE_TYPE_ATOM_03)
1991          {
1992              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1993              {
1994                  return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1995              }
1996          }
1997          if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1998          {
1999              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
2000              {
2001                  return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
2002              }
2003          }
2004          if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2005          {
2006              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
2007              {
2008                  return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
2009              }
2010          }
2011          return null;
2012      }
2013  
2014      /**
2015       * Get data for an channel-level element
2016       *
2017       * This method allows you to get access to ANY element/attribute in the
2018       * channel/header section of the feed.
2019       *
2020       * See {@see SimplePie::get_feed_tags()} for a description of the return value
2021       *
2022       * @since 1.0
2023       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
2024       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
2025       * @param string $tag Tag name
2026       * @return array
2027       */
2028  	public function get_channel_tags($namespace, $tag)
2029      {
2030          $type = $this->get_type();
2031          if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
2032          {
2033              if ($return = $this->get_feed_tags($namespace, $tag))
2034              {
2035                  return $return;
2036              }
2037          }
2038          if ($type & SIMPLEPIE_TYPE_RSS_10)
2039          {
2040              if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
2041              {
2042                  if (isset($channel[0]['child'][$namespace][$tag]))
2043                  {
2044                      return $channel[0]['child'][$namespace][$tag];
2045                  }
2046              }
2047          }
2048          if ($type & SIMPLEPIE_TYPE_RSS_090)
2049          {
2050              if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
2051              {
2052                  if (isset($channel[0]['child'][$namespace][$tag]))
2053                  {
2054                      return $channel[0]['child'][$namespace][$tag];
2055                  }
2056              }
2057          }
2058          if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2059          {
2060              if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
2061              {
2062                  if (isset($channel[0]['child'][$namespace][$tag]))
2063                  {
2064                      return $channel[0]['child'][$namespace][$tag];
2065                  }
2066              }
2067          }
2068          return null;
2069      }
2070  
2071      /**
2072       * Get data for an channel-level element
2073       *
2074       * This method allows you to get access to ANY element/attribute in the
2075       * image/logo section of the feed.
2076       *
2077       * See {@see SimplePie::get_feed_tags()} for a description of the return value
2078       *
2079       * @since 1.0
2080       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
2081       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
2082       * @param string $tag Tag name
2083       * @return array
2084       */
2085  	public function get_image_tags($namespace, $tag)
2086      {
2087          $type = $this->get_type();
2088          if ($type & SIMPLEPIE_TYPE_RSS_10)
2089          {
2090              if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
2091              {
2092                  if (isset($image[0]['child'][$namespace][$tag]))
2093                  {
2094                      return $image[0]['child'][$namespace][$tag];
2095                  }
2096              }
2097          }
2098          if ($type & SIMPLEPIE_TYPE_RSS_090)
2099          {
2100              if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
2101              {
2102                  if (isset($image[0]['child'][$namespace][$tag]))
2103                  {
2104                      return $image[0]['child'][$namespace][$tag];
2105                  }
2106              }
2107          }
2108          if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
2109          {
2110              if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
2111              {
2112                  if (isset($image[0]['child'][$namespace][$tag]))
2113                  {
2114                      return $image[0]['child'][$namespace][$tag];
2115                  }
2116              }
2117          }
2118          return null;
2119      }
2120  
2121      /**
2122       * Get the base URL value from the feed
2123       *
2124       * Uses `<xml:base>` if available, otherwise uses the first link in the
2125       * feed, or failing that, the URL of the feed itself.
2126       *
2127       * @see get_link
2128       * @see subscribe_url
2129       *
2130       * @param array $element
2131       * @return string
2132       */
2133  	public function get_base($element = array())
2134      {
2135          if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
2136          {
2137              return $element['xml_base'];
2138          }
2139          elseif ($this->get_link() !== null)
2140          {
2141              return $this->get_link();
2142          }
2143  
2144          return $this->subscribe_url();
2145      }
2146  
2147      /**
2148       * Sanitize feed data
2149       *
2150       * @access private
2151       * @see SimplePie_Sanitize::sanitize()
2152       * @param string $data Data to sanitize
2153       * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
2154       * @param string $base Base URL to resolve URLs against
2155       * @return string Sanitized data
2156       */
2157  	public function sanitize($data, $type, $base = '')
2158      {
2159          try
2160          {
2161              return $this->sanitize->sanitize($data, $type, $base);
2162          }
2163          catch (SimplePie_Exception $e)
2164          {
2165              if (!$this->enable_exceptions)
2166              {
2167                  $this->error = $e->getMessage();
2168                  $this->registry->call('Misc', 'error', array($this->error, E_USER_WARNING, $e->getFile(), $e->getLine()));
2169                  return '';
2170              }
2171  
2172              throw $e;
2173          }
2174      }
2175  
2176      /**
2177       * Get the title of the feed
2178       *
2179       * Uses `<atom:title>`, `<title>` or `<dc:title>`
2180       *
2181       * @since 1.0 (previously called `get_feed_title` since 0.8)
2182       * @return string|null
2183       */
2184  	public function get_title()
2185      {
2186          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
2187          {
2188              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2189          }
2190          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
2191          {
2192              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2193          }
2194          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2195          {
2196              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2197          }
2198          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2199          {
2200              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2201          }
2202          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2203          {
2204              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2205          }
2206          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2207          {
2208              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2209          }
2210          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2211          {
2212              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2213          }
2214  
2215          return null;
2216      }
2217  
2218      /**
2219       * Get a category for the feed
2220       *
2221       * @since Unknown
2222       * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
2223       * @return SimplePie_Category|null
2224       */
2225  	public function get_category($key = 0)
2226      {
2227          $categories = $this->get_categories();
2228          if (isset($categories[$key]))
2229          {
2230              return $categories[$key];
2231          }
2232  
2233          return null;
2234      }
2235  
2236      /**
2237       * Get all categories for the feed
2238       *
2239       * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2240       *
2241       * @since Unknown
2242       * @return array|null List of {@see SimplePie_Category} objects
2243       */
2244  	public function get_categories()
2245      {
2246          $categories = array();
2247  
2248          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2249          {
2250              $term = null;
2251              $scheme = null;
2252              $label = null;
2253              if (isset($category['attribs']['']['term']))
2254              {
2255                  $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2256              }
2257              if (isset($category['attribs']['']['scheme']))
2258              {
2259                  $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2260              }
2261              if (isset($category['attribs']['']['label']))
2262              {
2263                  $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2264              }
2265              $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2266          }
2267          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2268          {
2269              // This is really the label, but keep this as the term also for BC.
2270              // Label will also work on retrieving because that falls back to term.
2271              $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2272              if (isset($category['attribs']['']['domain']))
2273              {
2274                  $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2275              }
2276              else
2277              {
2278                  $scheme = null;
2279              }
2280              $categories[] = $this->registry->create('Category', array($term, $scheme, null));
2281          }
2282          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2283          {
2284              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2285          }
2286          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2287          {
2288              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2289          }
2290  
2291          if (!empty($categories))
2292          {
2293              return array_unique($categories);
2294          }
2295  
2296          return null;
2297      }
2298  
2299      /**
2300       * Get an author for the feed
2301       *
2302       * @since 1.1
2303       * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
2304       * @return SimplePie_Author|null
2305       */
2306  	public function get_author($key = 0)
2307      {
2308          $authors = $this->get_authors();
2309          if (isset($authors[$key]))
2310          {
2311              return $authors[$key];
2312          }
2313  
2314          return null;
2315      }
2316  
2317      /**
2318       * Get all authors for the feed
2319       *
2320       * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2321       *
2322       * @since 1.1
2323       * @return array|null List of {@see SimplePie_Author} objects
2324       */
2325  	public function get_authors()
2326      {
2327          $authors = array();
2328          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2329          {
2330              $name = null;
2331              $uri = null;
2332              $email = null;
2333              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2334              {
2335                  $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2336              }
2337              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2338              {
2339                  $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
2340              }
2341              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2342              {
2343                  $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2344              }
2345              if ($name !== null || $email !== null || $uri !== null)
2346              {
2347                  $authors[] = $this->registry->create('Author', array($name, $uri, $email));
2348              }
2349          }
2350          if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2351          {
2352              $name = null;
2353              $url = null;
2354              $email = null;
2355              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2356              {
2357                  $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2358              }
2359              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2360              {
2361                  $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
2362              }
2363              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2364              {
2365                  $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2366              }
2367              if ($name !== null || $email !== null || $url !== null)
2368              {
2369                  $authors[] = $this->registry->create('Author', array($name, $url, $email));
2370              }
2371          }
2372          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2373          {
2374              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2375          }
2376          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2377          {
2378              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2379          }
2380          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2381          {
2382              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2383          }
2384  
2385          if (!empty($authors))
2386          {
2387              return array_unique($authors);
2388          }
2389  
2390          return null;
2391      }
2392  
2393      /**
2394       * Get a contributor for the feed
2395       *
2396       * @since 1.1
2397       * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
2398       * @return SimplePie_Author|null
2399       */
2400  	public function get_contributor($key = 0)
2401      {
2402          $contributors = $this->get_contributors();
2403          if (isset($contributors[$key]))
2404          {
2405              return $contributors[$key];
2406          }
2407  
2408          return null;
2409      }
2410  
2411      /**
2412       * Get all contributors for the feed
2413       *
2414       * Uses `<atom:contributor>`
2415       *
2416       * @since 1.1
2417       * @return array|null List of {@see SimplePie_Author} objects
2418       */
2419  	public function get_contributors()
2420      {
2421          $contributors = array();
2422          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2423          {
2424              $name = null;
2425              $uri = null;
2426              $email = null;
2427              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2428              {
2429                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2430              }
2431              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2432              {
2433                  $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
2434              }
2435              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2436              {
2437                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2438              }
2439              if ($name !== null || $email !== null || $uri !== null)
2440              {
2441                  $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
2442              }
2443          }
2444          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2445          {
2446              $name = null;
2447              $url = null;
2448              $email = null;
2449              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2450              {
2451                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2452              }
2453              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2454              {
2455                  $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
2456              }
2457              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2458              {
2459                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2460              }
2461              if ($name !== null || $email !== null || $url !== null)
2462              {
2463                  $contributors[] = $this->registry->create('Author', array($name, $url, $email));
2464              }
2465          }
2466  
2467          if (!empty($contributors))
2468          {
2469              return array_unique($contributors);
2470          }
2471  
2472          return null;
2473      }
2474  
2475      /**
2476       * Get a single link for the feed
2477       *
2478       * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2479       * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
2480       * @param string $rel The relationship of the link to return
2481       * @return string|null Link URL
2482       */
2483  	public function get_link($key = 0, $rel = 'alternate')
2484      {
2485          $links = $this->get_links($rel);
2486          if (isset($links[$key]))
2487          {
2488              return $links[$key];
2489          }
2490  
2491          return null;
2492      }
2493  
2494      /**
2495       * Get the permalink for the item
2496       *
2497       * Returns the first link available with a relationship of "alternate".
2498       * Identical to {@see get_link()} with key 0
2499       *
2500       * @see get_link
2501       * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2502       * @internal Added for parity between the parent-level and the item/entry-level.
2503       * @return string|null Link URL
2504       */
2505  	public function get_permalink()
2506      {
2507          return $this->get_link(0);
2508      }
2509  
2510      /**
2511       * Get all links for the feed
2512       *
2513       * Uses `<atom:link>` or `<link>`
2514       *
2515       * @since Beta 2
2516       * @param string $rel The relationship of links to return
2517       * @return array|null Links found for the feed (strings)
2518       */
2519  	public function get_links($rel = 'alternate')
2520      {
2521          if (!isset($this->data['links']))
2522          {
2523              $this->data['links'] = array();
2524              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2525              {
2526                  foreach ($links as $link)
2527                  {
2528                      if (isset($link['attribs']['']['href']))
2529                      {
2530                          $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2531                          $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2532                      }
2533                  }
2534              }
2535              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2536              {
2537                  foreach ($links as $link)
2538                  {
2539                      if (isset($link['attribs']['']['href']))
2540                      {
2541                          $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2542                          $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2543  
2544                      }
2545                  }
2546              }
2547              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2548              {
2549                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2550              }
2551              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2552              {
2553                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2554              }
2555              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2556              {
2557                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2558              }
2559  
2560              $keys = array_keys($this->data['links']);
2561              foreach ($keys as $key)
2562              {
2563                  if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
2564                  {
2565                      if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2566                      {
2567                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2568                          $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2569                      }
2570                      else
2571                      {
2572                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2573                      }
2574                  }
2575                  elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2576                  {
2577                      $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2578                  }
2579                  $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2580              }
2581          }
2582  
2583          if (isset($this->data['headers']['link']) &&
2584              preg_match('/<([^>]+)>; rel='.preg_quote($rel).'/',
2585                         $this->data['headers']['link'], $match))
2586          {
2587              return array($match[1]);
2588          }
2589          else if (isset($this->data['links'][$rel]))
2590          {
2591              return $this->data['links'][$rel];
2592          }
2593  
2594          return null;
2595      }
2596  
2597  	public function get_all_discovered_feeds()
2598      {
2599          return $this->all_discovered_feeds;
2600      }
2601  
2602      /**
2603       * Get the content for the item
2604       *
2605       * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2606       * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2607       *
2608       * @since 1.0 (previously called `get_feed_description()` since 0.8)
2609       * @return string|null
2610       */
2611  	public function get_description()
2612      {
2613          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2614          {
2615              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2616          }
2617          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2618          {
2619              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2620          }
2621          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2622          {
2623              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2624          }
2625          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2626          {
2627              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2628          }
2629          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2630          {
2631              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2632          }
2633          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2634          {
2635              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2636          }
2637          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2638          {
2639              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2640          }
2641          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2642          {
2643              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2644          }
2645          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2646          {
2647              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2648          }
2649  
2650          return null;
2651      }
2652  
2653      /**
2654       * Get the copyright info for the feed
2655       *
2656       * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2657       *
2658       * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2659       * @return string|null
2660       */
2661  	public function get_copyright()
2662      {
2663          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2664          {
2665              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2666          }
2667          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2668          {
2669              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2670          }
2671          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2672          {
2673              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2674          }
2675          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2676          {
2677              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2678          }
2679          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2680          {
2681              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2682          }
2683  
2684          return null;
2685      }
2686  
2687      /**
2688       * Get the language for the feed
2689       *
2690       * Uses `<language>`, `<dc:language>`, or @xml_lang
2691       *
2692       * @since 1.0 (previously called `get_feed_language()` since 0.8)
2693       * @return string|null
2694       */
2695  	public function get_language()
2696      {
2697          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2698          {
2699              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2700          }
2701          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2702          {
2703              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2704          }
2705          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2706          {
2707              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2708          }
2709          elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2710          {
2711              return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2712          }
2713          elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2714          {
2715              return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2716          }
2717          elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2718          {
2719              return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2720          }
2721          elseif (isset($this->data['headers']['content-language']))
2722          {
2723              return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2724          }
2725  
2726          return null;
2727      }
2728  
2729      /**
2730       * Get the latitude coordinates for the item
2731       *
2732       * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2733       *
2734       * Uses `<geo:lat>` or `<georss:point>`
2735       *
2736       * @since 1.0
2737       * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2738       * @link http://www.georss.org/ GeoRSS
2739       * @return string|null
2740       */
2741  	public function get_latitude()
2742      {
2743  
2744          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2745          {
2746              return (float) $return[0]['data'];
2747          }
2748          elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2749          {
2750              return (float) $match[1];
2751          }
2752  
2753          return null;
2754      }
2755  
2756      /**
2757       * Get the longitude coordinates for the feed
2758       *
2759       * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2760       *
2761       * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2762       *
2763       * @since 1.0
2764       * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2765       * @link http://www.georss.org/ GeoRSS
2766       * @return string|null
2767       */
2768  	public function get_longitude()
2769      {
2770          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2771          {
2772              return (float) $return[0]['data'];
2773          }
2774          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2775          {
2776              return (float) $return[0]['data'];
2777          }
2778          elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
2779          {
2780              return (float) $match[2];
2781          }
2782  
2783          return null;
2784      }
2785  
2786      /**
2787       * Get the feed logo's title
2788       *
2789       * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2790       *
2791       * Uses `<image><title>` or `<image><dc:title>`
2792       *
2793       * @return string|null
2794       */
2795  	public function get_image_title()
2796      {
2797          if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2798          {
2799              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2800          }
2801          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2802          {
2803              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2804          }
2805          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2806          {
2807              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2808          }
2809          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2810          {
2811              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2812          }
2813          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2814          {
2815              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2816          }
2817  
2818          return null;
2819      }
2820  
2821      /**
2822       * Get the feed logo's URL
2823       *
2824       * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
2825       * have a "feed logo" URL. This points directly to the image itself.
2826       *
2827       * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2828       * `<image><title>` or `<image><dc:title>`
2829       *
2830       * @return string|null
2831       */
2832  	public function get_image_url()
2833      {
2834          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2835          {
2836              return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2837          }
2838          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2839          {
2840              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2841          }
2842          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2843          {
2844              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2845          }
2846          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2847          {
2848              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2849          }
2850          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2851          {
2852              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2853          }
2854          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2855          {
2856              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2857          }
2858  
2859          return null;
2860      }
2861  
2862  
2863      /**
2864       * Get the feed logo's link
2865       *
2866       * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
2867       * points to a human-readable page that the image should link to.
2868       *
2869       * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2870       * `<image><title>` or `<image><dc:title>`
2871       *
2872       * @return string|null
2873       */
2874  	public function get_image_link()
2875      {
2876          if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2877          {
2878              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2879          }
2880          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2881          {
2882              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2883          }
2884          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2885          {
2886              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2887          }
2888  
2889          return null;
2890      }
2891  
2892      /**
2893       * Get the feed logo's link
2894       *
2895       * RSS 2.0 feeds are allowed to have a "feed logo" width.
2896       *
2897       * Uses `<image><width>` or defaults to 88.0 if no width is specified and
2898       * the feed is an RSS 2.0 feed.
2899       *
2900       * @return int|float|null
2901       */
2902  	public function get_image_width()
2903      {
2904          if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
2905          {
2906              return round($return[0]['data']);
2907          }
2908          elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2909          {
2910              return 88.0;
2911          }
2912  
2913          return null;
2914      }
2915  
2916      /**
2917       * Get the feed logo's height
2918       *
2919       * RSS 2.0 feeds are allowed to have a "feed logo" height.
2920       *
2921       * Uses `<image><height>` or defaults to 31.0 if no height is specified and
2922       * the feed is an RSS 2.0 feed.
2923       *
2924       * @return int|float|null
2925       */
2926  	public function get_image_height()
2927      {
2928          if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
2929          {
2930              return round($return[0]['data']);
2931          }
2932          elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2933          {
2934              return 31.0;
2935          }
2936  
2937          return null;
2938      }
2939  
2940      /**
2941       * Get the number of items in the feed
2942       *
2943       * This is well-suited for {@link http://php.net/for for()} loops with
2944       * {@see get_item()}
2945       *
2946       * @param int $max Maximum value to return. 0 for no limit
2947       * @return int Number of items in the feed
2948       */
2949  	public function get_item_quantity($max = 0)
2950      {
2951          $max = (int) $max;
2952          $qty = count($this->get_items());
2953          if ($max === 0)
2954          {
2955              return $qty;
2956          }
2957  
2958          return ($qty > $max) ? $max : $qty;
2959      }
2960  
2961      /**
2962       * Get a single item from the feed
2963       *
2964       * This is better suited for {@link http://php.net/for for()} loops, whereas
2965       * {@see get_items()} is better suited for
2966       * {@link http://php.net/foreach foreach()} loops.
2967       *
2968       * @see get_item_quantity()
2969       * @since Beta 2
2970       * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
2971       * @return SimplePie_Item|null
2972       */
2973  	public function get_item($key = 0)
2974      {
2975          $items = $this->get_items();
2976          if (isset($items[$key]))
2977          {
2978              return $items[$key];
2979          }
2980  
2981          return null;
2982      }
2983  
2984      /**
2985       * Get all items from the feed
2986       *
2987       * This is better suited for {@link http://php.net/for for()} loops, whereas
2988       * {@see get_items()} is better suited for
2989       * {@link http://php.net/foreach foreach()} loops.
2990       *
2991       * @see get_item_quantity
2992       * @since Beta 2
2993       * @param int $start Index to start at
2994       * @param int $end Number of items to return. 0 for all items after `$start`
2995       * @return SimplePie_Item[]|null List of {@see SimplePie_Item} objects
2996       */
2997  	public function get_items($start = 0, $end = 0)
2998      {
2999          if (!isset($this->data['items']))
3000          {
3001              if (!empty($this->multifeed_objects))
3002              {
3003                  $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
3004                  if (empty($this->data['items']))
3005                  {
3006                      return array();
3007                  }
3008                  return $this->data['items'];
3009              }
3010              $this->data['items'] = array();
3011              if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
3012              {
3013                  $keys = array_keys($items);
3014                  foreach ($keys as $key)
3015                  {
3016                      $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
3017                  }
3018              }
3019              if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
3020              {
3021                  $keys = array_keys($items);
3022                  foreach ($keys as $key)
3023                  {
3024                      $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
3025                  }
3026              }
3027              if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
3028              {
3029                  $keys = array_keys($items);
3030                  foreach ($keys as $key)
3031                  {
3032                      $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
3033                  }
3034              }
3035              if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
3036              {
3037                  $keys = array_keys($items);
3038                  foreach ($keys as $key)
3039                  {
3040                      $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
3041                  }
3042              }
3043              if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
3044              {
3045                  $keys = array_keys($items);
3046                  foreach ($keys as $key)
3047                  {
3048                      $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
3049                  }
3050              }
3051          }
3052  
3053          if (empty($this->data['items']))
3054          {
3055              return array();
3056          }
3057  
3058          if ($this->order_by_date)
3059          {
3060              if (!isset($this->data['ordered_items']))
3061              {
3062                  $this->data['ordered_items'] = $this->data['items'];
3063                  usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
3064               }
3065              $items = $this->data['ordered_items'];
3066          }
3067          else
3068          {
3069              $items = $this->data['items'];
3070          }
3071          // Slice the data as desired
3072          if ($end === 0)
3073          {
3074              return array_slice($items, $start);
3075          }
3076  
3077          return array_slice($items, $start, $end);
3078      }
3079  
3080      /**
3081       * Set the favicon handler
3082       *
3083       * @deprecated Use your own favicon handling instead
3084       */
3085  	public function set_favicon_handler($page = false, $qs = 'i')
3086      {
3087          $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
3088          trigger_error('Favicon handling has been removed, please use your own handling', $level);
3089          return false;
3090      }
3091  
3092      /**
3093       * Get the favicon for the current feed
3094       *
3095       * @deprecated Use your own favicon handling instead
3096       */
3097  	public function get_favicon()
3098      {
3099          $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
3100          trigger_error('Favicon handling has been removed, please use your own handling', $level);
3101  
3102          if (($url = $this->get_link()) !== null)
3103          {
3104              return 'https://www.google.com/s2/favicons?domain=' . urlencode($url);
3105          }
3106  
3107          return false;
3108      }
3109  
3110      /**
3111       * Magic method handler
3112       *
3113       * @param string $method Method name
3114       * @param array $args Arguments to the method
3115       * @return mixed
3116       */
3117  	public function __call($method, $args)
3118      {
3119          if (strpos($method, 'subscribe_') === 0)
3120          {
3121              $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
3122              trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
3123              return '';
3124          }
3125          if ($method === 'enable_xml_dump')
3126          {
3127              $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
3128              trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
3129              return false;
3130          }
3131  
3132          $class = get_class($this);
3133          $trace = debug_backtrace();
3134          $file = $trace[0]['file'];
3135          $line = $trace[0]['line'];
3136          trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
3137      }
3138  
3139      /**
3140       * Sorting callback for items
3141       *
3142       * @access private
3143       * @param SimplePie $a
3144       * @param SimplePie $b
3145       * @return boolean
3146       */
3147  	public static function sort_items($a, $b)
3148      {
3149          $a_date = $a->get_date('U');
3150          $b_date = $b->get_date('U');
3151          if ($a_date && $b_date) {
3152              return $a_date > $b_date ? -1 : 1;
3153          }
3154          // Sort items without dates to the top.
3155          if ($a_date) {
3156              return 1;
3157          }
3158          if ($b_date) {
3159              return -1;
3160          }
3161          return 0;
3162      }
3163  
3164      /**
3165       * Merge items from several feeds into one
3166       *
3167       * If you're merging multiple feeds together, they need to all have dates
3168       * for the items or else SimplePie will refuse to sort them.
3169       *
3170       * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
3171       * @param array $urls List of SimplePie feed objects to merge
3172       * @param int $start Starting item
3173       * @param int $end Number of items to return
3174       * @param int $limit Maximum number of items per feed
3175       * @return array
3176       */
3177  	public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
3178      {
3179          if (is_array($urls) && sizeof($urls) > 0)
3180          {
3181              $items = array();
3182              foreach ($urls as $arg)
3183              {
3184                  if ($arg instanceof SimplePie)
3185                  {
3186                      $items = array_merge($items, $arg->get_items(0, $limit));
3187                  }
3188                  else
3189                  {
3190                      trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
3191                  }
3192              }
3193  
3194              usort($items, array(get_class($urls[0]), 'sort_items'));
3195  
3196              if ($end === 0)
3197              {
3198                  return array_slice($items, $start);
3199              }
3200  
3201              return array_slice($items, $start, $end);
3202          }
3203  
3204          trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
3205          return array();
3206      }
3207  
3208      /**
3209       * Store PubSubHubbub links as headers
3210       *
3211       * There is no way to find PuSH links in the body of a microformats feed,
3212       * so they are added to the headers when found, to be used later by get_links.
3213       * @param SimplePie_File $file
3214       * @param string $hub
3215       * @param string $self
3216       */
3217  	private function store_links(&$file, $hub, $self) {
3218          if (isset($file->headers['link']['hub']) ||
3219                (isset($file->headers['link']) &&
3220                 preg_match('/rel=hub/', $file->headers['link'])))
3221          {
3222              return;
3223          }
3224  
3225          if ($hub)
3226          {
3227              if (isset($file->headers['link']))
3228              {
3229                  if ($file->headers['link'] !== '')
3230                  {
3231                      $file->headers['link'] = ', ';
3232                  }
3233              }
3234              else
3235              {
3236                  $file->headers['link'] = '';
3237              }
3238              $file->headers['link'] .= '<'.$hub.'>; rel=hub';
3239              if ($self)
3240              {
3241                  $file->headers['link'] .= ', <'.$self.'>; rel=self';
3242              }
3243          }
3244      }
3245  }