[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/ -> class-simplepie.php (source)

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


Generated: Tue Mar 19 01:00:02 2024 Cross-referenced by PHPXref 0.7.1