SimplePie PHP Cross Reference Developer Tools

Source: /library/SimplePie.php - 3058 lines - 88125 bytes - Summary - Text - Print

Description: SimplePie A PHP-Based RSS and Atom Feed Framework. Takes the hard work out of managing a complete RSS/Atom solution.

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

title

Description

title

Description

title

Description

title

title

Body