[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> SimplePie.php (source)

   1  <?php
   2  /**
   3   * SimplePie
   4   *
   5   * A PHP-Based RSS and Atom Feed Framework.
   6   * Takes the hard work out of managing a complete RSS/Atom solution.
   7   *
   8   * Please note: This file is automatically generated by a build script. The
   9   * full original source is always available from http://simplepie.org/
  10   *
  11   * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
  12   * All rights reserved.
  13   *
  14   * Redistribution and use in source and binary forms, with or without modification, are
  15   * permitted provided that the following conditions are met:
  16   *
  17   *     * Redistributions of source code must retain the above copyright notice, this list of
  18   *       conditions and the following disclaimer.
  19   *
  20   *     * Redistributions in binary form must reproduce the above copyright notice, this list
  21   *       of conditions and the following disclaimer in the documentation and/or other materials
  22   *       provided with the distribution.
  23   *
  24   *     * Neither the name of the SimplePie Team nor the names of its contributors may be used
  25   *       to endorse or promote products derived from this software without specific prior
  26   *       written permission.
  27   *
  28   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  29   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  30   * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
  31   * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  33   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  34   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  35   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36   * POSSIBILITY OF SUCH DAMAGE.
  37   *
  38   * @package SimplePie
  39   * @version 1.3.1
  40   * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
  41   * @author Ryan Parman
  42   * @author Geoffrey Sneddon
  43   * @author Ryan McCue
  44   * @link http://simplepie.org/ SimplePie
  45   * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  46   */
  47  
  48  /**
  49   * SimplePie Name
  50   */
  51  define('SIMPLEPIE_NAME', 'SimplePie');
  52  
  53  /**
  54   * SimplePie Version
  55   */
  56  define('SIMPLEPIE_VERSION', '1.3.1');
  57  
  58  /**
  59   * SimplePie Build
  60   * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
  61   */
  62  define('SIMPLEPIE_BUILD', '20121030175911');
  63  
  64  /**
  65   * SimplePie Website URL
  66   */
  67  define('SIMPLEPIE_URL', 'http://simplepie.org');
  68  
  69  /**
  70   * SimplePie Useragent
  71   * @see SimplePie::set_useragent()
  72   */
  73  define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
  74  
  75  /**
  76   * SimplePie Linkback
  77   */
  78  define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
  79  
  80  /**
  81   * No Autodiscovery
  82   * @see SimplePie::set_autodiscovery_level()
  83   */
  84  define('SIMPLEPIE_LOCATOR_NONE', 0);
  85  
  86  /**
  87   * Feed Link Element Autodiscovery
  88   * @see SimplePie::set_autodiscovery_level()
  89   */
  90  define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
  91  
  92  /**
  93   * Local Feed Extension Autodiscovery
  94   * @see SimplePie::set_autodiscovery_level()
  95   */
  96  define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
  97  
  98  /**
  99   * Local Feed Body Autodiscovery
 100   * @see SimplePie::set_autodiscovery_level()
 101   */
 102  define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
 103  
 104  /**
 105   * Remote Feed Extension Autodiscovery
 106   * @see SimplePie::set_autodiscovery_level()
 107   */
 108  define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
 109  
 110  /**
 111   * Remote Feed Body Autodiscovery
 112   * @see SimplePie::set_autodiscovery_level()
 113   */
 114  define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
 115  
 116  /**
 117   * All Feed Autodiscovery
 118   * @see SimplePie::set_autodiscovery_level()
 119   */
 120  define('SIMPLEPIE_LOCATOR_ALL', 31);
 121  
 122  /**
 123   * No known feed type
 124   */
 125  define('SIMPLEPIE_TYPE_NONE', 0);
 126  
 127  /**
 128   * RSS 0.90
 129   */
 130  define('SIMPLEPIE_TYPE_RSS_090', 1);
 131  
 132  /**
 133   * RSS 0.91 (Netscape)
 134   */
 135  define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
 136  
 137  /**
 138   * RSS 0.91 (Userland)
 139   */
 140  define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
 141  
 142  /**
 143   * RSS 0.91 (both Netscape and Userland)
 144   */
 145  define('SIMPLEPIE_TYPE_RSS_091', 6);
 146  
 147  /**
 148   * RSS 0.92
 149   */
 150  define('SIMPLEPIE_TYPE_RSS_092', 8);
 151  
 152  /**
 153   * RSS 0.93
 154   */
 155  define('SIMPLEPIE_TYPE_RSS_093', 16);
 156  
 157  /**
 158   * RSS 0.94
 159   */
 160  define('SIMPLEPIE_TYPE_RSS_094', 32);
 161  
 162  /**
 163   * RSS 1.0
 164   */
 165  define('SIMPLEPIE_TYPE_RSS_10', 64);
 166  
 167  /**
 168   * RSS 2.0
 169   */
 170  define('SIMPLEPIE_TYPE_RSS_20', 128);
 171  
 172  /**
 173   * RDF-based RSS
 174   */
 175  define('SIMPLEPIE_TYPE_RSS_RDF', 65);
 176  
 177  /**
 178   * Non-RDF-based RSS (truly intended as syndication format)
 179   */
 180  define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
 181  
 182  /**
 183   * All RSS
 184   */
 185  define('SIMPLEPIE_TYPE_RSS_ALL', 255);
 186  
 187  /**
 188   * Atom 0.3
 189   */
 190  define('SIMPLEPIE_TYPE_ATOM_03', 256);
 191  
 192  /**
 193   * Atom 1.0
 194   */
 195  define('SIMPLEPIE_TYPE_ATOM_10', 512);
 196  
 197  /**
 198   * All Atom
 199   */
 200  define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
 201  
 202  /**
 203   * All feed types
 204   */
 205  define('SIMPLEPIE_TYPE_ALL', 1023);
 206  
 207  /**
 208   * No construct
 209   */
 210  define('SIMPLEPIE_CONSTRUCT_NONE', 0);
 211  
 212  /**
 213   * Text construct
 214   */
 215  define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
 216  
 217  /**
 218   * HTML construct
 219   */
 220  define('SIMPLEPIE_CONSTRUCT_HTML', 2);
 221  
 222  /**
 223   * XHTML construct
 224   */
 225  define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
 226  
 227  /**
 228   * base64-encoded construct
 229   */
 230  define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
 231  
 232  /**
 233   * IRI construct
 234   */
 235  define('SIMPLEPIE_CONSTRUCT_IRI', 16);
 236  
 237  /**
 238   * A construct that might be HTML
 239   */
 240  define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
 241  
 242  /**
 243   * All constructs
 244   */
 245  define('SIMPLEPIE_CONSTRUCT_ALL', 63);
 246  
 247  /**
 248   * Don't change case
 249   */
 250  define('SIMPLEPIE_SAME_CASE', 1);
 251  
 252  /**
 253   * Change to lowercase
 254   */
 255  define('SIMPLEPIE_LOWERCASE', 2);
 256  
 257  /**
 258   * Change to uppercase
 259   */
 260  define('SIMPLEPIE_UPPERCASE', 4);
 261  
 262  /**
 263   * PCRE for HTML attributes
 264   */
 265  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]*');
 266  
 267  /**
 268   * PCRE for XML attributes
 269   */
 270  define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
 271  
 272  /**
 273   * XML Namespace
 274   */
 275  define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
 276  
 277  /**
 278   * Atom 1.0 Namespace
 279   */
 280  define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
 281  
 282  /**
 283   * Atom 0.3 Namespace
 284   */
 285  define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
 286  
 287  /**
 288   * RDF Namespace
 289   */
 290  define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
 291  
 292  /**
 293   * RSS 0.90 Namespace
 294   */
 295  define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
 296  
 297  /**
 298   * RSS 1.0 Namespace
 299   */
 300  define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
 301  
 302  /**
 303   * RSS 1.0 Content Module Namespace
 304   */
 305  define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
 306  
 307  /**
 308   * RSS 2.0 Namespace
 309   * (Stupid, I know, but I'm certain it will confuse people less with support.)
 310   */
 311  define('SIMPLEPIE_NAMESPACE_RSS_20', '');
 312  
 313  /**
 314   * DC 1.0 Namespace
 315   */
 316  define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
 317  
 318  /**
 319   * DC 1.1 Namespace
 320   */
 321  define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
 322  
 323  /**
 324   * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
 325   */
 326  define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
 327  
 328  /**
 329   * GeoRSS Namespace
 330   */
 331  define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
 332  
 333  /**
 334   * Media RSS Namespace
 335   */
 336  define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
 337  
 338  /**
 339   * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
 340   */
 341  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
 342  
 343  /**
 344   * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
 345   */
 346  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
 347  
 348  /**
 349   * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
 350   */
 351  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
 352  
 353  /**
 354   * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
 355   */
 356  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
 357  
 358  /**
 359   * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
 360   */
 361  define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
 362  
 363  /**
 364   * iTunes RSS Namespace
 365   */
 366  define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
 367  
 368  /**
 369   * XHTML Namespace
 370   */
 371  define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
 372  
 373  /**
 374   * IANA Link Relations Registry
 375   */
 376  define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
 377  
 378  /**
 379   * No file source
 380   */
 381  define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
 382  
 383  /**
 384   * Remote file source
 385   */
 386  define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
 387  
 388  /**
 389   * Local file source
 390   */
 391  define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
 392  
 393  /**
 394   * fsockopen() file source
 395   */
 396  define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
 397  
 398  /**
 399   * cURL file source
 400   */
 401  define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
 402  
 403  /**
 404   * file_get_contents() file source
 405   */
 406  define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
 407  
 408  /**
 409   * SimplePie
 410   *
 411   * @package SimplePie
 412   * @subpackage API
 413   */
 414  class SimplePie
 415  {
 416      /**
 417       * @var array Raw data
 418       * @access private
 419       */
 420      public $data = array();
 421  
 422      /**
 423       * @var mixed Error string
 424       * @access private
 425       */
 426      public $error;
 427  
 428      /**
 429       * @var object Instance of SimplePie_Sanitize (or other class)
 430       * @see SimplePie::set_sanitize_class()
 431       * @access private
 432       */
 433      public $sanitize;
 434  
 435      /**
 436       * @var string SimplePie Useragent
 437       * @see SimplePie::set_useragent()
 438       * @access private
 439       */
 440      public $useragent = SIMPLEPIE_USERAGENT;
 441  
 442      /**
 443       * @var string Feed URL
 444       * @see SimplePie::set_feed_url()
 445       * @access private
 446       */
 447      public $feed_url;
 448  
 449      /**
 450       * @var object Instance of SimplePie_File to use as a feed
 451       * @see SimplePie::set_file()
 452       * @access private
 453       */
 454      public $file;
 455  
 456      /**
 457       * @var string Raw feed data
 458       * @see SimplePie::set_raw_data()
 459       * @access private
 460       */
 461      public $raw_data;
 462  
 463      /**
 464       * @var int Timeout for fetching remote files
 465       * @see SimplePie::set_timeout()
 466       * @access private
 467       */
 468      public $timeout = 10;
 469  
 470      /**
 471       * @var bool Forces fsockopen() to be used for remote files instead
 472       * of cURL, even if a new enough version is installed
 473       * @see SimplePie::force_fsockopen()
 474       * @access private
 475       */
 476      public $force_fsockopen = false;
 477  
 478      /**
 479       * @var bool Force the given data/URL to be treated as a feed no matter what
 480       * it appears like
 481       * @see SimplePie::force_feed()
 482       * @access private
 483       */
 484      public $force_feed = false;
 485  
 486      /**
 487       * @var bool Enable/Disable Caching
 488       * @see SimplePie::enable_cache()
 489       * @access private
 490       */
 491      public $cache = true;
 492  
 493      /**
 494       * @var int Cache duration (in seconds)
 495       * @see SimplePie::set_cache_duration()
 496       * @access private
 497       */
 498      public $cache_duration = 3600;
 499  
 500      /**
 501       * @var int Auto-discovery cache duration (in seconds)
 502       * @see SimplePie::set_autodiscovery_cache_duration()
 503       * @access private
 504       */
 505      public $autodiscovery_cache_duration = 604800; // 7 Days.
 506  
 507      /**
 508       * @var string Cache location (relative to executing script)
 509       * @see SimplePie::set_cache_location()
 510       * @access private
 511       */
 512      public $cache_location = './cache';
 513  
 514      /**
 515       * @var string Function that creates the cache filename
 516       * @see SimplePie::set_cache_name_function()
 517       * @access private
 518       */
 519      public $cache_name_function = 'md5';
 520  
 521      /**
 522       * @var bool Reorder feed by date descending
 523       * @see SimplePie::enable_order_by_date()
 524       * @access private
 525       */
 526      public $order_by_date = true;
 527  
 528      /**
 529       * @var mixed Force input encoding to be set to the follow value
 530       * (false, or anything type-cast to false, disables this feature)
 531       * @see SimplePie::set_input_encoding()
 532       * @access private
 533       */
 534      public $input_encoding = false;
 535  
 536      /**
 537       * @var int Feed Autodiscovery Level
 538       * @see SimplePie::set_autodiscovery_level()
 539       * @access private
 540       */
 541      public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
 542  
 543      /**
 544       * Class registry object
 545       *
 546       * @var SimplePie_Registry
 547       */
 548      public $registry;
 549  
 550      /**
 551       * @var int Maximum number of feeds to check with autodiscovery
 552       * @see SimplePie::set_max_checked_feeds()
 553       * @access private
 554       */
 555      public $max_checked_feeds = 10;
 556  
 557      /**
 558       * @var array All the feeds found during the autodiscovery process
 559       * @see SimplePie::get_all_discovered_feeds()
 560       * @access private
 561       */
 562      public $all_discovered_feeds = array();
 563  
 564      /**
 565       * @var string Web-accessible path to the handler_image.php file.
 566       * @see SimplePie::set_image_handler()
 567       * @access private
 568       */
 569      public $image_handler = '';
 570  
 571      /**
 572       * @var array Stores the URLs when multiple feeds are being initialized.
 573       * @see SimplePie::set_feed_url()
 574       * @access private
 575       */
 576      public $multifeed_url = array();
 577  
 578      /**
 579       * @var array Stores SimplePie objects when multiple feeds initialized.
 580       * @access private
 581       */
 582      public $multifeed_objects = array();
 583  
 584      /**
 585       * @var array Stores the get_object_vars() array for use with multifeeds.
 586       * @see SimplePie::set_feed_url()
 587       * @access private
 588       */
 589      public $config_settings = null;
 590  
 591      /**
 592       * @var integer Stores the number of items to return per-feed with multifeeds.
 593       * @see SimplePie::set_item_limit()
 594       * @access private
 595       */
 596      public $item_limit = 0;
 597  
 598      /**
 599       * @var array Stores the default attributes to be stripped by strip_attributes().
 600       * @see SimplePie::strip_attributes()
 601       * @access private
 602       */
 603      public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
 604  
 605      /**
 606       * @var array Stores the default tags to be stripped by strip_htmltags().
 607       * @see SimplePie::strip_htmltags()
 608       * @access private
 609       */
 610      public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
 611  
 612      /**
 613       * The SimplePie class contains feed level data and options
 614       *
 615       * To use SimplePie, create the SimplePie object with no parameters. You can
 616       * then set configuration options using the provided methods. After setting
 617       * them, you must initialise the feed using $feed->init(). At that point the
 618       * object's methods and properties will be available to you.
 619       *
 620       * Previously, it was possible to pass in the feed URL along with cache
 621       * options directly into the constructor. This has been removed as of 1.3 as
 622       * it caused a lot of confusion.
 623       *
 624       * @since 1.0 Preview Release
 625       */
 626  	public function __construct()
 627      {
 628          if (version_compare(PHP_VERSION, '5.2', '<'))
 629          {
 630              trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
 631              die();
 632          }
 633  
 634          // Other objects, instances created here so we can set options on them
 635          $this->sanitize = new SimplePie_Sanitize();
 636          $this->registry = new SimplePie_Registry();
 637  
 638          if (func_num_args() > 0)
 639          {
 640              $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
 641              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);
 642  
 643              $args = func_get_args();
 644              switch (count($args)) {
 645                  case 3:
 646                      $this->set_cache_duration($args[2]);
 647                  case 2:
 648                      $this->set_cache_location($args[1]);
 649                  case 1:
 650                      $this->set_feed_url($args[0]);
 651                      $this->init();
 652              }
 653          }
 654      }
 655  
 656      /**
 657       * Used for converting object to a string
 658       */
 659  	public function __toString()
 660      {
 661          return md5(serialize($this->data));
 662      }
 663  
 664      /**
 665       * Remove items that link back to this before destroying this object
 666       */
 667  	public function __destruct()
 668      {
 669          if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
 670          {
 671              if (!empty($this->data['items']))
 672              {
 673                  foreach ($this->data['items'] as $item)
 674                  {
 675                      $item->__destruct();
 676                  }
 677                  unset($item, $this->data['items']);
 678              }
 679              if (!empty($this->data['ordered_items']))
 680              {
 681                  foreach ($this->data['ordered_items'] as $item)
 682                  {
 683                      $item->__destruct();
 684                  }
 685                  unset($item, $this->data['ordered_items']);
 686              }
 687          }
 688      }
 689  
 690      /**
 691       * Force the given data/URL to be treated as a feed
 692       *
 693       * This tells SimplePie to ignore the content-type provided by the server.
 694       * Be careful when using this option, as it will also disable autodiscovery.
 695       *
 696       * @since 1.1
 697       * @param bool $enable Force the given data/URL to be treated as a feed
 698       */
 699  	public function force_feed($enable = false)
 700      {
 701          $this->force_feed = (bool) $enable;
 702      }
 703  
 704      /**
 705       * Set the URL of the feed you want to parse
 706       *
 707       * This allows you to enter the URL of the feed you want to parse, or the
 708       * website you want to try to use auto-discovery on. This takes priority
 709       * over any set raw data.
 710       *
 711       * You can set multiple feeds to mash together by passing an array instead
 712       * of a string for the $url. Remember that with each additional feed comes
 713       * additional processing and resources.
 714       *
 715       * @since 1.0 Preview Release
 716       * @see set_raw_data()
 717       * @param string|array $url This is the URL (or array of URLs) that you want to parse.
 718       */
 719  	public function set_feed_url($url)
 720      {
 721          $this->multifeed_url = array();
 722          if (is_array($url))
 723          {
 724              foreach ($url as $value)
 725              {
 726                  $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
 727              }
 728          }
 729          else
 730          {
 731              $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
 732          }
 733      }
 734  
 735      /**
 736       * Set an instance of {@see SimplePie_File} to use as a feed
 737       *
 738       * @param SimplePie_File &$file
 739       * @return bool True on success, false on failure
 740       */
 741  	public function set_file(&$file)
 742      {
 743          if ($file instanceof SimplePie_File)
 744          {
 745              $this->feed_url = $file->url;
 746              $this->file =& $file;
 747              return true;
 748          }
 749          return false;
 750      }
 751  
 752      /**
 753       * Set the raw XML data to parse
 754       *
 755       * Allows you to use a string of RSS/Atom data instead of a remote feed.
 756       *
 757       * If you have a feed available as a string in PHP, you can tell SimplePie
 758       * to parse that data string instead of a remote feed. Any set feed URL
 759       * takes precedence.
 760       *
 761       * @since 1.0 Beta 3
 762       * @param string $data RSS or Atom data as a string.
 763       * @see set_feed_url()
 764       */
 765  	public function set_raw_data($data)
 766      {
 767          $this->raw_data = $data;
 768      }
 769  
 770      /**
 771       * Set the the default timeout for fetching remote feeds
 772       *
 773       * This allows you to change the maximum time the feed's server to respond
 774       * and send the feed back.
 775       *
 776       * @since 1.0 Beta 3
 777       * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
 778       */
 779  	public function set_timeout($timeout = 10)
 780      {
 781          $this->timeout = (int) $timeout;
 782      }
 783  
 784      /**
 785       * Force SimplePie to use fsockopen() instead of cURL
 786       *
 787       * @since 1.0 Beta 3
 788       * @param bool $enable Force fsockopen() to be used
 789       */
 790  	public function force_fsockopen($enable = false)
 791      {
 792          $this->force_fsockopen = (bool) $enable;
 793      }
 794  
 795      /**
 796       * Enable/disable caching in SimplePie.
 797       *
 798       * This option allows you to disable caching all-together in SimplePie.
 799       * However, disabling the cache can lead to longer load times.
 800       *
 801       * @since 1.0 Preview Release
 802       * @param bool $enable Enable caching
 803       */
 804  	public function enable_cache($enable = true)
 805      {
 806          $this->cache = (bool) $enable;
 807      }
 808  
 809      /**
 810       * Set the length of time (in seconds) that the contents of a feed will be
 811       * cached
 812       *
 813       * @param int $seconds The feed content cache duration
 814       */
 815  	public function set_cache_duration($seconds = 3600)
 816      {
 817          $this->cache_duration = (int) $seconds;
 818      }
 819  
 820      /**
 821       * Set the length of time (in seconds) that the autodiscovered feed URL will
 822       * be cached
 823       *
 824       * @param int $seconds The autodiscovered feed URL cache duration.
 825       */
 826  	public function set_autodiscovery_cache_duration($seconds = 604800)
 827      {
 828          $this->autodiscovery_cache_duration = (int) $seconds;
 829      }
 830  
 831      /**
 832       * Set the file system location where the cached files should be stored
 833       *
 834       * @param string $location The file system location.
 835       */
 836  	public function set_cache_location($location = './cache')
 837      {
 838          $this->cache_location = (string) $location;
 839      }
 840  
 841      /**
 842       * Set whether feed items should be sorted into reverse chronological order
 843       *
 844       * @param bool $enable Sort as reverse chronological order.
 845       */
 846  	public function enable_order_by_date($enable = true)
 847      {
 848          $this->order_by_date = (bool) $enable;
 849      }
 850  
 851      /**
 852       * Set the character encoding used to parse the feed
 853       *
 854       * This overrides the encoding reported by the feed, however it will fall
 855       * back to the normal encoding detection if the override fails
 856       *
 857       * @param string $encoding Character encoding
 858       */
 859  	public function set_input_encoding($encoding = false)
 860      {
 861          if ($encoding)
 862          {
 863              $this->input_encoding = (string) $encoding;
 864          }
 865          else
 866          {
 867              $this->input_encoding = false;
 868          }
 869      }
 870  
 871      /**
 872       * Set how much feed autodiscovery to do
 873       *
 874       * @see SIMPLEPIE_LOCATOR_NONE
 875       * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
 876       * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
 877       * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
 878       * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
 879       * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
 880       * @see SIMPLEPIE_LOCATOR_ALL
 881       * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
 882       */
 883  	public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
 884      {
 885          $this->autodiscovery = (int) $level;
 886      }
 887  
 888      /**
 889       * Get the class registry
 890       *
 891       * Use this to override SimplePie's default classes
 892       * @see SimplePie_Registry
 893       * @return SimplePie_Registry
 894       */
 895      public function &get_registry()
 896      {
 897          return $this->registry;
 898      }
 899  
 900      /**#@+
 901       * Useful when you are overloading or extending SimplePie's default classes.
 902       *
 903       * @deprecated Use {@see get_registry()} instead
 904       * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
 905       * @param string $class Name of custom class
 906       * @return boolean True on success, false otherwise
 907       */
 908      /**
 909       * Set which class SimplePie uses for caching
 910       */
 911  	public function set_cache_class($class = 'SimplePie_Cache')
 912      {
 913          return $this->registry->register('Cache', $class, true);
 914      }
 915  
 916      /**
 917       * Set which class SimplePie uses for auto-discovery
 918       */
 919  	public function set_locator_class($class = 'SimplePie_Locator')
 920      {
 921          return $this->registry->register('Locator', $class, true);
 922      }
 923  
 924      /**
 925       * Set which class SimplePie uses for XML parsing
 926       */
 927  	public function set_parser_class($class = 'SimplePie_Parser')
 928      {
 929          return $this->registry->register('Parser', $class, true);
 930      }
 931  
 932      /**
 933       * Set which class SimplePie uses for remote file fetching
 934       */
 935  	public function set_file_class($class = 'SimplePie_File')
 936      {
 937          return $this->registry->register('File', $class, true);
 938      }
 939  
 940      /**
 941       * Set which class SimplePie uses for data sanitization
 942       */
 943  	public function set_sanitize_class($class = 'SimplePie_Sanitize')
 944      {
 945          return $this->registry->register('Sanitize', $class, true);
 946      }
 947  
 948      /**
 949       * Set which class SimplePie uses for handling feed items
 950       */
 951  	public function set_item_class($class = 'SimplePie_Item')
 952      {
 953          return $this->registry->register('Item', $class, true);
 954      }
 955  
 956      /**
 957       * Set which class SimplePie uses for handling author data
 958       */
 959  	public function set_author_class($class = 'SimplePie_Author')
 960      {
 961          return $this->registry->register('Author', $class, true);
 962      }
 963  
 964      /**
 965       * Set which class SimplePie uses for handling category data
 966       */
 967  	public function set_category_class($class = 'SimplePie_Category')
 968      {
 969          return $this->registry->register('Category', $class, true);
 970      }
 971  
 972      /**
 973       * Set which class SimplePie uses for feed enclosures
 974       */
 975  	public function set_enclosure_class($class = 'SimplePie_Enclosure')
 976      {
 977          return $this->registry->register('Enclosure', $class, true);
 978      }
 979  
 980      /**
 981       * Set which class SimplePie uses for `<media:text>` captions
 982       */
 983  	public function set_caption_class($class = 'SimplePie_Caption')
 984      {
 985          return $this->registry->register('Caption', $class, true);
 986      }
 987  
 988      /**
 989       * Set which class SimplePie uses for `<media:copyright>`
 990       */
 991  	public function set_copyright_class($class = 'SimplePie_Copyright')
 992      {
 993          return $this->registry->register('Copyright', $class, true);
 994      }
 995  
 996      /**
 997       * Set which class SimplePie uses for `<media:credit>`
 998       */
 999  	public function set_credit_class($class = 'SimplePie_Credit')
1000      {
1001          return $this->registry->register('Credit', $class, true);
1002      }
1003  
1004      /**
1005       * Set which class SimplePie uses for `<media:rating>`
1006       */
1007  	public function set_rating_class($class = 'SimplePie_Rating')
1008      {
1009          return $this->registry->register('Rating', $class, true);
1010      }
1011  
1012      /**
1013       * Set which class SimplePie uses for `<media:restriction>`
1014       */
1015  	public function set_restriction_class($class = 'SimplePie_Restriction')
1016      {
1017          return $this->registry->register('Restriction', $class, true);
1018      }
1019  
1020      /**
1021       * Set which class SimplePie uses for content-type sniffing
1022       */
1023  	public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
1024      {
1025          return $this->registry->register('Content_Type_Sniffer', $class, true);
1026      }
1027  
1028      /**
1029       * Set which class SimplePie uses item sources
1030       */
1031  	public function set_source_class($class = 'SimplePie_Source')
1032      {
1033          return $this->registry->register('Source', $class, true);
1034      }
1035      /**#@-*/
1036  
1037      /**
1038       * Set the user agent string
1039       *
1040       * @param string $ua New user agent string.
1041       */
1042  	public function set_useragent($ua = SIMPLEPIE_USERAGENT)
1043      {
1044          $this->useragent = (string) $ua;
1045      }
1046  
1047      /**
1048       * Set callback function to create cache filename with
1049       *
1050       * @param mixed $function Callback function
1051       */
1052  	public function set_cache_name_function($function = 'md5')
1053      {
1054          if (is_callable($function))
1055          {
1056              $this->cache_name_function = $function;
1057          }
1058      }
1059  
1060      /**
1061       * Set options to make SP as fast as possible
1062       *
1063       * Forgoes a substantial amount of data sanitization in favor of speed. This
1064       * turns SimplePie into a dumb parser of feeds.
1065       *
1066       * @param bool $set Whether to set them or not
1067       */
1068  	public function set_stupidly_fast($set = false)
1069      {
1070          if ($set)
1071          {
1072              $this->enable_order_by_date(false);
1073              $this->remove_div(false);
1074              $this->strip_comments(false);
1075              $this->strip_htmltags(false);
1076              $this->strip_attributes(false);
1077              $this->set_image_handler(false);
1078          }
1079      }
1080  
1081      /**
1082       * Set maximum number of feeds to check with autodiscovery
1083       *
1084       * @param int $max Maximum number of feeds to check
1085       */
1086  	public function set_max_checked_feeds($max = 10)
1087      {
1088          $this->max_checked_feeds = (int) $max;
1089      }
1090  
1091  	public function remove_div($enable = true)
1092      {
1093          $this->sanitize->remove_div($enable);
1094      }
1095  
1096  	public function strip_htmltags($tags = '', $encode = null)
1097      {
1098          if ($tags === '')
1099          {
1100              $tags = $this->strip_htmltags;
1101          }
1102          $this->sanitize->strip_htmltags($tags);
1103          if ($encode !== null)
1104          {
1105              $this->sanitize->encode_instead_of_strip($tags);
1106          }
1107      }
1108  
1109  	public function encode_instead_of_strip($enable = true)
1110      {
1111          $this->sanitize->encode_instead_of_strip($enable);
1112      }
1113  
1114  	public function strip_attributes($attribs = '')
1115      {
1116          if ($attribs === '')
1117          {
1118              $attribs = $this->strip_attributes;
1119          }
1120          $this->sanitize->strip_attributes($attribs);
1121      }
1122  
1123      /**
1124       * Set the output encoding
1125       *
1126       * Allows you to override SimplePie's output to match that of your webpage.
1127       * This is useful for times when your webpages are not being served as
1128       * UTF-8.  This setting will be obeyed by {@see handle_content_type()}, and
1129       * is similar to {@see set_input_encoding()}.
1130       *
1131       * It should be noted, however, that not all character encodings can support
1132       * all characters.  If your page is being served as ISO-8859-1 and you try
1133       * to display a Japanese feed, you'll likely see garbled characters.
1134       * Because of this, it is highly recommended to ensure that your webpages
1135       * are served as UTF-8.
1136       *
1137       * The number of supported character encodings depends on whether your web
1138       * host supports {@link http://php.net/mbstring mbstring},
1139       * {@link http://php.net/iconv iconv}, or both. See
1140       * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
1141       * more information.
1142       *
1143       * @param string $encoding
1144       */
1145  	public function set_output_encoding($encoding = 'UTF-8')
1146      {
1147          $this->sanitize->set_output_encoding($encoding);
1148      }
1149  
1150  	public function strip_comments($strip = false)
1151      {
1152          $this->sanitize->strip_comments($strip);
1153      }
1154  
1155      /**
1156       * Set element/attribute key/value pairs of HTML attributes
1157       * containing URLs that need to be resolved relative to the feed
1158       *
1159       * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
1160       * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
1161       * |q|@cite
1162       *
1163       * @since 1.0
1164       * @param array|null $element_attribute Element/attribute key/value pairs, null for default
1165       */
1166  	public function set_url_replacements($element_attribute = null)
1167      {
1168          $this->sanitize->set_url_replacements($element_attribute);
1169      }
1170  
1171      /**
1172       * Set the handler to enable the display of cached images.
1173       *
1174       * @param str $page Web-accessible path to the handler_image.php file.
1175       * @param str $qs The query string that the value should be passed to.
1176       */
1177  	public function set_image_handler($page = false, $qs = 'i')
1178      {
1179          if ($page !== false)
1180          {
1181              $this->sanitize->set_image_handler($page . '?' . $qs . '=');
1182          }
1183          else
1184          {
1185              $this->image_handler = '';
1186          }
1187      }
1188  
1189      /**
1190       * Set the limit for items returned per-feed with multifeeds
1191       *
1192       * @param integer $limit The maximum number of items to return.
1193       */
1194  	public function set_item_limit($limit = 0)
1195      {
1196          $this->item_limit = (int) $limit;
1197      }
1198  
1199      /**
1200       * Initialize the feed object
1201       *
1202       * This is what makes everything happen.  Period.  This is where all of the
1203       * configuration options get processed, feeds are fetched, cached, and
1204       * parsed, and all of that other good stuff.
1205       *
1206       * @return boolean True if successful, false otherwise
1207       */
1208  	public function init()
1209      {
1210          // Check absolute bare minimum requirements.
1211          if (!extension_loaded('xml') || !extension_loaded('pcre'))
1212          {
1213              return false;
1214          }
1215          // 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.
1216          elseif (!extension_loaded('xmlreader'))
1217          {
1218              static $xml_is_sane = null;
1219              if ($xml_is_sane === null)
1220              {
1221                  $parser_check = xml_parser_create();
1222                  xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
1223                  xml_parser_free($parser_check);
1224                  $xml_is_sane = isset($values[0]['value']);
1225              }
1226              if (!$xml_is_sane)
1227              {
1228                  return false;
1229              }
1230          }
1231  
1232          if (method_exists($this->sanitize, 'set_registry'))
1233          {
1234              $this->sanitize->set_registry($this->registry);
1235          }
1236  
1237          // Pass whatever was set with config options over to the sanitizer.
1238          // Pass the classes in for legacy support; new classes should use the registry instead
1239          $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
1240          $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
1241  
1242          if (!empty($this->multifeed_url))
1243          {
1244              $i = 0;
1245              $success = 0;
1246              $this->multifeed_objects = array();
1247              $this->error = array();
1248              foreach ($this->multifeed_url as $url)
1249              {
1250                  $this->multifeed_objects[$i] = clone $this;
1251                  $this->multifeed_objects[$i]->set_feed_url($url);
1252                  $single_success = $this->multifeed_objects[$i]->init();
1253                  $success |= $single_success;
1254                  if (!$single_success)
1255                  {
1256                      $this->error[$i] = $this->multifeed_objects[$i]->error();
1257                  }
1258                  $i++;
1259              }
1260              return (bool) $success;
1261          }
1262          elseif ($this->feed_url === null && $this->raw_data === null)
1263          {
1264              return false;
1265          }
1266  
1267          $this->error = null;
1268          $this->data = array();
1269          $this->multifeed_objects = array();
1270          $cache = false;
1271  
1272          if ($this->feed_url !== null)
1273          {
1274              $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
1275  
1276              // Decide whether to enable caching
1277              if ($this->cache && $parsed_feed_url['scheme'] !== '')
1278              {
1279                  $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
1280              }
1281  
1282              // Fetch the data via SimplePie_File into $this->raw_data
1283              if (($fetched = $this->fetch_data($cache)) === true)
1284              {
1285                  return true;
1286              }
1287              elseif ($fetched === false) {
1288                  return false;
1289              }
1290  
1291              list($headers, $sniffed) = $fetched;
1292          }
1293  
1294          // Set up array of possible encodings
1295          $encodings = array();
1296  
1297          // First check to see if input has been overridden.
1298          if ($this->input_encoding !== false)
1299          {
1300              $encodings[] = $this->input_encoding;
1301          }
1302  
1303          $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
1304          $text_types = array('text/xml', 'text/xml-external-parsed-entity');
1305  
1306          // RFC 3023 (only applies to sniffed content)
1307          if (isset($sniffed))
1308          {
1309              if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
1310              {
1311                  if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1312                  {
1313                      $encodings[] = strtoupper($charset[1]);
1314                  }
1315                  $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1316                  $encodings[] = 'UTF-8';
1317              }
1318              elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
1319              {
1320                  if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
1321                  {
1322                      $encodings[] = $charset[1];
1323                  }
1324                  $encodings[] = 'US-ASCII';
1325              }
1326              // Text MIME-type default
1327              elseif (substr($sniffed, 0, 5) === 'text/')
1328              {
1329                  $encodings[] = 'US-ASCII';
1330              }
1331          }
1332  
1333          // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
1334          $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
1335          $encodings[] = 'UTF-8';
1336          $encodings[] = 'ISO-8859-1';
1337  
1338          // There's no point in trying an encoding twice
1339          $encodings = array_unique($encodings);
1340  
1341          // Loop through each possible encoding, till we return something, or run out of possibilities
1342          foreach ($encodings as $encoding)
1343          {
1344              // Change the encoding to UTF-8 (as we always use UTF-8 internally)
1345              if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
1346              {
1347                  // Create new parser
1348                  $parser = $this->registry->create('Parser');
1349  
1350                  // If it's parsed fine
1351                  if ($parser->parse($utf8_data, 'UTF-8'))
1352                  {
1353                      $this->data = $parser->get_data();
1354                      if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
1355                      {
1356                          $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
1357                          $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1358                          return false;
1359                      }
1360  
1361                      if (isset($headers))
1362                      {
1363                          $this->data['headers'] = $headers;
1364                      }
1365                      $this->data['build'] = SIMPLEPIE_BUILD;
1366  
1367                      // Cache the file if caching is enabled
1368                      if ($cache && !$cache->save($this))
1369                      {
1370                          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);
1371                      }
1372                      return true;
1373                  }
1374              }
1375          }
1376  
1377          if (isset($parser))
1378          {
1379              // We have an error, just set SimplePie_Misc::error to it and quit
1380              $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());
1381          }
1382          else
1383          {
1384              $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.';
1385          }
1386  
1387          $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1388  
1389          return false;
1390      }
1391  
1392      /**
1393       * Fetch the data via SimplePie_File
1394       *
1395       * If the data is already cached, attempt to fetch it from there instead
1396       * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
1397       * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
1398       */
1399  	protected function fetch_data(&$cache)
1400      {
1401          // If it's enabled, use the cache
1402          if ($cache)
1403          {
1404              // Load the Cache
1405              $this->data = $cache->load();
1406              if (!empty($this->data))
1407              {
1408                  // If the cache is for an outdated build of SimplePie
1409                  if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
1410                  {
1411                      $cache->unlink();
1412                      $this->data = array();
1413                  }
1414                  // If we've hit a collision just rerun it with caching disabled
1415                  elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
1416                  {
1417                      $cache = false;
1418                      $this->data = array();
1419                  }
1420                  // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
1421                  elseif (isset($this->data['feed_url']))
1422                  {
1423                      // If the autodiscovery cache is still valid use it.
1424                      if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
1425                      {
1426                          // Do not need to do feed autodiscovery yet.
1427                          if ($this->data['feed_url'] !== $this->data['url'])
1428                          {
1429                              $this->set_feed_url($this->data['feed_url']);
1430                              return $this->init();
1431                          }
1432  
1433                          $cache->unlink();
1434                          $this->data = array();
1435                      }
1436                  }
1437                  // Check if the cache has been updated
1438                  elseif ($cache->mtime() + $this->cache_duration < time())
1439                  {
1440                      // If we have last-modified and/or etag set
1441                      if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
1442                      {
1443                          $headers = array(
1444                              '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',
1445                          );
1446                          if (isset($this->data['headers']['last-modified']))
1447                          {
1448                              $headers['if-modified-since'] = $this->data['headers']['last-modified'];
1449                          }
1450                          if (isset($this->data['headers']['etag']))
1451                          {
1452                              $headers['if-none-match'] = $this->data['headers']['etag'];
1453                          }
1454  
1455                          $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
1456  
1457                          if ($file->success)
1458                          {
1459                              if ($file->status_code === 304)
1460                              {
1461                                  $cache->touch();
1462                                  return true;
1463                              }
1464                          }
1465                          else
1466                          {
1467                              unset($file);
1468                          }
1469                      }
1470                  }
1471                  // If the cache is still valid, just return true
1472                  else
1473                  {
1474                      $this->raw_data = false;
1475                      return true;
1476                  }
1477              }
1478              // If the cache is empty, delete it
1479              else
1480              {
1481                  $cache->unlink();
1482                  $this->data = array();
1483              }
1484          }
1485          // 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.
1486          if (!isset($file))
1487          {
1488              if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
1489              {
1490                  $file =& $this->file;
1491              }
1492              else
1493              {
1494                  $headers = array(
1495                      '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',
1496                  );
1497                  $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
1498              }
1499          }
1500          // If the file connection has an error, set SimplePie::error to that and quit
1501          if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
1502          {
1503              $this->error = $file->error;
1504              return !empty($this->data);
1505          }
1506  
1507          if (!$this->force_feed)
1508          {
1509              // Check if the supplied URL is a feed, if it isn't, look for it.
1510              $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
1511  
1512              if (!$locate->is_feed($file))
1513              {
1514                  // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
1515                  unset($file);
1516                  try
1517                  {
1518                      if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
1519                      {
1520                          $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.";
1521                          $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
1522                          return false;
1523                      }
1524                  }
1525                  catch (SimplePie_Exception $e)
1526                  {
1527                      // This is usually because DOMDocument doesn't exist
1528                      $this->error = $e->getMessage();
1529                      $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
1530                      return false;
1531                  }
1532                  if ($cache)
1533                  {
1534                      $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
1535                      if (!$cache->save($this))
1536                      {
1537                          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);
1538                      }
1539                      $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
1540                  }
1541                  $this->feed_url = $file->url;
1542              }
1543              $locate = null;
1544          }
1545  
1546          $this->raw_data = $file->body;
1547  
1548          $headers = $file->headers;
1549          $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
1550          $sniffed = $sniffer->get_type();
1551  
1552          return array($headers, $sniffed);
1553      }
1554  
1555      /**
1556       * Get the error message for the occured error
1557       *
1558       * @return string|array Error message, or array of messages for multifeeds
1559       */
1560  	public function error()
1561      {
1562          return $this->error;
1563      }
1564  
1565      /**
1566       * Get the raw XML
1567       *
1568       * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
1569       * the data instead of printing it.
1570       *
1571       * @return string|boolean Raw XML data, false if the cache is used
1572       */
1573  	public function get_raw_data()
1574      {
1575          return $this->raw_data;
1576      }
1577  
1578      /**
1579       * Get the character encoding used for output
1580       *
1581       * @since Preview Release
1582       * @return string
1583       */
1584  	public function get_encoding()
1585      {
1586          return $this->sanitize->output_encoding;
1587      }
1588  
1589      /**
1590       * Send the content-type header with correct encoding
1591       *
1592       * This method ensures that the SimplePie-enabled page is being served with
1593       * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
1594       * and character encoding HTTP headers (character encoding determined by the
1595       * {@see set_output_encoding} config option).
1596       *
1597       * This won't work properly if any content or whitespace has already been
1598       * sent to the browser, because it relies on PHP's
1599       * {@link http://php.net/header header()} function, and these are the
1600       * circumstances under which the function works.
1601       *
1602       * Because it's setting these settings for the entire page (as is the nature
1603       * of HTTP headers), this should only be used once per page (again, at the
1604       * top).
1605       *
1606       * @param string $mime MIME type to serve the page as
1607       */
1608  	public function handle_content_type($mime = 'text/html')
1609      {
1610          if (!headers_sent())
1611          {
1612              $header = "Content-type: $mime;";
1613              if ($this->get_encoding())
1614              {
1615                  $header .= ' charset=' . $this->get_encoding();
1616              }
1617              else
1618              {
1619                  $header .= ' charset=UTF-8';
1620              }
1621              header($header);
1622          }
1623      }
1624  
1625      /**
1626       * Get the type of the feed
1627       *
1628       * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
1629       * using {@link http://php.net/language.operators.bitwise bitwise operators}
1630       *
1631       * @since 0.8 (usage changed to using constants in 1.0)
1632       * @see SIMPLEPIE_TYPE_NONE Unknown.
1633       * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
1634       * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
1635       * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
1636       * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
1637       * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
1638       * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
1639       * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
1640       * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
1641       * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
1642       * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
1643       * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
1644       * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
1645       * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
1646       * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
1647       * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
1648       * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
1649       * @return int SIMPLEPIE_TYPE_* constant
1650       */
1651  	public function get_type()
1652      {
1653          if (!isset($this->data['type']))
1654          {
1655              $this->data['type'] = SIMPLEPIE_TYPE_ALL;
1656              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
1657              {
1658                  $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
1659              }
1660              elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
1661              {
1662                  $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
1663              }
1664              elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
1665              {
1666                  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
1667                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
1668                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
1669                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
1670                  {
1671                      $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
1672                  }
1673                  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
1674                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
1675                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
1676                  || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
1677                  {
1678                      $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
1679                  }
1680              }
1681              elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
1682              {
1683                  $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
1684                  if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1685                  {
1686                      switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
1687                      {
1688                          case '0.91':
1689                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
1690                              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1691                              {
1692                                  switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
1693                                  {
1694                                      case '0':
1695                                          $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
1696                                          break;
1697  
1698                                      case '24':
1699                                          $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
1700                                          break;
1701                                  }
1702                              }
1703                              break;
1704  
1705                          case '0.92':
1706                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
1707                              break;
1708  
1709                          case '0.93':
1710                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
1711                              break;
1712  
1713                          case '0.94':
1714                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
1715                              break;
1716  
1717                          case '2.0':
1718                              $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
1719                              break;
1720                      }
1721                  }
1722              }
1723              else
1724              {
1725                  $this->data['type'] = SIMPLEPIE_TYPE_NONE;
1726              }
1727          }
1728          return $this->data['type'];
1729      }
1730  
1731      /**
1732       * Get the URL for the feed
1733       *
1734       * May or may not be different from the URL passed to {@see set_feed_url()},
1735       * depending on whether auto-discovery was used.
1736       *
1737       * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
1738       * @todo If we have a perm redirect we should return the new URL
1739       * @todo When we make the above change, let's support <itunes:new-feed-url> as well
1740       * @todo Also, |atom:link|@rel=self
1741       * @return string|null
1742       */
1743  	public function subscribe_url()
1744      {
1745          if ($this->feed_url !== null)
1746          {
1747              return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
1748          }
1749          else
1750          {
1751              return null;
1752          }
1753      }
1754  
1755      /**
1756       * Get data for an feed-level element
1757       *
1758       * This method allows you to get access to ANY element/attribute that is a
1759       * sub-element of the opening feed tag.
1760       *
1761       * The return value is an indexed array of elements matching the given
1762       * namespace and tag name. Each element has `attribs`, `data` and `child`
1763       * subkeys. For `attribs` and `child`, these contain namespace subkeys.
1764       * `attribs` then has one level of associative name => value data (where
1765       * `value` is a string) after the namespace. `child` has tag-indexed keys
1766       * after the namespace, each member of which is an indexed array matching
1767       * this same format.
1768       *
1769       * For example:
1770       * <pre>
1771       * // This is probably a bad example because we already support
1772       * // <media:content> natively, but it shows you how to parse through
1773       * // the nodes.
1774       * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
1775       * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
1776       * $file = $content[0]['attribs']['']['url'];
1777       * echo $file;
1778       * </pre>
1779       *
1780       * @since 1.0
1781       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1782       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1783       * @param string $tag Tag name
1784       * @return array
1785       */
1786  	public function get_feed_tags($namespace, $tag)
1787      {
1788          $type = $this->get_type();
1789          if ($type & SIMPLEPIE_TYPE_ATOM_10)
1790          {
1791              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
1792              {
1793                  return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
1794              }
1795          }
1796          if ($type & SIMPLEPIE_TYPE_ATOM_03)
1797          {
1798              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
1799              {
1800                  return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
1801              }
1802          }
1803          if ($type & SIMPLEPIE_TYPE_RSS_RDF)
1804          {
1805              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
1806              {
1807                  return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
1808              }
1809          }
1810          if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1811          {
1812              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
1813              {
1814                  return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
1815              }
1816          }
1817          return null;
1818      }
1819  
1820      /**
1821       * Get data for an channel-level element
1822       *
1823       * This method allows you to get access to ANY element/attribute in the
1824       * channel/header section of the feed.
1825       *
1826       * See {@see SimplePie::get_feed_tags()} for a description of the return value
1827       *
1828       * @since 1.0
1829       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1830       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1831       * @param string $tag Tag name
1832       * @return array
1833       */
1834  	public function get_channel_tags($namespace, $tag)
1835      {
1836          $type = $this->get_type();
1837          if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
1838          {
1839              if ($return = $this->get_feed_tags($namespace, $tag))
1840              {
1841                  return $return;
1842              }
1843          }
1844          if ($type & SIMPLEPIE_TYPE_RSS_10)
1845          {
1846              if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
1847              {
1848                  if (isset($channel[0]['child'][$namespace][$tag]))
1849                  {
1850                      return $channel[0]['child'][$namespace][$tag];
1851                  }
1852              }
1853          }
1854          if ($type & SIMPLEPIE_TYPE_RSS_090)
1855          {
1856              if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
1857              {
1858                  if (isset($channel[0]['child'][$namespace][$tag]))
1859                  {
1860                      return $channel[0]['child'][$namespace][$tag];
1861                  }
1862              }
1863          }
1864          if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1865          {
1866              if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
1867              {
1868                  if (isset($channel[0]['child'][$namespace][$tag]))
1869                  {
1870                      return $channel[0]['child'][$namespace][$tag];
1871                  }
1872              }
1873          }
1874          return null;
1875      }
1876  
1877      /**
1878       * Get data for an channel-level element
1879       *
1880       * This method allows you to get access to ANY element/attribute in the
1881       * image/logo section of the feed.
1882       *
1883       * See {@see SimplePie::get_feed_tags()} for a description of the return value
1884       *
1885       * @since 1.0
1886       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
1887       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
1888       * @param string $tag Tag name
1889       * @return array
1890       */
1891  	public function get_image_tags($namespace, $tag)
1892      {
1893          $type = $this->get_type();
1894          if ($type & SIMPLEPIE_TYPE_RSS_10)
1895          {
1896              if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
1897              {
1898                  if (isset($image[0]['child'][$namespace][$tag]))
1899                  {
1900                      return $image[0]['child'][$namespace][$tag];
1901                  }
1902              }
1903          }
1904          if ($type & SIMPLEPIE_TYPE_RSS_090)
1905          {
1906              if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
1907              {
1908                  if (isset($image[0]['child'][$namespace][$tag]))
1909                  {
1910                      return $image[0]['child'][$namespace][$tag];
1911                  }
1912              }
1913          }
1914          if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
1915          {
1916              if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
1917              {
1918                  if (isset($image[0]['child'][$namespace][$tag]))
1919                  {
1920                      return $image[0]['child'][$namespace][$tag];
1921                  }
1922              }
1923          }
1924          return null;
1925      }
1926  
1927      /**
1928       * Get the base URL value from the feed
1929       *
1930       * Uses `<xml:base>` if available, otherwise uses the first link in the
1931       * feed, or failing that, the URL of the feed itself.
1932       *
1933       * @see get_link
1934       * @see subscribe_url
1935       *
1936       * @param array $element
1937       * @return string
1938       */
1939  	public function get_base($element = array())
1940      {
1941          if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
1942          {
1943              return $element['xml_base'];
1944          }
1945          elseif ($this->get_link() !== null)
1946          {
1947              return $this->get_link();
1948          }
1949          else
1950          {
1951              return $this->subscribe_url();
1952          }
1953      }
1954  
1955      /**
1956       * Sanitize feed data
1957       *
1958       * @access private
1959       * @see SimplePie_Sanitize::sanitize()
1960       * @param string $data Data to sanitize
1961       * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
1962       * @param string $base Base URL to resolve URLs against
1963       * @return string Sanitized data
1964       */
1965  	public function sanitize($data, $type, $base = '')
1966      {
1967          return $this->sanitize->sanitize($data, $type, $base);
1968      }
1969  
1970      /**
1971       * Get the title of the feed
1972       *
1973       * Uses `<atom:title>`, `<title>` or `<dc:title>`
1974       *
1975       * @since 1.0 (previously called `get_feed_title` since 0.8)
1976       * @return string|null
1977       */
1978  	public function get_title()
1979      {
1980          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
1981          {
1982              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1983          }
1984          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
1985          {
1986              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
1987          }
1988          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
1989          {
1990              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1991          }
1992          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
1993          {
1994              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1995          }
1996          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
1997          {
1998              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
1999          }
2000          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2001          {
2002              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2003          }
2004          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2005          {
2006              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2007          }
2008          else
2009          {
2010              return null;
2011          }
2012      }
2013  
2014      /**
2015       * Get a category for the feed
2016       *
2017       * @since Unknown
2018       * @param int $key The category that you want to return.  Remember that arrays begin with 0, not 1
2019       * @return SimplePie_Category|null
2020       */
2021  	public function get_category($key = 0)
2022      {
2023          $categories = $this->get_categories();
2024          if (isset($categories[$key]))
2025          {
2026              return $categories[$key];
2027          }
2028          else
2029          {
2030              return null;
2031          }
2032      }
2033  
2034      /**
2035       * Get all categories for the feed
2036       *
2037       * Uses `<atom:category>`, `<category>` or `<dc:subject>`
2038       *
2039       * @since Unknown
2040       * @return array|null List of {@see SimplePie_Category} objects
2041       */
2042  	public function get_categories()
2043      {
2044          $categories = array();
2045  
2046          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
2047          {
2048              $term = null;
2049              $scheme = null;
2050              $label = null;
2051              if (isset($category['attribs']['']['term']))
2052              {
2053                  $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
2054              }
2055              if (isset($category['attribs']['']['scheme']))
2056              {
2057                  $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
2058              }
2059              if (isset($category['attribs']['']['label']))
2060              {
2061                  $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
2062              }
2063              $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
2064          }
2065          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
2066          {
2067              // This is really the label, but keep this as the term also for BC.
2068              // Label will also work on retrieving because that falls back to term.
2069              $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2070              if (isset($category['attribs']['']['domain']))
2071              {
2072                  $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
2073              }
2074              else
2075              {
2076                  $scheme = null;
2077              }
2078              $categories[] = $this->registry->create('Category', array($term, $scheme, null));
2079          }
2080          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
2081          {
2082              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2083          }
2084          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
2085          {
2086              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2087          }
2088  
2089          if (!empty($categories))
2090          {
2091              return array_unique($categories);
2092          }
2093          else
2094          {
2095              return null;
2096          }
2097      }
2098  
2099      /**
2100       * Get an author for the feed
2101       *
2102       * @since 1.1
2103       * @param int $key The author that you want to return.  Remember that arrays begin with 0, not 1
2104       * @return SimplePie_Author|null
2105       */
2106  	public function get_author($key = 0)
2107      {
2108          $authors = $this->get_authors();
2109          if (isset($authors[$key]))
2110          {
2111              return $authors[$key];
2112          }
2113          else
2114          {
2115              return null;
2116          }
2117      }
2118  
2119      /**
2120       * Get all authors for the feed
2121       *
2122       * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
2123       *
2124       * @since 1.1
2125       * @return array|null List of {@see SimplePie_Author} objects
2126       */
2127  	public function get_authors()
2128      {
2129          $authors = array();
2130          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
2131          {
2132              $name = null;
2133              $uri = null;
2134              $email = null;
2135              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2136              {
2137                  $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2138              }
2139              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2140              {
2141                  $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]));
2142              }
2143              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2144              {
2145                  $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2146              }
2147              if ($name !== null || $email !== null || $uri !== null)
2148              {
2149                  $authors[] = $this->registry->create('Author', array($name, $uri, $email));
2150              }
2151          }
2152          if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
2153          {
2154              $name = null;
2155              $url = null;
2156              $email = null;
2157              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2158              {
2159                  $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2160              }
2161              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2162              {
2163                  $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]));
2164              }
2165              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2166              {
2167                  $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2168              }
2169              if ($name !== null || $email !== null || $url !== null)
2170              {
2171                  $authors[] = $this->registry->create('Author', array($name, $url, $email));
2172              }
2173          }
2174          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
2175          {
2176              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2177          }
2178          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
2179          {
2180              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2181          }
2182          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
2183          {
2184              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
2185          }
2186  
2187          if (!empty($authors))
2188          {
2189              return array_unique($authors);
2190          }
2191          else
2192          {
2193              return null;
2194          }
2195      }
2196  
2197      /**
2198       * Get a contributor for the feed
2199       *
2200       * @since 1.1
2201       * @param int $key The contrbutor that you want to return.  Remember that arrays begin with 0, not 1
2202       * @return SimplePie_Author|null
2203       */
2204  	public function get_contributor($key = 0)
2205      {
2206          $contributors = $this->get_contributors();
2207          if (isset($contributors[$key]))
2208          {
2209              return $contributors[$key];
2210          }
2211          else
2212          {
2213              return null;
2214          }
2215      }
2216  
2217      /**
2218       * Get all contributors for the feed
2219       *
2220       * Uses `<atom:contributor>`
2221       *
2222       * @since 1.1
2223       * @return array|null List of {@see SimplePie_Author} objects
2224       */
2225  	public function get_contributors()
2226      {
2227          $contributors = array();
2228          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
2229          {
2230              $name = null;
2231              $uri = null;
2232              $email = null;
2233              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
2234              {
2235                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2236              }
2237              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
2238              {
2239                  $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]));
2240              }
2241              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
2242              {
2243                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2244              }
2245              if ($name !== null || $email !== null || $uri !== null)
2246              {
2247                  $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
2248              }
2249          }
2250          foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
2251          {
2252              $name = null;
2253              $url = null;
2254              $email = null;
2255              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
2256              {
2257                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2258              }
2259              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
2260              {
2261                  $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]));
2262              }
2263              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
2264              {
2265                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2266              }
2267              if ($name !== null || $email !== null || $url !== null)
2268              {
2269                  $contributors[] = $this->registry->create('Author', array($name, $url, $email));
2270              }
2271          }
2272  
2273          if (!empty($contributors))
2274          {
2275              return array_unique($contributors);
2276          }
2277          else
2278          {
2279              return null;
2280          }
2281      }
2282  
2283      /**
2284       * Get a single link for the feed
2285       *
2286       * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2287       * @param int $key The link that you want to return.  Remember that arrays begin with 0, not 1
2288       * @param string $rel The relationship of the link to return
2289       * @return string|null Link URL
2290       */
2291  	public function get_link($key = 0, $rel = 'alternate')
2292      {
2293          $links = $this->get_links($rel);
2294          if (isset($links[$key]))
2295          {
2296              return $links[$key];
2297          }
2298          else
2299          {
2300              return null;
2301          }
2302      }
2303  
2304      /**
2305       * Get the permalink for the item
2306       *
2307       * Returns the first link available with a relationship of "alternate".
2308       * Identical to {@see get_link()} with key 0
2309       *
2310       * @see get_link
2311       * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
2312       * @internal Added for parity between the parent-level and the item/entry-level.
2313       * @return string|null Link URL
2314       */
2315  	public function get_permalink()
2316      {
2317          return $this->get_link(0);
2318      }
2319  
2320      /**
2321       * Get all links for the feed
2322       *
2323       * Uses `<atom:link>` or `<link>`
2324       *
2325       * @since Beta 2
2326       * @param string $rel The relationship of links to return
2327       * @return array|null Links found for the feed (strings)
2328       */
2329  	public function get_links($rel = 'alternate')
2330      {
2331          if (!isset($this->data['links']))
2332          {
2333              $this->data['links'] = array();
2334              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
2335              {
2336                  foreach ($links as $link)
2337                  {
2338                      if (isset($link['attribs']['']['href']))
2339                      {
2340                          $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2341                          $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2342                      }
2343                  }
2344              }
2345              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
2346              {
2347                  foreach ($links as $link)
2348                  {
2349                      if (isset($link['attribs']['']['href']))
2350                      {
2351                          $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
2352                          $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
2353  
2354                      }
2355                  }
2356              }
2357              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
2358              {
2359                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2360              }
2361              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
2362              {
2363                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2364              }
2365              if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
2366              {
2367                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
2368              }
2369  
2370              $keys = array_keys($this->data['links']);
2371              foreach ($keys as $key)
2372              {
2373                  if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
2374                  {
2375                      if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
2376                      {
2377                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
2378                          $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
2379                      }
2380                      else
2381                      {
2382                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
2383                      }
2384                  }
2385                  elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
2386                  {
2387                      $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
2388                  }
2389                  $this->data['links'][$key] = array_unique($this->data['links'][$key]);
2390              }
2391          }
2392  
2393          if (isset($this->data['links'][$rel]))
2394          {
2395              return $this->data['links'][$rel];
2396          }
2397          else
2398          {
2399              return null;
2400          }
2401      }
2402  
2403  	public function get_all_discovered_feeds()
2404      {
2405          return $this->all_discovered_feeds;
2406      }
2407  
2408      /**
2409       * Get the content for the item
2410       *
2411       * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
2412       * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
2413       *
2414       * @since 1.0 (previously called `get_feed_description()` since 0.8)
2415       * @return string|null
2416       */
2417  	public function get_description()
2418      {
2419          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
2420          {
2421              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2422          }
2423          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
2424          {
2425              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2426          }
2427          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
2428          {
2429              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2430          }
2431          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
2432          {
2433              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
2434          }
2435          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
2436          {
2437              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2438          }
2439          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
2440          {
2441              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2442          }
2443          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
2444          {
2445              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2446          }
2447          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
2448          {
2449              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2450          }
2451          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
2452          {
2453              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
2454          }
2455          else
2456          {
2457              return null;
2458          }
2459      }
2460  
2461      /**
2462       * Get the copyright info for the feed
2463       *
2464       * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
2465       *
2466       * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
2467       * @return string|null
2468       */
2469  	public function get_copyright()
2470      {
2471          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
2472          {
2473              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2474          }
2475          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
2476          {
2477              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
2478          }
2479          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
2480          {
2481              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2482          }
2483          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
2484          {
2485              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2486          }
2487          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
2488          {
2489              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2490          }
2491          else
2492          {
2493              return null;
2494          }
2495      }
2496  
2497      /**
2498       * Get the language for the feed
2499       *
2500       * Uses `<language>`, `<dc:language>`, or @xml_lang
2501       *
2502       * @since 1.0 (previously called `get_feed_language()` since 0.8)
2503       * @return string|null
2504       */
2505  	public function get_language()
2506      {
2507          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
2508          {
2509              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2510          }
2511          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
2512          {
2513              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2514          }
2515          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
2516          {
2517              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2518          }
2519          elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
2520          {
2521              return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2522          }
2523          elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
2524          {
2525              return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2526          }
2527          elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
2528          {
2529              return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
2530          }
2531          elseif (isset($this->data['headers']['content-language']))
2532          {
2533              return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
2534          }
2535          else
2536          {
2537              return null;
2538          }
2539      }
2540  
2541      /**
2542       * Get the latitude coordinates for the item
2543       *
2544       * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2545       *
2546       * Uses `<geo:lat>` or `<georss:point>`
2547       *
2548       * @since 1.0
2549       * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2550       * @link http://www.georss.org/ GeoRSS
2551       * @return string|null
2552       */
2553  	public function get_latitude()
2554      {
2555  
2556          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
2557          {
2558              return (float) $return[0]['data'];
2559          }
2560          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))
2561          {
2562              return (float) $match[1];
2563          }
2564          else
2565          {
2566              return null;
2567          }
2568      }
2569  
2570      /**
2571       * Get the longitude coordinates for the feed
2572       *
2573       * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
2574       *
2575       * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
2576       *
2577       * @since 1.0
2578       * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
2579       * @link http://www.georss.org/ GeoRSS
2580       * @return string|null
2581       */
2582  	public function get_longitude()
2583      {
2584          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
2585          {
2586              return (float) $return[0]['data'];
2587          }
2588          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
2589          {
2590              return (float) $return[0]['data'];
2591          }
2592          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))
2593          {
2594              return (float) $match[2];
2595          }
2596          else
2597          {
2598              return null;
2599          }
2600      }
2601  
2602      /**
2603       * Get the feed logo's title
2604       *
2605       * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
2606       *
2607       * Uses `<image><title>` or `<image><dc:title>`
2608       *
2609       * @return string|null
2610       */
2611  	public function get_image_title()
2612      {
2613          if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
2614          {
2615              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2616          }
2617          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
2618          {
2619              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2620          }
2621          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
2622          {
2623              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2624          }
2625          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
2626          {
2627              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2628          }
2629          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
2630          {
2631              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
2632          }
2633          else
2634          {
2635              return null;
2636          }
2637      }
2638  
2639      /**
2640       * Get the feed logo's URL
2641       *
2642       * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
2643       * have a "feed logo" URL. This points directly to the image itself.
2644       *
2645       * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
2646       * `<image><title>` or `<image><dc:title>`
2647       *
2648       * @return string|null
2649       */
2650  	public function get_image_url()
2651      {
2652          if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
2653          {
2654              return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
2655          }
2656          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
2657          {
2658              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2659          }
2660          elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
2661          {
2662              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2663          }
2664          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
2665          {
2666              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2667          }
2668          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
2669          {
2670              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2671          }
2672          elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
2673          {
2674              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
2675          }
2676          else
2677          {
2678              return null;
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  }
3059  
3060  /**
3061   * Manages all author-related data
3062   *
3063   * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
3064   *
3065   * This class can be overloaded with {@see SimplePie::set_author_class()}
3066   *
3067   * @package SimplePie
3068   * @subpackage API
3069   */
3070  class SimplePie_Author
3071  {
3072      /**
3073       * Author's name
3074       *
3075       * @var string
3076       * @see get_name()
3077       */
3078      var $name;
3079  
3080      /**
3081       * Author's link
3082       *
3083       * @var string
3084       * @see get_link()
3085       */
3086      var $link;
3087  
3088      /**
3089       * Author's email address
3090       *
3091       * @var string
3092       * @see get_email()
3093       */
3094      var $email;
3095  
3096      /**
3097       * Constructor, used to input the data
3098       *
3099       * @param string $name
3100       * @param string $link
3101       * @param string $email
3102       */
3103  	public function __construct($name = null, $link = null, $email = null)
3104      {
3105          $this->name = $name;
3106          $this->link = $link;
3107          $this->email = $email;
3108      }
3109  
3110      /**
3111       * String-ified version
3112       *
3113       * @return string
3114       */
3115  	public function __toString()
3116      {
3117          // There is no $this->data here
3118          return md5(serialize($this));
3119      }
3120  
3121      /**
3122       * Author's name
3123       *
3124       * @return string|null
3125       */
3126  	public function get_name()
3127      {
3128          if ($this->name !== null)
3129          {
3130              return $this->name;
3131          }
3132          else
3133          {
3134              return null;
3135          }
3136      }
3137  
3138      /**
3139       * Author's link
3140       *
3141       * @return string|null
3142       */
3143  	public function get_link()
3144      {
3145          if ($this->link !== null)
3146          {
3147              return $this->link;
3148          }
3149          else
3150          {
3151              return null;
3152          }
3153      }
3154  
3155      /**
3156       * Author's email address
3157       *
3158       * @return string|null
3159       */
3160  	public function get_email()
3161      {
3162          if ($this->email !== null)
3163          {
3164              return $this->email;
3165          }
3166          else
3167          {
3168              return null;
3169          }
3170      }
3171  }
3172  
3173  /**
3174   * Base for cache objects
3175   *
3176   * Classes to be used with {@see SimplePie_Cache::register()} are expected
3177   * to implement this interface.
3178   *
3179   * @package SimplePie
3180   * @subpackage Caching
3181   */
3182  interface SimplePie_Cache_Base
3183  {
3184      /**
3185       * Feed cache type
3186       *
3187       * @var string
3188       */
3189      const TYPE_FEED = 'spc';
3190  
3191      /**
3192       * Image cache type
3193       *
3194       * @var string
3195       */
3196      const TYPE_IMAGE = 'spi';
3197  
3198      /**
3199       * Create a new cache object
3200       *
3201       * @param string $location Location string (from SimplePie::$cache_location)
3202       * @param string $name Unique ID for the cache
3203       * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3204       */
3205  	public function __construct($location, $name, $type);
3206  
3207      /**
3208       * Save data to the cache
3209       *
3210       * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3211       * @return bool Successfulness
3212       */
3213  	public function save($data);
3214  
3215      /**
3216       * Retrieve the data saved to the cache
3217       *
3218       * @return array Data for SimplePie::$data
3219       */
3220  	public function load();
3221  
3222      /**
3223       * Retrieve the last modified time for the cache
3224       *
3225       * @return int Timestamp
3226       */
3227  	public function mtime();
3228  
3229      /**
3230       * Set the last modified time to the current time
3231       *
3232       * @return bool Success status
3233       */
3234  	public function touch();
3235  
3236      /**
3237       * Remove the cache
3238       *
3239       * @return bool Success status
3240       */
3241  	public function unlink();
3242  }
3243  
3244  /**
3245   * Base class for database-based caches
3246   *
3247   * @package SimplePie
3248   * @subpackage Caching
3249   */
3250  abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
3251  {
3252      /**
3253       * Helper for database conversion
3254       *
3255       * Converts a given {@see SimplePie} object into data to be stored
3256       *
3257       * @param SimplePie $data
3258       * @return array First item is the serialized data for storage, second item is the unique ID for this item
3259       */
3260  	protected static function prepare_simplepie_object_for_cache($data)
3261      {
3262          $items = $data->get_items();
3263          $items_by_id = array();
3264  
3265          if (!empty($items))
3266          {
3267              foreach ($items as $item)
3268              {
3269                  $items_by_id[$item->get_id()] = $item;
3270              }
3271  
3272              if (count($items_by_id) !== count($items))
3273              {
3274                  $items_by_id = array();
3275                  foreach ($items as $item)
3276                  {
3277                      $items_by_id[$item->get_id(true)] = $item;
3278                  }
3279              }
3280  
3281              if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3282              {
3283                  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3284              }
3285              elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3286              {
3287                  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3288              }
3289              elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3290              {
3291                  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3292              }
3293              elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
3294              {
3295                  $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
3296              }
3297              else
3298              {
3299                  $channel = null;
3300              }
3301  
3302              if ($channel !== null)
3303              {
3304                  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
3305                  {
3306                      unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
3307                  }
3308                  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
3309                  {
3310                      unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
3311                  }
3312                  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
3313                  {
3314                      unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
3315                  }
3316                  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
3317                  {
3318                      unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
3319                  }
3320                  if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
3321                  {
3322                      unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
3323                  }
3324              }
3325              if (isset($data->data['items']))
3326              {
3327                  unset($data->data['items']);
3328              }
3329              if (isset($data->data['ordered_items']))
3330              {
3331                  unset($data->data['ordered_items']);
3332              }
3333          }
3334          return array(serialize($data->data), $items_by_id);
3335      }
3336  }
3337  
3338  /**
3339   * Caches data to the filesystem
3340   *
3341   * @package SimplePie
3342   * @subpackage Caching
3343   */
3344  class SimplePie_Cache_File implements SimplePie_Cache_Base
3345  {
3346      /**
3347       * Location string
3348       *
3349       * @see SimplePie::$cache_location
3350       * @var string
3351       */
3352      protected $location;
3353  
3354      /**
3355       * Filename
3356       *
3357       * @var string
3358       */
3359      protected $filename;
3360  
3361      /**
3362       * File extension
3363       *
3364       * @var string
3365       */
3366      protected $extension;
3367  
3368      /**
3369       * File path
3370       *
3371       * @var string
3372       */
3373      protected $name;
3374  
3375      /**
3376       * Create a new cache object
3377       *
3378       * @param string $location Location string (from SimplePie::$cache_location)
3379       * @param string $name Unique ID for the cache
3380       * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3381       */
3382  	public function __construct($location, $name, $type)
3383      {
3384          $this->location = $location;
3385          $this->filename = $name;
3386          $this->extension = $type;
3387          $this->name = "$this->location/$this->filename.$this->extension";
3388      }
3389  
3390      /**
3391       * Save data to the cache
3392       *
3393       * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3394       * @return bool Successfulness
3395       */
3396  	public function save($data)
3397      {
3398          if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
3399          {
3400              if ($data instanceof SimplePie)
3401              {
3402                  $data = $data->data;
3403              }
3404  
3405              $data = serialize($data);
3406              return (bool) file_put_contents($this->name, $data);
3407          }
3408          return false;
3409      }
3410  
3411      /**
3412       * Retrieve the data saved to the cache
3413       *
3414       * @return array Data for SimplePie::$data
3415       */
3416  	public function load()
3417      {
3418          if (file_exists($this->name) && is_readable($this->name))
3419          {
3420              return unserialize(file_get_contents($this->name));
3421          }
3422          return false;
3423      }
3424  
3425      /**
3426       * Retrieve the last modified time for the cache
3427       *
3428       * @return int Timestamp
3429       */
3430  	public function mtime()
3431      {
3432          if (file_exists($this->name))
3433          {
3434              return filemtime($this->name);
3435          }
3436          return false;
3437      }
3438  
3439      /**
3440       * Set the last modified time to the current time
3441       *
3442       * @return bool Success status
3443       */
3444  	public function touch()
3445      {
3446          if (file_exists($this->name))
3447          {
3448              return touch($this->name);
3449          }
3450          return false;
3451      }
3452  
3453      /**
3454       * Remove the cache
3455       *
3456       * @return bool Success status
3457       */
3458  	public function unlink()
3459      {
3460          if (file_exists($this->name))
3461          {
3462              return unlink($this->name);
3463          }
3464          return false;
3465      }
3466  }
3467  
3468  /**
3469   * Caches data to memcache
3470   *
3471   * Registered for URLs with the "memcache" protocol
3472   *
3473   * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
3474   * connect to memcache on `localhost` on port 11211. All tables will be
3475   * prefixed with `sp_` and data will expire after 3600 seconds
3476   *
3477   * @package SimplePie
3478   * @subpackage Caching
3479   * @uses Memcache
3480   */
3481  class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
3482  {
3483      /**
3484       * Memcache instance
3485       *
3486       * @var Memcache
3487       */
3488      protected $cache;
3489  
3490      /**
3491       * Options
3492       *
3493       * @var array
3494       */
3495      protected $options;
3496  
3497      /**
3498       * Cache name
3499       *
3500       * @var string
3501       */
3502      protected $name;
3503  
3504      /**
3505       * Create a new cache object
3506       *
3507       * @param string $location Location string (from SimplePie::$cache_location)
3508       * @param string $name Unique ID for the cache
3509       * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3510       */
3511  	public function __construct($location, $name, $type)
3512      {
3513          $this->options = array(
3514              'host' => '127.0.0.1',
3515              'port' => 11211,
3516              'extras' => array(
3517                  'timeout' => 3600, // one hour
3518                  'prefix' => 'simplepie_',
3519              ),
3520          );
3521          $parsed = SimplePie_Cache::parse_URL($location);
3522          $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
3523          $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
3524          $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
3525          $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
3526  
3527          $this->cache = new Memcache();
3528          $this->cache->addServer($this->options['host'], (int) $this->options['port']);
3529      }
3530  
3531      /**
3532       * Save data to the cache
3533       *
3534       * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3535       * @return bool Successfulness
3536       */
3537  	public function save($data)
3538      {
3539          if ($data instanceof SimplePie)
3540          {
3541              $data = $data->data;
3542          }
3543          return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
3544      }
3545  
3546      /**
3547       * Retrieve the data saved to the cache
3548       *
3549       * @return array Data for SimplePie::$data
3550       */
3551  	public function load()
3552      {
3553          $data = $this->cache->get($this->name);
3554  
3555          if ($data !== false)
3556          {
3557              return unserialize($data);
3558          }
3559          return false;
3560      }
3561  
3562      /**
3563       * Retrieve the last modified time for the cache
3564       *
3565       * @return int Timestamp
3566       */
3567  	public function mtime()
3568      {
3569          $data = $this->cache->get($this->name);
3570  
3571          if ($data !== false)
3572          {
3573              // essentially ignore the mtime because Memcache expires on it's own
3574              return time();
3575          }
3576  
3577          return false;
3578      }
3579  
3580      /**
3581       * Set the last modified time to the current time
3582       *
3583       * @return bool Success status
3584       */
3585  	public function touch()
3586      {
3587          $data = $this->cache->get($this->name);
3588  
3589          if ($data !== false)
3590          {
3591              return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
3592          }
3593  
3594          return false;
3595      }
3596  
3597      /**
3598       * Remove the cache
3599       *
3600       * @return bool Success status
3601       */
3602  	public function unlink()
3603      {
3604          return $this->cache->delete($this->name, 0);
3605      }
3606  }
3607  
3608  /**
3609   * Caches data to a MySQL database
3610   *
3611   * Registered for URLs with the "mysql" protocol
3612   *
3613   * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
3614   * connect to the `mydb` database on `localhost` on port 3306, with the user
3615   * `root` and the password `password`. All tables will be prefixed with `sp_`
3616   *
3617   * @package SimplePie
3618   * @subpackage Caching
3619   */
3620  class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
3621  {
3622      /**
3623       * PDO instance
3624       *
3625       * @var PDO
3626       */
3627      protected $mysql;
3628  
3629      /**
3630       * Options
3631       *
3632       * @var array
3633       */
3634      protected $options;
3635  
3636      /**
3637       * Cache ID
3638       *
3639       * @var string
3640       */
3641      protected $id;
3642  
3643      /**
3644       * Create a new cache object
3645       *
3646       * @param string $location Location string (from SimplePie::$cache_location)
3647       * @param string $name Unique ID for the cache
3648       * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
3649       */
3650  	public function __construct($location, $name, $type)
3651      {
3652          $this->options = array(
3653              'user' => null,
3654              'pass' => null,
3655              'host' => '127.0.0.1',
3656              'port' => '3306',
3657              'path' => '',
3658              'extras' => array(
3659                  'prefix' => '',
3660              ),
3661          );
3662          $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
3663  
3664          // Path is prefixed with a "/"
3665          $this->options['dbname'] = substr($this->options['path'], 1);
3666  
3667          try
3668          {
3669              $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
3670          }
3671          catch (PDOException $e)
3672          {
3673              $this->mysql = null;
3674              return;
3675          }
3676  
3677          $this->id = $name . $type;
3678  
3679          if (!$query = $this->mysql->query('SHOW TABLES'))
3680          {
3681              $this->mysql = null;
3682              return;
3683          }
3684  
3685          $db = array();
3686          while ($row = $query->fetchColumn())
3687          {
3688              $db[] = $row;
3689          }
3690  
3691          if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
3692          {
3693              $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
3694              if ($query === false)
3695              {
3696                  $this->mysql = null;
3697              }
3698          }
3699  
3700          if (!in_array($this->options['extras']['prefix'] . 'items', $db))
3701          {
3702              $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
3703              if ($query === false)
3704              {
3705                  $this->mysql = null;
3706              }
3707          }
3708      }
3709  
3710      /**
3711       * Save data to the cache
3712       *
3713       * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
3714       * @return bool Successfulness
3715       */
3716  	public function save($data)
3717      {
3718          if ($this->mysql === null)
3719          {
3720              return false;
3721          }
3722  
3723          if ($data instanceof SimplePie)
3724          {
3725              $data = clone $data;
3726  
3727              $prepared = self::prepare_simplepie_object_for_cache($data);
3728  
3729              $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
3730              $query->bindValue(':feed', $this->id);
3731              if ($query->execute())
3732              {
3733                  if ($query->fetchColumn() > 0)
3734                  {
3735                      $items = count($prepared[1]);
3736                      if ($items)
3737                      {
3738                          $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
3739                          $query = $this->mysql->prepare($sql);
3740                          $query->bindValue(':items', $items);
3741                      }
3742                      else
3743                      {
3744                          $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
3745                          $query = $this->mysql->prepare($sql);
3746                      }
3747  
3748                      $query->bindValue(':data', $prepared[0]);
3749                      $query->bindValue(':time', time());
3750                      $query->bindValue(':feed', $this->id);
3751                      if (!$query->execute())
3752                      {
3753                          return false;
3754                      }
3755                  }
3756                  else
3757                  {
3758                      $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
3759                      $query->bindValue(':feed', $this->id);
3760                      $query->bindValue(':count', count($prepared[1]));
3761                      $query->bindValue(':data', $prepared[0]);
3762                      $query->bindValue(':time', time());
3763                      if (!$query->execute())
3764                      {
3765                          return false;
3766                      }
3767                  }
3768  
3769                  $ids = array_keys($prepared[1]);
3770                  if (!empty($ids))
3771                  {
3772                      foreach ($ids as $id)
3773                      {
3774                          $database_ids[] = $this->mysql->quote($id);
3775                      }
3776  
3777                      $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
3778                      $query->bindValue(':feed', $this->id);
3779  
3780                      if ($query->execute())
3781                      {
3782                          $existing_ids = array();
3783                          while ($row = $query->fetchColumn())
3784                          {
3785                              $existing_ids[] = $row;
3786                          }
3787  
3788                          $new_ids = array_diff($ids, $existing_ids);
3789  
3790                          foreach ($new_ids as $new_id)
3791                          {
3792                              if (!($date = $prepared[1][$new_id]->get_date('U')))
3793                              {
3794                                  $date = time();
3795                              }
3796  
3797                              $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
3798                              $query->bindValue(':feed', $this->id);
3799                              $query->bindValue(':id', $new_id);
3800                              $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
3801                              $query->bindValue(':date', $date);
3802                              if (!$query->execute())
3803                              {
3804                                  return false;
3805                              }
3806                          }
3807                          return true;
3808                      }
3809                  }
3810                  else
3811                  {
3812                      return true;
3813                  }
3814              }
3815          }
3816          else
3817          {
3818              $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
3819              $query->bindValue(':feed', $this->id);
3820              if ($query->execute())
3821              {
3822                  if ($query->rowCount() > 0)
3823                  {
3824                      $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
3825                      $query->bindValue(':data', serialize($data));
3826                      $query->bindValue(':time', time());
3827                      $query->bindValue(':feed', $this->id);
3828                      if ($this->execute())
3829                      {
3830                          return true;
3831                      }
3832                  }
3833                  else
3834                  {
3835                      $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
3836                      $query->bindValue(':id', $this->id);
3837                      $query->bindValue(':data', serialize($data));
3838                      $query->bindValue(':time', time());
3839                      if ($query->execute())
3840                      {
3841                          return true;
3842                      }
3843                  }
3844              }
3845          }
3846          return false;
3847      }
3848  
3849      /**
3850       * Retrieve the data saved to the cache
3851       *
3852       * @return array Data for SimplePie::$data
3853       */
3854  	public function load()
3855      {
3856          if ($this->mysql === null)
3857          {
3858              return false;
3859          }
3860  
3861          $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3862          $query->bindValue(':id', $this->id);
3863          if ($query->execute() && ($row = $query->fetch()))
3864          {
3865              $data = unserialize($row[1]);
3866  
3867              if (isset($this->options['items'][0]))
3868              {
3869                  $items = (int) $this->options['items'][0];
3870              }
3871              else
3872              {
3873                  $items = (int) $row[0];
3874              }
3875  
3876              if ($items !== 0)
3877              {
3878                  if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
3879                  {
3880                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
3881                  }
3882                  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
3883                  {
3884                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
3885                  }
3886                  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
3887                  {
3888                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
3889                  }
3890                  elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
3891                  {
3892                      $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
3893                  }
3894                  else
3895                  {
3896                      $feed = null;
3897                  }
3898  
3899                  if ($feed !== null)
3900                  {
3901                      $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
3902                      if ($items > 0)
3903                      {
3904                          $sql .= ' LIMIT ' . $items;
3905                      }
3906  
3907                      $query = $this->mysql->prepare($sql);
3908                      $query->bindValue(':feed', $this->id);
3909                      if ($query->execute())
3910                      {
3911                          while ($row = $query->fetchColumn())
3912                          {
3913                              $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
3914                          }
3915                      }
3916                      else
3917                      {
3918                          return false;
3919                      }
3920                  }
3921              }
3922              return $data;
3923          }
3924          return false;
3925      }
3926  
3927      /**
3928       * Retrieve the last modified time for the cache
3929       *
3930       * @return int Timestamp
3931       */
3932  	public function mtime()
3933      {
3934          if ($this->mysql === null)
3935          {
3936              return false;
3937          }
3938  
3939          $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3940          $query->bindValue(':id', $this->id);
3941          if ($query->execute() && ($time = $query->fetchColumn()))
3942          {
3943              return $time;
3944          }
3945          else
3946          {
3947              return false;
3948          }
3949      }
3950  
3951      /**
3952       * Set the last modified time to the current time
3953       *
3954       * @return bool Success status
3955       */
3956  	public function touch()
3957      {
3958          if ($this->mysql === null)
3959          {
3960              return false;
3961          }
3962  
3963          $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
3964          $query->bindValue(':time', time());
3965          $query->bindValue(':id', $this->id);
3966          if ($query->execute() && $query->rowCount() > 0)
3967          {
3968              return true;
3969          }
3970          else
3971          {
3972              return false;
3973          }
3974      }
3975  
3976      /**
3977       * Remove the cache
3978       *
3979       * @return bool Success status
3980       */
3981  	public function unlink()
3982      {
3983          if ($this->mysql === null)
3984          {
3985              return false;
3986          }
3987  
3988          $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
3989          $query->bindValue(':id', $this->id);
3990          $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
3991          $query2->bindValue(':id', $this->id);
3992          if ($query->execute() && $query2->execute())
3993          {
3994              return true;
3995          }
3996          else
3997          {
3998              return false;
3999          }
4000      }
4001  }
4002  
4003  /**
4004   * Used to create cache objects
4005   *
4006   * This class can be overloaded with {@see SimplePie::set_cache_class()},
4007   * although the preferred way is to create your own handler
4008   * via {@see register()}
4009   *
4010   * @package SimplePie
4011   * @subpackage Caching
4012   */
4013  class SimplePie_Cache
4014  {
4015      /**
4016       * Cache handler classes
4017       *
4018       * These receive 3 parameters to their constructor, as documented in
4019       * {@see register()}
4020       * @var array
4021       */
4022      protected static $handlers = array(
4023          'mysql' => 'SimplePie_Cache_MySQL',
4024          'memcache' => 'SimplePie_Cache_Memcache',
4025      );
4026  
4027      /**
4028       * Don't call the constructor. Please.
4029       */
4030  	private function __construct() { }
4031  
4032      /**
4033       * Create a new SimplePie_Cache object
4034       *
4035       * @param string $location URL location (scheme is used to determine handler)
4036       * @param string $filename Unique identifier for cache object
4037       * @param string $extension 'spi' or 'spc'
4038       * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
4039       */
4040  	public static function get_handler($location, $filename, $extension)
4041      {
4042          $type = explode(':', $location, 2);
4043          $type = $type[0];
4044          if (!empty(self::$handlers[$type]))
4045          {
4046              $class = self::$handlers[$type];
4047              return new $class($location, $filename, $extension);
4048          }
4049  
4050          return new SimplePie_Cache_File($location, $filename, $extension);
4051      }
4052  
4053      /**
4054       * Create a new SimplePie_Cache object
4055       *
4056       * @deprecated Use {@see get_handler} instead
4057       */
4058  	public function create($location, $filename, $extension)
4059      {
4060          trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
4061          return self::get_handler($location, $filename, $extension);
4062      }
4063  
4064      /**
4065       * Register a handler
4066       *
4067       * @param string $type DSN type to register for
4068       * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
4069       */
4070  	public static function register($type, $class)
4071      {
4072          self::$handlers[$type] = $class;
4073      }
4074  
4075      /**
4076       * Parse a URL into an array
4077       *
4078       * @param string $url
4079       * @return array
4080       */
4081  	public static function parse_URL($url)
4082      {
4083          $params = parse_url($url);
4084          $params['extras'] = array();
4085          if (isset($params['query']))
4086          {
4087              parse_str($params['query'], $params['extras']);
4088          }
4089          return $params;
4090      }
4091  }
4092  
4093  /**
4094   * Handles `<media:text>` captions as defined in Media RSS.
4095   *
4096   * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
4097   *
4098   * This class can be overloaded with {@see SimplePie::set_caption_class()}
4099   *
4100   * @package SimplePie
4101   * @subpackage API
4102   */
4103  class SimplePie_Caption
4104  {
4105      /**
4106       * Content type
4107       *
4108       * @var string
4109       * @see get_type()
4110       */
4111      var $type;
4112  
4113      /**
4114       * Language
4115       *
4116       * @var string
4117       * @see get_language()
4118       */
4119      var $lang;
4120  
4121      /**
4122       * Start time
4123       *
4124       * @var string
4125       * @see get_starttime()
4126       */
4127      var $startTime;
4128  
4129      /**
4130       * End time
4131       *
4132       * @var string
4133       * @see get_endtime()
4134       */
4135      var $endTime;
4136  
4137      /**
4138       * Caption text
4139       *
4140       * @var string
4141       * @see get_text()
4142       */
4143      var $text;
4144  
4145      /**
4146       * Constructor, used to input the data
4147       *
4148       * For documentation on all the parameters, see the corresponding
4149       * properties and their accessors
4150       */
4151  	public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
4152      {
4153          $this->type = $type;
4154          $this->lang = $lang;
4155          $this->startTime = $startTime;
4156          $this->endTime = $endTime;
4157          $this->text = $text;
4158      }
4159  
4160      /**
4161       * String-ified version
4162       *
4163       * @return string
4164       */
4165  	public function __toString()
4166      {
4167          // There is no $this->data here
4168          return md5(serialize($this));
4169      }
4170  
4171      /**
4172       * Get the end time
4173       *
4174       * @return string|null Time in the format 'hh:mm:ss.SSS'
4175       */
4176  	public function get_endtime()
4177      {
4178          if ($this->endTime !== null)
4179          {
4180              return $this->endTime;
4181          }
4182          else
4183          {
4184              return null;
4185          }
4186      }
4187  
4188      /**
4189       * Get the language
4190       *
4191       * @link http://tools.ietf.org/html/rfc3066
4192       * @return string|null Language code as per RFC 3066
4193       */
4194  	public function get_language()
4195      {
4196          if ($this->lang !== null)
4197          {
4198              return $this->lang;
4199          }
4200          else
4201          {
4202              return null;
4203          }
4204      }
4205  
4206      /**
4207       * Get the start time
4208       *
4209       * @return string|null Time in the format 'hh:mm:ss.SSS'
4210       */
4211  	public function get_starttime()
4212      {
4213          if ($this->startTime !== null)
4214          {
4215              return $this->startTime;
4216          }
4217          else
4218          {
4219              return null;
4220          }
4221      }
4222  
4223      /**
4224       * Get the text of the caption
4225       *
4226       * @return string|null
4227       */
4228  	public function get_text()
4229      {
4230          if ($this->text !== null)
4231          {
4232              return $this->text;
4233          }
4234          else
4235          {
4236              return null;
4237          }
4238      }
4239  
4240      /**
4241       * Get the content type (not MIME type)
4242       *
4243       * @return string|null Either 'text' or 'html'
4244       */
4245  	public function get_type()
4246      {
4247          if ($this->type !== null)
4248          {
4249              return $this->type;
4250          }
4251          else
4252          {
4253              return null;
4254          }
4255      }
4256  }
4257  
4258  /**
4259   * Manages all category-related data
4260   *
4261   * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
4262   *
4263   * This class can be overloaded with {@see SimplePie::set_category_class()}
4264   *
4265   * @package SimplePie
4266   * @subpackage API
4267   */
4268  class SimplePie_Category
4269  {
4270      /**
4271       * Category identifier
4272       *
4273       * @var string
4274       * @see get_term
4275       */
4276      var $term;
4277  
4278      /**
4279       * Categorization scheme identifier
4280       *
4281       * @var string
4282       * @see get_scheme()
4283       */
4284      var $scheme;
4285  
4286      /**
4287       * Human readable label
4288       *
4289       * @var string
4290       * @see get_label()
4291       */
4292      var $label;
4293  
4294      /**
4295       * Constructor, used to input the data
4296       *
4297       * @param string $term
4298       * @param string $scheme
4299       * @param string $label
4300       */
4301  	public function __construct($term = null, $scheme = null, $label = null)
4302      {
4303          $this->term = $term;
4304          $this->scheme = $scheme;
4305          $this->label = $label;
4306      }
4307  
4308      /**
4309       * String-ified version
4310       *
4311       * @return string
4312       */
4313  	public function __toString()
4314      {
4315          // There is no $this->data here
4316          return md5(serialize($this));
4317      }
4318  
4319      /**
4320       * Get the category identifier
4321       *
4322       * @return string|null
4323       */
4324  	public function get_term()
4325      {
4326          if ($this->term !== null)
4327          {
4328              return $this->term;
4329          }
4330          else
4331          {
4332              return null;
4333          }
4334      }
4335  
4336      /**
4337       * Get the categorization scheme identifier
4338       *
4339       * @return string|null
4340       */
4341  	public function get_scheme()
4342      {
4343          if ($this->scheme !== null)
4344          {
4345              return $this->scheme;
4346          }
4347          else
4348          {
4349              return null;
4350          }
4351      }
4352  
4353      /**
4354       * Get the human readable label
4355       *
4356       * @return string|null
4357       */
4358  	public function get_label()
4359      {
4360          if ($this->label !== null)
4361          {
4362              return $this->label;
4363          }
4364          else
4365          {
4366              return $this->get_term();
4367          }
4368      }
4369  }
4370  
4371  /**
4372   * Content-type sniffing
4373   *
4374   * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
4375   *
4376   * This is used since we can't always trust Content-Type headers, and is based
4377   * upon the HTML5 parsing rules.
4378   *
4379   *
4380   * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
4381   *
4382   * @package SimplePie
4383   * @subpackage HTTP
4384   */
4385  class SimplePie_Content_Type_Sniffer
4386  {
4387      /**
4388       * File object
4389       *
4390       * @var SimplePie_File
4391       */
4392      var $file;
4393  
4394      /**
4395       * Create an instance of the class with the input file
4396       *
4397       * @param SimplePie_Content_Type_Sniffer $file Input file
4398       */
4399  	public function __construct($file)
4400      {
4401          $this->file = $file;
4402      }
4403  
4404      /**
4405       * Get the Content-Type of the specified file
4406       *
4407       * @return string Actual Content-Type
4408       */
4409  	public function get_type()
4410      {
4411          if (isset($this->file->headers['content-type']))
4412          {
4413              if (!isset($this->file->headers['content-encoding'])
4414                  && ($this->file->headers['content-type'] === 'text/plain'
4415                      || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
4416                      || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
4417                      || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
4418              {
4419                  return $this->text_or_binary();
4420              }
4421  
4422              if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
4423              {
4424                  $official = substr($this->file->headers['content-type'], 0, $pos);
4425              }
4426              else
4427              {
4428                  $official = $this->file->headers['content-type'];
4429              }
4430              $official = trim(strtolower($official));
4431  
4432              if ($official === 'unknown/unknown'
4433                  || $official === 'application/unknown')
4434              {
4435                  return $this->unknown();
4436              }
4437              elseif (substr($official, -4) === '+xml'
4438                  || $official === 'text/xml'
4439                  || $official === 'application/xml')
4440              {
4441                  return $official;
4442              }
4443              elseif (substr($official, 0, 6) === 'image/')
4444              {
4445                  if ($return = $this->image())
4446                  {
4447                      return $return;
4448                  }
4449                  else
4450                  {
4451                      return $official;
4452                  }
4453              }
4454              elseif ($official === 'text/html')
4455              {
4456                  return $this->feed_or_html();
4457              }
4458              else
4459              {
4460                  return $official;
4461              }
4462          }
4463          else
4464          {
4465              return $this->unknown();
4466          }
4467      }
4468  
4469      /**
4470       * Sniff text or binary
4471       *
4472       * @return string Actual Content-Type
4473       */
4474  	public function text_or_binary()
4475      {
4476          if (substr($this->file->body, 0, 2) === "\xFE\xFF"
4477              || substr($this->file->body, 0, 2) === "\xFF\xFE"
4478              || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
4479              || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
4480          {
4481              return 'text/plain';
4482          }
4483          elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
4484          {
4485              return 'application/octect-stream';
4486          }
4487          else
4488          {
4489              return 'text/plain';
4490          }
4491      }
4492  
4493      /**
4494       * Sniff unknown
4495       *
4496       * @return string Actual Content-Type
4497       */
4498  	public function unknown()
4499      {
4500          $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
4501          if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
4502              || strtolower(substr($this->file->body, $ws, 5)) === '<html'
4503              || strtolower(substr($this->file->body, $ws, 7)) === '<script')
4504          {
4505              return 'text/html';
4506          }
4507          elseif (substr($this->file->body, 0, 5) === '%PDF-')
4508          {
4509              return 'application/pdf';
4510          }
4511          elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
4512          {
4513              return 'application/postscript';
4514          }
4515          elseif (substr($this->file->body, 0, 6) === 'GIF87a'
4516              || substr($this->file->body, 0, 6) === 'GIF89a')
4517          {
4518              return 'image/gif';
4519          }
4520          elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4521          {
4522              return 'image/png';
4523          }
4524          elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4525          {
4526              return 'image/jpeg';
4527          }
4528          elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4529          {
4530              return 'image/bmp';
4531          }
4532          elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4533          {
4534              return 'image/vnd.microsoft.icon';
4535          }
4536          else
4537          {
4538              return $this->text_or_binary();
4539          }
4540      }
4541  
4542      /**
4543       * Sniff images
4544       *
4545       * @return string Actual Content-Type
4546       */
4547  	public function image()
4548      {
4549          if (substr($this->file->body, 0, 6) === 'GIF87a'
4550              || substr($this->file->body, 0, 6) === 'GIF89a')
4551          {
4552              return 'image/gif';
4553          }
4554          elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
4555          {
4556              return 'image/png';
4557          }
4558          elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
4559          {
4560              return 'image/jpeg';
4561          }
4562          elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
4563          {
4564              return 'image/bmp';
4565          }
4566          elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
4567          {
4568              return 'image/vnd.microsoft.icon';
4569          }
4570          else
4571          {
4572              return false;
4573          }
4574      }
4575  
4576      /**
4577       * Sniff HTML
4578       *
4579       * @return string Actual Content-Type
4580       */
4581  	public function feed_or_html()
4582      {
4583          $len = strlen($this->file->body);
4584          $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
4585  
4586          while ($pos < $len)
4587          {
4588              switch ($this->file->body[$pos])
4589              {
4590                  case "\x09":
4591                  case "\x0A":
4592                  case "\x0D":
4593                  case "\x20":
4594                      $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
4595                      continue 2;
4596  
4597                  case '<':
4598                      $pos++;
4599                      break;
4600  
4601                  default:
4602                      return 'text/html';
4603              }
4604  
4605              if (substr($this->file->body, $pos, 3) === '!--')
4606              {
4607                  $pos += 3;
4608                  if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
4609                  {
4610                      $pos += 3;
4611                  }
4612                  else
4613                  {
4614                      return 'text/html';
4615                  }
4616              }
4617              elseif (substr($this->file->body, $pos, 1) === '!')
4618              {
4619                  if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
4620                  {
4621                      $pos++;
4622                  }
4623                  else
4624                  {
4625                      return 'text/html';
4626                  }
4627              }
4628              elseif (substr($this->file->body, $pos, 1) === '?')
4629              {
4630                  if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
4631                  {
4632                      $pos += 2;
4633                  }
4634                  else
4635                  {
4636                      return 'text/html';
4637                  }
4638              }
4639              elseif (substr($this->file->body, $pos, 3) === 'rss'
4640                  || substr($this->file->body, $pos, 7) === 'rdf:RDF')
4641              {
4642                  return 'application/rss+xml';
4643              }
4644              elseif (substr($this->file->body, $pos, 4) === 'feed')
4645              {
4646                  return 'application/atom+xml';
4647              }
4648              else
4649              {
4650                  return 'text/html';
4651              }
4652          }
4653  
4654          return 'text/html';
4655      }
4656  }
4657  
4658  /**
4659   * Manages `<media:copyright>` copyright tags as defined in Media RSS
4660   *
4661   * Used by {@see SimplePie_Enclosure::get_copyright()}
4662   *
4663   * This class can be overloaded with {@see SimplePie::set_copyright_class()}
4664   *
4665   * @package SimplePie
4666   * @subpackage API
4667   */
4668  class SimplePie_Copyright
4669  {
4670      /**
4671       * Copyright URL
4672       *
4673       * @var string
4674       * @see get_url()
4675       */
4676      var $url;
4677  
4678      /**
4679       * Attribution
4680       *
4681       * @var string
4682       * @see get_attribution()
4683       */
4684      var $label;
4685  
4686      /**
4687       * Constructor, used to input the data
4688       *
4689       * For documentation on all the parameters, see the corresponding
4690       * properties and their accessors
4691       */
4692  	public function __construct($url = null, $label = null)
4693      {
4694          $this->url = $url;
4695          $this->label = $label;
4696      }
4697  
4698      /**
4699       * String-ified version
4700       *
4701       * @return string
4702       */
4703  	public function __toString()
4704      {
4705          // There is no $this->data here
4706          return md5(serialize($this));
4707      }
4708  
4709      /**
4710       * Get the copyright URL
4711       *
4712       * @return string|null URL to copyright information
4713       */
4714  	public function get_url()
4715      {
4716          if ($this->url !== null)
4717          {
4718              return $this->url;
4719          }
4720          else
4721          {
4722              return null;
4723          }
4724      }
4725  
4726      /**
4727       * Get the attribution text
4728       *
4729       * @return string|null
4730       */
4731  	public function get_attribution()
4732      {
4733          if ($this->label !== null)
4734          {
4735              return $this->label;
4736          }
4737          else
4738          {
4739              return null;
4740          }
4741      }
4742  }
4743  
4744  /**
4745   * SimplePie class.
4746   *
4747   * Class for backward compatibility.
4748   *
4749   * @deprecated Use {@see SimplePie} directly
4750   * @package SimplePie
4751   * @subpackage API
4752   */
4753  class SimplePie_Core extends SimplePie
4754  {
4755  
4756  }
4757  
4758  /**
4759   * Handles `<media:credit>` as defined in Media RSS
4760   *
4761   * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
4762   *
4763   * This class can be overloaded with {@see SimplePie::set_credit_class()}
4764   *
4765   * @package SimplePie
4766   * @subpackage API
4767   */
4768  class SimplePie_Credit
4769  {
4770      /**
4771       * Credited role
4772       *
4773       * @var string
4774       * @see get_role()
4775       */
4776      var $role;
4777  
4778      /**
4779       * Organizational scheme
4780       *
4781       * @var string
4782       * @see get_scheme()
4783       */
4784      var $scheme;
4785  
4786      /**
4787       * Credited name
4788       *
4789       * @var string
4790       * @see get_name()
4791       */
4792      var $name;
4793  
4794      /**
4795       * Constructor, used to input the data
4796       *
4797       * For documentation on all the parameters, see the corresponding
4798       * properties and their accessors
4799       */
4800  	public function __construct($role = null, $scheme = null, $name = null)
4801      {
4802          $this->role = $role;
4803          $this->scheme = $scheme;
4804          $this->name = $name;
4805      }
4806  
4807      /**
4808       * String-ified version
4809       *
4810       * @return string
4811       */
4812  	public function __toString()
4813      {
4814          // There is no $this->data here
4815          return md5(serialize($this));
4816      }
4817  
4818      /**
4819       * Get the role of the person receiving credit
4820       *
4821       * @return string|null
4822       */
4823  	public function get_role()
4824      {
4825          if ($this->role !== null)
4826          {
4827              return $this->role;
4828          }
4829          else
4830          {
4831              return null;
4832          }
4833      }
4834  
4835      /**
4836       * Get the organizational scheme
4837       *
4838       * @return string|null
4839       */
4840  	public function get_scheme()
4841      {
4842          if ($this->scheme !== null)
4843          {
4844              return $this->scheme;
4845          }
4846          else
4847          {
4848              return null;
4849          }
4850      }
4851  
4852      /**
4853       * Get the credited person/entity's name
4854       *
4855       * @return string|null
4856       */
4857  	public function get_name()
4858      {
4859          if ($this->name !== null)
4860          {
4861              return $this->name;
4862          }
4863          else
4864          {
4865              return null;
4866          }
4867      }
4868  }
4869  
4870  /**
4871   * Decode HTML Entities
4872   *
4873   * This implements HTML5 as of revision 967 (2007-06-28)
4874   *
4875   * @deprecated Use DOMDocument instead!
4876   * @package SimplePie
4877   */
4878  class SimplePie_Decode_HTML_Entities
4879  {
4880      /**
4881       * Data to be parsed
4882       *
4883       * @access private
4884       * @var string
4885       */
4886      var $data = '';
4887  
4888      /**
4889       * Currently consumed bytes
4890       *
4891       * @access private
4892       * @var string
4893       */
4894      var $consumed = '';
4895  
4896      /**
4897       * Position of the current byte being parsed
4898       *
4899       * @access private
4900       * @var int
4901       */
4902      var $position = 0;
4903  
4904      /**
4905       * Create an instance of the class with the input data
4906       *
4907       * @access public
4908       * @param string $data Input data
4909       */
4910  	public function __construct($data)
4911      {
4912          $this->data = $data;
4913      }
4914  
4915      /**
4916       * Parse the input data
4917       *
4918       * @access public
4919       * @return string Output data
4920       */
4921  	public function parse()
4922      {
4923          while (($this->position = strpos($this->data, '&', $this->position)) !== false)
4924          {
4925              $this->consume();
4926              $this->entity();
4927              $this->consumed = '';
4928          }
4929          return $this->data;
4930      }
4931  
4932      /**
4933       * Consume the next byte
4934       *
4935       * @access private
4936       * @return mixed The next byte, or false, if there is no more data
4937       */
4938  	public function consume()
4939      {
4940          if (isset($this->data[$this->position]))
4941          {
4942              $this->consumed .= $this->data[$this->position];
4943              return $this->data[$this->position++];
4944          }
4945          else
4946          {
4947              return false;
4948          }
4949      }
4950  
4951      /**
4952       * Consume a range of characters
4953       *
4954       * @access private
4955       * @param string $chars Characters to consume
4956       * @return mixed A series of characters that match the range, or false
4957       */
4958  	public function consume_range($chars)
4959      {
4960          if ($len = strspn($this->data, $chars, $this->position))
4961          {
4962              $data = substr($this->data, $this->position, $len);
4963              $this->consumed .= $data;
4964              $this->position += $len;
4965              return $data;
4966          }
4967          else
4968          {
4969              return false;
4970          }
4971      }
4972  
4973      /**
4974       * Unconsume one byte
4975       *
4976       * @access private
4977       */
4978  	public function unconsume()
4979      {
4980          $this->consumed = substr($this->consumed, 0, -1);
4981          $this->position--;
4982      }
4983  
4984      /**
4985       * Decode an entity
4986       *
4987       * @access private
4988       */
4989  	public function entity()
4990      {
4991          switch ($this->consume())
4992          {
4993              case "\x09":
4994              case "\x0A":
4995              case "\x0B":
4996              case "\x0B":
4997              case "\x0C":
4998              case "\x20":
4999              case "\x3C":
5000              case "\x26":
5001              case false:
5002                  break;
5003  
5004              case "\x23":
5005                  switch ($this->consume())
5006                  {
5007                      case "\x78":
5008                      case "\x58":
5009                          $range = '0123456789ABCDEFabcdef';
5010                          $hex = true;
5011                          break;
5012  
5013                      default:
5014                          $range = '0123456789';
5015                          $hex = false;
5016                          $this->unconsume();
5017                          break;
5018                  }
5019  
5020                  if ($codepoint = $this->consume_range($range))
5021                  {
5022                      static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
5023  
5024                      if ($hex)
5025                      {
5026                          $codepoint = hexdec($codepoint);
5027                      }
5028                      else
5029                      {
5030                          $codepoint = intval($codepoint);
5031                      }
5032  
5033                      if (isset($windows_1252_specials[$codepoint]))
5034                      {
5035                          $replacement = $windows_1252_specials[$codepoint];
5036                      }
5037                      else
5038                      {
5039                          $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
5040                      }
5041  
5042                      if (!in_array($this->consume(), array(';', false), true))
5043                      {
5044                          $this->unconsume();
5045                      }
5046  
5047                      $consumed_length = strlen($this->consumed);
5048                      $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
5049                      $this->position += strlen($replacement) - $consumed_length;
5050                  }
5051                  break;
5052  
5053              default:
5054                  static $entities = array(
5055                      'Aacute' => "\xC3\x81",
5056                      'aacute' => "\xC3\xA1",
5057                      'Aacute;' => "\xC3\x81",
5058                      'aacute;' => "\xC3\xA1",
5059                      'Acirc' => "\xC3\x82",
5060                      'acirc' => "\xC3\xA2",
5061                      'Acirc;' => "\xC3\x82",
5062                      'acirc;' => "\xC3\xA2",
5063                      'acute' => "\xC2\xB4",
5064                      'acute;' => "\xC2\xB4",
5065                      'AElig' => "\xC3\x86",
5066                      'aelig' => "\xC3\xA6",
5067                      'AElig;' => "\xC3\x86",
5068                      'aelig;' => "\xC3\xA6",
5069                      'Agrave' => "\xC3\x80",
5070                      'agrave' => "\xC3\xA0",
5071                      'Agrave;' => "\xC3\x80",
5072                      'agrave;' => "\xC3\xA0",
5073                      'alefsym;' => "\xE2\x84\xB5",
5074                      'Alpha;' => "\xCE\x91",
5075                      'alpha;' => "\xCE\xB1",
5076                      'AMP' => "\x26",
5077                      'amp' => "\x26",
5078                      'AMP;' => "\x26",
5079                      'amp;' => "\x26",
5080                      'and;' => "\xE2\x88\xA7",
5081                      'ang;' => "\xE2\x88\xA0",
5082                      'apos;' => "\x27",
5083                      'Aring' => "\xC3\x85",
5084                      'aring' => "\xC3\xA5",
5085                      'Aring;' => "\xC3\x85",
5086                      'aring;' => "\xC3\xA5",
5087                      'asymp;' => "\xE2\x89\x88",
5088                      'Atilde' => "\xC3\x83",
5089                      'atilde' => "\xC3\xA3",
5090                      'Atilde;' => "\xC3\x83",
5091                      'atilde;' => "\xC3\xA3",
5092                      'Auml' => "\xC3\x84",
5093                      'auml' => "\xC3\xA4",
5094                      'Auml;' => "\xC3\x84",
5095                      'auml;' => "\xC3\xA4",
5096                      'bdquo;' => "\xE2\x80\x9E",
5097                      'Beta;' => "\xCE\x92",
5098                      'beta;' => "\xCE\xB2",
5099                      'brvbar' => "\xC2\xA6",
5100                      'brvbar;' => "\xC2\xA6",
5101                      'bull;' => "\xE2\x80\xA2",
5102                      'cap;' => "\xE2\x88\xA9",
5103                      'Ccedil' => "\xC3\x87",
5104                      'ccedil' => "\xC3\xA7",
5105                      'Ccedil;' => "\xC3\x87",
5106                      'ccedil;' => "\xC3\xA7",
5107                      'cedil' => "\xC2\xB8",
5108                      'cedil;' => "\xC2\xB8",
5109                      'cent' => "\xC2\xA2",
5110                      'cent;' => "\xC2\xA2",
5111                      'Chi;' => "\xCE\xA7",
5112                      'chi;' => "\xCF\x87",
5113                      'circ;' => "\xCB\x86",
5114                      'clubs;' => "\xE2\x99\xA3",
5115                      'cong;' => "\xE2\x89\x85",
5116                      'COPY' => "\xC2\xA9",
5117                      'copy' => "\xC2\xA9",
5118                      'COPY;' => "\xC2\xA9",
5119                      'copy;' => "\xC2\xA9",
5120                      'crarr;' => "\xE2\x86\xB5",
5121                      'cup;' => "\xE2\x88\xAA",
5122                      'curren' => "\xC2\xA4",
5123                      'curren;' => "\xC2\xA4",
5124                      'Dagger;' => "\xE2\x80\xA1",
5125                      'dagger;' => "\xE2\x80\xA0",
5126                      'dArr;' => "\xE2\x87\x93",
5127                      'darr;' => "\xE2\x86\x93",
5128                      'deg' => "\xC2\xB0",
5129                      'deg;' => "\xC2\xB0",
5130                      'Delta;' => "\xCE\x94",
5131                      'delta;' => "\xCE\xB4",
5132                      'diams;' => "\xE2\x99\xA6",
5133                      'divide' => "\xC3\xB7",
5134                      'divide;' => "\xC3\xB7",
5135                      'Eacute' => "\xC3\x89",
5136                      'eacute' => "\xC3\xA9",
5137                      'Eacute;' => "\xC3\x89",
5138                      'eacute;' => "\xC3\xA9",
5139                      'Ecirc' => "\xC3\x8A",
5140                      'ecirc' => "\xC3\xAA",
5141                      'Ecirc;' => "\xC3\x8A",
5142                      'ecirc;' => "\xC3\xAA",
5143                      'Egrave' => "\xC3\x88",
5144                      'egrave' => "\xC3\xA8",
5145                      'Egrave;' => "\xC3\x88",
5146                      'egrave;' => "\xC3\xA8",
5147                      'empty;' => "\xE2\x88\x85",
5148                      'emsp;' => "\xE2\x80\x83",
5149                      'ensp;' => "\xE2\x80\x82",
5150                      'Epsilon;' => "\xCE\x95",
5151                      'epsilon;' => "\xCE\xB5",
5152                      'equiv;' => "\xE2\x89\xA1",
5153                      'Eta;' => "\xCE\x97",
5154                      'eta;' => "\xCE\xB7",
5155                      'ETH' => "\xC3\x90",
5156                      'eth' => "\xC3\xB0",
5157                      'ETH;' => "\xC3\x90",
5158                      'eth;' => "\xC3\xB0",
5159                      'Euml' => "\xC3\x8B",
5160                      'euml' => "\xC3\xAB",
5161                      'Euml;' => "\xC3\x8B",
5162                      'euml;' => "\xC3\xAB",
5163                      'euro;' => "\xE2\x82\xAC",
5164                      'exist;' => "\xE2\x88\x83",
5165                      'fnof;' => "\xC6\x92",
5166                      'forall;' => "\xE2\x88\x80",
5167                      'frac12' => "\xC2\xBD",
5168                      'frac12;' => "\xC2\xBD",
5169                      'frac14' => "\xC2\xBC",
5170                      'frac14;' => "\xC2\xBC",
5171                      'frac34' => "\xC2\xBE",
5172                      'frac34;' => "\xC2\xBE",
5173                      'frasl;' => "\xE2\x81\x84",
5174                      'Gamma;' => "\xCE\x93",
5175                      'gamma;' => "\xCE\xB3",
5176                      'ge;' => "\xE2\x89\xA5",
5177                      'GT' => "\x3E",
5178                      'gt' => "\x3E",
5179                      'GT;' => "\x3E",
5180                      'gt;' => "\x3E",
5181                      'hArr;' => "\xE2\x87\x94",
5182                      'harr;' => "\xE2\x86\x94",
5183                      'hearts;' => "\xE2\x99\xA5",
5184                      'hellip;' => "\xE2\x80\xA6",
5185                      'Iacute' => "\xC3\x8D",
5186                      'iacute' => "\xC3\xAD",
5187                      'Iacute;' => "\xC3\x8D",
5188                      'iacute;' => "\xC3\xAD",
5189                      'Icirc' => "\xC3\x8E",
5190                      'icirc' => "\xC3\xAE",
5191                      'Icirc;' => "\xC3\x8E",
5192                      'icirc;' => "\xC3\xAE",
5193                      'iexcl' => "\xC2\xA1",
5194                      'iexcl;' => "\xC2\xA1",
5195                      'Igrave' => "\xC3\x8C",
5196                      'igrave' => "\xC3\xAC",
5197                      'Igrave;' => "\xC3\x8C",
5198                      'igrave;' => "\xC3\xAC",
5199                      'image;' => "\xE2\x84\x91",
5200                      'infin;' => "\xE2\x88\x9E",
5201                      'int;' => "\xE2\x88\xAB",
5202                      'Iota;' => "\xCE\x99",
5203                      'iota;' => "\xCE\xB9",
5204                      'iquest' => "\xC2\xBF",
5205                      'iquest;' => "\xC2\xBF",
5206                      'isin;' => "\xE2\x88\x88",
5207                      'Iuml' => "\xC3\x8F",
5208                      'iuml' => "\xC3\xAF",
5209                      'Iuml;' => "\xC3\x8F",
5210                      'iuml;' => "\xC3\xAF",
5211                      'Kappa;' => "\xCE\x9A",
5212                      'kappa;' => "\xCE\xBA",
5213                      'Lambda;' => "\xCE\x9B",
5214                      'lambda;' => "\xCE\xBB",
5215                      'lang;' => "\xE3\x80\x88",
5216                      'laquo' => "\xC2\xAB",
5217                      'laquo;' => "\xC2\xAB",
5218                      'lArr;' => "\xE2\x87\x90",
5219                      'larr;' => "\xE2\x86\x90",
5220                      'lceil;' => "\xE2\x8C\x88",
5221                      'ldquo;' => "\xE2\x80\x9C",
5222                      'le;' => "\xE2\x89\xA4",
5223                      'lfloor;' => "\xE2\x8C\x8A",
5224                      'lowast;' => "\xE2\x88\x97",
5225                      'loz;' => "\xE2\x97\x8A",
5226                      'lrm;' => "\xE2\x80\x8E",
5227                      'lsaquo;' => "\xE2\x80\xB9",
5228                      'lsquo;' => "\xE2\x80\x98",
5229                      'LT' => "\x3C",
5230                      'lt' => "\x3C",
5231                      'LT;' => "\x3C",
5232                      'lt;' => "\x3C",
5233                      'macr' => "\xC2\xAF",
5234                      'macr;' => "\xC2\xAF",
5235                      'mdash;' => "\xE2\x80\x94",
5236                      'micro' => "\xC2\xB5",
5237                      'micro;' => "\xC2\xB5",
5238                      'middot' => "\xC2\xB7",
5239                      'middot;' => "\xC2\xB7",
5240                      'minus;' => "\xE2\x88\x92",
5241                      'Mu;' => "\xCE\x9C",
5242                      'mu;' => "\xCE\xBC",
5243                      'nabla;' => "\xE2\x88\x87",
5244                      'nbsp' => "\xC2\xA0",
5245                      'nbsp;' => "\xC2\xA0",
5246                      'ndash;' => "\xE2\x80\x93",
5247                      'ne;' => "\xE2\x89\xA0",
5248                      'ni;' => "\xE2\x88\x8B",
5249                      'not' => "\xC2\xAC",
5250                      'not;' => "\xC2\xAC",
5251                      'notin;' => "\xE2\x88\x89",
5252                      'nsub;' => "\xE2\x8A\x84",
5253                      'Ntilde' => "\xC3\x91",
5254                      'ntilde' => "\xC3\xB1",
5255                      'Ntilde;' => "\xC3\x91",
5256                      'ntilde;' => "\xC3\xB1",
5257                      'Nu;' => "\xCE\x9D",
5258                      'nu;' => "\xCE\xBD",
5259                      'Oacute' => "\xC3\x93",
5260                      'oacute' => "\xC3\xB3",
5261                      'Oacute;' => "\xC3\x93",
5262                      'oacute;' => "\xC3\xB3",
5263                      'Ocirc' => "\xC3\x94",
5264                      'ocirc' => "\xC3\xB4",
5265                      'Ocirc;' => "\xC3\x94",
5266                      'ocirc;' => "\xC3\xB4",
5267                      'OElig;' => "\xC5\x92",
5268                      'oelig;' => "\xC5\x93",
5269                      'Ograve' => "\xC3\x92",
5270                      'ograve' => "\xC3\xB2",
5271                      'Ograve;' => "\xC3\x92",
5272                      'ograve;' => "\xC3\xB2",
5273                      'oline;' => "\xE2\x80\xBE",
5274                      'Omega;' => "\xCE\xA9",
5275                      'omega;' => "\xCF\x89",
5276                      'Omicron;' => "\xCE\x9F",
5277                      'omicron;' => "\xCE\xBF",
5278                      'oplus;' => "\xE2\x8A\x95",
5279                      'or;' => "\xE2\x88\xA8",
5280                      'ordf' => "\xC2\xAA",
5281                      'ordf;' => "\xC2\xAA",
5282                      'ordm' => "\xC2\xBA",
5283                      'ordm;' => "\xC2\xBA",
5284                      'Oslash' => "\xC3\x98",
5285                      'oslash' => "\xC3\xB8",
5286                      'Oslash;' => "\xC3\x98",
5287                      'oslash;' => "\xC3\xB8",
5288                      'Otilde' => "\xC3\x95",
5289                      'otilde' => "\xC3\xB5",
5290                      'Otilde;' => "\xC3\x95",
5291                      'otilde;' => "\xC3\xB5",
5292                      'otimes;' => "\xE2\x8A\x97",
5293                      'Ouml' => "\xC3\x96",
5294                      'ouml' => "\xC3\xB6",
5295                      'Ouml;' => "\xC3\x96",
5296                      'ouml;' => "\xC3\xB6",
5297                      'para' => "\xC2\xB6",
5298                      'para;' => "\xC2\xB6",
5299                      'part;' => "\xE2\x88\x82",
5300                      'permil;' => "\xE2\x80\xB0",
5301                      'perp;' => "\xE2\x8A\xA5",
5302                      'Phi;' => "\xCE\xA6",
5303                      'phi;' => "\xCF\x86",
5304                      'Pi;' => "\xCE\xA0",
5305                      'pi;' => "\xCF\x80",
5306                      'piv;' => "\xCF\x96",
5307                      'plusmn' => "\xC2\xB1",
5308                      'plusmn;' => "\xC2\xB1",
5309                      'pound' => "\xC2\xA3",
5310                      'pound;' => "\xC2\xA3",
5311                      'Prime;' => "\xE2\x80\xB3",
5312                      'prime;' => "\xE2\x80\xB2",
5313                      'prod;' => "\xE2\x88\x8F",
5314                      'prop;' => "\xE2\x88\x9D",
5315                      'Psi;' => "\xCE\xA8",
5316                      'psi;' => "\xCF\x88",
5317                      'QUOT' => "\x22",
5318                      'quot' => "\x22",
5319                      'QUOT;' => "\x22",
5320                      'quot;' => "\x22",
5321                      'radic;' => "\xE2\x88\x9A",
5322                      'rang;' => "\xE3\x80\x89",
5323                      'raquo' => "\xC2\xBB",
5324                      'raquo;' => "\xC2\xBB",
5325                      'rArr;' => "\xE2\x87\x92",
5326                      'rarr;' => "\xE2\x86\x92",
5327                      'rceil;' => "\xE2\x8C\x89",
5328                      'rdquo;' => "\xE2\x80\x9D",
5329                      'real;' => "\xE2\x84\x9C",
5330                      'REG' => "\xC2\xAE",
5331                      'reg' => "\xC2\xAE",
5332                      'REG;' => "\xC2\xAE",
5333                      'reg;' => "\xC2\xAE",
5334                      'rfloor;' => "\xE2\x8C\x8B",
5335                      'Rho;' => "\xCE\xA1",
5336                      'rho;' => "\xCF\x81",
5337                      'rlm;' => "\xE2\x80\x8F",
5338                      'rsaquo;' => "\xE2\x80\xBA",
5339                      'rsquo;' => "\xE2\x80\x99",
5340                      'sbquo;' => "\xE2\x80\x9A",
5341                      'Scaron;' => "\xC5\xA0",
5342                      'scaron;' => "\xC5\xA1",
5343                      'sdot;' => "\xE2\x8B\x85",
5344                      'sect' => "\xC2\xA7",
5345                      'sect;' => "\xC2\xA7",
5346                      'shy' => "\xC2\xAD",
5347                      'shy;' => "\xC2\xAD",
5348                      'Sigma;' => "\xCE\xA3",
5349                      'sigma;' => "\xCF\x83",
5350                      'sigmaf;' => "\xCF\x82",
5351                      'sim;' => "\xE2\x88\xBC",
5352                      'spades;' => "\xE2\x99\xA0",
5353                      'sub;' => "\xE2\x8A\x82",
5354                      'sube;' => "\xE2\x8A\x86",
5355                      'sum;' => "\xE2\x88\x91",
5356                      'sup;' => "\xE2\x8A\x83",
5357                      'sup1' => "\xC2\xB9",
5358                      'sup1;' => "\xC2\xB9",
5359                      'sup2' => "\xC2\xB2",
5360                      'sup2;' => "\xC2\xB2",
5361                      'sup3' => "\xC2\xB3",
5362                      'sup3;' => "\xC2\xB3",
5363                      'supe;' => "\xE2\x8A\x87",
5364                      'szlig' => "\xC3\x9F",
5365                      'szlig;' => "\xC3\x9F",
5366                      'Tau;' => "\xCE\xA4",
5367                      'tau;' => "\xCF\x84",
5368                      'there4;' => "\xE2\x88\xB4",
5369                      'Theta;' => "\xCE\x98",
5370                      'theta;' => "\xCE\xB8",
5371                      'thetasym;' => "\xCF\x91",
5372                      'thinsp;' => "\xE2\x80\x89",
5373                      'THORN' => "\xC3\x9E",
5374                      'thorn' => "\xC3\xBE",
5375                      'THORN;' => "\xC3\x9E",
5376                      'thorn;' => "\xC3\xBE",
5377                      'tilde;' => "\xCB\x9C",
5378                      'times' => "\xC3\x97",
5379                      'times;' => "\xC3\x97",
5380                      'TRADE;' => "\xE2\x84\xA2",
5381                      'trade;' => "\xE2\x84\xA2",
5382                      'Uacute' => "\xC3\x9A",
5383                      'uacute' => "\xC3\xBA",
5384                      'Uacute;' => "\xC3\x9A",
5385                      'uacute;' => "\xC3\xBA",
5386                      'uArr;' => "\xE2\x87\x91",
5387                      'uarr;' => "\xE2\x86\x91",
5388                      'Ucirc' => "\xC3\x9B",
5389                      'ucirc' => "\xC3\xBB",
5390                      'Ucirc;' => "\xC3\x9B",
5391                      'ucirc;' => "\xC3\xBB",
5392                      'Ugrave' => "\xC3\x99",
5393                      'ugrave' => "\xC3\xB9",
5394                      'Ugrave;' => "\xC3\x99",
5395                      'ugrave;' => "\xC3\xB9",
5396                      'uml' => "\xC2\xA8",
5397                      'uml;' => "\xC2\xA8",
5398                      'upsih;' => "\xCF\x92",
5399                      'Upsilon;' => "\xCE\xA5",
5400                      'upsilon;' => "\xCF\x85",
5401                      'Uuml' => "\xC3\x9C",
5402                      'uuml' => "\xC3\xBC",
5403                      'Uuml;' => "\xC3\x9C",
5404                      'uuml;' => "\xC3\xBC",
5405                      'weierp;' => "\xE2\x84\x98",
5406                      'Xi;' => "\xCE\x9E",
5407                      'xi;' => "\xCE\xBE",
5408                      'Yacute' => "\xC3\x9D",
5409                      'yacute' => "\xC3\xBD",
5410                      'Yacute;' => "\xC3\x9D",
5411                      'yacute;' => "\xC3\xBD",
5412                      'yen' => "\xC2\xA5",
5413                      'yen;' => "\xC2\xA5",
5414                      'yuml' => "\xC3\xBF",
5415                      'Yuml;' => "\xC5\xB8",
5416                      'yuml;' => "\xC3\xBF",
5417                      'Zeta;' => "\xCE\x96",
5418                      'zeta;' => "\xCE\xB6",
5419                      'zwj;' => "\xE2\x80\x8D",
5420                      'zwnj;' => "\xE2\x80\x8C"
5421                  );
5422  
5423                  for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
5424                  {
5425                      $consumed = substr($this->consumed, 1);
5426                      if (isset($entities[$consumed]))
5427                      {
5428                          $match = $consumed;
5429                      }
5430                  }
5431  
5432                  if ($match !== null)
5433                  {
5434                       $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
5435                      $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
5436                  }
5437                  break;
5438          }
5439      }
5440  }
5441  
5442  /**
5443   * Handles everything related to enclosures (including Media RSS and iTunes RSS)
5444   *
5445   * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
5446   *
5447   * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
5448   *
5449   * @package SimplePie
5450   * @subpackage API
5451   */
5452  class SimplePie_Enclosure
5453  {
5454      /**
5455       * @var string
5456       * @see get_bitrate()
5457       */
5458      var $bitrate;
5459  
5460      /**
5461       * @var array
5462       * @see get_captions()
5463       */
5464      var $captions;
5465  
5466      /**
5467       * @var array
5468       * @see get_categories()
5469       */
5470      var $categories;
5471  
5472      /**
5473       * @var int
5474       * @see get_channels()
5475       */
5476      var $channels;
5477  
5478      /**
5479       * @var SimplePie_Copyright
5480       * @see get_copyright()
5481       */
5482      var $copyright;
5483  
5484      /**
5485       * @var array
5486       * @see get_credits()
5487       */
5488      var $credits;
5489  
5490      /**
5491       * @var string
5492       * @see get_description()
5493       */
5494      var $description;
5495  
5496      /**
5497       * @var int
5498       * @see get_duration()
5499       */
5500      var $duration;
5501  
5502      /**
5503       * @var string
5504       * @see get_expression()
5505       */
5506      var $expression;
5507  
5508      /**
5509       * @var string
5510       * @see get_framerate()
5511       */
5512      var $framerate;
5513  
5514      /**
5515       * @var string
5516       * @see get_handler()
5517       */
5518      var $handler;
5519  
5520      /**
5521       * @var array
5522       * @see get_hashes()
5523       */
5524      var $hashes;
5525  
5526      /**
5527       * @var string
5528       * @see get_height()
5529       */
5530      var $height;
5531  
5532      /**
5533       * @deprecated
5534       * @var null
5535       */
5536      var $javascript;
5537  
5538      /**
5539       * @var array
5540       * @see get_keywords()
5541       */
5542      var $keywords;
5543  
5544      /**
5545       * @var string
5546       * @see get_language()
5547       */
5548      var $lang;
5549  
5550      /**
5551       * @var string
5552       * @see get_length()
5553       */
5554      var $length;
5555  
5556      /**
5557       * @var string
5558       * @see get_link()
5559       */
5560      var $link;
5561  
5562      /**
5563       * @var string
5564       * @see get_medium()
5565       */
5566      var $medium;
5567  
5568      /**
5569       * @var string
5570       * @see get_player()
5571       */
5572      var $player;
5573  
5574      /**
5575       * @var array
5576       * @see get_ratings()
5577       */
5578      var $ratings;
5579  
5580      /**
5581       * @var array
5582       * @see get_restrictions()
5583       */
5584      var $restrictions;
5585  
5586      /**
5587       * @var string
5588       * @see get_sampling_rate()
5589       */
5590      var $samplingrate;
5591  
5592      /**
5593       * @var array
5594       * @see get_thumbnails()
5595       */
5596      var $thumbnails;
5597  
5598      /**
5599       * @var string
5600       * @see get_title()
5601       */
5602      var $title;
5603  
5604      /**
5605       * @var string
5606       * @see get_type()
5607       */
5608      var $type;
5609  
5610      /**
5611       * @var string
5612       * @see get_width()
5613       */
5614      var $width;
5615  
5616      /**
5617       * Constructor, used to input the data
5618       *
5619       * For documentation on all the parameters, see the corresponding
5620       * properties and their accessors
5621       *
5622       * @uses idna_convert If available, this will convert an IDN
5623       */
5624  	public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
5625      {
5626          $this->bitrate = $bitrate;
5627          $this->captions = $captions;
5628          $this->categories = $categories;
5629          $this->channels = $channels;
5630          $this->copyright = $copyright;
5631          $this->credits = $credits;
5632          $this->description = $description;
5633          $this->duration = $duration;
5634          $this->expression = $expression;
5635          $this->framerate = $framerate;
5636          $this->hashes = $hashes;
5637          $this->height = $height;
5638          $this->keywords = $keywords;
5639          $this->lang = $lang;
5640          $this->length = $length;
5641          $this->link = $link;
5642          $this->medium = $medium;
5643          $this->player = $player;
5644          $this->ratings = $ratings;
5645          $this->restrictions = $restrictions;
5646          $this->samplingrate = $samplingrate;
5647          $this->thumbnails = $thumbnails;
5648          $this->title = $title;
5649          $this->type = $type;
5650          $this->width = $width;
5651  
5652          if (class_exists('idna_convert'))
5653          {
5654              $idn = new idna_convert();
5655              $parsed = SimplePie_Misc::parse_url($link);
5656              $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
5657          }
5658          $this->handler = $this->get_handler(); // Needs to load last
5659      }
5660  
5661      /**
5662       * String-ified version
5663       *
5664       * @return string
5665       */
5666  	public function __toString()
5667      {
5668          // There is no $this->data here
5669          return md5(serialize($this));
5670      }
5671  
5672      /**
5673       * Get the bitrate
5674       *
5675       * @return string|null
5676       */
5677  	public function get_bitrate()
5678      {
5679          if ($this->bitrate !== null)
5680          {
5681              return $this->bitrate;
5682          }
5683          else
5684          {
5685              return null;
5686          }
5687      }
5688  
5689      /**
5690       * Get a single caption
5691       *
5692       * @param int $key
5693       * @return SimplePie_Caption|null
5694       */
5695  	public function get_caption($key = 0)
5696      {
5697          $captions = $this->get_captions();
5698          if (isset($captions[$key]))
5699          {
5700              return $captions[$key];
5701          }
5702          else
5703          {
5704              return null;
5705          }
5706      }
5707  
5708      /**
5709       * Get all captions
5710       *
5711       * @return array|null Array of {@see SimplePie_Caption} objects
5712       */
5713  	public function get_captions()
5714      {
5715          if ($this->captions !== null)
5716          {
5717              return $this->captions;
5718          }
5719          else
5720          {
5721              return null;
5722          }
5723      }
5724  
5725      /**
5726       * Get a single category
5727       *
5728       * @param int $key
5729       * @return SimplePie_Category|null
5730       */
5731  	public function get_category($key = 0)
5732      {
5733          $categories = $this->get_categories();
5734          if (isset($categories[$key]))
5735          {
5736              return $categories[$key];
5737          }
5738          else
5739          {
5740              return null;
5741          }
5742      }
5743  
5744      /**
5745       * Get all categories
5746       *
5747       * @return array|null Array of {@see SimplePie_Category} objects
5748       */
5749  	public function get_categories()
5750      {
5751          if ($this->categories !== null)
5752          {
5753              return $this->categories;
5754          }
5755          else
5756          {
5757              return null;
5758          }
5759      }
5760  
5761      /**
5762       * Get the number of audio channels
5763       *
5764       * @return int|null
5765       */
5766  	public function get_channels()
5767      {
5768          if ($this->channels !== null)
5769          {
5770              return $this->channels;
5771          }
5772          else
5773          {
5774              return null;
5775          }
5776      }
5777  
5778      /**
5779       * Get the copyright information
5780       *
5781       * @return SimplePie_Copyright|null
5782       */
5783  	public function get_copyright()
5784      {
5785          if ($this->copyright !== null)
5786          {
5787              return $this->copyright;
5788          }
5789          else
5790          {
5791              return null;
5792          }
5793      }
5794  
5795      /**
5796       * Get a single credit
5797       *
5798       * @param int $key
5799       * @return SimplePie_Credit|null
5800       */
5801  	public function get_credit($key = 0)
5802      {
5803          $credits = $this->get_credits();
5804          if (isset($credits[$key]))
5805          {
5806              return $credits[$key];
5807          }
5808          else
5809          {
5810              return null;
5811          }
5812      }
5813  
5814      /**
5815       * Get all credits
5816       *
5817       * @return array|null Array of {@see SimplePie_Credit} objects
5818       */
5819  	public function get_credits()
5820      {
5821          if ($this->credits !== null)
5822          {
5823              return $this->credits;
5824          }
5825          else
5826          {
5827              return null;
5828          }
5829      }
5830  
5831      /**
5832       * Get the description of the enclosure
5833       *
5834       * @return string|null
5835       */
5836  	public function get_description()
5837      {
5838          if ($this->description !== null)
5839          {
5840              return $this->description;
5841          }
5842          else
5843          {
5844              return null;
5845          }
5846      }
5847  
5848      /**
5849       * Get the duration of the enclosure
5850       *
5851       * @param string $convert Convert seconds into hh:mm:ss
5852       * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
5853       */
5854  	public function get_duration($convert = false)
5855      {
5856          if ($this->duration !== null)
5857          {
5858              if ($convert)
5859              {
5860                  $time = SimplePie_Misc::time_hms($this->duration);
5861                  return $time;
5862              }
5863              else
5864              {
5865                  return $this->duration;
5866              }
5867          }
5868          else
5869          {
5870              return null;
5871          }
5872      }
5873  
5874      /**
5875       * Get the expression
5876       *
5877       * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
5878       */
5879  	public function get_expression()
5880      {
5881          if ($this->expression !== null)
5882          {
5883              return $this->expression;
5884          }
5885          else
5886          {
5887              return 'full';
5888          }
5889      }
5890  
5891      /**
5892       * Get the file extension
5893       *
5894       * @return string|null
5895       */
5896  	public function get_extension()
5897      {
5898          if ($this->link !== null)
5899          {
5900              $url = SimplePie_Misc::parse_url($this->link);
5901              if ($url['path'] !== '')
5902              {
5903                  return pathinfo($url['path'], PATHINFO_EXTENSION);
5904              }
5905          }
5906          return null;
5907      }
5908  
5909      /**
5910       * Get the framerate (in frames-per-second)
5911       *
5912       * @return string|null
5913       */
5914  	public function get_framerate()
5915      {
5916          if ($this->framerate !== null)
5917          {
5918              return $this->framerate;
5919          }
5920          else
5921          {
5922              return null;
5923          }
5924      }
5925  
5926      /**
5927       * Get the preferred handler
5928       *
5929       * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
5930       */
5931  	public function get_handler()
5932      {
5933          return $this->get_real_type(true);
5934      }
5935  
5936      /**
5937       * Get a single hash
5938       *
5939       * @link http://www.rssboard.org/media-rss#media-hash
5940       * @param int $key
5941       * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
5942       */
5943  	public function get_hash($key = 0)
5944      {
5945          $hashes = $this->get_hashes();
5946          if (isset($hashes[$key]))
5947          {
5948              return $hashes[$key];
5949          }
5950          else
5951          {
5952              return null;
5953          }
5954      }
5955  
5956      /**
5957       * Get all credits
5958       *
5959       * @return array|null Array of strings, see {@see get_hash()}
5960       */
5961  	public function get_hashes()
5962      {
5963          if ($this->hashes !== null)
5964          {
5965              return $this->hashes;
5966          }
5967          else
5968          {
5969              return null;
5970          }
5971      }
5972  
5973      /**
5974       * Get the height
5975       *
5976       * @return string|null
5977       */
5978  	public function get_height()
5979      {
5980          if ($this->height !== null)
5981          {
5982              return $this->height;
5983          }
5984          else
5985          {
5986              return null;
5987          }
5988      }
5989  
5990      /**
5991       * Get the language
5992       *
5993       * @link http://tools.ietf.org/html/rfc3066
5994       * @return string|null Language code as per RFC 3066
5995       */
5996  	public function get_language()
5997      {
5998          if ($this->lang !== null)
5999          {
6000              return $this->lang;
6001          }
6002          else
6003          {
6004              return null;
6005          }
6006      }
6007  
6008      /**
6009       * Get a single keyword
6010       *
6011       * @param int $key
6012       * @return string|null
6013       */
6014  	public function get_keyword($key = 0)
6015      {
6016          $keywords = $this->get_keywords();
6017          if (isset($keywords[$key]))
6018          {
6019              return $keywords[$key];
6020          }
6021          else
6022          {
6023              return null;
6024          }
6025      }
6026  
6027      /**
6028       * Get all keywords
6029       *
6030       * @return array|null Array of strings
6031       */
6032  	public function get_keywords()
6033      {
6034          if ($this->keywords !== null)
6035          {
6036              return $this->keywords;
6037          }
6038          else
6039          {
6040              return null;
6041          }
6042      }
6043  
6044      /**
6045       * Get length
6046       *
6047       * @return float Length in bytes
6048       */
6049  	public function get_length()
6050      {
6051          if ($this->length !== null)
6052          {
6053              return $this->length;
6054          }
6055          else
6056          {
6057              return null;
6058          }
6059      }
6060  
6061      /**
6062       * Get the URL
6063       *
6064       * @return string|null
6065       */
6066  	public function get_link()
6067      {
6068          if ($this->link !== null)
6069          {
6070              return urldecode($this->link);
6071          }
6072          else
6073          {
6074              return null;
6075          }
6076      }
6077  
6078      /**
6079       * Get the medium
6080       *
6081       * @link http://www.rssboard.org/media-rss#media-content
6082       * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
6083       */
6084  	public function get_medium()
6085      {
6086          if ($this->medium !== null)
6087          {
6088              return $this->medium;
6089          }
6090          else
6091          {
6092              return null;
6093          }
6094      }
6095  
6096      /**
6097       * Get the player URL
6098       *
6099       * Typically the same as {@see get_permalink()}
6100       * @return string|null Player URL
6101       */
6102  	public function get_player()
6103      {
6104          if ($this->player !== null)
6105          {
6106              return $this->player;
6107          }
6108          else
6109          {
6110              return null;
6111          }
6112      }
6113  
6114      /**
6115       * Get a single rating
6116       *
6117       * @param int $key
6118       * @return SimplePie_Rating|null
6119       */
6120  	public function get_rating($key = 0)
6121      {
6122          $ratings = $this->get_ratings();
6123          if (isset($ratings[$key]))
6124          {
6125              return $ratings[$key];
6126          }
6127          else
6128          {
6129              return null;
6130          }
6131      }
6132  
6133      /**
6134       * Get all ratings
6135       *
6136       * @return array|null Array of {@see SimplePie_Rating} objects
6137       */
6138  	public function get_ratings()
6139      {
6140          if ($this->ratings !== null)
6141          {
6142              return $this->ratings;
6143          }
6144          else
6145          {
6146              return null;
6147          }
6148      }
6149  
6150      /**
6151       * Get a single restriction
6152       *
6153       * @param int $key
6154       * @return SimplePie_Restriction|null
6155       */
6156  	public function get_restriction($key = 0)
6157      {
6158          $restrictions = $this->get_restrictions();
6159          if (isset($restrictions[$key]))
6160          {
6161              return $restrictions[$key];
6162          }
6163          else
6164          {
6165              return null;
6166          }
6167      }
6168  
6169      /**
6170       * Get all restrictions
6171       *
6172       * @return array|null Array of {@see SimplePie_Restriction} objects
6173       */
6174  	public function get_restrictions()
6175      {
6176          if ($this->restrictions !== null)
6177          {
6178              return $this->restrictions;
6179          }
6180          else
6181          {
6182              return null;
6183          }
6184      }
6185  
6186      /**
6187       * Get the sampling rate (in kHz)
6188       *
6189       * @return string|null
6190       */
6191  	public function get_sampling_rate()
6192      {
6193          if ($this->samplingrate !== null)
6194          {
6195              return $this->samplingrate;
6196          }
6197          else
6198          {
6199              return null;
6200          }
6201      }
6202  
6203      /**
6204       * Get the file size (in MiB)
6205       *
6206       * @return float|null File size in mebibytes (1048 bytes)
6207       */
6208  	public function get_size()
6209      {
6210          $length = $this->get_length();
6211          if ($length !== null)
6212          {
6213              return round($length/1048576, 2);
6214          }
6215          else
6216          {
6217              return null;
6218          }
6219      }
6220  
6221      /**
6222       * Get a single thumbnail
6223       *
6224       * @param int $key
6225       * @return string|null Thumbnail URL
6226       */
6227  	public function get_thumbnail($key = 0)
6228      {
6229          $thumbnails = $this->get_thumbnails();
6230          if (isset($thumbnails[$key]))
6231          {
6232              return $thumbnails[$key];
6233          }
6234          else
6235          {
6236              return null;
6237          }
6238      }
6239  
6240      /**
6241       * Get all thumbnails
6242       *
6243       * @return array|null Array of thumbnail URLs
6244       */
6245  	public function get_thumbnails()
6246      {
6247          if ($this->thumbnails !== null)
6248          {
6249              return $this->thumbnails;
6250          }
6251          else
6252          {
6253              return null;
6254          }
6255      }
6256  
6257      /**
6258       * Get the title
6259       *
6260       * @return string|null
6261       */
6262  	public function get_title()
6263      {
6264          if ($this->title !== null)
6265          {
6266              return $this->title;
6267          }
6268          else
6269          {
6270              return null;
6271          }
6272      }
6273  
6274      /**
6275       * Get mimetype of the enclosure
6276       *
6277       * @see get_real_type()
6278       * @return string|null MIME type
6279       */
6280  	public function get_type()
6281      {
6282          if ($this->type !== null)
6283          {
6284              return $this->type;
6285          }
6286          else
6287          {
6288              return null;
6289          }
6290      }
6291  
6292      /**
6293       * Get the width
6294       *
6295       * @return string|null
6296       */
6297  	public function get_width()
6298      {
6299          if ($this->width !== null)
6300          {
6301              return $this->width;
6302          }
6303          else
6304          {
6305              return null;
6306          }
6307      }
6308  
6309      /**
6310       * Embed the enclosure using `<embed>`
6311       *
6312       * @deprecated Use the second parameter to {@see embed} instead
6313       *
6314       * @param array|string $options See first paramter to {@see embed}
6315       * @return string HTML string to output
6316       */
6317  	public function native_embed($options='')
6318      {
6319          return $this->embed($options, true);
6320      }
6321  
6322      /**
6323       * Embed the enclosure using Javascript
6324       *
6325       * `$options` is an array or comma-separated key:value string, with the
6326       * following properties:
6327       *
6328       * - `alt` (string): Alternate content for when an end-user does not have
6329       *    the appropriate handler installed or when a file type is
6330       *    unsupported. Can be any text or HTML. Defaults to blank.
6331       * - `altclass` (string): If a file type is unsupported, the end-user will
6332       *    see the alt text (above) linked directly to the content. That link
6333       *    will have this value as its class name. Defaults to blank.
6334       * - `audio` (string): This is an image that should be used as a
6335       *    placeholder for audio files before they're loaded (QuickTime-only).
6336       *    Can be any relative or absolute URL. Defaults to blank.
6337       * - `bgcolor` (string): The background color for the media, if not
6338       *    already transparent. Defaults to `#ffffff`.
6339       * - `height` (integer): The height of the embedded media. Accepts any
6340       *    numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
6341       *    and it is recommended that you use this default.
6342       * - `loop` (boolean): Do you want the media to loop when its done?
6343       *    Defaults to `false`.
6344       * - `mediaplayer` (string): The location of the included
6345       *    `mediaplayer.swf` file. This allows for the playback of Flash Video
6346       *    (`.flv`) files, and is the default handler for non-Odeo MP3's.
6347       *    Defaults to blank.
6348       * - `video` (string): This is an image that should be used as a
6349       *    placeholder for video files before they're loaded (QuickTime-only).
6350       *    Can be any relative or absolute URL. Defaults to blank.
6351       * - `width` (integer): The width of the embedded media. Accepts any
6352       *    numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
6353       *    and it is recommended that you use this default.
6354       * - `widescreen` (boolean): Is the enclosure widescreen or standard?
6355       *    This applies only to video enclosures, and will automatically resize
6356       *    the content appropriately.  Defaults to `false`, implying 4:3 mode.
6357       *
6358       * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
6359       * will default to 480x360 video resolution.  Widescreen (16:9) mode with
6360       * `width` and `height` set to `auto` will default to 480x270 video resolution.
6361       *
6362       * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
6363       * @param array|string $options Comma-separated key:value list, or array
6364       * @param bool $native Use `<embed>`
6365       * @return string HTML string to output
6366       */
6367  	public function embed($options = '', $native = false)
6368      {
6369          // Set up defaults
6370          $audio = '';
6371          $video = '';
6372          $alt = '';
6373          $altclass = '';
6374          $loop = 'false';
6375          $width = 'auto';
6376          $height = 'auto';
6377          $bgcolor = '#ffffff';
6378          $mediaplayer = '';
6379          $widescreen = false;
6380          $handler = $this->get_handler();
6381          $type = $this->get_real_type();
6382  
6383          // Process options and reassign values as necessary
6384          if (is_array($options))
6385          {
6386              extract($options);
6387          }
6388          else
6389          {
6390              $options = explode(',', $options);
6391              foreach($options as $option)
6392              {
6393                  $opt = explode(':', $option, 2);
6394                  if (isset($opt[0], $opt[1]))
6395                  {
6396                      $opt[0] = trim($opt[0]);
6397                      $opt[1] = trim($opt[1]);
6398                      switch ($opt[0])
6399                      {
6400                          case 'audio':
6401                              $audio = $opt[1];
6402                              break;
6403  
6404                          case 'video':
6405                              $video = $opt[1];
6406                              break;
6407  
6408                          case 'alt':
6409                              $alt = $opt[1];
6410                              break;
6411  
6412                          case 'altclass':
6413                              $altclass = $opt[1];
6414                              break;
6415  
6416                          case 'loop':
6417                              $loop = $opt[1];
6418                              break;
6419  
6420                          case 'width':
6421                              $width = $opt[1];
6422                              break;
6423  
6424                          case 'height':
6425                              $height = $opt[1];
6426                              break;
6427  
6428                          case 'bgcolor':
6429                              $bgcolor = $opt[1];
6430                              break;
6431  
6432                          case 'mediaplayer':
6433                              $mediaplayer = $opt[1];
6434                              break;
6435  
6436                          case 'widescreen':
6437                              $widescreen = $opt[1];
6438                              break;
6439                      }
6440                  }
6441              }
6442          }
6443  
6444          $mime = explode('/', $type, 2);
6445          $mime = $mime[0];
6446  
6447          // Process values for 'auto'
6448          if ($width === 'auto')
6449          {
6450              if ($mime === 'video')
6451              {
6452                  if ($height === 'auto')
6453                  {
6454                      $width = 480;
6455                  }
6456                  elseif ($widescreen)
6457                  {
6458                      $width = round((intval($height)/9)*16);
6459                  }
6460                  else
6461                  {
6462                      $width = round((intval($height)/3)*4);
6463                  }
6464              }
6465              else
6466              {
6467                  $width = '100%';
6468              }
6469          }
6470  
6471          if ($height === 'auto')
6472          {
6473              if ($mime === 'audio')
6474              {
6475                  $height = 0;
6476              }
6477              elseif ($mime === 'video')
6478              {
6479                  if ($width === 'auto')
6480                  {
6481                      if ($widescreen)
6482                      {
6483                          $height = 270;
6484                      }
6485                      else
6486                      {
6487                          $height = 360;
6488                      }
6489                  }
6490                  elseif ($widescreen)
6491                  {
6492                      $height = round((intval($width)/16)*9);
6493                  }
6494                  else
6495                  {
6496                      $height = round((intval($width)/4)*3);
6497                  }
6498              }
6499              else
6500              {
6501                  $height = 376;
6502              }
6503          }
6504          elseif ($mime === 'audio')
6505          {
6506              $height = 0;
6507          }
6508  
6509          // Set proper placeholder value
6510          if ($mime === 'audio')
6511          {
6512              $placeholder = $audio;
6513          }
6514          elseif ($mime === 'video')
6515          {
6516              $placeholder = $video;
6517          }
6518  
6519          $embed = '';
6520  
6521          // Flash
6522          if ($handler === 'flash')
6523          {
6524              if ($native)
6525              {
6526                  $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
6527              }
6528              else
6529              {
6530                  $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
6531              }
6532          }
6533  
6534          // Flash Media Player file types.
6535          // Preferred handler for MP3 file types.
6536          elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
6537          {
6538              $height += 20;
6539              if ($native)
6540              {
6541                  $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
6542              }
6543              else
6544              {
6545                  $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
6546              }
6547          }
6548  
6549          // QuickTime 7 file types.  Need to test with QuickTime 6.
6550          // Only handle MP3's if the Flash Media Player is not present.
6551          elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
6552          {
6553              $height += 16;
6554              if ($native)
6555              {
6556                  if ($placeholder !== '')
6557                  {
6558                      $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
6559                  }
6560                  else
6561                  {
6562                      $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
6563                  }
6564              }
6565              else
6566              {
6567                  $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
6568              }
6569          }
6570  
6571          // Windows Media
6572          elseif ($handler === 'wmedia')
6573          {
6574              $height += 45;
6575              if ($native)
6576              {
6577                  $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
6578              }
6579              else
6580              {
6581                  $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
6582              }
6583          }
6584  
6585          // Everything else
6586          else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
6587  
6588          return $embed;
6589      }
6590  
6591      /**
6592       * Get the real media type
6593       *
6594       * Often, feeds lie to us, necessitating a bit of deeper inspection. This
6595       * converts types to their canonical representations based on the file
6596       * extension
6597       *
6598       * @see get_type()
6599       * @param bool $find_handler Internal use only, use {@see get_handler()} instead
6600       * @return string MIME type
6601       */
6602  	public function get_real_type($find_handler = false)
6603      {
6604          // Mime-types by handler.
6605          $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
6606          $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
6607          $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
6608          $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
6609          $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
6610  
6611          if ($this->get_type() !== null)
6612          {
6613              $type = strtolower($this->type);
6614          }
6615          else
6616          {
6617              $type = null;
6618          }
6619  
6620          // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
6621          if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
6622          {
6623              switch (strtolower($this->get_extension()))
6624              {
6625                  // Audio mime-types
6626                  case 'aac':
6627                  case 'adts':
6628                      $type = 'audio/acc';
6629                      break;
6630  
6631                  case 'aif':
6632                  case 'aifc':
6633                  case 'aiff':
6634                  case 'cdda':
6635                      $type = 'audio/aiff';
6636                      break;
6637  
6638                  case 'bwf':
6639                      $type = 'audio/wav';
6640                      break;
6641  
6642                  case 'kar':
6643                  case 'mid':
6644                  case 'midi':
6645                  case 'smf':
6646                      $type = 'audio/midi';
6647                      break;
6648  
6649                  case 'm4a':
6650                      $type = 'audio/x-m4a';
6651                      break;
6652  
6653                  case 'mp3':
6654                  case 'swa':
6655                      $type = 'audio/mp3';
6656                      break;
6657  
6658                  case 'wav':
6659                      $type = 'audio/wav';
6660                      break;
6661  
6662                  case 'wax':
6663                      $type = 'audio/x-ms-wax';
6664                      break;
6665  
6666                  case 'wma':
6667                      $type = 'audio/x-ms-wma';
6668                      break;
6669  
6670                  // Video mime-types
6671                  case '3gp':
6672                  case '3gpp':
6673                      $type = 'video/3gpp';
6674                      break;
6675  
6676                  case '3g2':
6677                  case '3gp2':
6678                      $type = 'video/3gpp2';
6679                      break;
6680  
6681                  case 'asf':
6682                      $type = 'video/x-ms-asf';
6683                      break;
6684  
6685                  case 'flv':
6686                      $type = 'video/x-flv';
6687                      break;
6688  
6689                  case 'm1a':
6690                  case 'm1s':
6691                  case 'm1v':
6692                  case 'm15':
6693                  case 'm75':
6694                  case 'mp2':
6695                  case 'mpa':
6696                  case 'mpeg':
6697                  case 'mpg':
6698                  case 'mpm':
6699                  case 'mpv':
6700                      $type = 'video/mpeg';
6701                      break;
6702  
6703                  case 'm4v':
6704                      $type = 'video/x-m4v';
6705                      break;
6706  
6707                  case 'mov':
6708                  case 'qt':
6709                      $type = 'video/quicktime';
6710                      break;
6711  
6712                  case 'mp4':
6713                  case 'mpg4':
6714                      $type = 'video/mp4';
6715                      break;
6716  
6717                  case 'sdv':
6718                      $type = 'video/sd-video';
6719                      break;
6720  
6721                  case 'wm':
6722                      $type = 'video/x-ms-wm';
6723                      break;
6724  
6725                  case 'wmv':
6726                      $type = 'video/x-ms-wmv';
6727                      break;
6728  
6729                  case 'wvx':
6730                      $type = 'video/x-ms-wvx';
6731                      break;
6732  
6733                  // Flash mime-types
6734                  case 'spl':
6735                      $type = 'application/futuresplash';
6736                      break;
6737  
6738                  case 'swf':
6739                      $type = 'application/x-shockwave-flash';
6740                      break;
6741              }
6742          }
6743  
6744          if ($find_handler)
6745          {
6746              if (in_array($type, $types_flash))
6747              {
6748                  return 'flash';
6749              }
6750              elseif (in_array($type, $types_fmedia))
6751              {
6752                  return 'fmedia';
6753              }
6754              elseif (in_array($type, $types_quicktime))
6755              {
6756                  return 'quicktime';
6757              }
6758              elseif (in_array($type, $types_wmedia))
6759              {
6760                  return 'wmedia';
6761              }
6762              elseif (in_array($type, $types_mp3))
6763              {
6764                  return 'mp3';
6765              }
6766              else
6767              {
6768                  return null;
6769              }
6770          }
6771          else
6772          {
6773              return $type;
6774          }
6775      }
6776  }
6777  
6778  /**
6779   * General SimplePie exception class
6780   *
6781   * @package SimplePie
6782   */
6783  class SimplePie_Exception extends Exception
6784  {
6785  }
6786  
6787  /**
6788   * Used for fetching remote files and reading local files
6789   *
6790   * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
6791   *
6792   * This class can be overloaded with {@see SimplePie::set_file_class()}
6793   *
6794   * @package SimplePie
6795   * @subpackage HTTP
6796   * @todo Move to properly supporting RFC2616 (HTTP/1.1)
6797   */
6798  class SimplePie_File
6799  {
6800      var $url;
6801      var $useragent;
6802      var $success = true;
6803      var $headers = array();
6804      var $body;
6805      var $status_code;
6806      var $redirects = 0;
6807      var $error;
6808      var $method = SIMPLEPIE_FILE_SOURCE_NONE;
6809  
6810  	public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
6811      {
6812          if (class_exists('idna_convert'))
6813          {
6814              $idn = new idna_convert();
6815              $parsed = SimplePie_Misc::parse_url($url);
6816              $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
6817          }
6818          $this->url = $url;
6819          $this->useragent = $useragent;
6820          if (preg_match('/^http(s)?:\/\//i', $url))
6821          {
6822              if ($useragent === null)
6823              {
6824                  $useragent = ini_get('user_agent');
6825                  $this->useragent = $useragent;
6826              }
6827              if (!is_array($headers))
6828              {
6829                  $headers = array();
6830              }
6831              if (!$force_fsockopen && function_exists('curl_exec'))
6832              {
6833                  $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
6834                  $fp = curl_init();
6835                  $headers2 = array();
6836                  foreach ($headers as $key => $value)
6837                  {
6838                      $headers2[] = "$key: $value";
6839                  }
6840                  if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
6841                  {
6842                      curl_setopt($fp, CURLOPT_ENCODING, '');
6843                  }
6844                  curl_setopt($fp, CURLOPT_URL, $url);
6845                  curl_setopt($fp, CURLOPT_HEADER, 1);
6846                  curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
6847                  curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
6848                  curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
6849                  curl_setopt($fp, CURLOPT_REFERER, $url);
6850                  curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
6851                  curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
6852                  if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
6853                  {
6854                      curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
6855                      curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
6856                  }
6857  
6858                  $this->headers = curl_exec($fp);
6859                  if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
6860                  {
6861                      curl_setopt($fp, CURLOPT_ENCODING, 'none');
6862                      $this->headers = curl_exec($fp);
6863                  }
6864                  if (curl_errno($fp))
6865                  {
6866                      $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
6867                      $this->success = false;
6868                  }
6869                  else
6870                  {
6871                      $info = curl_getinfo($fp);
6872                      curl_close($fp);
6873                      $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
6874                      $this->headers = array_pop($this->headers);
6875                      $parser = new SimplePie_HTTP_Parser($this->headers);
6876                      if ($parser->parse())
6877                      {
6878                          $this->headers = $parser->headers;
6879                          $this->body = $parser->body;
6880                          $this->status_code = $parser->status_code;
6881                          if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
6882                          {
6883                              $this->redirects++;
6884                              $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6885                              return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6886                          }
6887                      }
6888                  }
6889              }
6890              else
6891              {
6892                  $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
6893                  $url_parts = parse_url($url);
6894                  $socket_host = $url_parts['host'];
6895                  if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
6896                  {
6897                      $socket_host = "ssl://$url_parts[host]";
6898                      $url_parts['port'] = 443;
6899                  }
6900                  if (!isset($url_parts['port']))
6901                  {
6902                      $url_parts['port'] = 80;
6903                  }
6904                  $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
6905                  if (!$fp)
6906                  {
6907                      $this->error = 'fsockopen error: ' . $errstr;
6908                      $this->success = false;
6909                  }
6910                  else
6911                  {
6912                      stream_set_timeout($fp, $timeout);
6913                      if (isset($url_parts['path']))
6914                      {
6915                          if (isset($url_parts['query']))
6916                          {
6917                              $get = "$url_parts[path]?$url_parts[query]";
6918                          }
6919                          else
6920                          {
6921                              $get = $url_parts['path'];
6922                          }
6923                      }
6924                      else
6925                      {
6926                          $get = '/';
6927                      }
6928                      $out = "GET $get HTTP/1.1\r\n";
6929                      $out .= "Host: $url_parts[host]\r\n";
6930                      $out .= "User-Agent: $useragent\r\n";
6931                      if (extension_loaded('zlib'))
6932                      {
6933                          $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
6934                      }
6935  
6936                      if (isset($url_parts['user']) && isset($url_parts['pass']))
6937                      {
6938                          $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
6939                      }
6940                      foreach ($headers as $key => $value)
6941                      {
6942                          $out .= "$key: $value\r\n";
6943                      }
6944                      $out .= "Connection: Close\r\n\r\n";
6945                      fwrite($fp, $out);
6946  
6947                      $info = stream_get_meta_data($fp);
6948  
6949                      $this->headers = '';
6950                      while (!$info['eof'] && !$info['timed_out'])
6951                      {
6952                          $this->headers .= fread($fp, 1160);
6953                          $info = stream_get_meta_data($fp);
6954                      }
6955                      if (!$info['timed_out'])
6956                      {
6957                          $parser = new SimplePie_HTTP_Parser($this->headers);
6958                          if ($parser->parse())
6959                          {
6960                              $this->headers = $parser->headers;
6961                              $this->body = $parser->body;
6962                              $this->status_code = $parser->status_code;
6963                              if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
6964                              {
6965                                  $this->redirects++;
6966                                  $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
6967                                  return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
6968                              }
6969                              if (isset($this->headers['content-encoding']))
6970                              {
6971                                  // Hey, we act dumb elsewhere, so let's do that here too
6972                                  switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
6973                                  {
6974                                      case 'gzip':
6975                                      case 'x-gzip':
6976                                          $decoder = new SimplePie_gzdecode($this->body);
6977                                          if (!$decoder->parse())
6978                                          {
6979                                              $this->error = 'Unable to decode HTTP "gzip" stream';
6980                                              $this->success = false;
6981                                          }
6982                                          else
6983                                          {
6984                                              $this->body = $decoder->data;
6985                                          }
6986                                          break;
6987  
6988                                      case 'deflate':
6989                                          if (($decompressed = gzinflate($this->body)) !== false)
6990                                          {
6991                                              $this->body = $decompressed;
6992                                          }
6993                                          else if (($decompressed = gzuncompress($this->body)) !== false)
6994                                          {
6995                                              $this->body = $decompressed;
6996                                          }
6997                                          else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
6998                                          {
6999                                              $this->body = $decompressed;
7000                                          }
7001                                          else
7002                                          {
7003                                              $this->error = 'Unable to decode HTTP "deflate" stream';
7004                                              $this->success = false;
7005                                          }
7006                                          break;
7007  
7008                                      default:
7009                                          $this->error = 'Unknown content coding';
7010                                          $this->success = false;
7011                                  }
7012                              }
7013                          }
7014                      }
7015                      else
7016                      {
7017                          $this->error = 'fsocket timed out';
7018                          $this->success = false;
7019                      }
7020                      fclose($fp);
7021                  }
7022              }
7023          }
7024          else
7025          {
7026              $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
7027              if (!$this->body = file_get_contents($url))
7028              {
7029                  $this->error = 'file_get_contents could not read the file';
7030                  $this->success = false;
7031              }
7032          }
7033      }
7034  }
7035  
7036  /**
7037   * Decode 'gzip' encoded HTTP data
7038   *
7039   * @package SimplePie
7040   * @subpackage HTTP
7041   * @link http://www.gzip.org/format.txt
7042   */
7043  class SimplePie_gzdecode
7044  {
7045      /**
7046       * Compressed data
7047       *
7048       * @access private
7049       * @var string
7050       * @see gzdecode::$data
7051       */
7052      var $compressed_data;
7053  
7054      /**
7055       * Size of compressed data
7056       *
7057       * @access private
7058       * @var int
7059       */
7060      var $compressed_size;
7061  
7062      /**
7063       * Minimum size of a valid gzip string
7064       *
7065       * @access private
7066       * @var int
7067       */
7068      var $min_compressed_size = 18;
7069  
7070      /**
7071       * Current position of pointer
7072       *
7073       * @access private
7074       * @var int
7075       */
7076      var $position = 0;
7077  
7078      /**
7079       * Flags (FLG)
7080       *
7081       * @access private
7082       * @var int
7083       */
7084      var $flags;
7085  
7086      /**
7087       * Uncompressed data
7088       *
7089       * @access public
7090       * @see gzdecode::$compressed_data
7091       * @var string
7092       */
7093      var $data;
7094  
7095      /**
7096       * Modified time
7097       *
7098       * @access public
7099       * @var int
7100       */
7101      var $MTIME;
7102  
7103      /**
7104       * Extra Flags
7105       *
7106       * @access public
7107       * @var int
7108       */
7109      var $XFL;
7110  
7111      /**
7112       * Operating System
7113       *
7114       * @access public
7115       * @var int
7116       */
7117      var $OS;
7118  
7119      /**
7120       * Subfield ID 1
7121       *
7122       * @access public
7123       * @see gzdecode::$extra_field
7124       * @see gzdecode::$SI2
7125       * @var string
7126       */
7127      var $SI1;
7128  
7129      /**
7130       * Subfield ID 2
7131       *
7132       * @access public
7133       * @see gzdecode::$extra_field
7134       * @see gzdecode::$SI1
7135       * @var string
7136       */
7137      var $SI2;
7138  
7139      /**
7140       * Extra field content
7141       *
7142       * @access public
7143       * @see gzdecode::$SI1
7144       * @see gzdecode::$SI2
7145       * @var string
7146       */
7147      var $extra_field;
7148  
7149      /**
7150       * Original filename
7151       *
7152       * @access public
7153       * @var string
7154       */
7155      var $filename;
7156  
7157      /**
7158       * Human readable comment
7159       *
7160       * @access public
7161       * @var string
7162       */
7163      var $comment;
7164  
7165      /**
7166       * Don't allow anything to be set
7167       *
7168       * @param string $name
7169       * @param mixed $value
7170       */
7171  	public function __set($name, $value)
7172      {
7173          trigger_error("Cannot write property $name", E_USER_ERROR);
7174      }
7175  
7176      /**
7177       * Set the compressed string and related properties
7178       *
7179       * @param string $data
7180       */
7181  	public function __construct($data)
7182      {
7183          $this->compressed_data = $data;
7184          $this->compressed_size = strlen($data);
7185      }
7186  
7187      /**
7188       * Decode the GZIP stream
7189       *
7190       * @return bool Successfulness
7191       */
7192  	public function parse()
7193      {
7194          if ($this->compressed_size >= $this->min_compressed_size)
7195          {
7196              // Check ID1, ID2, and CM
7197              if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
7198              {
7199                  return false;
7200              }
7201  
7202              // Get the FLG (FLaGs)
7203              $this->flags = ord($this->compressed_data[3]);
7204  
7205              // FLG bits above (1 << 4) are reserved
7206              if ($this->flags > 0x1F)
7207              {
7208                  return false;
7209              }
7210  
7211              // Advance the pointer after the above
7212              $this->position += 4;
7213  
7214              // MTIME
7215              $mtime = substr($this->compressed_data, $this->position, 4);
7216              // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
7217              if (current(unpack('S', "\x00\x01")) === 1)
7218              {
7219                  $mtime = strrev($mtime);
7220              }
7221              $this->MTIME = current(unpack('l', $mtime));
7222              $this->position += 4;
7223  
7224              // Get the XFL (eXtra FLags)
7225              $this->XFL = ord($this->compressed_data[$this->position++]);
7226  
7227              // Get the OS (Operating System)
7228              $this->OS = ord($this->compressed_data[$this->position++]);
7229  
7230              // Parse the FEXTRA
7231              if ($this->flags & 4)
7232              {
7233                  // Read subfield IDs
7234                  $this->SI1 = $this->compressed_data[$this->position++];
7235                  $this->SI2 = $this->compressed_data[$this->position++];
7236  
7237                  // SI2 set to zero is reserved for future use
7238                  if ($this->SI2 === "\x00")
7239                  {
7240                      return false;
7241                  }
7242  
7243                  // Get the length of the extra field
7244                  $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7245                  $this->position += 2;
7246  
7247                  // Check the length of the string is still valid
7248                  $this->min_compressed_size += $len + 4;
7249                  if ($this->compressed_size >= $this->min_compressed_size)
7250                  {
7251                      // Set the extra field to the given data
7252                      $this->extra_field = substr($this->compressed_data, $this->position, $len);
7253                      $this->position += $len;
7254                  }
7255                  else
7256                  {
7257                      return false;
7258                  }
7259              }
7260  
7261              // Parse the FNAME
7262              if ($this->flags & 8)
7263              {
7264                  // Get the length of the filename
7265                  $len = strcspn($this->compressed_data, "\x00", $this->position);
7266  
7267                  // Check the length of the string is still valid
7268                  $this->min_compressed_size += $len + 1;
7269                  if ($this->compressed_size >= $this->min_compressed_size)
7270                  {
7271                      // Set the original filename to the given string
7272                      $this->filename = substr($this->compressed_data, $this->position, $len);
7273                      $this->position += $len + 1;
7274                  }
7275                  else
7276                  {
7277                      return false;
7278                  }
7279              }
7280  
7281              // Parse the FCOMMENT
7282              if ($this->flags & 16)
7283              {
7284                  // Get the length of the comment
7285                  $len = strcspn($this->compressed_data, "\x00", $this->position);
7286  
7287                  // Check the length of the string is still valid
7288                  $this->min_compressed_size += $len + 1;
7289                  if ($this->compressed_size >= $this->min_compressed_size)
7290                  {
7291                      // Set the original comment to the given string
7292                      $this->comment = substr($this->compressed_data, $this->position, $len);
7293                      $this->position += $len + 1;
7294                  }
7295                  else
7296                  {
7297                      return false;
7298                  }
7299              }
7300  
7301              // Parse the FHCRC
7302              if ($this->flags & 2)
7303              {
7304                  // Check the length of the string is still valid
7305                  $this->min_compressed_size += $len + 2;
7306                  if ($this->compressed_size >= $this->min_compressed_size)
7307                  {
7308                      // Read the CRC
7309                      $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
7310  
7311                      // Check the CRC matches
7312                      if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
7313                      {
7314                          $this->position += 2;
7315                      }
7316                      else
7317                      {
7318                          return false;
7319                      }
7320                  }
7321                  else
7322                  {
7323                      return false;
7324                  }
7325              }
7326  
7327              // Decompress the actual data
7328              if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
7329              {
7330                  return false;
7331              }
7332              else
7333              {
7334                  $this->position = $this->compressed_size - 8;
7335              }
7336  
7337              // Check CRC of data
7338              $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7339              $this->position += 4;
7340              /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
7341              {
7342                  return false;
7343              }*/
7344  
7345              // Check ISIZE of data
7346              $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
7347              $this->position += 4;
7348              if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
7349              {
7350                  return false;
7351              }
7352  
7353              // Wow, against all odds, we've actually got a valid gzip string
7354              return true;
7355          }
7356          else
7357          {
7358              return false;
7359          }
7360      }
7361  }
7362  
7363  /**
7364   * HTTP Response Parser
7365   *
7366   * @package SimplePie
7367   * @subpackage HTTP
7368   */
7369  class SimplePie_HTTP_Parser
7370  {
7371      /**
7372       * HTTP Version
7373       *
7374       * @var float
7375       */
7376      public $http_version = 0.0;
7377  
7378      /**
7379       * Status code
7380       *
7381       * @var int
7382       */
7383      public $status_code = 0;
7384  
7385      /**
7386       * Reason phrase
7387       *
7388       * @var string
7389       */
7390      public $reason = '';
7391  
7392      /**
7393       * Key/value pairs of the headers
7394       *
7395       * @var array
7396       */
7397      public $headers = array();
7398  
7399      /**
7400       * Body of the response
7401       *
7402       * @var string
7403       */
7404      public $body = '';
7405  
7406      /**
7407       * Current state of the state machine
7408       *
7409       * @var string
7410       */
7411      protected $state = 'http_version';
7412  
7413      /**
7414       * Input data
7415       *
7416       * @var string
7417       */
7418      protected $data = '';
7419  
7420      /**
7421       * Input data length (to avoid calling strlen() everytime this is needed)
7422       *
7423       * @var int
7424       */
7425      protected $data_length = 0;
7426  
7427      /**
7428       * Current position of the pointer
7429       *
7430       * @var int
7431       */
7432      protected $position = 0;
7433  
7434      /**
7435       * Name of the hedaer currently being parsed
7436       *
7437       * @var string
7438       */
7439      protected $name = '';
7440  
7441      /**
7442       * Value of the hedaer currently being parsed
7443       *
7444       * @var string
7445       */
7446      protected $value = '';
7447  
7448      /**
7449       * Create an instance of the class with the input data
7450       *
7451       * @param string $data Input data
7452       */
7453  	public function __construct($data)
7454      {
7455          $this->data = $data;
7456          $this->data_length = strlen($this->data);
7457      }
7458  
7459      /**
7460       * Parse the input data
7461       *
7462       * @return bool true on success, false on failure
7463       */
7464  	public function parse()
7465      {
7466          while ($this->state && $this->state !== 'emit' && $this->has_data())
7467          {
7468              $state = $this->state;
7469              $this->$state();
7470          }
7471          $this->data = '';
7472          if ($this->state === 'emit' || $this->state === 'body')
7473          {
7474              return true;
7475          }
7476          else
7477          {
7478              $this->http_version = '';
7479              $this->status_code = '';
7480              $this->reason = '';
7481              $this->headers = array();
7482              $this->body = '';
7483              return false;
7484          }
7485      }
7486  
7487      /**
7488       * Check whether there is data beyond the pointer
7489       *
7490       * @return bool true if there is further data, false if not
7491       */
7492  	protected function has_data()
7493      {
7494          return (bool) ($this->position < $this->data_length);
7495      }
7496  
7497      /**
7498       * See if the next character is LWS
7499       *
7500       * @return bool true if the next character is LWS, false if not
7501       */
7502  	protected function is_linear_whitespace()
7503      {
7504          return (bool) ($this->data[$this->position] === "\x09"
7505              || $this->data[$this->position] === "\x20"
7506              || ($this->data[$this->position] === "\x0A"
7507                  && isset($this->data[$this->position + 1])
7508                  && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
7509      }
7510  
7511      /**
7512       * Parse the HTTP version
7513       */
7514  	protected function http_version()
7515      {
7516          if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
7517          {
7518              $len = strspn($this->data, '0123456789.', 5);
7519              $this->http_version = substr($this->data, 5, $len);
7520              $this->position += 5 + $len;
7521              if (substr_count($this->http_version, '.') <= 1)
7522              {
7523                  $this->http_version = (float) $this->http_version;
7524                  $this->position += strspn($this->data, "\x09\x20", $this->position);
7525                  $this->state = 'status';
7526              }
7527              else
7528              {
7529                  $this->state = false;
7530              }
7531          }
7532          else
7533          {
7534              $this->state = false;
7535          }
7536      }
7537  
7538      /**
7539       * Parse the status code
7540       */
7541  	protected function status()
7542      {
7543          if ($len = strspn($this->data, '0123456789', $this->position))
7544          {
7545              $this->status_code = (int) substr($this->data, $this->position, $len);
7546              $this->position += $len;
7547              $this->state = 'reason';
7548          }
7549          else
7550          {
7551              $this->state = false;
7552          }
7553      }
7554  
7555      /**
7556       * Parse the reason phrase
7557       */
7558  	protected function reason()
7559      {
7560          $len = strcspn($this->data, "\x0A", $this->position);
7561          $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
7562          $this->position += $len + 1;
7563          $this->state = 'new_line';
7564      }
7565  
7566      /**
7567       * Deal with a new line, shifting data around as needed
7568       */
7569  	protected function new_line()
7570      {
7571          $this->value = trim($this->value, "\x0D\x20");
7572          if ($this->name !== '' && $this->value !== '')
7573          {
7574              $this->name = strtolower($this->name);
7575              // We should only use the last Content-Type header. c.f. issue #1
7576              if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
7577              {
7578                  $this->headers[$this->name] .= ', ' . $this->value;
7579              }
7580              else
7581              {
7582                  $this->headers[$this->name] = $this->value;
7583              }
7584          }
7585          $this->name = '';
7586          $this->value = '';
7587          if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
7588          {
7589              $this->position += 2;
7590              $this->state = 'body';
7591          }
7592          elseif ($this->data[$this->position] === "\x0A")
7593          {
7594              $this->position++;
7595              $this->state = 'body';
7596          }
7597          else
7598          {
7599              $this->state = 'name';
7600          }
7601      }
7602  
7603      /**
7604       * Parse a header name
7605       */
7606  	protected function name()
7607      {
7608          $len = strcspn($this->data, "\x0A:", $this->position);
7609          if (isset($this->data[$this->position + $len]))
7610          {
7611              if ($this->data[$this->position + $len] === "\x0A")
7612              {
7613                  $this->position += $len;
7614                  $this->state = 'new_line';
7615              }
7616              else
7617              {
7618                  $this->name = substr($this->data, $this->position, $len);
7619                  $this->position += $len + 1;
7620                  $this->state = 'value';
7621              }
7622          }
7623          else
7624          {
7625              $this->state = false;
7626          }
7627      }
7628  
7629      /**
7630       * Parse LWS, replacing consecutive LWS characters with a single space
7631       */
7632  	protected function linear_whitespace()
7633      {
7634          do
7635          {
7636              if (substr($this->data, $this->position, 2) === "\x0D\x0A")
7637              {
7638                  $this->position += 2;
7639              }
7640              elseif ($this->data[$this->position] === "\x0A")
7641              {
7642                  $this->position++;
7643              }
7644              $this->position += strspn($this->data, "\x09\x20", $this->position);
7645          } while ($this->has_data() && $this->is_linear_whitespace());
7646          $this->value .= "\x20";
7647      }
7648  
7649      /**
7650       * See what state to move to while within non-quoted header values
7651       */
7652  	protected function value()
7653      {
7654          if ($this->is_linear_whitespace())
7655          {
7656              $this->linear_whitespace();
7657          }
7658          else
7659          {
7660              switch ($this->data[$this->position])
7661              {
7662                  case '"':
7663                      // Workaround for ETags: we have to include the quotes as
7664                      // part of the tag.
7665                      if (strtolower($this->name) === 'etag')
7666                      {
7667                          $this->value .= '"';
7668                          $this->position++;
7669                          $this->state = 'value_char';
7670                          break;
7671                      }
7672                      $this->position++;
7673                      $this->state = 'quote';
7674                      break;
7675  
7676                  case "\x0A":
7677                      $this->position++;
7678                      $this->state = 'new_line';
7679                      break;
7680  
7681                  default:
7682                      $this->state = 'value_char';
7683                      break;
7684              }
7685          }
7686      }
7687  
7688      /**
7689       * Parse a header value while outside quotes
7690       */
7691  	protected function value_char()
7692      {
7693          $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
7694          $this->value .= substr($this->data, $this->position, $len);
7695          $this->position += $len;
7696          $this->state = 'value';
7697      }
7698  
7699      /**
7700       * See what state to move to while within quoted header values
7701       */
7702  	protected function quote()
7703      {
7704          if ($this->is_linear_whitespace())
7705          {
7706              $this->linear_whitespace();
7707          }
7708          else
7709          {
7710              switch ($this->data[$this->position])
7711              {
7712                  case '"':
7713                      $this->position++;
7714                      $this->state = 'value';
7715                      break;
7716  
7717                  case "\x0A":
7718                      $this->position++;
7719                      $this->state = 'new_line';
7720                      break;
7721  
7722                  case '\\':
7723                      $this->position++;
7724                      $this->state = 'quote_escaped';
7725                      break;
7726  
7727                  default:
7728                      $this->state = 'quote_char';
7729                      break;
7730              }
7731          }
7732      }
7733  
7734      /**
7735       * Parse a header value while within quotes
7736       */
7737  	protected function quote_char()
7738      {
7739          $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
7740          $this->value .= substr($this->data, $this->position, $len);
7741          $this->position += $len;
7742          $this->state = 'value';
7743      }
7744  
7745      /**
7746       * Parse an escaped character within quotes
7747       */
7748  	protected function quote_escaped()
7749      {
7750          $this->value .= $this->data[$this->position];
7751          $this->position++;
7752          $this->state = 'quote';
7753      }
7754  
7755      /**
7756       * Parse the body
7757       */
7758  	protected function body()
7759      {
7760          $this->body = substr($this->data, $this->position);
7761          if (!empty($this->headers['transfer-encoding']))
7762          {
7763              unset($this->headers['transfer-encoding']);
7764              $this->state = 'chunked';
7765          }
7766          else
7767          {
7768              $this->state = 'emit';
7769          }
7770      }
7771  
7772      /**
7773       * Parsed a "Transfer-Encoding: chunked" body
7774       */
7775  	protected function chunked()
7776      {
7777          if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
7778          {
7779              $this->state = 'emit';
7780              return;
7781          }
7782  
7783          $decoded = '';
7784          $encoded = $this->body;
7785  
7786          while (true)
7787          {
7788              $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
7789              if (!$is_chunked)
7790              {
7791                  // Looks like it's not chunked after all
7792                  $this->state = 'emit';
7793                  return;
7794              }
7795  
7796              $length = hexdec(trim($matches[1]));
7797              if ($length === 0)
7798              {
7799                  // Ignore trailer headers
7800                  $this->state = 'emit';
7801                  $this->body = $decoded;
7802                  return;
7803              }
7804  
7805              $chunk_length = strlen($matches[0]);
7806              $decoded .= $part = substr($encoded, $chunk_length, $length);
7807              $encoded = substr($encoded, $chunk_length + $length + 2);
7808  
7809              if (trim($encoded) === '0' || empty($encoded))
7810              {
7811                  $this->state = 'emit';
7812                  $this->body = $decoded;
7813                  return;
7814              }
7815          }
7816      }
7817  }
7818  
7819  /**
7820   * IRI parser/serialiser/normaliser
7821   *
7822   * @package SimplePie
7823   * @subpackage HTTP
7824   * @author Geoffrey Sneddon
7825   * @author Steve Minutillo
7826   * @author Ryan McCue
7827   * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
7828   * @license http://www.opensource.org/licenses/bsd-license.php
7829   */
7830  class SimplePie_IRI
7831  {
7832      /**
7833       * Scheme
7834       *
7835       * @var string
7836       */
7837      protected $scheme = null;
7838  
7839      /**
7840       * User Information
7841       *
7842       * @var string
7843       */
7844      protected $iuserinfo = null;
7845  
7846      /**
7847       * ihost
7848       *
7849       * @var string
7850       */
7851      protected $ihost = null;
7852  
7853      /**
7854       * Port
7855       *
7856       * @var string
7857       */
7858      protected $port = null;
7859  
7860      /**
7861       * ipath
7862       *
7863       * @var string
7864       */
7865      protected $ipath = '';
7866  
7867      /**
7868       * iquery
7869       *
7870       * @var string
7871       */
7872      protected $iquery = null;
7873  
7874      /**
7875       * ifragment
7876       *
7877       * @var string
7878       */
7879      protected $ifragment = null;
7880  
7881      /**
7882       * Normalization database
7883       *
7884       * Each key is the scheme, each value is an array with each key as the IRI
7885       * part and value as the default value for that part.
7886       */
7887      protected $normalization = array(
7888          'acap' => array(
7889              'port' => 674
7890          ),
7891          'dict' => array(
7892              'port' => 2628
7893          ),
7894          'file' => array(
7895              'ihost' => 'localhost'
7896          ),
7897          'http' => array(
7898              'port' => 80,
7899              'ipath' => '/'
7900          ),
7901          'https' => array(
7902              'port' => 443,
7903              'ipath' => '/'
7904          ),
7905      );
7906  
7907      /**
7908       * Return the entire IRI when you try and read the object as a string
7909       *
7910       * @return string
7911       */
7912  	public function __toString()
7913      {
7914          return $this->get_iri();
7915      }
7916  
7917      /**
7918       * Overload __set() to provide access via properties
7919       *
7920       * @param string $name Property name
7921       * @param mixed $value Property value
7922       */
7923  	public function __set($name, $value)
7924      {
7925          if (method_exists($this, 'set_' . $name))
7926          {
7927              call_user_func(array($this, 'set_' . $name), $value);
7928          }
7929          elseif (
7930                 $name === 'iauthority'
7931              || $name === 'iuserinfo'
7932              || $name === 'ihost'
7933              || $name === 'ipath'
7934              || $name === 'iquery'
7935              || $name === 'ifragment'
7936          )
7937          {
7938              call_user_func(array($this, 'set_' . substr($name, 1)), $value);
7939          }
7940      }
7941  
7942      /**
7943       * Overload __get() to provide access via properties
7944       *
7945       * @param string $name Property name
7946       * @return mixed
7947       */
7948  	public function __get($name)
7949      {
7950          // isset() returns false for null, we don't want to do that
7951          // Also why we use array_key_exists below instead of isset()
7952          $props = get_object_vars($this);
7953  
7954          if (
7955              $name === 'iri' ||
7956              $name === 'uri' ||
7957              $name === 'iauthority' ||
7958              $name === 'authority'
7959          )
7960          {
7961              $return = $this->{"get_$name"}();
7962          }
7963          elseif (array_key_exists($name, $props))
7964          {
7965              $return = $this->$name;
7966          }
7967          // host -> ihost
7968          elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
7969          {
7970              $name = $prop;
7971              $return = $this->$prop;
7972          }
7973          // ischeme -> scheme
7974          elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
7975          {
7976              $name = $prop;
7977              $return = $this->$prop;
7978          }
7979          else
7980          {
7981              trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
7982              $return = null;
7983          }
7984  
7985          if ($return === null && isset($this->normalization[$this->scheme][$name]))
7986          {
7987              return $this->normalization[$this->scheme][$name];
7988          }
7989          else
7990          {
7991              return $return;
7992          }
7993      }
7994  
7995      /**
7996       * Overload __isset() to provide access via properties
7997       *
7998       * @param string $name Property name
7999       * @return bool
8000       */
8001  	public function __isset($name)
8002      {
8003          if (method_exists($this, 'get_' . $name) || isset($this->$name))
8004          {
8005              return true;
8006          }
8007          else
8008          {
8009              return false;
8010          }
8011      }
8012  
8013      /**
8014       * Overload __unset() to provide access via properties
8015       *
8016       * @param string $name Property name
8017       */
8018  	public function __unset($name)
8019      {
8020          if (method_exists($this, 'set_' . $name))
8021          {
8022              call_user_func(array($this, 'set_' . $name), '');
8023          }
8024      }
8025  
8026      /**
8027       * Create a new IRI object, from a specified string
8028       *
8029       * @param string $iri
8030       */
8031  	public function __construct($iri = null)
8032      {
8033          $this->set_iri($iri);
8034      }
8035  
8036      /**
8037       * Create a new IRI object by resolving a relative IRI
8038       *
8039       * Returns false if $base is not absolute, otherwise an IRI.
8040       *
8041       * @param IRI|string $base (Absolute) Base IRI
8042       * @param IRI|string $relative Relative IRI
8043       * @return IRI|false
8044       */
8045  	public static function absolutize($base, $relative)
8046      {
8047          if (!($relative instanceof SimplePie_IRI))
8048          {
8049              $relative = new SimplePie_IRI($relative);
8050          }
8051          if (!$relative->is_valid())
8052          {
8053              return false;
8054          }
8055          elseif ($relative->scheme !== null)
8056          {
8057              return clone $relative;
8058          }
8059          else
8060          {
8061              if (!($base instanceof SimplePie_IRI))
8062              {
8063                  $base = new SimplePie_IRI($base);
8064              }
8065              if ($base->scheme !== null && $base->is_valid())
8066              {
8067                  if ($relative->get_iri() !== '')
8068                  {
8069                      if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
8070                      {
8071                          $target = clone $relative;
8072                          $target->scheme = $base->scheme;
8073                      }
8074                      else
8075                      {
8076                          $target = new SimplePie_IRI;
8077                          $target->scheme = $base->scheme;
8078                          $target->iuserinfo = $base->iuserinfo;
8079                          $target->ihost = $base->ihost;
8080                          $target->port = $base->port;
8081                          if ($relative->ipath !== '')
8082                          {
8083                              if ($relative->ipath[0] === '/')
8084                              {
8085                                  $target->ipath = $relative->ipath;
8086                              }
8087                              elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
8088                              {
8089                                  $target->ipath = '/' . $relative->ipath;
8090                              }
8091                              elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
8092                              {
8093                                  $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
8094                              }
8095                              else
8096                              {
8097                                  $target->ipath = $relative->ipath;
8098                              }
8099                              $target->ipath = $target->remove_dot_segments($target->ipath);
8100                              $target->iquery = $relative->iquery;
8101                          }
8102                          else
8103                          {
8104                              $target->ipath = $base->ipath;
8105                              if ($relative->iquery !== null)
8106                              {
8107                                  $target->iquery = $relative->iquery;
8108                              }
8109                              elseif ($base->iquery !== null)
8110                              {
8111                                  $target->iquery = $base->iquery;
8112                              }
8113                          }
8114                          $target->ifragment = $relative->ifragment;
8115                      }
8116                  }
8117                  else
8118                  {
8119                      $target = clone $base;
8120                      $target->ifragment = null;
8121                  }
8122                  $target->scheme_normalization();
8123                  return $target;
8124              }
8125              else
8126              {
8127                  return false;
8128              }
8129          }
8130      }
8131  
8132      /**
8133       * Parse an IRI into scheme/authority/path/query/fragment segments
8134       *
8135       * @param string $iri
8136       * @return array
8137       */
8138  	protected function parse_iri($iri)
8139      {
8140          $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
8141          if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
8142          {
8143              if ($match[1] === '')
8144              {
8145                  $match['scheme'] = null;
8146              }
8147              if (!isset($match[3]) || $match[3] === '')
8148              {
8149                  $match['authority'] = null;
8150              }
8151              if (!isset($match[5]))
8152              {
8153                  $match['path'] = '';
8154              }
8155              if (!isset($match[6]) || $match[6] === '')
8156              {
8157                  $match['query'] = null;
8158              }
8159              if (!isset($match[8]) || $match[8] === '')
8160              {
8161                  $match['fragment'] = null;
8162              }
8163              return $match;
8164          }
8165          else
8166          {
8167              // This can occur when a paragraph is accidentally parsed as a URI
8168              return false;
8169          }
8170      }
8171  
8172      /**
8173       * Remove dot segments from a path
8174       *
8175       * @param string $input
8176       * @return string
8177       */
8178  	protected function remove_dot_segments($input)
8179      {
8180          $output = '';
8181          while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
8182          {
8183              // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
8184              if (strpos($input, '../') === 0)
8185              {
8186                  $input = substr($input, 3);
8187              }
8188              elseif (strpos($input, './') === 0)
8189              {
8190                  $input = substr($input, 2);
8191              }
8192              // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
8193              elseif (strpos($input, '/./') === 0)
8194              {
8195                  $input = substr($input, 2);
8196              }
8197              elseif ($input === '/.')
8198              {
8199                  $input = '/';
8200              }
8201              // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
8202              elseif (strpos($input, '/../') === 0)
8203              {
8204                  $input = substr($input, 3);
8205                  $output = substr_replace($output, '', strrpos($output, '/'));
8206              }
8207              elseif ($input === '/..')
8208              {
8209                  $input = '/';
8210                  $output = substr_replace($output, '', strrpos($output, '/'));
8211              }
8212              // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
8213              elseif ($input === '.' || $input === '..')
8214              {
8215                  $input = '';
8216              }
8217              // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
8218              elseif (($pos = strpos($input, '/', 1)) !== false)
8219              {
8220                  $output .= substr($input, 0, $pos);
8221                  $input = substr_replace($input, '', 0, $pos);
8222              }
8223              else
8224              {
8225                  $output .= $input;
8226                  $input = '';
8227              }
8228          }
8229          return $output . $input;
8230      }
8231  
8232      /**
8233       * Replace invalid character with percent encoding
8234       *
8235       * @param string $string Input string
8236       * @param string $extra_chars Valid characters not in iunreserved or
8237       *                            iprivate (this is ASCII-only)
8238       * @param bool $iprivate Allow iprivate
8239       * @return string
8240       */
8241  	protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
8242      {
8243          // Normalize as many pct-encoded sections as possible
8244          $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
8245  
8246          // Replace invalid percent characters
8247          $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
8248  
8249          // Add unreserved and % to $extra_chars (the latter is safe because all
8250          // pct-encoded sections are now valid).
8251          $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
8252  
8253          // Now replace any bytes that aren't allowed with their pct-encoded versions
8254          $position = 0;
8255          $strlen = strlen($string);
8256          while (($position += strspn($string, $extra_chars, $position)) < $strlen)
8257          {
8258              $value = ord($string[$position]);
8259  
8260              // Start position
8261              $start = $position;
8262  
8263              // By default we are valid
8264              $valid = true;
8265  
8266              // No one byte sequences are valid due to the while.
8267              // Two byte sequence:
8268              if (($value & 0xE0) === 0xC0)
8269              {
8270                  $character = ($value & 0x1F) << 6;
8271                  $length = 2;
8272                  $remaining = 1;
8273              }
8274              // Three byte sequence:
8275              elseif (($value & 0xF0) === 0xE0)
8276              {
8277                  $character = ($value & 0x0F) << 12;
8278                  $length = 3;
8279                  $remaining = 2;
8280              }
8281              // Four byte sequence:
8282              elseif (($value & 0xF8) === 0xF0)
8283              {
8284                  $character = ($value & 0x07) << 18;
8285                  $length = 4;
8286                  $remaining = 3;
8287              }
8288              // Invalid byte:
8289              else
8290              {
8291                  $valid = false;
8292                  $length = 1;
8293                  $remaining = 0;
8294              }
8295  
8296              if ($remaining)
8297              {
8298                  if ($position + $length <= $strlen)
8299                  {
8300                      for ($position++; $remaining; $position++)
8301                      {
8302                          $value = ord($string[$position]);
8303  
8304                          // Check that the byte is valid, then add it to the character:
8305                          if (($value & 0xC0) === 0x80)
8306                          {
8307                              $character |= ($value & 0x3F) << (--$remaining * 6);
8308                          }
8309                          // If it is invalid, count the sequence as invalid and reprocess the current byte:
8310                          else
8311                          {
8312                              $valid = false;
8313                              $position--;
8314                              break;
8315                          }
8316                      }
8317                  }
8318                  else
8319                  {
8320                      $position = $strlen - 1;
8321                      $valid = false;
8322                  }
8323              }
8324  
8325              // Percent encode anything invalid or not in ucschar
8326              if (
8327                  // Invalid sequences
8328                  !$valid
8329                  // Non-shortest form sequences are invalid
8330                  || $length > 1 && $character <= 0x7F
8331                  || $length > 2 && $character <= 0x7FF
8332                  || $length > 3 && $character <= 0xFFFF
8333                  // Outside of range of ucschar codepoints
8334                  // Noncharacters
8335                  || ($character & 0xFFFE) === 0xFFFE
8336                  || $character >= 0xFDD0 && $character <= 0xFDEF
8337                  || (
8338                      // Everything else not in ucschar
8339                         $character > 0xD7FF && $character < 0xF900
8340                      || $character < 0xA0
8341                      || $character > 0xEFFFD
8342                  )
8343                  && (
8344                      // Everything not in iprivate, if it applies
8345                         !$iprivate
8346                      || $character < 0xE000
8347                      || $character > 0x10FFFD
8348                  )
8349              )
8350              {
8351                  // If we were a character, pretend we weren't, but rather an error.
8352                  if ($valid)
8353                      $position--;
8354  
8355                  for ($j = $start; $j <= $position; $j++)
8356                  {
8357                      $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
8358                      $j += 2;
8359                      $position += 2;
8360                      $strlen += 2;
8361                  }
8362              }
8363          }
8364  
8365          return $string;
8366      }
8367  
8368      /**
8369       * Callback function for preg_replace_callback.
8370       *
8371       * Removes sequences of percent encoded bytes that represent UTF-8
8372       * encoded characters in iunreserved
8373       *
8374       * @param array $match PCRE match
8375       * @return string Replacement
8376       */
8377  	protected function remove_iunreserved_percent_encoded($match)
8378      {
8379          // As we just have valid percent encoded sequences we can just explode
8380          // and ignore the first member of the returned array (an empty string).
8381          $bytes = explode('%', $match[0]);
8382  
8383          // Initialize the new string (this is what will be returned) and that
8384          // there are no bytes remaining in the current sequence (unsurprising
8385          // at the first byte!).
8386          $string = '';
8387          $remaining = 0;
8388  
8389          // Loop over each and every byte, and set $value to its value
8390          for ($i = 1, $len = count($bytes); $i < $len; $i++)
8391          {
8392              $value = hexdec($bytes[$i]);
8393  
8394              // If we're the first byte of sequence:
8395              if (!$remaining)
8396              {
8397                  // Start position
8398                  $start = $i;
8399  
8400                  // By default we are valid
8401                  $valid = true;
8402  
8403                  // One byte sequence:
8404                  if ($value <= 0x7F)
8405                  {
8406                      $character = $value;
8407                      $length = 1;
8408                  }
8409                  // Two byte sequence:
8410                  elseif (($value & 0xE0) === 0xC0)
8411                  {
8412                      $character = ($value & 0x1F) << 6;
8413                      $length = 2;
8414                      $remaining = 1;
8415                  }
8416                  // Three byte sequence:
8417                  elseif (($value & 0xF0) === 0xE0)
8418                  {
8419                      $character = ($value & 0x0F) << 12;
8420                      $length = 3;
8421                      $remaining = 2;
8422                  }
8423                  // Four byte sequence:
8424                  elseif (($value & 0xF8) === 0xF0)
8425                  {
8426                      $character = ($value & 0x07) << 18;
8427                      $length = 4;
8428                      $remaining = 3;
8429                  }
8430                  // Invalid byte:
8431                  else
8432                  {
8433                      $valid = false;
8434                      $remaining = 0;
8435                  }
8436              }
8437              // Continuation byte:
8438              else
8439              {
8440                  // Check that the byte is valid, then add it to the character:
8441                  if (($value & 0xC0) === 0x80)
8442                  {
8443                      $remaining--;
8444                      $character |= ($value & 0x3F) << ($remaining * 6);
8445                  }
8446                  // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
8447                  else
8448                  {
8449                      $valid = false;
8450                      $remaining = 0;
8451                      $i--;
8452                  }
8453              }
8454  
8455              // If we've reached the end of the current byte sequence, append it to Unicode::$data
8456              if (!$remaining)
8457              {
8458                  // Percent encode anything invalid or not in iunreserved
8459                  if (
8460                      // Invalid sequences
8461                      !$valid
8462                      // Non-shortest form sequences are invalid
8463                      || $length > 1 && $character <= 0x7F
8464                      || $length > 2 && $character <= 0x7FF
8465                      || $length > 3 && $character <= 0xFFFF
8466                      // Outside of range of iunreserved codepoints
8467                      || $character < 0x2D
8468                      || $character > 0xEFFFD
8469                      // Noncharacters
8470                      || ($character & 0xFFFE) === 0xFFFE
8471                      || $character >= 0xFDD0 && $character <= 0xFDEF
8472                      // Everything else not in iunreserved (this is all BMP)
8473                      || $character === 0x2F
8474                      || $character > 0x39 && $character < 0x41
8475                      || $character > 0x5A && $character < 0x61
8476                      || $character > 0x7A && $character < 0x7E
8477                      || $character > 0x7E && $character < 0xA0
8478                      || $character > 0xD7FF && $character < 0xF900
8479                  )
8480                  {
8481                      for ($j = $start; $j <= $i; $j++)
8482                      {
8483                          $string .= '%' . strtoupper($bytes[$j]);
8484                      }
8485                  }
8486                  else
8487                  {
8488                      for ($j = $start; $j <= $i; $j++)
8489                      {
8490                          $string .= chr(hexdec($bytes[$j]));
8491                      }
8492                  }
8493              }
8494          }
8495  
8496          // If we have any bytes left over they are invalid (i.e., we are
8497          // mid-way through a multi-byte sequence)
8498          if ($remaining)
8499          {
8500              for ($j = $start; $j < $len; $j++)
8501              {
8502                  $string .= '%' . strtoupper($bytes[$j]);
8503              }
8504          }
8505  
8506          return $string;
8507      }
8508  
8509  	protected function scheme_normalization()
8510      {
8511          if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
8512          {
8513              $this->iuserinfo = null;
8514          }
8515          if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
8516          {
8517              $this->ihost = null;
8518          }
8519          if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
8520          {
8521              $this->port = null;
8522          }
8523          if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
8524          {
8525              $this->ipath = '';
8526          }
8527          if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
8528          {
8529              $this->iquery = null;
8530          }
8531          if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
8532          {
8533              $this->ifragment = null;
8534          }
8535      }
8536  
8537      /**
8538       * Check if the object represents a valid IRI. This needs to be done on each
8539       * call as some things change depending on another part of the IRI.
8540       *
8541       * @return bool
8542       */
8543  	public function is_valid()
8544      {
8545          $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
8546          if ($this->ipath !== '' &&
8547              (
8548                  $isauthority && (
8549                      $this->ipath[0] !== '/' ||
8550                      substr($this->ipath, 0, 2) === '//'
8551                  ) ||
8552                  (
8553                      $this->scheme === null &&
8554                      !$isauthority &&
8555                      strpos($this->ipath, ':') !== false &&
8556                      (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
8557                  )
8558              )
8559          )
8560          {
8561              return false;
8562          }
8563  
8564          return true;
8565      }
8566  
8567      /**
8568       * Set the entire IRI. Returns true on success, false on failure (if there
8569       * are any invalid characters).
8570       *
8571       * @param string $iri
8572       * @return bool
8573       */
8574  	public function set_iri($iri)
8575      {
8576          static $cache;
8577          if (!$cache)
8578          {
8579              $cache = array();
8580          }
8581  
8582          if ($iri === null)
8583          {
8584              return true;
8585          }
8586          elseif (isset($cache[$iri]))
8587          {
8588              list($this->scheme,
8589                   $this->iuserinfo,
8590                   $this->ihost,
8591                   $this->port,
8592                   $this->ipath,
8593                   $this->iquery,
8594                   $this->ifragment,
8595                   $return) = $cache[$iri];
8596              return $return;
8597          }
8598          else
8599          {
8600              $parsed = $this->parse_iri((string) $iri);
8601              if (!$parsed)
8602              {
8603                  return false;
8604              }
8605  
8606              $return = $this->set_scheme($parsed['scheme'])
8607                  && $this->set_authority($parsed['authority'])
8608                  && $this->set_path($parsed['path'])
8609                  && $this->set_query($parsed['query'])
8610                  && $this->set_fragment($parsed['fragment']);
8611  
8612              $cache[$iri] = array($this->scheme,
8613                                   $this->iuserinfo,
8614                                   $this->ihost,
8615                                   $this->port,
8616                                   $this->ipath,
8617                                   $this->iquery,
8618                                   $this->ifragment,
8619                                   $return);
8620              return $return;
8621          }
8622      }
8623  
8624      /**
8625       * Set the scheme. Returns true on success, false on failure (if there are
8626       * any invalid characters).
8627       *
8628       * @param string $scheme
8629       * @return bool
8630       */
8631  	public function set_scheme($scheme)
8632      {
8633          if ($scheme === null)
8634          {
8635              $this->scheme = null;
8636          }
8637          elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
8638          {
8639              $this->scheme = null;
8640              return false;
8641          }
8642          else
8643          {
8644              $this->scheme = strtolower($scheme);
8645          }
8646          return true;
8647      }
8648  
8649      /**
8650       * Set the authority. Returns true on success, false on failure (if there are
8651       * any invalid characters).
8652       *
8653       * @param string $authority
8654       * @return bool
8655       */
8656  	public function set_authority($authority)
8657      {
8658          static $cache;
8659          if (!$cache)
8660              $cache = array();
8661  
8662          if ($authority === null)
8663          {
8664              $this->iuserinfo = null;
8665              $this->ihost = null;
8666              $this->port = null;
8667              return true;
8668          }
8669          elseif (isset($cache[$authority]))
8670          {
8671              list($this->iuserinfo,
8672                   $this->ihost,
8673                   $this->port,
8674                   $return) = $cache[$authority];
8675  
8676              return $return;
8677          }
8678          else
8679          {
8680              $remaining = $authority;
8681              if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
8682              {
8683                  $iuserinfo = substr($remaining, 0, $iuserinfo_end);
8684                  $remaining = substr($remaining, $iuserinfo_end + 1);
8685              }
8686              else
8687              {
8688                  $iuserinfo = null;
8689              }
8690              if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
8691              {
8692                  if (($port = substr($remaining, $port_start + 1)) === false)
8693                  {
8694                      $port = null;
8695                  }
8696                  $remaining = substr($remaining, 0, $port_start);
8697              }
8698              else
8699              {
8700                  $port = null;
8701              }
8702  
8703              $return = $this->set_userinfo($iuserinfo) &&
8704                        $this->set_host($remaining) &&
8705                        $this->set_port($port);
8706  
8707              $cache[$authority] = array($this->iuserinfo,
8708                                         $this->ihost,
8709                                         $this->port,
8710                                         $return);
8711  
8712              return $return;
8713          }
8714      }
8715  
8716      /**
8717       * Set the iuserinfo.
8718       *
8719       * @param string $iuserinfo
8720       * @return bool
8721       */
8722  	public function set_userinfo($iuserinfo)
8723      {
8724          if ($iuserinfo === null)
8725          {
8726              $this->iuserinfo = null;
8727          }
8728          else
8729          {
8730              $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
8731              $this->scheme_normalization();
8732          }
8733  
8734          return true;
8735      }
8736  
8737      /**
8738       * Set the ihost. Returns true on success, false on failure (if there are
8739       * any invalid characters).
8740       *
8741       * @param string $ihost
8742       * @return bool
8743       */
8744  	public function set_host($ihost)
8745      {
8746          if ($ihost === null)
8747          {
8748              $this->ihost = null;
8749              return true;
8750          }
8751          elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
8752          {
8753              if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
8754              {
8755                  $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
8756              }
8757              else
8758              {
8759                  $this->ihost = null;
8760                  return false;
8761              }
8762          }
8763          else
8764          {
8765              $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
8766  
8767              // Lowercase, but ignore pct-encoded sections (as they should
8768              // remain uppercase). This must be done after the previous step
8769              // as that can add unescaped characters.
8770              $position = 0;
8771              $strlen = strlen($ihost);
8772              while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
8773              {
8774                  if ($ihost[$position] === '%')
8775                  {
8776                      $position += 3;
8777                  }
8778                  else
8779                  {
8780                      $ihost[$position] = strtolower($ihost[$position]);
8781                      $position++;
8782                  }
8783              }
8784  
8785              $this->ihost = $ihost;
8786          }
8787  
8788          $this->scheme_normalization();
8789  
8790          return true;
8791      }
8792  
8793      /**
8794       * Set the port. Returns true on success, false on failure (if there are
8795       * any invalid characters).
8796       *
8797       * @param string $port
8798       * @return bool
8799       */
8800  	public function set_port($port)
8801      {
8802          if ($port === null)
8803          {
8804              $this->port = null;
8805              return true;
8806          }
8807          elseif (strspn($port, '0123456789') === strlen($port))
8808          {
8809              $this->port = (int) $port;
8810              $this->scheme_normalization();
8811              return true;
8812          }
8813          else
8814          {
8815              $this->port = null;
8816              return false;
8817          }
8818      }
8819  
8820      /**
8821       * Set the ipath.
8822       *
8823       * @param string $ipath
8824       * @return bool
8825       */
8826  	public function set_path($ipath)
8827      {
8828          static $cache;
8829          if (!$cache)
8830          {
8831              $cache = array();
8832          }
8833  
8834          $ipath = (string) $ipath;
8835  
8836          if (isset($cache[$ipath]))
8837          {
8838              $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
8839          }
8840          else
8841          {
8842              $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
8843              $removed = $this->remove_dot_segments($valid);
8844  
8845              $cache[$ipath] = array($valid, $removed);
8846              $this->ipath =  ($this->scheme !== null) ? $removed : $valid;
8847          }
8848  
8849          $this->scheme_normalization();
8850          return true;
8851      }
8852  
8853      /**
8854       * Set the iquery.
8855       *
8856       * @param string $iquery
8857       * @return bool
8858       */
8859  	public function set_query($iquery)
8860      {
8861          if ($iquery === null)
8862          {
8863              $this->iquery = null;
8864          }
8865          else
8866          {
8867              $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
8868              $this->scheme_normalization();
8869          }
8870          return true;
8871      }
8872  
8873      /**
8874       * Set the ifragment.
8875       *
8876       * @param string $ifragment
8877       * @return bool
8878       */
8879  	public function set_fragment($ifragment)
8880      {
8881          if ($ifragment === null)
8882          {
8883              $this->ifragment = null;
8884          }
8885          else
8886          {
8887              $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
8888              $this->scheme_normalization();
8889          }
8890          return true;
8891      }
8892  
8893      /**
8894       * Convert an IRI to a URI (or parts thereof)
8895       *
8896       * @return string
8897       */
8898  	public function to_uri($string)
8899      {
8900          static $non_ascii;
8901          if (!$non_ascii)
8902          {
8903              $non_ascii = implode('', range("\x80", "\xFF"));
8904          }
8905  
8906          $position = 0;
8907          $strlen = strlen($string);
8908          while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
8909          {
8910              $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
8911              $position += 3;
8912              $strlen += 2;
8913          }
8914  
8915          return $string;
8916      }
8917  
8918      /**
8919       * Get the complete IRI
8920       *
8921       * @return string
8922       */
8923  	public function get_iri()
8924      {
8925          if (!$this->is_valid())
8926          {
8927              return false;
8928          }
8929  
8930          $iri = '';
8931          if ($this->scheme !== null)
8932          {
8933              $iri .= $this->scheme . ':';
8934          }
8935          if (($iauthority = $this->get_iauthority()) !== null)
8936          {
8937              $iri .= '//' . $iauthority;
8938          }
8939          if ($this->ipath !== '')
8940          {
8941              $iri .= $this->ipath;
8942          }
8943          elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
8944          {
8945              $iri .= $this->normalization[$this->scheme]['ipath'];
8946          }
8947          if ($this->iquery !== null)
8948          {
8949              $iri .= '?' . $this->iquery;
8950          }
8951          if ($this->ifragment !== null)
8952          {
8953              $iri .= '#' . $this->ifragment;
8954          }
8955  
8956          return $iri;
8957      }
8958  
8959      /**
8960       * Get the complete URI
8961       *
8962       * @return string
8963       */
8964  	public function get_uri()
8965      {
8966          return $this->to_uri($this->get_iri());
8967      }
8968  
8969      /**
8970       * Get the complete iauthority
8971       *
8972       * @return string
8973       */
8974  	protected function get_iauthority()
8975      {
8976          if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
8977          {
8978              $iauthority = '';
8979              if ($this->iuserinfo !== null)
8980              {
8981                  $iauthority .= $this->iuserinfo . '@';
8982              }
8983              if ($this->ihost !== null)
8984              {
8985                  $iauthority .= $this->ihost;
8986              }
8987              if ($this->port !== null)
8988              {
8989                  $iauthority .= ':' . $this->port;
8990              }
8991              return $iauthority;
8992          }
8993          else
8994          {
8995              return null;
8996          }
8997      }
8998  
8999      /**
9000       * Get the complete authority
9001       *
9002       * @return string
9003       */
9004  	protected function get_authority()
9005      {
9006          $iauthority = $this->get_iauthority();
9007          if (is_string($iauthority))
9008              return $this->to_uri($iauthority);
9009          else
9010              return $iauthority;
9011      }
9012  }
9013  
9014  /**
9015   * Manages all item-related data
9016   *
9017   * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
9018   *
9019   * This class can be overloaded with {@see SimplePie::set_item_class()}
9020   *
9021   * @package SimplePie
9022   * @subpackage API
9023   */
9024  class SimplePie_Item
9025  {
9026      /**
9027       * Parent feed
9028       *
9029       * @access private
9030       * @var SimplePie
9031       */
9032      var $feed;
9033  
9034      /**
9035       * Raw data
9036       *
9037       * @access private
9038       * @var array
9039       */
9040      var $data = array();
9041  
9042      /**
9043       * Registry object
9044       *
9045       * @see set_registry
9046       * @var SimplePie_Registry
9047       */
9048      protected $registry;
9049  
9050      /**
9051       * Create a new item object
9052       *
9053       * This is usually used by {@see SimplePie::get_items} and
9054       * {@see SimplePie::get_item}. Avoid creating this manually.
9055       *
9056       * @param SimplePie $feed Parent feed
9057       * @param array $data Raw data
9058       */
9059  	public function __construct($feed, $data)
9060      {
9061          $this->feed = $feed;
9062          $this->data = $data;
9063      }
9064  
9065      /**
9066       * Set the registry handler
9067       *
9068       * This is usually used by {@see SimplePie_Registry::create}
9069       *
9070       * @since 1.3
9071       * @param SimplePie_Registry $registry
9072       */
9073  	public function set_registry(SimplePie_Registry $registry)
9074      {
9075          $this->registry = $registry;
9076      }
9077  
9078      /**
9079       * Get a string representation of the item
9080       *
9081       * @return string
9082       */
9083  	public function __toString()
9084      {
9085          return md5(serialize($this->data));
9086      }
9087  
9088      /**
9089       * Remove items that link back to this before destroying this object
9090       */
9091  	public function __destruct()
9092      {
9093          if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
9094          {
9095              unset($this->feed);
9096          }
9097      }
9098  
9099      /**
9100       * Get data for an item-level element
9101       *
9102       * This method allows you to get access to ANY element/attribute that is a
9103       * sub-element of the item/entry tag.
9104       *
9105       * See {@see SimplePie::get_feed_tags()} for a description of the return value
9106       *
9107       * @since 1.0
9108       * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
9109       * @param string $namespace The URL of the XML namespace of the elements you're trying to access
9110       * @param string $tag Tag name
9111       * @return array
9112       */
9113  	public function get_item_tags($namespace, $tag)
9114      {
9115          if (isset($this->data['child'][$namespace][$tag]))
9116          {
9117              return $this->data['child'][$namespace][$tag];
9118          }
9119          else
9120          {
9121              return null;
9122          }
9123      }
9124  
9125      /**
9126       * Get the base URL value from the parent feed
9127       *
9128       * Uses `<xml:base>`
9129       *
9130       * @param array $element
9131       * @return string
9132       */
9133  	public function get_base($element = array())
9134      {
9135          return $this->feed->get_base($element);
9136      }
9137  
9138      /**
9139       * Sanitize feed data
9140       *
9141       * @access private
9142       * @see SimplePie::sanitize()
9143       * @param string $data Data to sanitize
9144       * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
9145       * @param string $base Base URL to resolve URLs against
9146       * @return string Sanitized data
9147       */
9148  	public function sanitize($data, $type, $base = '')
9149      {
9150          return $this->feed->sanitize($data, $type, $base);
9151      }
9152  
9153      /**
9154       * Get the parent feed
9155       *
9156       * Note: this may not work as you think for multifeeds!
9157       *
9158       * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
9159       * @since 1.0
9160       * @return SimplePie
9161       */
9162  	public function get_feed()
9163      {
9164          return $this->feed;
9165      }
9166  
9167      /**
9168       * Get the unique identifier for the item
9169       *
9170       * This is usually used when writing code to check for new items in a feed.
9171       *
9172       * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
9173       * for RDF. If none of these are supplied (or `$hash` is true), creates an
9174       * MD5 hash based on the permalink and title. If either of those are not
9175       * supplied, creates a hash based on the full feed data.
9176       *
9177       * @since Beta 2
9178       * @param boolean $hash Should we force using a hash instead of the supplied ID?
9179       * @return string
9180       */
9181  	public function get_id($hash = false)
9182      {
9183          if (!$hash)
9184          {
9185              if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
9186              {
9187                  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9188              }
9189              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
9190              {
9191                  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9192              }
9193              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9194              {
9195                  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9196              }
9197              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
9198              {
9199                  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9200              }
9201              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
9202              {
9203                  return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9204              }
9205              elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
9206              {
9207                  return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
9208              }
9209              elseif (($return = $this->get_permalink()) !== null)
9210              {
9211                  return $return;
9212              }
9213              elseif (($return = $this->get_title()) !== null)
9214              {
9215                  return $return;
9216              }
9217          }
9218          if ($this->get_permalink() !== null || $this->get_title() !== null)
9219          {
9220              return md5($this->get_permalink() . $this->get_title());
9221          }
9222          else
9223          {
9224              return md5(serialize($this->data));
9225          }
9226      }
9227  
9228      /**
9229       * Get the title of the item
9230       *
9231       * Uses `<atom:title>`, `<title>` or `<dc:title>`
9232       *
9233       * @since Beta 2 (previously called `get_item_title` since 0.8)
9234       * @return string|null
9235       */
9236  	public function get_title()
9237      {
9238          if (!isset($this->data['title']))
9239          {
9240              if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
9241              {
9242                  $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9243              }
9244              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
9245              {
9246                  $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9247              }
9248              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
9249              {
9250                  $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9251              }
9252              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
9253              {
9254                  $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9255              }
9256              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
9257              {
9258                  $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9259              }
9260              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
9261              {
9262                  $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9263              }
9264              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
9265              {
9266                  $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9267              }
9268              else
9269              {
9270                  $this->data['title'] = null;
9271              }
9272          }
9273          return $this->data['title'];
9274      }
9275  
9276      /**
9277       * Get the content for the item
9278       *
9279       * Prefers summaries over full content , but will return full content if a
9280       * summary does not exist.
9281       *
9282       * To prefer full content instead, use {@see get_content}
9283       *
9284       * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
9285       * `<itunes:subtitle>`
9286       *
9287       * @since 0.8
9288       * @param boolean $description_only Should we avoid falling back to the content?
9289       * @return string|null
9290       */
9291  	public function get_description($description_only = false)
9292      {
9293          if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
9294          {
9295              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9296          }
9297          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
9298          {
9299              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9300          }
9301          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
9302          {
9303              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
9304          }
9305          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
9306          {
9307              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9308          }
9309          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
9310          {
9311              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9312          }
9313          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
9314          {
9315              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9316          }
9317          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
9318          {
9319              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9320          }
9321          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
9322          {
9323              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9324          }
9325          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
9326          {
9327              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
9328          }
9329  
9330          elseif (!$description_only)
9331          {
9332              return $this->get_content(true);
9333          }
9334          else
9335          {
9336              return null;
9337          }
9338      }
9339  
9340      /**
9341       * Get the content for the item
9342       *
9343       * Prefers full content over summaries, but will return a summary if full
9344       * content does not exist.
9345       *
9346       * To prefer summaries instead, use {@see get_description}
9347       *
9348       * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
9349       *
9350       * @since 1.0
9351       * @param boolean $content_only Should we avoid falling back to the description?
9352       * @return string|null
9353       */
9354  	public function get_content($content_only = false)
9355      {
9356          if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
9357          {
9358              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9359          }
9360          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
9361          {
9362              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9363          }
9364          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
9365          {
9366              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
9367          }
9368          elseif (!$content_only)
9369          {
9370              return $this->get_description(true);
9371          }
9372          else
9373          {
9374              return null;
9375          }
9376      }
9377  
9378      /**
9379       * Get a category for the item
9380       *
9381       * @since Beta 3 (previously called `get_categories()` since Beta 2)
9382       * @param int $key The category that you want to return.  Remember that arrays begin with 0, not 1
9383       * @return SimplePie_Category|null
9384       */
9385  	public function get_category($key = 0)
9386      {
9387          $categories = $this->get_categories();
9388          if (isset($categories[$key]))
9389          {
9390              return $categories[$key];
9391          }
9392          else
9393          {
9394              return null;
9395          }
9396      }
9397  
9398      /**
9399       * Get all categories for the item
9400       *
9401       * Uses `<atom:category>`, `<category>` or `<dc:subject>`
9402       *
9403       * @since Beta 3
9404       * @return array|null List of {@see SimplePie_Category} objects
9405       */
9406  	public function get_categories()
9407      {
9408          $categories = array();
9409  
9410          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
9411          {
9412              $term = null;
9413              $scheme = null;
9414              $label = null;
9415              if (isset($category['attribs']['']['term']))
9416              {
9417                  $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
9418              }
9419              if (isset($category['attribs']['']['scheme']))
9420              {
9421                  $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
9422              }
9423              if (isset($category['attribs']['']['label']))
9424              {
9425                  $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
9426              }
9427              $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
9428          }
9429          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
9430          {
9431              // This is really the label, but keep this as the term also for BC.
9432              // Label will also work on retrieving because that falls back to term.
9433              $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9434              if (isset($category['attribs']['']['domain']))
9435              {
9436                  $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
9437              }
9438              else
9439              {
9440                  $scheme = null;
9441              }
9442              $categories[] = $this->registry->create('Category', array($term, $scheme, null));
9443          }
9444          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
9445          {
9446              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9447          }
9448          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
9449          {
9450              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9451          }
9452  
9453          if (!empty($categories))
9454          {
9455              return array_unique($categories);
9456          }
9457          else
9458          {
9459              return null;
9460          }
9461      }
9462  
9463      /**
9464       * Get an author for the item
9465       *
9466       * @since Beta 2
9467       * @param int $key The author that you want to return.  Remember that arrays begin with 0, not 1
9468       * @return SimplePie_Author|null
9469       */
9470  	public function get_author($key = 0)
9471      {
9472          $authors = $this->get_authors();
9473          if (isset($authors[$key]))
9474          {
9475              return $authors[$key];
9476          }
9477          else
9478          {
9479              return null;
9480          }
9481      }
9482  
9483      /**
9484       * Get a contributor for the item
9485       *
9486       * @since 1.1
9487       * @param int $key The contrbutor that you want to return.  Remember that arrays begin with 0, not 1
9488       * @return SimplePie_Author|null
9489       */
9490  	public function get_contributor($key = 0)
9491      {
9492          $contributors = $this->get_contributors();
9493          if (isset($contributors[$key]))
9494          {
9495              return $contributors[$key];
9496          }
9497          else
9498          {
9499              return null;
9500          }
9501      }
9502  
9503      /**
9504       * Get all contributors for the item
9505       *
9506       * Uses `<atom:contributor>`
9507       *
9508       * @since 1.1
9509       * @return array|null List of {@see SimplePie_Author} objects
9510       */
9511  	public function get_contributors()
9512      {
9513          $contributors = array();
9514          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
9515          {
9516              $name = null;
9517              $uri = null;
9518              $email = null;
9519              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
9520              {
9521                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9522              }
9523              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
9524              {
9525                  $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]));
9526              }
9527              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9528              {
9529                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9530              }
9531              if ($name !== null || $email !== null || $uri !== null)
9532              {
9533                  $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
9534              }
9535          }
9536          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
9537          {
9538              $name = null;
9539              $url = null;
9540              $email = null;
9541              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9542              {
9543                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9544              }
9545              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9546              {
9547                  $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]));
9548              }
9549              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9550              {
9551                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9552              }
9553              if ($name !== null || $email !== null || $url !== null)
9554              {
9555                  $contributors[] = $this->registry->create('Author', array($name, $url, $email));
9556              }
9557          }
9558  
9559          if (!empty($contributors))
9560          {
9561              return array_unique($contributors);
9562          }
9563          else
9564          {
9565              return null;
9566          }
9567      }
9568  
9569      /**
9570       * Get all authors for the item
9571       *
9572       * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
9573       *
9574       * @since Beta 2
9575       * @return array|null List of {@see SimplePie_Author} objects
9576       */
9577  	public function get_authors()
9578      {
9579          $authors = array();
9580          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
9581          {
9582              $name = null;
9583              $uri = null;
9584              $email = null;
9585              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
9586              {
9587                  $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9588              }
9589              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
9590              {
9591                  $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]));
9592              }
9593              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
9594              {
9595                  $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9596              }
9597              if ($name !== null || $email !== null || $uri !== null)
9598              {
9599                  $authors[] = $this->registry->create('Author', array($name, $uri, $email));
9600              }
9601          }
9602          if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
9603          {
9604              $name = null;
9605              $url = null;
9606              $email = null;
9607              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
9608              {
9609                  $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9610              }
9611              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
9612              {
9613                  $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]));
9614              }
9615              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
9616              {
9617                  $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9618              }
9619              if ($name !== null || $email !== null || $url !== null)
9620              {
9621                  $authors[] = $this->registry->create('Author', array($name, $url, $email));
9622              }
9623          }
9624          if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
9625          {
9626              $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
9627          }
9628          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
9629          {
9630              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9631          }
9632          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
9633          {
9634              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9635          }
9636          foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
9637          {
9638              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
9639          }
9640  
9641          if (!empty($authors))
9642          {
9643              return array_unique($authors);
9644          }
9645          elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
9646          {
9647              return $authors;
9648          }
9649          elseif ($authors = $this->feed->get_authors())
9650          {
9651              return $authors;
9652          }
9653          else
9654          {
9655              return null;
9656          }
9657      }
9658  
9659      /**
9660       * Get the copyright info for the item
9661       *
9662       * Uses `<atom:rights>` or `<dc:rights>`
9663       *
9664       * @since 1.1
9665       * @return string
9666       */
9667  	public function get_copyright()
9668      {
9669          if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
9670          {
9671              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
9672          }
9673          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
9674          {
9675              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9676          }
9677          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
9678          {
9679              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
9680          }
9681          else
9682          {
9683              return null;
9684          }
9685      }
9686  
9687      /**
9688       * Get the posting date/time for the item
9689       *
9690       * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
9691       * `<atom:modified>`, `<pubDate>` or `<dc:date>`
9692       *
9693       * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9694       * {@see get_gmdate}
9695       *
9696       * @since Beta 2 (previously called `get_item_date` since 0.8)
9697       *
9698       * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9699       * @return int|string|null
9700       */
9701  	public function get_date($date_format = 'j F Y, g:i a')
9702      {
9703          if (!isset($this->data['date']))
9704          {
9705              if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
9706              {
9707                  $this->data['date']['raw'] = $return[0]['data'];
9708              }
9709              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9710              {
9711                  $this->data['date']['raw'] = $return[0]['data'];
9712              }
9713              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
9714              {
9715                  $this->data['date']['raw'] = $return[0]['data'];
9716              }
9717              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
9718              {
9719                  $this->data['date']['raw'] = $return[0]['data'];
9720              }
9721              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
9722              {
9723                  $this->data['date']['raw'] = $return[0]['data'];
9724              }
9725              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
9726              {
9727                  $this->data['date']['raw'] = $return[0]['data'];
9728              }
9729              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
9730              {
9731                  $this->data['date']['raw'] = $return[0]['data'];
9732              }
9733              elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
9734              {
9735                  $this->data['date']['raw'] = $return[0]['data'];
9736              }
9737  
9738              if (!empty($this->data['date']['raw']))
9739              {
9740                  $parser = $this->registry->call('Parse_Date', 'get');
9741                  $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
9742              }
9743              else
9744              {
9745                  $this->data['date'] = null;
9746              }
9747          }
9748          if ($this->data['date'])
9749          {
9750              $date_format = (string) $date_format;
9751              switch ($date_format)
9752              {
9753                  case '':
9754                      return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
9755  
9756                  case 'U':
9757                      return $this->data['date']['parsed'];
9758  
9759                  default:
9760                      return date($date_format, $this->data['date']['parsed']);
9761              }
9762          }
9763          else
9764          {
9765              return null;
9766          }
9767      }
9768  
9769      /**
9770       * Get the update date/time for the item
9771       *
9772       * Uses `<atom:updated>`
9773       *
9774       * Note: obeys PHP's timezone setting. To get a UTC date/time, use
9775       * {@see get_gmdate}
9776       *
9777       * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
9778       * @return int|string|null
9779       */
9780  	public function get_updated_date($date_format = 'j F Y, g:i a')
9781      {
9782          if (!isset($this->data['updated']))
9783          {
9784              if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
9785              {
9786                  $this->data['updated']['raw'] = $return[0]['data'];
9787              }
9788  
9789              if (!empty($this->data['updated']['raw']))
9790              {
9791                  $parser = $this->registry->call('Parse_Date', 'get');
9792                  $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
9793              }
9794              else
9795              {
9796                  $this->data['updated'] = null;
9797              }
9798          }
9799          if ($this->data['updated'])
9800          {
9801              $date_format = (string) $date_format;
9802              switch ($date_format)
9803              {
9804                  case '':
9805                      return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
9806  
9807                  case 'U':
9808                      return $this->data['updated']['parsed'];
9809  
9810                  default:
9811                      return date($date_format, $this->data['updated']['parsed']);
9812              }
9813          }
9814          else
9815          {
9816              return null;
9817          }
9818      }
9819  
9820      /**
9821       * Get the localized posting date/time for the item
9822       *
9823       * Returns the date formatted in the localized language. To display in
9824       * languages other than the server's default, you need to change the locale
9825       * with {@link http://php.net/setlocale setlocale()}. The available
9826       * localizations depend on which ones are installed on your web server.
9827       *
9828       * @since 1.0
9829       *
9830       * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
9831       * @return int|string|null
9832       */
9833  	public function get_local_date($date_format = '%c')
9834      {
9835          if (!$date_format)
9836          {
9837              return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
9838          }
9839          elseif (($date = $this->get_date('U')) !== null && $date !== false)
9840          {
9841              return strftime($date_format, $date);
9842          }
9843          else
9844          {
9845              return null;
9846          }
9847      }
9848  
9849      /**
9850       * Get the posting date/time for the item (UTC time)
9851       *
9852       * @see get_date
9853       * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9854       * @return int|string|null
9855       */
9856  	public function get_gmdate($date_format = 'j F Y, g:i a')
9857      {
9858          $date = $this->get_date('U');
9859          if ($date === null)
9860          {
9861              return null;
9862          }
9863  
9864          return gmdate($date_format, $date);
9865      }
9866  
9867      /**
9868       * Get the update date/time for the item (UTC time)
9869       *
9870       * @see get_updated_date
9871       * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
9872       * @return int|string|null
9873       */
9874  	public function get_updated_gmdate($date_format = 'j F Y, g:i a')
9875      {
9876          $date = $this->get_updated_date('U');
9877          if ($date === null)
9878          {
9879              return null;
9880          }
9881  
9882          return gmdate($date_format, $date);
9883      }
9884  
9885      /**
9886       * Get the permalink for the item
9887       *
9888       * Returns the first link available with a relationship of "alternate".
9889       * Identical to {@see get_link()} with key 0
9890       *
9891       * @see get_link
9892       * @since 0.8
9893       * @return string|null Permalink URL
9894       */
9895  	public function get_permalink()
9896      {
9897          $link = $this->get_link();
9898          $enclosure = $this->get_enclosure(0);
9899          if ($link !== null)
9900          {
9901              return $link;
9902          }
9903          elseif ($enclosure !== null)
9904          {
9905              return $enclosure->get_link();
9906          }
9907          else
9908          {
9909              return null;
9910          }
9911      }
9912  
9913      /**
9914       * Get a single link for the item
9915       *
9916       * @since Beta 3
9917       * @param int $key The link that you want to return.  Remember that arrays begin with 0, not 1
9918       * @param string $rel The relationship of the link to return
9919       * @return string|null Link URL
9920       */
9921  	public function get_link($key = 0, $rel = 'alternate')
9922      {
9923          $links = $this->get_links($rel);
9924          if ($links[$key] !== null)
9925          {
9926              return $links[$key];
9927          }
9928          else
9929          {
9930              return null;
9931          }
9932      }
9933  
9934      /**
9935       * Get all links for the item
9936       *
9937       * Uses `<atom:link>`, `<link>` or `<guid>`
9938       *
9939       * @since Beta 2
9940       * @param string $rel The relationship of links to return
9941       * @return array|null Links found for the item (strings)
9942       */
9943  	public function get_links($rel = 'alternate')
9944      {
9945          if (!isset($this->data['links']))
9946          {
9947              $this->data['links'] = array();
9948              foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
9949              {
9950                  if (isset($link['attribs']['']['href']))
9951                  {
9952                      $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9953                      $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9954  
9955                  }
9956              }
9957              foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
9958              {
9959                  if (isset($link['attribs']['']['href']))
9960                  {
9961                      $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
9962                      $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
9963                  }
9964              }
9965              if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
9966              {
9967                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9968              }
9969              if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
9970              {
9971                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9972              }
9973              if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
9974              {
9975                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9976              }
9977              if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
9978              {
9979                  if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
9980                  {
9981                      $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
9982                  }
9983              }
9984  
9985              $keys = array_keys($this->data['links']);
9986              foreach ($keys as $key)
9987              {
9988                  if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
9989                  {
9990                      if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
9991                      {
9992                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
9993                          $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
9994                      }
9995                      else
9996                      {
9997                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
9998                      }
9999                  }
10000                  elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
10001                  {
10002                      $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
10003                  }
10004                  $this->data['links'][$key] = array_unique($this->data['links'][$key]);
10005              }
10006          }
10007          if (isset($this->data['links'][$rel]))
10008          {
10009              return $this->data['links'][$rel];
10010          }
10011          else
10012          {
10013              return null;
10014          }
10015      }
10016  
10017      /**
10018       * Get an enclosure from the item
10019       *
10020       * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10021       *
10022       * @since Beta 2
10023       * @todo Add ability to prefer one type of content over another (in a media group).
10024       * @param int $key The enclosure that you want to return.  Remember that arrays begin with 0, not 1
10025       * @return SimplePie_Enclosure|null
10026       */
10027  	public function get_enclosure($key = 0, $prefer = null)
10028      {
10029          $enclosures = $this->get_enclosures();
10030          if (isset($enclosures[$key]))
10031          {
10032              return $enclosures[$key];
10033          }
10034          else
10035          {
10036              return null;
10037          }
10038      }
10039  
10040      /**
10041       * Get all available enclosures (podcasts, etc.)
10042       *
10043       * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
10044       *
10045       * At this point, we're pretty much assuming that all enclosures for an item
10046       * are the same content.  Anything else is too complicated to
10047       * properly support.
10048       *
10049       * @since Beta 2
10050       * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
10051       * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
10052       * @return array|null List of SimplePie_Enclosure items
10053       */
10054  	public function get_enclosures()
10055      {
10056          if (!isset($this->data['enclosures']))
10057          {
10058              $this->data['enclosures'] = array();
10059  
10060              // Elements
10061              $captions_parent = null;
10062              $categories_parent = null;
10063              $copyrights_parent = null;
10064              $credits_parent = null;
10065              $description_parent = null;
10066              $duration_parent = null;
10067              $hashes_parent = null;
10068              $keywords_parent = null;
10069              $player_parent = null;
10070              $ratings_parent = null;
10071              $restrictions_parent = null;
10072              $thumbnails_parent = null;
10073              $title_parent = null;
10074  
10075              // Let's do the channel and item-level ones first, and just re-use them if we need to.
10076              $parent = $this->get_feed();
10077  
10078              // CAPTIONS
10079              if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10080              {
10081                  foreach ($captions as $caption)
10082                  {
10083                      $caption_type = null;
10084                      $caption_lang = null;
10085                      $caption_startTime = null;
10086                      $caption_endTime = null;
10087                      $caption_text = null;
10088                      if (isset($caption['attribs']['']['type']))
10089                      {
10090                          $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10091                      }
10092                      if (isset($caption['attribs']['']['lang']))
10093                      {
10094                          $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10095                      }
10096                      if (isset($caption['attribs']['']['start']))
10097                      {
10098                          $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10099                      }
10100                      if (isset($caption['attribs']['']['end']))
10101                      {
10102                          $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10103                      }
10104                      if (isset($caption['data']))
10105                      {
10106                          $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10107                      }
10108                      $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10109                  }
10110              }
10111              elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
10112              {
10113                  foreach ($captions as $caption)
10114                  {
10115                      $caption_type = null;
10116                      $caption_lang = null;
10117                      $caption_startTime = null;
10118                      $caption_endTime = null;
10119                      $caption_text = null;
10120                      if (isset($caption['attribs']['']['type']))
10121                      {
10122                          $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10123                      }
10124                      if (isset($caption['attribs']['']['lang']))
10125                      {
10126                          $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10127                      }
10128                      if (isset($caption['attribs']['']['start']))
10129                      {
10130                          $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10131                      }
10132                      if (isset($caption['attribs']['']['end']))
10133                      {
10134                          $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10135                      }
10136                      if (isset($caption['data']))
10137                      {
10138                          $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10139                      }
10140                      $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10141                  }
10142              }
10143              if (is_array($captions_parent))
10144              {
10145                  $captions_parent = array_values(array_unique($captions_parent));
10146              }
10147  
10148              // CATEGORIES
10149              foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10150              {
10151                  $term = null;
10152                  $scheme = null;
10153                  $label = null;
10154                  if (isset($category['data']))
10155                  {
10156                      $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10157                  }
10158                  if (isset($category['attribs']['']['scheme']))
10159                  {
10160                      $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10161                  }
10162                  else
10163                  {
10164                      $scheme = 'http://search.yahoo.com/mrss/category_schema';
10165                  }
10166                  if (isset($category['attribs']['']['label']))
10167                  {
10168                      $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10169                  }
10170                  $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10171              }
10172              foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
10173              {
10174                  $term = null;
10175                  $scheme = null;
10176                  $label = null;
10177                  if (isset($category['data']))
10178                  {
10179                      $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10180                  }
10181                  if (isset($category['attribs']['']['scheme']))
10182                  {
10183                      $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10184                  }
10185                  else
10186                  {
10187                      $scheme = 'http://search.yahoo.com/mrss/category_schema';
10188                  }
10189                  if (isset($category['attribs']['']['label']))
10190                  {
10191                      $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10192                  }
10193                  $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10194              }
10195              foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
10196              {
10197                  $term = null;
10198                  $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
10199                  $label = null;
10200                  if (isset($category['attribs']['']['text']))
10201                  {
10202                      $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10203                  }
10204                  $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10205  
10206                  if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
10207                  {
10208                      foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
10209                      {
10210                          if (isset($subcategory['attribs']['']['text']))
10211                          {
10212                              $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
10213                          }
10214                          $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
10215                      }
10216                  }
10217              }
10218              if (is_array($categories_parent))
10219              {
10220                  $categories_parent = array_values(array_unique($categories_parent));
10221              }
10222  
10223              // COPYRIGHT
10224              if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
10225              {
10226                  $copyright_url = null;
10227                  $copyright_label = null;
10228                  if (isset($copyright[0]['attribs']['']['url']))
10229                  {
10230                      $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10231                  }
10232                  if (isset($copyright[0]['data']))
10233                  {
10234                      $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10235                  }
10236                  $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10237              }
10238              elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
10239              {
10240                  $copyright_url = null;
10241                  $copyright_label = null;
10242                  if (isset($copyright[0]['attribs']['']['url']))
10243                  {
10244                      $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10245                  }
10246                  if (isset($copyright[0]['data']))
10247                  {
10248                      $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10249                  }
10250                  $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10251              }
10252  
10253              // CREDITS
10254              if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10255              {
10256                  foreach ($credits as $credit)
10257                  {
10258                      $credit_role = null;
10259                      $credit_scheme = null;
10260                      $credit_name = null;
10261                      if (isset($credit['attribs']['']['role']))
10262                      {
10263                          $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10264                      }
10265                      if (isset($credit['attribs']['']['scheme']))
10266                      {
10267                          $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10268                      }
10269                      else
10270                      {
10271                          $credit_scheme = 'urn:ebu';
10272                      }
10273                      if (isset($credit['data']))
10274                      {
10275                          $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10276                      }
10277                      $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
10278                  }
10279              }
10280              elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
10281              {
10282                  foreach ($credits as $credit)
10283                  {
10284                      $credit_role = null;
10285                      $credit_scheme = null;
10286                      $credit_name = null;
10287                      if (isset($credit['attribs']['']['role']))
10288                      {
10289                          $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10290                      }
10291                      if (isset($credit['attribs']['']['scheme']))
10292                      {
10293                          $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10294                      }
10295                      else
10296                      {
10297                          $credit_scheme = 'urn:ebu';
10298                      }
10299                      if (isset($credit['data']))
10300                      {
10301                          $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10302                      }
10303                      $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
10304                  }
10305              }
10306              if (is_array($credits_parent))
10307              {
10308                  $credits_parent = array_values(array_unique($credits_parent));
10309              }
10310  
10311              // DESCRIPTION
10312              if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
10313              {
10314                  if (isset($description_parent[0]['data']))
10315                  {
10316                      $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10317                  }
10318              }
10319              elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
10320              {
10321                  if (isset($description_parent[0]['data']))
10322                  {
10323                      $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10324                  }
10325              }
10326  
10327              // DURATION
10328              if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
10329              {
10330                  $seconds = null;
10331                  $minutes = null;
10332                  $hours = null;
10333                  if (isset($duration_parent[0]['data']))
10334                  {
10335                      $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10336                      if (sizeof($temp) > 0)
10337                      {
10338                          $seconds = (int) array_pop($temp);
10339                      }
10340                      if (sizeof($temp) > 0)
10341                      {
10342                          $minutes = (int) array_pop($temp);
10343                          $seconds += $minutes * 60;
10344                      }
10345                      if (sizeof($temp) > 0)
10346                      {
10347                          $hours = (int) array_pop($temp);
10348                          $seconds += $hours * 3600;
10349                      }
10350                      unset($temp);
10351                      $duration_parent = $seconds;
10352                  }
10353              }
10354  
10355              // HASHES
10356              if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
10357              {
10358                  foreach ($hashes_iterator as $hash)
10359                  {
10360                      $value = null;
10361                      $algo = null;
10362                      if (isset($hash['data']))
10363                      {
10364                          $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10365                      }
10366                      if (isset($hash['attribs']['']['algo']))
10367                      {
10368                          $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10369                      }
10370                      else
10371                      {
10372                          $algo = 'md5';
10373                      }
10374                      $hashes_parent[] = $algo.':'.$value;
10375                  }
10376              }
10377              elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
10378              {
10379                  foreach ($hashes_iterator as $hash)
10380                  {
10381                      $value = null;
10382                      $algo = null;
10383                      if (isset($hash['data']))
10384                      {
10385                          $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10386                      }
10387                      if (isset($hash['attribs']['']['algo']))
10388                      {
10389                          $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
10390                      }
10391                      else
10392                      {
10393                          $algo = 'md5';
10394                      }
10395                      $hashes_parent[] = $algo.':'.$value;
10396                  }
10397              }
10398              if (is_array($hashes_parent))
10399              {
10400                  $hashes_parent = array_values(array_unique($hashes_parent));
10401              }
10402  
10403              // KEYWORDS
10404              if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10405              {
10406                  if (isset($keywords[0]['data']))
10407                  {
10408                      $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10409                      foreach ($temp as $word)
10410                      {
10411                          $keywords_parent[] = trim($word);
10412                      }
10413                  }
10414                  unset($temp);
10415              }
10416              elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10417              {
10418                  if (isset($keywords[0]['data']))
10419                  {
10420                      $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10421                      foreach ($temp as $word)
10422                      {
10423                          $keywords_parent[] = trim($word);
10424                      }
10425                  }
10426                  unset($temp);
10427              }
10428              elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
10429              {
10430                  if (isset($keywords[0]['data']))
10431                  {
10432                      $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10433                      foreach ($temp as $word)
10434                      {
10435                          $keywords_parent[] = trim($word);
10436                      }
10437                  }
10438                  unset($temp);
10439              }
10440              elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
10441              {
10442                  if (isset($keywords[0]['data']))
10443                  {
10444                      $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
10445                      foreach ($temp as $word)
10446                      {
10447                          $keywords_parent[] = trim($word);
10448                      }
10449                  }
10450                  unset($temp);
10451              }
10452              if (is_array($keywords_parent))
10453              {
10454                  $keywords_parent = array_values(array_unique($keywords_parent));
10455              }
10456  
10457              // PLAYER
10458              if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
10459              {
10460                  if (isset($player_parent[0]['attribs']['']['url']))
10461                  {
10462                      $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10463                  }
10464              }
10465              elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
10466              {
10467                  if (isset($player_parent[0]['attribs']['']['url']))
10468                  {
10469                      $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10470                  }
10471              }
10472  
10473              // RATINGS
10474              if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10475              {
10476                  foreach ($ratings as $rating)
10477                  {
10478                      $rating_scheme = null;
10479                      $rating_value = null;
10480                      if (isset($rating['attribs']['']['scheme']))
10481                      {
10482                          $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10483                      }
10484                      else
10485                      {
10486                          $rating_scheme = 'urn:simple';
10487                      }
10488                      if (isset($rating['data']))
10489                      {
10490                          $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10491                      }
10492                      $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10493                  }
10494              }
10495              elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10496              {
10497                  foreach ($ratings as $rating)
10498                  {
10499                      $rating_scheme = 'urn:itunes';
10500                      $rating_value = null;
10501                      if (isset($rating['data']))
10502                      {
10503                          $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10504                      }
10505                      $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10506                  }
10507              }
10508              elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
10509              {
10510                  foreach ($ratings as $rating)
10511                  {
10512                      $rating_scheme = null;
10513                      $rating_value = null;
10514                      if (isset($rating['attribs']['']['scheme']))
10515                      {
10516                          $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10517                      }
10518                      else
10519                      {
10520                          $rating_scheme = 'urn:simple';
10521                      }
10522                      if (isset($rating['data']))
10523                      {
10524                          $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10525                      }
10526                      $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10527                  }
10528              }
10529              elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
10530              {
10531                  foreach ($ratings as $rating)
10532                  {
10533                      $rating_scheme = 'urn:itunes';
10534                      $rating_value = null;
10535                      if (isset($rating['data']))
10536                      {
10537                          $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10538                      }
10539                      $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
10540                  }
10541              }
10542              if (is_array($ratings_parent))
10543              {
10544                  $ratings_parent = array_values(array_unique($ratings_parent));
10545              }
10546  
10547              // RESTRICTIONS
10548              if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
10549              {
10550                  foreach ($restrictions as $restriction)
10551                  {
10552                      $restriction_relationship = null;
10553                      $restriction_type = null;
10554                      $restriction_value = null;
10555                      if (isset($restriction['attribs']['']['relationship']))
10556                      {
10557                          $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10558                      }
10559                      if (isset($restriction['attribs']['']['type']))
10560                      {
10561                          $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10562                      }
10563                      if (isset($restriction['data']))
10564                      {
10565                          $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10566                      }
10567                      $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10568                  }
10569              }
10570              elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10571              {
10572                  foreach ($restrictions as $restriction)
10573                  {
10574                      $restriction_relationship = 'allow';
10575                      $restriction_type = null;
10576                      $restriction_value = 'itunes';
10577                      if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10578                      {
10579                          $restriction_relationship = 'deny';
10580                      }
10581                      $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10582                  }
10583              }
10584              elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
10585              {
10586                  foreach ($restrictions as $restriction)
10587                  {
10588                      $restriction_relationship = null;
10589                      $restriction_type = null;
10590                      $restriction_value = null;
10591                      if (isset($restriction['attribs']['']['relationship']))
10592                      {
10593                          $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
10594                      }
10595                      if (isset($restriction['attribs']['']['type']))
10596                      {
10597                          $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10598                      }
10599                      if (isset($restriction['data']))
10600                      {
10601                          $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10602                      }
10603                      $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10604                  }
10605              }
10606              elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
10607              {
10608                  foreach ($restrictions as $restriction)
10609                  {
10610                      $restriction_relationship = 'allow';
10611                      $restriction_type = null;
10612                      $restriction_value = 'itunes';
10613                      if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
10614                      {
10615                          $restriction_relationship = 'deny';
10616                      }
10617                      $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
10618                  }
10619              }
10620              if (is_array($restrictions_parent))
10621              {
10622                  $restrictions_parent = array_values(array_unique($restrictions_parent));
10623              }
10624              else
10625              {
10626                  $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
10627              }
10628  
10629              // THUMBNAILS
10630              if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10631              {
10632                  foreach ($thumbnails as $thumbnail)
10633                  {
10634                      if (isset($thumbnail['attribs']['']['url']))
10635                      {
10636                          $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10637                      }
10638                  }
10639              }
10640              elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
10641              {
10642                  foreach ($thumbnails as $thumbnail)
10643                  {
10644                      if (isset($thumbnail['attribs']['']['url']))
10645                      {
10646                          $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10647                      }
10648                  }
10649              }
10650  
10651              // TITLES
10652              if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10653              {
10654                  if (isset($title_parent[0]['data']))
10655                  {
10656                      $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10657                  }
10658              }
10659              elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
10660              {
10661                  if (isset($title_parent[0]['data']))
10662                  {
10663                      $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10664                  }
10665              }
10666  
10667              // Clear the memory
10668              unset($parent);
10669  
10670              // Attributes
10671              $bitrate = null;
10672              $channels = null;
10673              $duration = null;
10674              $expression = null;
10675              $framerate = null;
10676              $height = null;
10677              $javascript = null;
10678              $lang = null;
10679              $length = null;
10680              $medium = null;
10681              $samplingrate = null;
10682              $type = null;
10683              $url = null;
10684              $width = null;
10685  
10686              // Elements
10687              $captions = null;
10688              $categories = null;
10689              $copyrights = null;
10690              $credits = null;
10691              $description = null;
10692              $hashes = null;
10693              $keywords = null;
10694              $player = null;
10695              $ratings = null;
10696              $restrictions = null;
10697              $thumbnails = null;
10698              $title = null;
10699  
10700              // If we have media:group tags, loop through them.
10701              foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
10702              {
10703                  if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
10704                  {
10705                      // If we have media:content tags, loop through them.
10706                      foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
10707                      {
10708                          if (isset($content['attribs']['']['url']))
10709                          {
10710                              // Attributes
10711                              $bitrate = null;
10712                              $channels = null;
10713                              $duration = null;
10714                              $expression = null;
10715                              $framerate = null;
10716                              $height = null;
10717                              $javascript = null;
10718                              $lang = null;
10719                              $length = null;
10720                              $medium = null;
10721                              $samplingrate = null;
10722                              $type = null;
10723                              $url = null;
10724                              $width = null;
10725  
10726                              // Elements
10727                              $captions = null;
10728                              $categories = null;
10729                              $copyrights = null;
10730                              $credits = null;
10731                              $description = null;
10732                              $hashes = null;
10733                              $keywords = null;
10734                              $player = null;
10735                              $ratings = null;
10736                              $restrictions = null;
10737                              $thumbnails = null;
10738                              $title = null;
10739  
10740                              // Start checking the attributes of media:content
10741                              if (isset($content['attribs']['']['bitrate']))
10742                              {
10743                                  $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10744                              }
10745                              if (isset($content['attribs']['']['channels']))
10746                              {
10747                                  $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
10748                              }
10749                              if (isset($content['attribs']['']['duration']))
10750                              {
10751                                  $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
10752                              }
10753                              else
10754                              {
10755                                  $duration = $duration_parent;
10756                              }
10757                              if (isset($content['attribs']['']['expression']))
10758                              {
10759                                  $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
10760                              }
10761                              if (isset($content['attribs']['']['framerate']))
10762                              {
10763                                  $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
10764                              }
10765                              if (isset($content['attribs']['']['height']))
10766                              {
10767                                  $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
10768                              }
10769                              if (isset($content['attribs']['']['lang']))
10770                              {
10771                                  $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10772                              }
10773                              if (isset($content['attribs']['']['fileSize']))
10774                              {
10775                                  $length = ceil($content['attribs']['']['fileSize']);
10776                              }
10777                              if (isset($content['attribs']['']['medium']))
10778                              {
10779                                  $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
10780                              }
10781                              if (isset($content['attribs']['']['samplingrate']))
10782                              {
10783                                  $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
10784                              }
10785                              if (isset($content['attribs']['']['type']))
10786                              {
10787                                  $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10788                              }
10789                              if (isset($content['attribs']['']['width']))
10790                              {
10791                                  $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
10792                              }
10793                              $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
10794  
10795                              // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
10796  
10797                              // CAPTIONS
10798                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10799                              {
10800                                  foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10801                                  {
10802                                      $caption_type = null;
10803                                      $caption_lang = null;
10804                                      $caption_startTime = null;
10805                                      $caption_endTime = null;
10806                                      $caption_text = null;
10807                                      if (isset($caption['attribs']['']['type']))
10808                                      {
10809                                          $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10810                                      }
10811                                      if (isset($caption['attribs']['']['lang']))
10812                                      {
10813                                          $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10814                                      }
10815                                      if (isset($caption['attribs']['']['start']))
10816                                      {
10817                                          $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10818                                      }
10819                                      if (isset($caption['attribs']['']['end']))
10820                                      {
10821                                          $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10822                                      }
10823                                      if (isset($caption['data']))
10824                                      {
10825                                          $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10826                                      }
10827                                      $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10828                                  }
10829                                  if (is_array($captions))
10830                                  {
10831                                      $captions = array_values(array_unique($captions));
10832                                  }
10833                              }
10834                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
10835                              {
10836                                  foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
10837                                  {
10838                                      $caption_type = null;
10839                                      $caption_lang = null;
10840                                      $caption_startTime = null;
10841                                      $caption_endTime = null;
10842                                      $caption_text = null;
10843                                      if (isset($caption['attribs']['']['type']))
10844                                      {
10845                                          $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
10846                                      }
10847                                      if (isset($caption['attribs']['']['lang']))
10848                                      {
10849                                          $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
10850                                      }
10851                                      if (isset($caption['attribs']['']['start']))
10852                                      {
10853                                          $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
10854                                      }
10855                                      if (isset($caption['attribs']['']['end']))
10856                                      {
10857                                          $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
10858                                      }
10859                                      if (isset($caption['data']))
10860                                      {
10861                                          $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10862                                      }
10863                                      $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
10864                                  }
10865                                  if (is_array($captions))
10866                                  {
10867                                      $captions = array_values(array_unique($captions));
10868                                  }
10869                              }
10870                              else
10871                              {
10872                                  $captions = $captions_parent;
10873                              }
10874  
10875                              // CATEGORIES
10876                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10877                              {
10878                                  foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10879                                  {
10880                                      $term = null;
10881                                      $scheme = null;
10882                                      $label = null;
10883                                      if (isset($category['data']))
10884                                      {
10885                                          $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10886                                      }
10887                                      if (isset($category['attribs']['']['scheme']))
10888                                      {
10889                                          $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10890                                      }
10891                                      else
10892                                      {
10893                                          $scheme = 'http://search.yahoo.com/mrss/category_schema';
10894                                      }
10895                                      if (isset($category['attribs']['']['label']))
10896                                      {
10897                                          $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10898                                      }
10899                                      $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10900                                  }
10901                              }
10902                              if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
10903                              {
10904                                  foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
10905                                  {
10906                                      $term = null;
10907                                      $scheme = null;
10908                                      $label = null;
10909                                      if (isset($category['data']))
10910                                      {
10911                                          $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10912                                      }
10913                                      if (isset($category['attribs']['']['scheme']))
10914                                      {
10915                                          $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10916                                      }
10917                                      else
10918                                      {
10919                                          $scheme = 'http://search.yahoo.com/mrss/category_schema';
10920                                      }
10921                                      if (isset($category['attribs']['']['label']))
10922                                      {
10923                                          $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
10924                                      }
10925                                      $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
10926                                  }
10927                              }
10928                              if (is_array($categories) && is_array($categories_parent))
10929                              {
10930                                  $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
10931                              }
10932                              elseif (is_array($categories))
10933                              {
10934                                  $categories = array_values(array_unique($categories));
10935                              }
10936                              elseif (is_array($categories_parent))
10937                              {
10938                                  $categories = array_values(array_unique($categories_parent));
10939                              }
10940  
10941                              // COPYRIGHTS
10942                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10943                              {
10944                                  $copyright_url = null;
10945                                  $copyright_label = null;
10946                                  if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10947                                  {
10948                                      $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10949                                  }
10950                                  if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10951                                  {
10952                                      $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10953                                  }
10954                                  $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10955                              }
10956                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
10957                              {
10958                                  $copyright_url = null;
10959                                  $copyright_label = null;
10960                                  if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
10961                                  {
10962                                      $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
10963                                  }
10964                                  if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
10965                                  {
10966                                      $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10967                                  }
10968                                  $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
10969                              }
10970                              else
10971                              {
10972                                  $copyrights = $copyrights_parent;
10973                              }
10974  
10975                              // CREDITS
10976                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
10977                              {
10978                                  foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
10979                                  {
10980                                      $credit_role = null;
10981                                      $credit_scheme = null;
10982                                      $credit_name = null;
10983                                      if (isset($credit['attribs']['']['role']))
10984                                      {
10985                                          $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
10986                                      }
10987                                      if (isset($credit['attribs']['']['scheme']))
10988                                      {
10989                                          $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
10990                                      }
10991                                      else
10992                                      {
10993                                          $credit_scheme = 'urn:ebu';
10994                                      }
10995                                      if (isset($credit['data']))
10996                                      {
10997                                          $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
10998                                      }
10999                                      $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11000                                  }
11001                                  if (is_array($credits))
11002                                  {
11003                                      $credits = array_values(array_unique($credits));
11004                                  }
11005                              }
11006                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11007                              {
11008                                  foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11009                                  {
11010                                      $credit_role = null;
11011                                      $credit_scheme = null;
11012                                      $credit_name = null;
11013                                      if (isset($credit['attribs']['']['role']))
11014                                      {
11015                                          $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11016                                      }
11017                                      if (isset($credit['attribs']['']['scheme']))
11018                                      {
11019                                          $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11020                                      }
11021                                      else
11022                                      {
11023                                          $credit_scheme = 'urn:ebu';
11024                                      }
11025                                      if (isset($credit['data']))
11026                                      {
11027                                          $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11028                                      }
11029                                      $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11030                                  }
11031                                  if (is_array($credits))
11032                                  {
11033                                      $credits = array_values(array_unique($credits));
11034                                  }
11035                              }
11036                              else
11037                              {
11038                                  $credits = $credits_parent;
11039                              }
11040  
11041                              // DESCRIPTION
11042                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11043                              {
11044                                  $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11045                              }
11046                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11047                              {
11048                                  $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11049                              }
11050                              else
11051                              {
11052                                  $description = $description_parent;
11053                              }
11054  
11055                              // HASHES
11056                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11057                              {
11058                                  foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11059                                  {
11060                                      $value = null;
11061                                      $algo = null;
11062                                      if (isset($hash['data']))
11063                                      {
11064                                          $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11065                                      }
11066                                      if (isset($hash['attribs']['']['algo']))
11067                                      {
11068                                          $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11069                                      }
11070                                      else
11071                                      {
11072                                          $algo = 'md5';
11073                                      }
11074                                      $hashes[] = $algo.':'.$value;
11075                                  }
11076                                  if (is_array($hashes))
11077                                  {
11078                                      $hashes = array_values(array_unique($hashes));
11079                                  }
11080                              }
11081                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11082                              {
11083                                  foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11084                                  {
11085                                      $value = null;
11086                                      $algo = null;
11087                                      if (isset($hash['data']))
11088                                      {
11089                                          $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11090                                      }
11091                                      if (isset($hash['attribs']['']['algo']))
11092                                      {
11093                                          $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11094                                      }
11095                                      else
11096                                      {
11097                                          $algo = 'md5';
11098                                      }
11099                                      $hashes[] = $algo.':'.$value;
11100                                  }
11101                                  if (is_array($hashes))
11102                                  {
11103                                      $hashes = array_values(array_unique($hashes));
11104                                  }
11105                              }
11106                              else
11107                              {
11108                                  $hashes = $hashes_parent;
11109                              }
11110  
11111                              // KEYWORDS
11112                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11113                              {
11114                                  if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11115                                  {
11116                                      $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11117                                      foreach ($temp as $word)
11118                                      {
11119                                          $keywords[] = trim($word);
11120                                      }
11121                                      unset($temp);
11122                                  }
11123                                  if (is_array($keywords))
11124                                  {
11125                                      $keywords = array_values(array_unique($keywords));
11126                                  }
11127                              }
11128                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11129                              {
11130                                  if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11131                                  {
11132                                      $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11133                                      foreach ($temp as $word)
11134                                      {
11135                                          $keywords[] = trim($word);
11136                                      }
11137                                      unset($temp);
11138                                  }
11139                                  if (is_array($keywords))
11140                                  {
11141                                      $keywords = array_values(array_unique($keywords));
11142                                  }
11143                              }
11144                              else
11145                              {
11146                                  $keywords = $keywords_parent;
11147                              }
11148  
11149                              // PLAYER
11150                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11151                              {
11152                                  $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11153                              }
11154                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11155                              {
11156                                  $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11157                              }
11158                              else
11159                              {
11160                                  $player = $player_parent;
11161                              }
11162  
11163                              // RATINGS
11164                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11165                              {
11166                                  foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11167                                  {
11168                                      $rating_scheme = null;
11169                                      $rating_value = null;
11170                                      if (isset($rating['attribs']['']['scheme']))
11171                                      {
11172                                          $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11173                                      }
11174                                      else
11175                                      {
11176                                          $rating_scheme = 'urn:simple';
11177                                      }
11178                                      if (isset($rating['data']))
11179                                      {
11180                                          $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11181                                      }
11182                                      $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11183                                  }
11184                                  if (is_array($ratings))
11185                                  {
11186                                      $ratings = array_values(array_unique($ratings));
11187                                  }
11188                              }
11189                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11190                              {
11191                                  foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11192                                  {
11193                                      $rating_scheme = null;
11194                                      $rating_value = null;
11195                                      if (isset($rating['attribs']['']['scheme']))
11196                                      {
11197                                          $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11198                                      }
11199                                      else
11200                                      {
11201                                          $rating_scheme = 'urn:simple';
11202                                      }
11203                                      if (isset($rating['data']))
11204                                      {
11205                                          $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11206                                      }
11207                                      $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11208                                  }
11209                                  if (is_array($ratings))
11210                                  {
11211                                      $ratings = array_values(array_unique($ratings));
11212                                  }
11213                              }
11214                              else
11215                              {
11216                                  $ratings = $ratings_parent;
11217                              }
11218  
11219                              // RESTRICTIONS
11220                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11221                              {
11222                                  foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11223                                  {
11224                                      $restriction_relationship = null;
11225                                      $restriction_type = null;
11226                                      $restriction_value = null;
11227                                      if (isset($restriction['attribs']['']['relationship']))
11228                                      {
11229                                          $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11230                                      }
11231                                      if (isset($restriction['attribs']['']['type']))
11232                                      {
11233                                          $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11234                                      }
11235                                      if (isset($restriction['data']))
11236                                      {
11237                                          $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11238                                      }
11239                                      $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11240                                  }
11241                                  if (is_array($restrictions))
11242                                  {
11243                                      $restrictions = array_values(array_unique($restrictions));
11244                                  }
11245                              }
11246                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11247                              {
11248                                  foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11249                                  {
11250                                      $restriction_relationship = null;
11251                                      $restriction_type = null;
11252                                      $restriction_value = null;
11253                                      if (isset($restriction['attribs']['']['relationship']))
11254                                      {
11255                                          $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11256                                      }
11257                                      if (isset($restriction['attribs']['']['type']))
11258                                      {
11259                                          $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11260                                      }
11261                                      if (isset($restriction['data']))
11262                                      {
11263                                          $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11264                                      }
11265                                      $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11266                                  }
11267                                  if (is_array($restrictions))
11268                                  {
11269                                      $restrictions = array_values(array_unique($restrictions));
11270                                  }
11271                              }
11272                              else
11273                              {
11274                                  $restrictions = $restrictions_parent;
11275                              }
11276  
11277                              // THUMBNAILS
11278                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11279                              {
11280                                  foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11281                                  {
11282                                      $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11283                                  }
11284                                  if (is_array($thumbnails))
11285                                  {
11286                                      $thumbnails = array_values(array_unique($thumbnails));
11287                                  }
11288                              }
11289                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11290                              {
11291                                  foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11292                                  {
11293                                      $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11294                                  }
11295                                  if (is_array($thumbnails))
11296                                  {
11297                                      $thumbnails = array_values(array_unique($thumbnails));
11298                                  }
11299                              }
11300                              else
11301                              {
11302                                  $thumbnails = $thumbnails_parent;
11303                              }
11304  
11305                              // TITLES
11306                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11307                              {
11308                                  $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11309                              }
11310                              elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11311                              {
11312                                  $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11313                              }
11314                              else
11315                              {
11316                                  $title = $title_parent;
11317                              }
11318  
11319                              $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
11320                          }
11321                      }
11322                  }
11323              }
11324  
11325              // If we have standalone media:content tags, loop through them.
11326              if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
11327              {
11328                  foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
11329                  {
11330                      if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11331                      {
11332                          // Attributes
11333                          $bitrate = null;
11334                          $channels = null;
11335                          $duration = null;
11336                          $expression = null;
11337                          $framerate = null;
11338                          $height = null;
11339                          $javascript = null;
11340                          $lang = null;
11341                          $length = null;
11342                          $medium = null;
11343                          $samplingrate = null;
11344                          $type = null;
11345                          $url = null;
11346                          $width = null;
11347  
11348                          // Elements
11349                          $captions = null;
11350                          $categories = null;
11351                          $copyrights = null;
11352                          $credits = null;
11353                          $description = null;
11354                          $hashes = null;
11355                          $keywords = null;
11356                          $player = null;
11357                          $ratings = null;
11358                          $restrictions = null;
11359                          $thumbnails = null;
11360                          $title = null;
11361  
11362                          // Start checking the attributes of media:content
11363                          if (isset($content['attribs']['']['bitrate']))
11364                          {
11365                              $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11366                          }
11367                          if (isset($content['attribs']['']['channels']))
11368                          {
11369                              $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
11370                          }
11371                          if (isset($content['attribs']['']['duration']))
11372                          {
11373                              $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
11374                          }
11375                          else
11376                          {
11377                              $duration = $duration_parent;
11378                          }
11379                          if (isset($content['attribs']['']['expression']))
11380                          {
11381                              $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
11382                          }
11383                          if (isset($content['attribs']['']['framerate']))
11384                          {
11385                              $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
11386                          }
11387                          if (isset($content['attribs']['']['height']))
11388                          {
11389                              $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
11390                          }
11391                          if (isset($content['attribs']['']['lang']))
11392                          {
11393                              $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11394                          }
11395                          if (isset($content['attribs']['']['fileSize']))
11396                          {
11397                              $length = ceil($content['attribs']['']['fileSize']);
11398                          }
11399                          if (isset($content['attribs']['']['medium']))
11400                          {
11401                              $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
11402                          }
11403                          if (isset($content['attribs']['']['samplingrate']))
11404                          {
11405                              $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
11406                          }
11407                          if (isset($content['attribs']['']['type']))
11408                          {
11409                              $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11410                          }
11411                          if (isset($content['attribs']['']['width']))
11412                          {
11413                              $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
11414                          }
11415                          if (isset($content['attribs']['']['url']))
11416                          {
11417                              $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11418                          }
11419                          // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
11420  
11421                          // CAPTIONS
11422                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
11423                          {
11424                              foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
11425                              {
11426                                  $caption_type = null;
11427                                  $caption_lang = null;
11428                                  $caption_startTime = null;
11429                                  $caption_endTime = null;
11430                                  $caption_text = null;
11431                                  if (isset($caption['attribs']['']['type']))
11432                                  {
11433                                      $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11434                                  }
11435                                  if (isset($caption['attribs']['']['lang']))
11436                                  {
11437                                      $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
11438                                  }
11439                                  if (isset($caption['attribs']['']['start']))
11440                                  {
11441                                      $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
11442                                  }
11443                                  if (isset($caption['attribs']['']['end']))
11444                                  {
11445                                      $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
11446                                  }
11447                                  if (isset($caption['data']))
11448                                  {
11449                                      $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11450                                  }
11451                                  $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
11452                              }
11453                              if (is_array($captions))
11454                              {
11455                                  $captions = array_values(array_unique($captions));
11456                              }
11457                          }
11458                          else
11459                          {
11460                              $captions = $captions_parent;
11461                          }
11462  
11463                          // CATEGORIES
11464                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
11465                          {
11466                              foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
11467                              {
11468                                  $term = null;
11469                                  $scheme = null;
11470                                  $label = null;
11471                                  if (isset($category['data']))
11472                                  {
11473                                      $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11474                                  }
11475                                  if (isset($category['attribs']['']['scheme']))
11476                                  {
11477                                      $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11478                                  }
11479                                  else
11480                                  {
11481                                      $scheme = 'http://search.yahoo.com/mrss/category_schema';
11482                                  }
11483                                  if (isset($category['attribs']['']['label']))
11484                                  {
11485                                      $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
11486                                  }
11487                                  $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
11488                              }
11489                          }
11490                          if (is_array($categories) && is_array($categories_parent))
11491                          {
11492                              $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
11493                          }
11494                          elseif (is_array($categories))
11495                          {
11496                              $categories = array_values(array_unique($categories));
11497                          }
11498                          elseif (is_array($categories_parent))
11499                          {
11500                              $categories = array_values(array_unique($categories_parent));
11501                          }
11502                          else
11503                          {
11504                              $categories = null;
11505                          }
11506  
11507                          // COPYRIGHTS
11508                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
11509                          {
11510                              $copyright_url = null;
11511                              $copyright_label = null;
11512                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
11513                              {
11514                                  $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
11515                              }
11516                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
11517                              {
11518                                  $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11519                              }
11520                              $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
11521                          }
11522                          else
11523                          {
11524                              $copyrights = $copyrights_parent;
11525                          }
11526  
11527                          // CREDITS
11528                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
11529                          {
11530                              foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
11531                              {
11532                                  $credit_role = null;
11533                                  $credit_scheme = null;
11534                                  $credit_name = null;
11535                                  if (isset($credit['attribs']['']['role']))
11536                                  {
11537                                      $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
11538                                  }
11539                                  if (isset($credit['attribs']['']['scheme']))
11540                                  {
11541                                      $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11542                                  }
11543                                  else
11544                                  {
11545                                      $credit_scheme = 'urn:ebu';
11546                                  }
11547                                  if (isset($credit['data']))
11548                                  {
11549                                      $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11550                                  }
11551                                  $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
11552                              }
11553                              if (is_array($credits))
11554                              {
11555                                  $credits = array_values(array_unique($credits));
11556                              }
11557                          }
11558                          else
11559                          {
11560                              $credits = $credits_parent;
11561                          }
11562  
11563                          // DESCRIPTION
11564                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
11565                          {
11566                              $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11567                          }
11568                          else
11569                          {
11570                              $description = $description_parent;
11571                          }
11572  
11573                          // HASHES
11574                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
11575                          {
11576                              foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
11577                              {
11578                                  $value = null;
11579                                  $algo = null;
11580                                  if (isset($hash['data']))
11581                                  {
11582                                      $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11583                                  }
11584                                  if (isset($hash['attribs']['']['algo']))
11585                                  {
11586                                      $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
11587                                  }
11588                                  else
11589                                  {
11590                                      $algo = 'md5';
11591                                  }
11592                                  $hashes[] = $algo.':'.$value;
11593                              }
11594                              if (is_array($hashes))
11595                              {
11596                                  $hashes = array_values(array_unique($hashes));
11597                              }
11598                          }
11599                          else
11600                          {
11601                              $hashes = $hashes_parent;
11602                          }
11603  
11604                          // KEYWORDS
11605                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
11606                          {
11607                              if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
11608                              {
11609                                  $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
11610                                  foreach ($temp as $word)
11611                                  {
11612                                      $keywords[] = trim($word);
11613                                  }
11614                                  unset($temp);
11615                              }
11616                              if (is_array($keywords))
11617                              {
11618                                  $keywords = array_values(array_unique($keywords));
11619                              }
11620                          }
11621                          else
11622                          {
11623                              $keywords = $keywords_parent;
11624                          }
11625  
11626                          // PLAYER
11627                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
11628                          {
11629                              $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11630                          }
11631                          else
11632                          {
11633                              $player = $player_parent;
11634                          }
11635  
11636                          // RATINGS
11637                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
11638                          {
11639                              foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
11640                              {
11641                                  $rating_scheme = null;
11642                                  $rating_value = null;
11643                                  if (isset($rating['attribs']['']['scheme']))
11644                                  {
11645                                      $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
11646                                  }
11647                                  else
11648                                  {
11649                                      $rating_scheme = 'urn:simple';
11650                                  }
11651                                  if (isset($rating['data']))
11652                                  {
11653                                      $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11654                                  }
11655                                  $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
11656                              }
11657                              if (is_array($ratings))
11658                              {
11659                                  $ratings = array_values(array_unique($ratings));
11660                              }
11661                          }
11662                          else
11663                          {
11664                              $ratings = $ratings_parent;
11665                          }
11666  
11667                          // RESTRICTIONS
11668                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
11669                          {
11670                              foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
11671                              {
11672                                  $restriction_relationship = null;
11673                                  $restriction_type = null;
11674                                  $restriction_value = null;
11675                                  if (isset($restriction['attribs']['']['relationship']))
11676                                  {
11677                                      $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
11678                                  }
11679                                  if (isset($restriction['attribs']['']['type']))
11680                                  {
11681                                      $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11682                                  }
11683                                  if (isset($restriction['data']))
11684                                  {
11685                                      $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11686                                  }
11687                                  $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
11688                              }
11689                              if (is_array($restrictions))
11690                              {
11691                                  $restrictions = array_values(array_unique($restrictions));
11692                              }
11693                          }
11694                          else
11695                          {
11696                              $restrictions = $restrictions_parent;
11697                          }
11698  
11699                          // THUMBNAILS
11700                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
11701                          {
11702                              foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
11703                              {
11704                                  $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
11705                              }
11706                              if (is_array($thumbnails))
11707                              {
11708                                  $thumbnails = array_values(array_unique($thumbnails));
11709                              }
11710                          }
11711                          else
11712                          {
11713                              $thumbnails = $thumbnails_parent;
11714                          }
11715  
11716                          // TITLES
11717                          if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
11718                          {
11719                              $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
11720                          }
11721                          else
11722                          {
11723                              $title = $title_parent;
11724                          }
11725  
11726                          $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
11727                      }
11728                  }
11729              }
11730  
11731              foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
11732              {
11733                  if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11734                  {
11735                      // Attributes
11736                      $bitrate = null;
11737                      $channels = null;
11738                      $duration = null;
11739                      $expression = null;
11740                      $framerate = null;
11741                      $height = null;
11742                      $javascript = null;
11743                      $lang = null;
11744                      $length = null;
11745                      $medium = null;
11746                      $samplingrate = null;
11747                      $type = null;
11748                      $url = null;
11749                      $width = null;
11750  
11751                      $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11752                      if (isset($link['attribs']['']['type']))
11753                      {
11754                          $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11755                      }
11756                      if (isset($link['attribs']['']['length']))
11757                      {
11758                          $length = ceil($link['attribs']['']['length']);
11759                      }
11760  
11761                      // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11762                      $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11763                  }
11764              }
11765  
11766              foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
11767              {
11768                  if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
11769                  {
11770                      // Attributes
11771                      $bitrate = null;
11772                      $channels = null;
11773                      $duration = null;
11774                      $expression = null;
11775                      $framerate = null;
11776                      $height = null;
11777                      $javascript = null;
11778                      $lang = null;
11779                      $length = null;
11780                      $medium = null;
11781                      $samplingrate = null;
11782                      $type = null;
11783                      $url = null;
11784                      $width = null;
11785  
11786                      $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
11787                      if (isset($link['attribs']['']['type']))
11788                      {
11789                          $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11790                      }
11791                      if (isset($link['attribs']['']['length']))
11792                      {
11793                          $length = ceil($link['attribs']['']['length']);
11794                      }
11795  
11796                      // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11797                      $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11798                  }
11799              }
11800  
11801              if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
11802              {
11803                  if (isset($enclosure[0]['attribs']['']['url']))
11804                  {
11805                      // Attributes
11806                      $bitrate = null;
11807                      $channels = null;
11808                      $duration = null;
11809                      $expression = null;
11810                      $framerate = null;
11811                      $height = null;
11812                      $javascript = null;
11813                      $lang = null;
11814                      $length = null;
11815                      $medium = null;
11816                      $samplingrate = null;
11817                      $type = null;
11818                      $url = null;
11819                      $width = null;
11820  
11821                      $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
11822                      if (isset($enclosure[0]['attribs']['']['type']))
11823                      {
11824                          $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
11825                      }
11826                      if (isset($enclosure[0]['attribs']['']['length']))
11827                      {
11828                          $length = ceil($enclosure[0]['attribs']['']['length']);
11829                      }
11830  
11831                      // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11832                      $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11833                  }
11834              }
11835  
11836              if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
11837              {
11838                  // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
11839                  $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
11840              }
11841  
11842              $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
11843          }
11844          if (!empty($this->data['enclosures']))
11845          {
11846              return $this->data['enclosures'];
11847          }
11848          else
11849          {
11850              return null;
11851          }
11852      }
11853  
11854      /**
11855       * Get the latitude coordinates for the item
11856       *
11857       * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11858       *
11859       * Uses `<geo:lat>` or `<georss:point>`
11860       *
11861       * @since 1.0
11862       * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11863       * @link http://www.georss.org/ GeoRSS
11864       * @return string|null
11865       */
11866  	public function get_latitude()
11867      {
11868          if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
11869          {
11870              return (float) $return[0]['data'];
11871          }
11872          elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
11873          {
11874              return (float) $match[1];
11875          }
11876          else
11877          {
11878              return null;
11879          }
11880      }
11881  
11882      /**
11883       * Get the longitude coordinates for the item
11884       *
11885       * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
11886       *
11887       * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
11888       *
11889       * @since 1.0
11890       * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
11891       * @link http://www.georss.org/ GeoRSS
11892       * @return string|null
11893       */
11894  	public function get_longitude()
11895      {
11896          if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
11897          {
11898              return (float) $return[0]['data'];
11899          }
11900          elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
11901          {
11902              return (float) $return[0]['data'];
11903          }
11904          elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
11905          {
11906              return (float) $match[2];
11907          }
11908          else
11909          {
11910              return null;
11911          }
11912      }
11913  
11914      /**
11915       * Get the `<atom:source>` for the item
11916       *
11917       * @since 1.1
11918       * @return SimplePie_Source|null
11919       */
11920  	public function get_source()
11921      {
11922          if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
11923          {
11924              return $this->registry->create('Source', array($this, $return[0]));
11925          }
11926          else
11927          {
11928              return null;
11929          }
11930      }
11931  }
11932  
11933  /**
11934   * Used for feed auto-discovery
11935   *
11936   *
11937   * This class can be overloaded with {@see SimplePie::set_locator_class()}
11938   *
11939   * @package SimplePie
11940   */
11941  class SimplePie_Locator
11942  {
11943      var $useragent;
11944      var $timeout;
11945      var $file;
11946      var $local = array();
11947      var $elsewhere = array();
11948      var $cached_entities = array();
11949      var $http_base;
11950      var $base;
11951      var $base_location = 0;
11952      var $checked_feeds = 0;
11953      var $max_checked_feeds = 10;
11954      protected $registry;
11955  
11956  	public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
11957      {
11958          $this->file = $file;
11959          $this->useragent = $useragent;
11960          $this->timeout = $timeout;
11961          $this->max_checked_feeds = $max_checked_feeds;
11962  
11963          if (class_exists('DOMDocument'))
11964          {
11965              $this->dom = new DOMDocument();
11966  
11967              set_error_handler(array('SimplePie_Misc', 'silence_errors'));
11968              $this->dom->loadHTML($this->file->body);
11969              restore_error_handler();
11970          }
11971          else
11972          {
11973              $this->dom = null;
11974          }
11975      }
11976  
11977  	public function set_registry(SimplePie_Registry $registry)
11978      {
11979          $this->registry = $registry;
11980      }
11981  
11982  	public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
11983      {
11984          if ($this->is_feed($this->file))
11985          {
11986              return $this->file;
11987          }
11988  
11989          if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
11990          {
11991              $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
11992              if ($sniffer->get_type() !== 'text/html')
11993              {
11994                  return null;
11995              }
11996          }
11997  
11998          if ($type & ~SIMPLEPIE_LOCATOR_NONE)
11999          {
12000              $this->get_base();
12001          }
12002  
12003          if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
12004          {
12005              return $working[0];
12006          }
12007  
12008          if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
12009          {
12010              if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
12011              {
12012                  return $working;
12013              }
12014  
12015              if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
12016              {
12017                  return $working;
12018              }
12019  
12020              if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
12021              {
12022                  return $working;
12023              }
12024  
12025              if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
12026              {
12027                  return $working;
12028              }
12029          }
12030          return null;
12031      }
12032  
12033  	public function is_feed($file)
12034      {
12035          if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
12036          {
12037              $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
12038              $sniffed = $sniffer->get_type();
12039              if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
12040              {
12041                  return true;
12042              }
12043              else
12044              {
12045                  return false;
12046              }
12047          }
12048          elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
12049          {
12050              return true;
12051          }
12052          else
12053          {
12054              return false;
12055          }
12056      }
12057  
12058  	public function get_base()
12059      {
12060          if ($this->dom === null)
12061          {
12062              throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12063          }
12064          $this->http_base = $this->file->url;
12065          $this->base = $this->http_base;
12066          $elements = $this->dom->getElementsByTagName('base');
12067          foreach ($elements as $element)
12068          {
12069              if ($element->hasAttribute('href'))
12070              {
12071                  $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
12072                  if ($base === false)
12073                  {
12074                      continue;
12075                  }
12076                  $this->base = $base;
12077                  $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
12078                  break;
12079              }
12080          }
12081      }
12082  
12083  	public function autodiscovery()
12084      {
12085          $done = array();
12086          $feeds = array();
12087          $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
12088          $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
12089          $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
12090  
12091          if (!empty($feeds))
12092          {
12093              return array_values($feeds);
12094          }
12095          else
12096          {
12097              return null;
12098          }
12099      }
12100  
12101  	protected function search_elements_by_tag($name, &$done, $feeds)
12102      {
12103          if ($this->dom === null)
12104          {
12105              throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12106          }
12107  
12108          $links = $this->dom->getElementsByTagName($name);
12109          foreach ($links as $link)
12110          {
12111              if ($this->checked_feeds === $this->max_checked_feeds)
12112              {
12113                  break;
12114              }
12115              if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
12116              {
12117                  $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
12118                  $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
12119  
12120                  if ($this->base_location < $line)
12121                  {
12122                      $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12123                  }
12124                  else
12125                  {
12126                      $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12127                  }
12128                  if ($href === false)
12129                  {
12130                      continue;
12131                  }
12132  
12133                  if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
12134                  {
12135                      $this->checked_feeds++;
12136                      $headers = array(
12137                          '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',
12138                      );
12139                      $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
12140                      if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
12141                      {
12142                          $feeds[$href] = $feed;
12143                      }
12144                  }
12145                  $done[] = $href;
12146              }
12147          }
12148  
12149          return $feeds;
12150      }
12151  
12152      public function get_links()
12153      {
12154          if ($this->dom === null)
12155          {
12156              throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
12157          }
12158  
12159          $links = $this->dom->getElementsByTagName('a');
12160          foreach ($links as $link)
12161          {
12162              if ($link->hasAttribute('href'))
12163              {
12164                  $href = trim($link->getAttribute('href'));
12165                  $parsed = $this->registry->call('Misc', 'parse_url', array($href));
12166                  if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
12167                  {
12168                      if ($this->base_location < $link->getLineNo())
12169                      {
12170                          $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
12171                      }
12172                      else
12173                      {
12174                          $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
12175                      }
12176                      if ($href === false)
12177                      {
12178                          continue;
12179                      }
12180  
12181                      $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
12182  
12183                      if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
12184                      {
12185                          $this->local[] = $href;
12186                      }
12187                      else
12188                      {
12189                          $this->elsewhere[] = $href;
12190                      }
12191                  }
12192              }
12193          }
12194          $this->local = array_unique($this->local);
12195          $this->elsewhere = array_unique($this->elsewhere);
12196          if (!empty($this->local) || !empty($this->elsewhere))
12197          {
12198              return true;
12199          }
12200          return null;
12201      }
12202  
12203      public function extension(&$array)
12204      {
12205          foreach ($array as $key => $value)
12206          {
12207              if ($this->checked_feeds === $this->max_checked_feeds)
12208              {
12209                  break;
12210              }
12211              if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
12212              {
12213                  $this->checked_feeds++;
12214  
12215                  $headers = array(
12216                      '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',
12217                  );
12218                  $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
12219                  if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
12220                  {
12221                      return $feed;
12222                  }
12223                  else
12224                  {
12225                      unset($array[$key]);
12226                  }
12227              }
12228          }
12229          return null;
12230      }
12231  
12232  	public function body(&$array)
12233      {
12234          foreach ($array as $key => $value)
12235          {
12236              if ($this->checked_feeds === $this->max_checked_feeds)
12237              {
12238                  break;
12239              }
12240              if (preg_match('/(rss|rdf|atom|xml)/i', $value))
12241              {
12242                  $this->checked_feeds++;
12243                  $headers = array(
12244                      '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',
12245                  );
12246                  $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
12247                  if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
12248                  {
12249                      return $feed;
12250                  }
12251                  else
12252                  {
12253                      unset($array[$key]);
12254                  }
12255              }
12256          }
12257          return null;
12258      }
12259  }
12260  
12261  /**
12262   * Miscellanous utilities
12263   *
12264   * @package SimplePie
12265   */
12266  class SimplePie_Misc
12267  {
12268  	public static function time_hms($seconds)
12269      {
12270          $time = '';
12271  
12272          $hours = floor($seconds / 3600);
12273          $remainder = $seconds % 3600;
12274          if ($hours > 0)
12275          {
12276              $time .= $hours.':';
12277          }
12278  
12279          $minutes = floor($remainder / 60);
12280          $seconds = $remainder % 60;
12281          if ($minutes < 10 && $hours > 0)
12282          {
12283              $minutes = '0' . $minutes;
12284          }
12285          if ($seconds < 10)
12286          {
12287              $seconds = '0' . $seconds;
12288          }
12289  
12290          $time .= $minutes.':';
12291          $time .= $seconds;
12292  
12293          return $time;
12294      }
12295  
12296  	public static function absolutize_url($relative, $base)
12297      {
12298          $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
12299          if ($iri === false)
12300          {
12301              return false;
12302          }
12303          return $iri->get_uri();
12304      }
12305  
12306      /**
12307       * Get a HTML/XML element from a HTML string
12308       *
12309       * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
12310       * @param string $realname Element name (including namespace prefix if applicable)
12311       * @param string $string HTML document
12312       * @return array
12313       */
12314  	public static function get_element($realname, $string)
12315      {
12316          $return = array();
12317          $name = preg_quote($realname, '/');
12318          if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
12319          {
12320              for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
12321              {
12322                  $return[$i]['tag'] = $realname;
12323                  $return[$i]['full'] = $matches[$i][0][0];
12324                  $return[$i]['offset'] = $matches[$i][0][1];
12325                  if (strlen($matches[$i][3][0]) <= 2)
12326                  {
12327                      $return[$i]['self_closing'] = true;
12328                  }
12329                  else
12330                  {
12331                      $return[$i]['self_closing'] = false;
12332                      $return[$i]['content'] = $matches[$i][4][0];
12333                  }
12334                  $return[$i]['attribs'] = array();
12335                  if (isset($matches[$i][2][0]) && preg_match_all('/[\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]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
12336                  {
12337                      for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
12338                      {
12339                          if (count($attribs[$j]) === 2)
12340                          {
12341                              $attribs[$j][2] = $attribs[$j][1];
12342                          }
12343                          $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
12344                      }
12345                  }
12346              }
12347          }
12348          return $return;
12349      }
12350  
12351  	public static function element_implode($element)
12352      {
12353          $full = "<$element[tag]";
12354          foreach ($element['attribs'] as $key => $value)
12355          {
12356              $key = strtolower($key);
12357              $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
12358          }
12359          if ($element['self_closing'])
12360          {
12361              $full .= ' />';
12362          }
12363          else
12364          {
12365              $full .= ">$element[content]</$element[tag]>";
12366          }
12367          return $full;
12368      }
12369  
12370  	public static function error($message, $level, $file, $line)
12371      {
12372          if ((ini_get('error_reporting') & $level) > 0)
12373          {
12374              switch ($level)
12375              {
12376                  case E_USER_ERROR:
12377                      $note = 'PHP Error';
12378                      break;
12379                  case E_USER_WARNING:
12380                      $note = 'PHP Warning';
12381                      break;
12382                  case E_USER_NOTICE:
12383                      $note = 'PHP Notice';
12384                      break;
12385                  default:
12386                      $note = 'Unknown Error';
12387                      break;
12388              }
12389  
12390              $log_error = true;
12391              if (!function_exists('error_log'))
12392              {
12393                  $log_error = false;
12394              }
12395  
12396              $log_file = @ini_get('error_log');
12397              if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
12398              {
12399                  $log_error = false;
12400              }
12401  
12402              if ($log_error)
12403              {
12404                  @error_log("$note: $message in $file on line $line", 0);
12405              }
12406          }
12407  
12408          return $message;
12409      }
12410  
12411  	public static function fix_protocol($url, $http = 1)
12412      {
12413          $url = SimplePie_Misc::normalize_url($url);
12414          $parsed = SimplePie_Misc::parse_url($url);
12415          if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
12416          {
12417              return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
12418          }
12419  
12420          if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
12421          {
12422              return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
12423          }
12424  
12425          if ($http === 2 && $parsed['scheme'] !== '')
12426          {
12427              return "feed:$url";
12428          }
12429          elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
12430          {
12431              return substr_replace($url, 'podcast', 0, 4);
12432          }
12433          elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
12434          {
12435              return substr_replace($url, 'itpc', 0, 4);
12436          }
12437          else
12438          {
12439              return $url;
12440          }
12441      }
12442  
12443  	public static function parse_url($url)
12444      {
12445          $iri = new SimplePie_IRI($url);
12446          return array(
12447              'scheme' => (string) $iri->scheme,
12448              'authority' => (string) $iri->authority,
12449              'path' => (string) $iri->path,
12450              'query' => (string) $iri->query,
12451              'fragment' => (string) $iri->fragment
12452          );
12453      }
12454  
12455  	public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
12456      {
12457          $iri = new SimplePie_IRI('');
12458          $iri->scheme = $scheme;
12459          $iri->authority = $authority;
12460          $iri->path = $path;
12461          $iri->query = $query;
12462          $iri->fragment = $fragment;
12463          return $iri->get_uri();
12464      }
12465  
12466  	public static function normalize_url($url)
12467      {
12468          $iri = new SimplePie_IRI($url);
12469          return $iri->get_uri();
12470      }
12471  
12472  	public static function percent_encoding_normalization($match)
12473      {
12474          $integer = hexdec($match[1]);
12475          if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
12476          {
12477              return chr($integer);
12478          }
12479          else
12480          {
12481              return strtoupper($match[0]);
12482          }
12483      }
12484  
12485      /**
12486       * Converts a Windows-1252 encoded string to a UTF-8 encoded string
12487       *
12488       * @static
12489       * @param string $string Windows-1252 encoded string
12490       * @return string UTF-8 encoded string
12491       */
12492  	public static function windows_1252_to_utf8($string)
12493      {
12494          static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
12495  
12496          return strtr($string, $convert_table);
12497      }
12498  
12499      /**
12500       * Change a string from one encoding to another
12501       *
12502       * @param string $data Raw data in $input encoding
12503       * @param string $input Encoding of $data
12504       * @param string $output Encoding you want
12505       * @return string|boolean False if we can't convert it
12506       */
12507  	public static function change_encoding($data, $input, $output)
12508      {
12509          $input = SimplePie_Misc::encoding($input);
12510          $output = SimplePie_Misc::encoding($output);
12511  
12512          // We fail to fail on non US-ASCII bytes
12513          if ($input === 'US-ASCII')
12514          {
12515              static $non_ascii_octects = '';
12516              if (!$non_ascii_octects)
12517              {
12518                  for ($i = 0x80; $i <= 0xFF; $i++)
12519                  {
12520                      $non_ascii_octects .= chr($i);
12521                  }
12522              }
12523              $data = substr($data, 0, strcspn($data, $non_ascii_octects));
12524          }
12525  
12526          // This is first, as behaviour of this is completely predictable
12527          if ($input === 'windows-1252' && $output === 'UTF-8')
12528          {
12529              return SimplePie_Misc::windows_1252_to_utf8($data);
12530          }
12531          // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
12532          elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
12533          {
12534              return $return;
12535           }
12536          // This is last, as behaviour of this varies with OS userland and PHP version
12537          elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
12538          {
12539              return $return;
12540          }
12541          // If we can't do anything, just fail
12542          else
12543          {
12544              return false;
12545          }
12546      }
12547  
12548  	protected static function change_encoding_mbstring($data, $input, $output)
12549      {
12550          if ($input === 'windows-949')
12551          {
12552              $input = 'EUC-KR';
12553          }
12554          if ($output === 'windows-949')
12555          {
12556              $output = 'EUC-KR';
12557          }
12558          if ($input === 'Windows-31J')
12559          {
12560              $input = 'SJIS';
12561          }
12562          if ($output === 'Windows-31J')
12563          {
12564              $output = 'SJIS';
12565          }
12566  
12567          // Check that the encoding is supported
12568          if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
12569          {
12570              return false;
12571          }
12572          if (!in_array($input, mb_list_encodings()))
12573          {
12574              return false;
12575          }
12576  
12577          // Let's do some conversion
12578          if ($return = @mb_convert_encoding($data, $output, $input))
12579          {
12580              return $return;
12581          }
12582  
12583          return false;
12584      }
12585  
12586  	protected static function change_encoding_iconv($data, $input, $output)
12587      {
12588          return @iconv($input, $output, $data);
12589      }
12590  
12591      /**
12592       * Normalize an encoding name
12593       *
12594       * This is automatically generated by create.php
12595       *
12596       * To generate it, run `php create.php` on the command line, and copy the
12597       * output to replace this function.
12598       *
12599       * @param string $charset Character set to standardise
12600       * @return string Standardised name
12601       */
12602  	public static function encoding($charset)
12603      {
12604          // Normalization from UTS #22
12605          switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
12606          {
12607              case 'adobestandardencoding':
12608              case 'csadobestandardencoding':
12609                  return 'Adobe-Standard-Encoding';
12610  
12611              case 'adobesymbolencoding':
12612              case 'cshppsmath':
12613                  return 'Adobe-Symbol-Encoding';
12614  
12615              case 'ami1251':
12616              case 'amiga1251':
12617                  return 'Amiga-1251';
12618  
12619              case 'ansix31101983':
12620              case 'csat5001983':
12621              case 'csiso99naplps':
12622              case 'isoir99':
12623              case 'naplps':
12624                  return 'ANSI_X3.110-1983';
12625  
12626              case 'arabic7':
12627              case 'asmo449':
12628              case 'csiso89asmo449':
12629              case 'iso9036':
12630              case 'isoir89':
12631                  return 'ASMO_449';
12632  
12633              case 'big5':
12634              case 'csbig5':
12635                  return 'Big5';
12636  
12637              case 'big5hkscs':
12638                  return 'Big5-HKSCS';
12639  
12640              case 'bocu1':
12641              case 'csbocu1':
12642                  return 'BOCU-1';
12643  
12644              case 'brf':
12645              case 'csbrf':
12646                  return 'BRF';
12647  
12648              case 'bs4730':
12649              case 'csiso4unitedkingdom':
12650              case 'gb':
12651              case 'iso646gb':
12652              case 'isoir4':
12653              case 'uk':
12654                  return 'BS_4730';
12655  
12656              case 'bsviewdata':
12657              case 'csiso47bsviewdata':
12658              case 'isoir47':
12659                  return 'BS_viewdata';
12660  
12661              case 'cesu8':
12662              case 'cscesu8':
12663                  return 'CESU-8';
12664  
12665              case 'ca':
12666              case 'csa71':
12667              case 'csaz243419851':
12668              case 'csiso121canadian1':
12669              case 'iso646ca':
12670              case 'isoir121':
12671                  return 'CSA_Z243.4-1985-1';
12672  
12673              case 'csa72':
12674              case 'csaz243419852':
12675              case 'csiso122canadian2':
12676              case 'iso646ca2':
12677              case 'isoir122':
12678                  return 'CSA_Z243.4-1985-2';
12679  
12680              case 'csaz24341985gr':
12681              case 'csiso123csaz24341985gr':
12682              case 'isoir123':
12683                  return 'CSA_Z243.4-1985-gr';
12684  
12685              case 'csiso139csn369103':
12686              case 'csn369103':
12687              case 'isoir139':
12688                  return 'CSN_369103';
12689  
12690              case 'csdecmcs':
12691              case 'dec':
12692              case 'decmcs':
12693                  return 'DEC-MCS';
12694  
12695              case 'csiso21german':
12696              case 'de':
12697              case 'din66003':
12698              case 'iso646de':
12699              case 'isoir21':
12700                  return 'DIN_66003';
12701  
12702              case 'csdkus':
12703              case 'dkus':
12704                  return 'dk-us';
12705  
12706              case 'csiso646danish':
12707              case 'dk':
12708              case 'ds2089':
12709              case 'iso646dk':
12710                  return 'DS_2089';
12711  
12712              case 'csibmebcdicatde':
12713              case 'ebcdicatde':
12714                  return 'EBCDIC-AT-DE';
12715  
12716              case 'csebcdicatdea':
12717              case 'ebcdicatdea':
12718                  return 'EBCDIC-AT-DE-A';
12719  
12720              case 'csebcdiccafr':
12721              case 'ebcdiccafr':
12722                  return 'EBCDIC-CA-FR';
12723  
12724              case 'csebcdicdkno':
12725              case 'ebcdicdkno':
12726                  return 'EBCDIC-DK-NO';
12727  
12728              case 'csebcdicdknoa':
12729              case 'ebcdicdknoa':
12730                  return 'EBCDIC-DK-NO-A';
12731  
12732              case 'csebcdices':
12733              case 'ebcdices':
12734                  return 'EBCDIC-ES';
12735  
12736              case 'csebcdicesa':
12737              case 'ebcdicesa':
12738                  return 'EBCDIC-ES-A';
12739  
12740              case 'csebcdicess':
12741              case 'ebcdicess':
12742                  return 'EBCDIC-ES-S';
12743  
12744              case 'csebcdicfise':
12745              case 'ebcdicfise':
12746                  return 'EBCDIC-FI-SE';
12747  
12748              case 'csebcdicfisea':
12749              case 'ebcdicfisea':
12750                  return 'EBCDIC-FI-SE-A';
12751  
12752              case 'csebcdicfr':
12753              case 'ebcdicfr':
12754                  return 'EBCDIC-FR';
12755  
12756              case 'csebcdicit':
12757              case 'ebcdicit':
12758                  return 'EBCDIC-IT';
12759  
12760              case 'csebcdicpt':
12761              case 'ebcdicpt':
12762                  return 'EBCDIC-PT';
12763  
12764              case 'csebcdicuk':
12765              case 'ebcdicuk':
12766                  return 'EBCDIC-UK';
12767  
12768              case 'csebcdicus':
12769              case 'ebcdicus':
12770                  return 'EBCDIC-US';
12771  
12772              case 'csiso111ecmacyrillic':
12773              case 'ecmacyrillic':
12774              case 'isoir111':
12775              case 'koi8e':
12776                  return 'ECMA-cyrillic';
12777  
12778              case 'csiso17spanish':
12779              case 'es':
12780              case 'iso646es':
12781              case 'isoir17':
12782                  return 'ES';
12783  
12784              case 'csiso85spanish2':
12785              case 'es2':
12786              case 'iso646es2':
12787              case 'isoir85':
12788                  return 'ES2';
12789  
12790              case 'cseucpkdfmtjapanese':
12791              case 'eucjp':
12792              case 'extendedunixcodepackedformatforjapanese':
12793                  return 'EUC-JP';
12794  
12795              case 'cseucfixwidjapanese':
12796              case 'extendedunixcodefixedwidthforjapanese':
12797                  return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
12798  
12799              case 'gb18030':
12800                  return 'GB18030';
12801  
12802              case 'chinese':
12803              case 'cp936':
12804              case 'csgb2312':
12805              case 'csiso58gb231280':
12806              case 'gb2312':
12807              case 'gb231280':
12808              case 'gbk':
12809              case 'isoir58':
12810              case 'ms936':
12811              case 'windows936':
12812                  return 'GBK';
12813  
12814              case 'cn':
12815              case 'csiso57gb1988':
12816              case 'gb198880':
12817              case 'iso646cn':
12818              case 'isoir57':
12819                  return 'GB_1988-80';
12820  
12821              case 'csiso153gost1976874':
12822              case 'gost1976874':
12823              case 'isoir153':
12824              case 'stsev35888':
12825                  return 'GOST_19768-74';
12826  
12827              case 'csiso150':
12828              case 'csiso150greekccitt':
12829              case 'greekccitt':
12830              case 'isoir150':
12831                  return 'greek-ccitt';
12832  
12833              case 'csiso88greek7':
12834              case 'greek7':
12835              case 'isoir88':
12836                  return 'greek7';
12837  
12838              case 'csiso18greek7old':
12839              case 'greek7old':
12840              case 'isoir18':
12841                  return 'greek7-old';
12842  
12843              case 'cshpdesktop':
12844              case 'hpdesktop':
12845                  return 'HP-DeskTop';
12846  
12847              case 'cshplegal':
12848              case 'hplegal':
12849                  return 'HP-Legal';
12850  
12851              case 'cshpmath8':
12852              case 'hpmath8':
12853                  return 'HP-Math8';
12854  
12855              case 'cshppifont':
12856              case 'hppifont':
12857                  return 'HP-Pi-font';
12858  
12859              case 'cshproman8':
12860              case 'hproman8':
12861              case 'r8':
12862              case 'roman8':
12863                  return 'hp-roman8';
12864  
12865              case 'hzgb2312':
12866                  return 'HZ-GB-2312';
12867  
12868              case 'csibmsymbols':
12869              case 'ibmsymbols':
12870                  return 'IBM-Symbols';
12871  
12872              case 'csibmthai':
12873              case 'ibmthai':
12874                  return 'IBM-Thai';
12875  
12876              case 'cp37':
12877              case 'csibm37':
12878              case 'ebcdiccpca':
12879              case 'ebcdiccpnl':
12880              case 'ebcdiccpus':
12881              case 'ebcdiccpwt':
12882              case 'ibm37':
12883                  return 'IBM037';
12884  
12885              case 'cp38':
12886              case 'csibm38':
12887              case 'ebcdicint':
12888              case 'ibm38':
12889                  return 'IBM038';
12890  
12891              case 'cp273':
12892              case 'csibm273':
12893              case 'ibm273':
12894                  return 'IBM273';
12895  
12896              case 'cp274':
12897              case 'csibm274':
12898              case 'ebcdicbe':
12899              case 'ibm274':
12900                  return 'IBM274';
12901  
12902              case 'cp275':
12903              case 'csibm275':
12904              case 'ebcdicbr':
12905              case 'ibm275':
12906                  return 'IBM275';
12907  
12908              case 'csibm277':
12909              case 'ebcdiccpdk':
12910              case 'ebcdiccpno':
12911              case 'ibm277':
12912                  return 'IBM277';
12913  
12914              case 'cp278':
12915              case 'csibm278':
12916              case 'ebcdiccpfi':
12917              case 'ebcdiccpse':
12918              case 'ibm278':
12919                  return 'IBM278';
12920  
12921              case 'cp280':
12922              case 'csibm280':
12923              case 'ebcdiccpit':
12924              case 'ibm280':
12925                  return 'IBM280';
12926  
12927              case 'cp281':
12928              case 'csibm281':
12929              case 'ebcdicjpe':
12930              case 'ibm281':
12931                  return 'IBM281';
12932  
12933              case 'cp284':
12934              case 'csibm284':
12935              case 'ebcdiccpes':
12936              case 'ibm284':
12937                  return 'IBM284';
12938  
12939              case 'cp285':
12940              case 'csibm285':
12941              case 'ebcdiccpgb':
12942              case 'ibm285':
12943                  return 'IBM285';
12944  
12945              case 'cp290':
12946              case 'csibm290':
12947              case 'ebcdicjpkana':
12948              case 'ibm290':
12949                  return 'IBM290';
12950  
12951              case 'cp297':
12952              case 'csibm297':
12953              case 'ebcdiccpfr':
12954              case 'ibm297':
12955                  return 'IBM297';
12956  
12957              case 'cp420':
12958              case 'csibm420':
12959              case 'ebcdiccpar1':
12960              case 'ibm420':
12961                  return 'IBM420';
12962  
12963              case 'cp423':
12964              case 'csibm423':
12965              case 'ebcdiccpgr':
12966              case 'ibm423':
12967                  return 'IBM423';
12968  
12969              case 'cp424':
12970              case 'csibm424':
12971              case 'ebcdiccphe':
12972              case 'ibm424':
12973                  return 'IBM424';
12974  
12975              case '437':
12976              case 'cp437':
12977              case 'cspc8codepage437':
12978              case 'ibm437':
12979                  return 'IBM437';
12980  
12981              case 'cp500':
12982              case 'csibm500':
12983              case 'ebcdiccpbe':
12984              case 'ebcdiccpch':
12985              case 'ibm500':
12986                  return 'IBM500';
12987  
12988              case 'cp775':
12989              case 'cspc775baltic':
12990              case 'ibm775':
12991                  return 'IBM775';
12992  
12993              case '850':
12994              case 'cp850':
12995              case 'cspc850multilingual':
12996              case 'ibm850':
12997                  return 'IBM850';
12998  
12999              case '851':
13000              case 'cp851':
13001              case 'csibm851':
13002              case 'ibm851':
13003                  return 'IBM851';
13004  
13005              case '852':
13006              case 'cp852':
13007              case 'cspcp852':
13008              case 'ibm852':
13009                  return 'IBM852';
13010  
13011              case '855':
13012              case 'cp855':
13013              case 'csibm855':
13014              case 'ibm855':
13015                  return 'IBM855';
13016  
13017              case '857':
13018              case 'cp857':
13019              case 'csibm857':
13020              case 'ibm857':
13021                  return 'IBM857';
13022  
13023              case 'ccsid858':
13024              case 'cp858':
13025              case 'ibm858':
13026              case 'pcmultilingual850euro':
13027                  return 'IBM00858';
13028  
13029              case '860':
13030              case 'cp860':
13031              case 'csibm860':
13032              case 'ibm860':
13033                  return 'IBM860';
13034  
13035              case '861':
13036              case 'cp861':
13037              case 'cpis':
13038              case 'csibm861':
13039              case 'ibm861':
13040                  return 'IBM861';
13041  
13042              case '862':
13043              case 'cp862':
13044              case 'cspc862latinhebrew':
13045              case 'ibm862':
13046                  return 'IBM862';
13047  
13048              case '863':
13049              case 'cp863':
13050              case 'csibm863':
13051              case 'ibm863':
13052                  return 'IBM863';
13053  
13054              case 'cp864':
13055              case 'csibm864':
13056              case 'ibm864':
13057                  return 'IBM864';
13058  
13059              case '865':
13060              case 'cp865':
13061              case 'csibm865':
13062              case 'ibm865':
13063                  return 'IBM865';
13064  
13065              case '866':
13066              case 'cp866':
13067              case 'csibm866':
13068              case 'ibm866':
13069                  return 'IBM866';
13070  
13071              case 'cp868':
13072              case 'cpar':
13073              case 'csibm868':
13074              case 'ibm868':
13075                  return 'IBM868';
13076  
13077              case '869':
13078              case 'cp869':
13079              case 'cpgr':
13080              case 'csibm869':
13081              case 'ibm869':
13082                  return 'IBM869';
13083  
13084              case 'cp870':
13085              case 'csibm870':
13086              case 'ebcdiccproece':
13087              case 'ebcdiccpyu':
13088              case 'ibm870':
13089                  return 'IBM870';
13090  
13091              case 'cp871':
13092              case 'csibm871':
13093              case 'ebcdiccpis':
13094              case 'ibm871':
13095                  return 'IBM871';
13096  
13097              case 'cp880':
13098              case 'csibm880':
13099              case 'ebcdiccyrillic':
13100              case 'ibm880':
13101                  return 'IBM880';
13102  
13103              case 'cp891':
13104              case 'csibm891':
13105              case 'ibm891':
13106                  return 'IBM891';
13107  
13108              case 'cp903':
13109              case 'csibm903':
13110              case 'ibm903':
13111                  return 'IBM903';
13112  
13113              case '904':
13114              case 'cp904':
13115              case 'csibbm904':
13116              case 'ibm904':
13117                  return 'IBM904';
13118  
13119              case 'cp905':
13120              case 'csibm905':
13121              case 'ebcdiccptr':
13122              case 'ibm905':
13123                  return 'IBM905';
13124  
13125              case 'cp918':
13126              case 'csibm918':
13127              case 'ebcdiccpar2':
13128              case 'ibm918':
13129                  return 'IBM918';
13130  
13131              case 'ccsid924':
13132              case 'cp924':
13133              case 'ebcdiclatin9euro':
13134              case 'ibm924':
13135                  return 'IBM00924';
13136  
13137              case 'cp1026':
13138              case 'csibm1026':
13139              case 'ibm1026':
13140                  return 'IBM1026';
13141  
13142              case 'ibm1047':
13143                  return 'IBM1047';
13144  
13145              case 'ccsid1140':
13146              case 'cp1140':
13147              case 'ebcdicus37euro':
13148              case 'ibm1140':
13149                  return 'IBM01140';
13150  
13151              case 'ccsid1141':
13152              case 'cp1141':
13153              case 'ebcdicde273euro':
13154              case 'ibm1141':
13155                  return 'IBM01141';
13156  
13157              case 'ccsid1142':
13158              case 'cp1142':
13159              case 'ebcdicdk277euro':
13160              case 'ebcdicno277euro':
13161              case 'ibm1142':
13162                  return 'IBM01142';
13163  
13164              case 'ccsid1143':
13165              case 'cp1143':
13166              case 'ebcdicfi278euro':
13167              case 'ebcdicse278euro':
13168              case 'ibm1143':
13169                  return 'IBM01143';
13170  
13171              case 'ccsid1144':
13172              case 'cp1144':
13173              case 'ebcdicit280euro':
13174              case 'ibm1144':
13175                  return 'IBM01144';
13176  
13177              case 'ccsid1145':
13178              case 'cp1145':
13179              case 'ebcdices284euro':
13180              case 'ibm1145':
13181                  return 'IBM01145';
13182  
13183              case 'ccsid1146':
13184              case 'cp1146':
13185              case 'ebcdicgb285euro':
13186              case 'ibm1146':
13187                  return 'IBM01146';
13188  
13189              case 'ccsid1147':
13190              case 'cp1147':
13191              case 'ebcdicfr297euro':
13192              case 'ibm1147':
13193                  return 'IBM01147';
13194  
13195              case 'ccsid1148':
13196              case 'cp1148':
13197              case 'ebcdicinternational500euro':
13198              case 'ibm1148':
13199                  return 'IBM01148';
13200  
13201              case 'ccsid1149':
13202              case 'cp1149':
13203              case 'ebcdicis871euro':
13204              case 'ibm1149':
13205                  return 'IBM01149';
13206  
13207              case 'csiso143iecp271':
13208              case 'iecp271':
13209              case 'isoir143':
13210                  return 'IEC_P27-1';
13211  
13212              case 'csiso49inis':
13213              case 'inis':
13214              case 'isoir49':
13215                  return 'INIS';
13216  
13217              case 'csiso50inis8':
13218              case 'inis8':
13219              case 'isoir50':
13220                  return 'INIS-8';
13221  
13222              case 'csiso51iniscyrillic':
13223              case 'iniscyrillic':
13224              case 'isoir51':
13225                  return 'INIS-cyrillic';
13226  
13227              case 'csinvariant':
13228              case 'invariant':
13229                  return 'INVARIANT';
13230  
13231              case 'iso2022cn':
13232                  return 'ISO-2022-CN';
13233  
13234              case 'iso2022cnext':
13235                  return 'ISO-2022-CN-EXT';
13236  
13237              case 'csiso2022jp':
13238              case 'iso2022jp':
13239                  return 'ISO-2022-JP';
13240  
13241              case 'csiso2022jp2':
13242              case 'iso2022jp2':
13243                  return 'ISO-2022-JP-2';
13244  
13245              case 'csiso2022kr':
13246              case 'iso2022kr':
13247                  return 'ISO-2022-KR';
13248  
13249              case 'cswindows30latin1':
13250              case 'iso88591windows30latin1':
13251                  return 'ISO-8859-1-Windows-3.0-Latin-1';
13252  
13253              case 'cswindows31latin1':
13254              case 'iso88591windows31latin1':
13255                  return 'ISO-8859-1-Windows-3.1-Latin-1';
13256  
13257              case 'csisolatin2':
13258              case 'iso88592':
13259              case 'iso885921987':
13260              case 'isoir101':
13261              case 'l2':
13262              case 'latin2':
13263                  return 'ISO-8859-2';
13264  
13265              case 'cswindows31latin2':
13266              case 'iso88592windowslatin2':
13267                  return 'ISO-8859-2-Windows-Latin-2';
13268  
13269              case 'csisolatin3':
13270              case 'iso88593':
13271              case 'iso885931988':
13272              case 'isoir109':
13273              case 'l3':
13274              case 'latin3':
13275                  return 'ISO-8859-3';
13276  
13277              case 'csisolatin4':
13278              case 'iso88594':
13279              case 'iso885941988':
13280              case 'isoir110':
13281              case 'l4':
13282              case 'latin4':
13283                  return 'ISO-8859-4';
13284  
13285              case 'csisolatincyrillic':
13286              case 'cyrillic':
13287              case 'iso88595':
13288              case 'iso885951988':
13289              case 'isoir144':
13290                  return 'ISO-8859-5';
13291  
13292              case 'arabic':
13293              case 'asmo708':
13294              case 'csisolatinarabic':
13295              case 'ecma114':
13296              case 'iso88596':
13297              case 'iso885961987':
13298              case 'isoir127':
13299                  return 'ISO-8859-6';
13300  
13301              case 'csiso88596e':
13302              case 'iso88596e':
13303                  return 'ISO-8859-6-E';
13304  
13305              case 'csiso88596i':
13306              case 'iso88596i':
13307                  return 'ISO-8859-6-I';
13308  
13309              case 'csisolatingreek':
13310              case 'ecma118':
13311              case 'elot928':
13312              case 'greek':
13313              case 'greek8':
13314              case 'iso88597':
13315              case 'iso885971987':
13316              case 'isoir126':
13317                  return 'ISO-8859-7';
13318  
13319              case 'csisolatinhebrew':
13320              case 'hebrew':
13321              case 'iso88598':
13322              case 'iso885981988':
13323              case 'isoir138':
13324                  return 'ISO-8859-8';
13325  
13326              case 'csiso88598e':
13327              case 'iso88598e':
13328                  return 'ISO-8859-8-E';
13329  
13330              case 'csiso88598i':
13331              case 'iso88598i':
13332                  return 'ISO-8859-8-I';
13333  
13334              case 'cswindows31latin5':
13335              case 'iso88599windowslatin5':
13336                  return 'ISO-8859-9-Windows-Latin-5';
13337  
13338              case 'csisolatin6':
13339              case 'iso885910':
13340              case 'iso8859101992':
13341              case 'isoir157':
13342              case 'l6':
13343              case 'latin6':
13344                  return 'ISO-8859-10';
13345  
13346              case 'iso885913':
13347                  return 'ISO-8859-13';
13348  
13349              case 'iso885914':
13350              case 'iso8859141998':
13351              case 'isoceltic':
13352              case 'isoir199':
13353              case 'l8':
13354              case 'latin8':
13355                  return 'ISO-8859-14';
13356  
13357              case 'iso885915':
13358              case 'latin9':
13359                  return 'ISO-8859-15';
13360  
13361              case 'iso885916':
13362              case 'iso8859162001':
13363              case 'isoir226':
13364              case 'l10':
13365              case 'latin10':
13366                  return 'ISO-8859-16';
13367  
13368              case 'iso10646j1':
13369                  return 'ISO-10646-J-1';
13370  
13371              case 'csunicode':
13372              case 'iso10646ucs2':
13373                  return 'ISO-10646-UCS-2';
13374  
13375              case 'csucs4':
13376              case 'iso10646ucs4':
13377                  return 'ISO-10646-UCS-4';
13378  
13379              case 'csunicodeascii':
13380              case 'iso10646ucsbasic':
13381                  return 'ISO-10646-UCS-Basic';
13382  
13383              case 'csunicodelatin1':
13384              case 'iso10646':
13385              case 'iso10646unicodelatin1':
13386                  return 'ISO-10646-Unicode-Latin1';
13387  
13388              case 'csiso10646utf1':
13389              case 'iso10646utf1':
13390                  return 'ISO-10646-UTF-1';
13391  
13392              case 'csiso115481':
13393              case 'iso115481':
13394              case 'isotr115481':
13395                  return 'ISO-11548-1';
13396  
13397              case 'csiso90':
13398              case 'isoir90':
13399                  return 'iso-ir-90';
13400  
13401              case 'csunicodeibm1261':
13402              case 'isounicodeibm1261':
13403                  return 'ISO-Unicode-IBM-1261';
13404  
13405              case 'csunicodeibm1264':
13406              case 'isounicodeibm1264':
13407                  return 'ISO-Unicode-IBM-1264';
13408  
13409              case 'csunicodeibm1265':
13410              case 'isounicodeibm1265':
13411                  return 'ISO-Unicode-IBM-1265';
13412  
13413              case 'csunicodeibm1268':
13414              case 'isounicodeibm1268':
13415                  return 'ISO-Unicode-IBM-1268';
13416  
13417              case 'csunicodeibm1276':
13418              case 'isounicodeibm1276':
13419                  return 'ISO-Unicode-IBM-1276';
13420  
13421              case 'csiso646basic1983':
13422              case 'iso646basic1983':
13423              case 'ref':
13424                  return 'ISO_646.basic:1983';
13425  
13426              case 'csiso2intlrefversion':
13427              case 'irv':
13428              case 'iso646irv1983':
13429              case 'isoir2':
13430                  return 'ISO_646.irv:1983';
13431  
13432              case 'csiso2033':
13433              case 'e13b':
13434              case 'iso20331983':
13435              case 'isoir98':
13436                  return 'ISO_2033-1983';
13437  
13438              case 'csiso5427cyrillic':
13439              case 'iso5427':
13440              case 'isoir37':
13441                  return 'ISO_5427';
13442  
13443              case 'iso5427cyrillic1981':
13444              case 'iso54271981':
13445              case 'isoir54':
13446                  return 'ISO_5427:1981';
13447  
13448              case 'csiso5428greek':
13449              case 'iso54281980':
13450              case 'isoir55':
13451                  return 'ISO_5428:1980';
13452  
13453              case 'csiso6937add':
13454              case 'iso6937225':
13455              case 'isoir152':
13456                  return 'ISO_6937-2-25';
13457  
13458              case 'csisotextcomm':
13459              case 'iso69372add':
13460              case 'isoir142':
13461                  return 'ISO_6937-2-add';
13462  
13463              case 'csiso8859supp':
13464              case 'iso8859supp':
13465              case 'isoir154':
13466              case 'latin125':
13467                  return 'ISO_8859-supp';
13468  
13469              case 'csiso10367box':
13470              case 'iso10367box':
13471              case 'isoir155':
13472                  return 'ISO_10367-box';
13473  
13474              case 'csiso15italian':
13475              case 'iso646it':
13476              case 'isoir15':
13477              case 'it':
13478                  return 'IT';
13479  
13480              case 'csiso13jisc6220jp':
13481              case 'isoir13':
13482              case 'jisc62201969':
13483              case 'jisc62201969jp':
13484              case 'katakana':
13485              case 'x2017':
13486                  return 'JIS_C6220-1969-jp';
13487  
13488              case 'csiso14jisc6220ro':
13489              case 'iso646jp':
13490              case 'isoir14':
13491              case 'jisc62201969ro':
13492              case 'jp':
13493                  return 'JIS_C6220-1969-ro';
13494  
13495              case 'csiso42jisc62261978':
13496              case 'isoir42':
13497              case 'jisc62261978':
13498                  return 'JIS_C6226-1978';
13499  
13500              case 'csiso87jisx208':
13501              case 'isoir87':
13502              case 'jisc62261983':
13503              case 'jisx2081983':
13504              case 'x208':
13505                  return 'JIS_C6226-1983';
13506  
13507              case 'csiso91jisc62291984a':
13508              case 'isoir91':
13509              case 'jisc62291984a':
13510              case 'jpocra':
13511                  return 'JIS_C6229-1984-a';
13512  
13513              case 'csiso92jisc62991984b':
13514              case 'iso646jpocrb':
13515              case 'isoir92':
13516              case 'jisc62291984b':
13517              case 'jpocrb':
13518                  return 'JIS_C6229-1984-b';
13519  
13520              case 'csiso93jis62291984badd':
13521              case 'isoir93':
13522              case 'jisc62291984badd':
13523              case 'jpocrbadd':
13524                  return 'JIS_C6229-1984-b-add';
13525  
13526              case 'csiso94jis62291984hand':
13527              case 'isoir94':
13528              case 'jisc62291984hand':
13529              case 'jpocrhand':
13530                  return 'JIS_C6229-1984-hand';
13531  
13532              case 'csiso95jis62291984handadd':
13533              case 'isoir95':
13534              case 'jisc62291984handadd':
13535              case 'jpocrhandadd':
13536                  return 'JIS_C6229-1984-hand-add';
13537  
13538              case 'csiso96jisc62291984kana':
13539              case 'isoir96':
13540              case 'jisc62291984kana':
13541                  return 'JIS_C6229-1984-kana';
13542  
13543              case 'csjisencoding':
13544              case 'jisencoding':
13545                  return 'JIS_Encoding';
13546  
13547              case 'cshalfwidthkatakana':
13548              case 'jisx201':
13549              case 'x201':
13550                  return 'JIS_X0201';
13551  
13552              case 'csiso159jisx2121990':
13553              case 'isoir159':
13554              case 'jisx2121990':
13555              case 'x212':
13556                  return 'JIS_X0212-1990';
13557  
13558              case 'csiso141jusib1002':
13559              case 'iso646yu':
13560              case 'isoir141':
13561              case 'js':
13562              case 'jusib1002':
13563              case 'yu':
13564                  return 'JUS_I.B1.002';
13565  
13566              case 'csiso147macedonian':
13567              case 'isoir147':
13568              case 'jusib1003mac':
13569              case 'macedonian':
13570                  return 'JUS_I.B1.003-mac';
13571  
13572              case 'csiso146serbian':
13573              case 'isoir146':
13574              case 'jusib1003serb':
13575              case 'serbian':
13576                  return 'JUS_I.B1.003-serb';
13577  
13578              case 'koi7switched':
13579                  return 'KOI7-switched';
13580  
13581              case 'cskoi8r':
13582              case 'koi8r':
13583                  return 'KOI8-R';
13584  
13585              case 'koi8u':
13586                  return 'KOI8-U';
13587  
13588              case 'csksc5636':
13589              case 'iso646kr':
13590              case 'ksc5636':
13591                  return 'KSC5636';
13592  
13593              case 'cskz1048':
13594              case 'kz1048':
13595              case 'rk1048':
13596              case 'strk10482002':
13597                  return 'KZ-1048';
13598  
13599              case 'csiso19latingreek':
13600              case 'isoir19':
13601              case 'latingreek':
13602                  return 'latin-greek';
13603  
13604              case 'csiso27latingreek1':
13605              case 'isoir27':
13606              case 'latingreek1':
13607                  return 'Latin-greek-1';
13608  
13609              case 'csiso158lap':
13610              case 'isoir158':
13611              case 'lap':
13612              case 'latinlap':
13613                  return 'latin-lap';
13614  
13615              case 'csmacintosh':
13616              case 'mac':
13617              case 'macintosh':
13618                  return 'macintosh';
13619  
13620              case 'csmicrosoftpublishing':
13621              case 'microsoftpublishing':
13622                  return 'Microsoft-Publishing';
13623  
13624              case 'csmnem':
13625              case 'mnem':
13626                  return 'MNEM';
13627  
13628              case 'csmnemonic':
13629              case 'mnemonic':
13630                  return 'MNEMONIC';
13631  
13632              case 'csiso86hungarian':
13633              case 'hu':
13634              case 'iso646hu':
13635              case 'isoir86':
13636              case 'msz77953':
13637                  return 'MSZ_7795.3';
13638  
13639              case 'csnatsdano':
13640              case 'isoir91':
13641              case 'natsdano':
13642                  return 'NATS-DANO';
13643  
13644              case 'csnatsdanoadd':
13645              case 'isoir92':
13646              case 'natsdanoadd':
13647                  return 'NATS-DANO-ADD';
13648  
13649              case 'csnatssefi':
13650              case 'isoir81':
13651              case 'natssefi':
13652                  return 'NATS-SEFI';
13653  
13654              case 'csnatssefiadd':
13655              case 'isoir82':
13656              case 'natssefiadd':
13657                  return 'NATS-SEFI-ADD';
13658  
13659              case 'csiso151cuba':
13660              case 'cuba':
13661              case 'iso646cu':
13662              case 'isoir151':
13663              case 'ncnc1081':
13664                  return 'NC_NC00-10:81';
13665  
13666              case 'csiso69french':
13667              case 'fr':
13668              case 'iso646fr':
13669              case 'isoir69':
13670              case 'nfz62010':
13671                  return 'NF_Z_62-010';
13672  
13673              case 'csiso25french':
13674              case 'iso646fr1':
13675              case 'isoir25':
13676              case 'nfz620101973':
13677                  return 'NF_Z_62-010_(1973)';
13678  
13679              case 'csiso60danishnorwegian':
13680              case 'csiso60norwegian1':
13681              case 'iso646no':
13682              case 'isoir60':
13683              case 'no':
13684              case 'ns45511':
13685                  return 'NS_4551-1';
13686  
13687              case 'csiso61norwegian2':
13688              case 'iso646no2':
13689              case 'isoir61':
13690              case 'no2':
13691              case 'ns45512':
13692                  return 'NS_4551-2';
13693  
13694              case 'osdebcdicdf3irv':
13695                  return 'OSD_EBCDIC_DF03_IRV';
13696  
13697              case 'osdebcdicdf41':
13698                  return 'OSD_EBCDIC_DF04_1';
13699  
13700              case 'osdebcdicdf415':
13701                  return 'OSD_EBCDIC_DF04_15';
13702  
13703              case 'cspc8danishnorwegian':
13704              case 'pc8danishnorwegian':
13705                  return 'PC8-Danish-Norwegian';
13706  
13707              case 'cspc8turkish':
13708              case 'pc8turkish':
13709                  return 'PC8-Turkish';
13710  
13711              case 'csiso16portuguese':
13712              case 'iso646pt':
13713              case 'isoir16':
13714              case 'pt':
13715                  return 'PT';
13716  
13717              case 'csiso84portuguese2':
13718              case 'iso646pt2':
13719              case 'isoir84':
13720              case 'pt2':
13721                  return 'PT2';
13722  
13723              case 'cp154':
13724              case 'csptcp154':
13725              case 'cyrillicasian':
13726              case 'pt154':
13727              case 'ptcp154':
13728                  return 'PTCP154';
13729  
13730              case 'scsu':
13731                  return 'SCSU';
13732  
13733              case 'csiso10swedish':
13734              case 'fi':
13735              case 'iso646fi':
13736              case 'iso646se':
13737              case 'isoir10':
13738              case 'se':
13739              case 'sen850200b':
13740                  return 'SEN_850200_B';
13741  
13742              case 'csiso11swedishfornames':
13743              case 'iso646se2':
13744              case 'isoir11':
13745              case 'se2':
13746              case 'sen850200c':
13747                  return 'SEN_850200_C';
13748  
13749              case 'csiso102t617bit':
13750              case 'isoir102':
13751              case 't617bit':
13752                  return 'T.61-7bit';
13753  
13754              case 'csiso103t618bit':
13755              case 'isoir103':
13756              case 't61':
13757              case 't618bit':
13758                  return 'T.61-8bit';
13759  
13760              case 'csiso128t101g2':
13761              case 'isoir128':
13762              case 't101g2':
13763                  return 'T.101-G2';
13764  
13765              case 'cstscii':
13766              case 'tscii':
13767                  return 'TSCII';
13768  
13769              case 'csunicode11':
13770              case 'unicode11':
13771                  return 'UNICODE-1-1';
13772  
13773              case 'csunicode11utf7':
13774              case 'unicode11utf7':
13775                  return 'UNICODE-1-1-UTF-7';
13776  
13777              case 'csunknown8bit':
13778              case 'unknown8bit':
13779                  return 'UNKNOWN-8BIT';
13780  
13781              case 'ansix341968':
13782              case 'ansix341986':
13783              case 'ascii':
13784              case 'cp367':
13785              case 'csascii':
13786              case 'ibm367':
13787              case 'iso646irv1991':
13788              case 'iso646us':
13789              case 'isoir6':
13790              case 'us':
13791              case 'usascii':
13792                  return 'US-ASCII';
13793  
13794              case 'csusdk':
13795              case 'usdk':
13796                  return 'us-dk';
13797  
13798              case 'utf7':
13799                  return 'UTF-7';
13800  
13801              case 'utf8':
13802                  return 'UTF-8';
13803  
13804              case 'utf16':
13805                  return 'UTF-16';
13806  
13807              case 'utf16be':
13808                  return 'UTF-16BE';
13809  
13810              case 'utf16le':
13811                  return 'UTF-16LE';
13812  
13813              case 'utf32':
13814                  return 'UTF-32';
13815  
13816              case 'utf32be':
13817                  return 'UTF-32BE';
13818  
13819              case 'utf32le':
13820                  return 'UTF-32LE';
13821  
13822              case 'csventurainternational':
13823              case 'venturainternational':
13824                  return 'Ventura-International';
13825  
13826              case 'csventuramath':
13827              case 'venturamath':
13828                  return 'Ventura-Math';
13829  
13830              case 'csventuraus':
13831              case 'venturaus':
13832                  return 'Ventura-US';
13833  
13834              case 'csiso70videotexsupp1':
13835              case 'isoir70':
13836              case 'videotexsuppl':
13837                  return 'videotex-suppl';
13838  
13839              case 'csviqr':
13840              case 'viqr':
13841                  return 'VIQR';
13842  
13843              case 'csviscii':
13844              case 'viscii':
13845                  return 'VISCII';
13846  
13847              case 'csshiftjis':
13848              case 'cswindows31j':
13849              case 'mskanji':
13850              case 'shiftjis':
13851              case 'windows31j':
13852                  return 'Windows-31J';
13853  
13854              case 'iso885911':
13855              case 'tis620':
13856                  return 'windows-874';
13857  
13858              case 'cseuckr':
13859              case 'csksc56011987':
13860              case 'euckr':
13861              case 'isoir149':
13862              case 'korean':
13863              case 'ksc5601':
13864              case 'ksc56011987':
13865              case 'ksc56011989':
13866              case 'windows949':
13867                  return 'windows-949';
13868  
13869              case 'windows1250':
13870                  return 'windows-1250';
13871  
13872              case 'windows1251':
13873                  return 'windows-1251';
13874  
13875              case 'cp819':
13876              case 'csisolatin1':
13877              case 'ibm819':
13878              case 'iso88591':
13879              case 'iso885911987':
13880              case 'isoir100':
13881              case 'l1':
13882              case 'latin1':
13883              case 'windows1252':
13884                  return 'windows-1252';
13885  
13886              case 'windows1253':
13887                  return 'windows-1253';
13888  
13889              case 'csisolatin5':
13890              case 'iso88599':
13891              case 'iso885991989':
13892              case 'isoir148':
13893              case 'l5':
13894              case 'latin5':
13895              case 'windows1254':
13896                  return 'windows-1254';
13897  
13898              case 'windows1255':
13899                  return 'windows-1255';
13900  
13901              case 'windows1256':
13902                  return 'windows-1256';
13903  
13904              case 'windows1257':
13905                  return 'windows-1257';
13906  
13907              case 'windows1258':
13908                  return 'windows-1258';
13909  
13910              default:
13911                  return $charset;
13912          }
13913      }
13914  
13915  	public static function get_curl_version()
13916      {
13917          if (is_array($curl = curl_version()))
13918          {
13919              $curl = $curl['version'];
13920          }
13921          elseif (substr($curl, 0, 5) === 'curl/')
13922          {
13923              $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
13924          }
13925          elseif (substr($curl, 0, 8) === 'libcurl/')
13926          {
13927              $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
13928          }
13929          else
13930          {
13931              $curl = 0;
13932          }
13933          return $curl;
13934      }
13935  
13936      /**
13937       * Strip HTML comments
13938       *
13939       * @param string $data Data to strip comments from
13940       * @return string Comment stripped string
13941       */
13942  	public static function strip_comments($data)
13943      {
13944          $output = '';
13945          while (($start = strpos($data, '<!--')) !== false)
13946          {
13947              $output .= substr($data, 0, $start);
13948              if (($end = strpos($data, '-->', $start)) !== false)
13949              {
13950                  $data = substr_replace($data, '', 0, $end + 3);
13951              }
13952              else
13953              {
13954                  $data = '';
13955              }
13956          }
13957          return $output . $data;
13958      }
13959  
13960  	public static function parse_date($dt)
13961      {
13962          $parser = SimplePie_Parse_Date::get();
13963          return $parser->parse($dt);
13964      }
13965  
13966      /**
13967       * Decode HTML entities
13968       *
13969       * @deprecated Use DOMDocument instead
13970       * @param string $data Input data
13971       * @return string Output data
13972       */
13973  	public static function entities_decode($data)
13974      {
13975          $decoder = new SimplePie_Decode_HTML_Entities($data);
13976          return $decoder->parse();
13977      }
13978  
13979      /**
13980       * Remove RFC822 comments
13981       *
13982       * @param string $data Data to strip comments from
13983       * @return string Comment stripped string
13984       */
13985  	public static function uncomment_rfc822($string)
13986      {
13987          $string = (string) $string;
13988          $position = 0;
13989          $length = strlen($string);
13990          $depth = 0;
13991  
13992          $output = '';
13993  
13994          while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
13995          {
13996              $output .= substr($string, $position, $pos - $position);
13997              $position = $pos + 1;
13998              if ($string[$pos - 1] !== '\\')
13999              {
14000                  $depth++;
14001                  while ($depth && $position < $length)
14002                  {
14003                      $position += strcspn($string, '()', $position);
14004                      if ($string[$position - 1] === '\\')
14005                      {
14006                          $position++;
14007                          continue;
14008                      }
14009                      elseif (isset($string[$position]))
14010                      {
14011                          switch ($string[$position])
14012                          {
14013                              case '(':
14014                                  $depth++;
14015                                  break;
14016  
14017                              case ')':
14018                                  $depth--;
14019                                  break;
14020                          }
14021                          $position++;
14022                      }
14023                      else
14024                      {
14025                          break;
14026                      }
14027                  }
14028              }
14029              else
14030              {
14031                  $output .= '(';
14032              }
14033          }
14034          $output .= substr($string, $position);
14035  
14036          return $output;
14037      }
14038  
14039  	public static function parse_mime($mime)
14040      {
14041          if (($pos = strpos($mime, ';')) === false)
14042          {
14043              return trim($mime);
14044          }
14045          else
14046          {
14047              return trim(substr($mime, 0, $pos));
14048          }
14049      }
14050  
14051  	public static function atom_03_construct_type($attribs)
14052      {
14053          if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
14054          {
14055              $mode = SIMPLEPIE_CONSTRUCT_BASE64;
14056          }
14057          else
14058          {
14059              $mode = SIMPLEPIE_CONSTRUCT_NONE;
14060          }
14061          if (isset($attribs['']['type']))
14062          {
14063              switch (strtolower(trim($attribs['']['type'])))
14064              {
14065                  case 'text':
14066                  case 'text/plain':
14067                      return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
14068  
14069                  case 'html':
14070                  case 'text/html':
14071                      return SIMPLEPIE_CONSTRUCT_HTML | $mode;
14072  
14073                  case 'xhtml':
14074                  case 'application/xhtml+xml':
14075                      return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
14076  
14077                  default:
14078                      return SIMPLEPIE_CONSTRUCT_NONE | $mode;
14079              }
14080          }
14081          else
14082          {
14083              return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
14084          }
14085      }
14086  
14087  	public static function atom_10_construct_type($attribs)
14088      {
14089          if (isset($attribs['']['type']))
14090          {
14091              switch (strtolower(trim($attribs['']['type'])))
14092              {
14093                  case 'text':
14094                      return SIMPLEPIE_CONSTRUCT_TEXT;
14095  
14096                  case 'html':
14097                      return SIMPLEPIE_CONSTRUCT_HTML;
14098  
14099                  case 'xhtml':
14100                      return SIMPLEPIE_CONSTRUCT_XHTML;
14101  
14102                  default:
14103                      return SIMPLEPIE_CONSTRUCT_NONE;
14104              }
14105          }
14106          return SIMPLEPIE_CONSTRUCT_TEXT;
14107      }
14108  
14109  	public static function atom_10_content_construct_type($attribs)
14110      {
14111          if (isset($attribs['']['type']))
14112          {
14113              $type = strtolower(trim($attribs['']['type']));
14114              switch ($type)
14115              {
14116                  case 'text':
14117                      return SIMPLEPIE_CONSTRUCT_TEXT;
14118  
14119                  case 'html':
14120                      return SIMPLEPIE_CONSTRUCT_HTML;
14121  
14122                  case 'xhtml':
14123                      return SIMPLEPIE_CONSTRUCT_XHTML;
14124              }
14125              if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
14126              {
14127                  return SIMPLEPIE_CONSTRUCT_NONE;
14128              }
14129              else
14130              {
14131                  return SIMPLEPIE_CONSTRUCT_BASE64;
14132              }
14133          }
14134          else
14135          {
14136              return SIMPLEPIE_CONSTRUCT_TEXT;
14137          }
14138      }
14139  
14140  	public static function is_isegment_nz_nc($string)
14141      {
14142          return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
14143      }
14144  
14145  	public static function space_seperated_tokens($string)
14146      {
14147          $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
14148          $string_length = strlen($string);
14149  
14150          $position = strspn($string, $space_characters);
14151          $tokens = array();
14152  
14153          while ($position < $string_length)
14154          {
14155              $len = strcspn($string, $space_characters, $position);
14156              $tokens[] = substr($string, $position, $len);
14157              $position += $len;
14158              $position += strspn($string, $space_characters, $position);
14159          }
14160  
14161          return $tokens;
14162      }
14163  
14164      /**
14165       * Converts a unicode codepoint to a UTF-8 character
14166       *
14167       * @static
14168       * @param int $codepoint Unicode codepoint
14169       * @return string UTF-8 character
14170       */
14171  	public static function codepoint_to_utf8($codepoint)
14172      {
14173          $codepoint = (int) $codepoint;
14174          if ($codepoint < 0)
14175          {
14176              return false;
14177          }
14178          else if ($codepoint <= 0x7f)
14179          {
14180              return chr($codepoint);
14181          }
14182          else if ($codepoint <= 0x7ff)
14183          {
14184              return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
14185          }
14186          else if ($codepoint <= 0xffff)
14187          {
14188              return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14189          }
14190          else if ($codepoint <= 0x10ffff)
14191          {
14192              return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
14193          }
14194          else
14195          {
14196              // U+FFFD REPLACEMENT CHARACTER
14197              return "\xEF\xBF\xBD";
14198          }
14199      }
14200  
14201      /**
14202       * Similar to parse_str()
14203       *
14204       * Returns an associative array of name/value pairs, where the value is an
14205       * array of values that have used the same name
14206       *
14207       * @static
14208       * @param string $str The input string.
14209       * @return array
14210       */
14211  	public static function parse_str($str)
14212      {
14213          $return = array();
14214          $str = explode('&', $str);
14215  
14216          foreach ($str as $section)
14217          {
14218              if (strpos($section, '=') !== false)
14219              {
14220                  list($name, $value) = explode('=', $section, 2);
14221                  $return[urldecode($name)][] = urldecode($value);
14222              }
14223              else
14224              {
14225                  $return[urldecode($section)][] = null;
14226              }
14227          }
14228  
14229          return $return;
14230      }
14231  
14232      /**
14233       * Detect XML encoding, as per XML 1.0 Appendix F.1
14234       *
14235       * @todo Add support for EBCDIC
14236       * @param string $data XML data
14237       * @param SimplePie_Registry $registry Class registry
14238       * @return array Possible encodings
14239       */
14240  	public static function xml_encoding($data, $registry)
14241      {
14242          // UTF-32 Big Endian BOM
14243          if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
14244          {
14245              $encoding[] = 'UTF-32BE';
14246          }
14247          // UTF-32 Little Endian BOM
14248          elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
14249          {
14250              $encoding[] = 'UTF-32LE';
14251          }
14252          // UTF-16 Big Endian BOM
14253          elseif (substr($data, 0, 2) === "\xFE\xFF")
14254          {
14255              $encoding[] = 'UTF-16BE';
14256          }
14257          // UTF-16 Little Endian BOM
14258          elseif (substr($data, 0, 2) === "\xFF\xFE")
14259          {
14260              $encoding[] = 'UTF-16LE';
14261          }
14262          // UTF-8 BOM
14263          elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
14264          {
14265              $encoding[] = 'UTF-8';
14266          }
14267          // UTF-32 Big Endian Without BOM
14268          elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
14269          {
14270              if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
14271              {
14272                  $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
14273                  if ($parser->parse())
14274                  {
14275                      $encoding[] = $parser->encoding;
14276                  }
14277              }
14278              $encoding[] = 'UTF-32BE';
14279          }
14280          // UTF-32 Little Endian Without BOM
14281          elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
14282          {
14283              if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
14284              {
14285                  $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
14286                  if ($parser->parse())
14287                  {
14288                      $encoding[] = $parser->encoding;
14289                  }
14290              }
14291              $encoding[] = 'UTF-32LE';
14292          }
14293          // UTF-16 Big Endian Without BOM
14294          elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
14295          {
14296              if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
14297              {
14298                  $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
14299                  if ($parser->parse())
14300                  {
14301                      $encoding[] = $parser->encoding;
14302                  }
14303              }
14304              $encoding[] = 'UTF-16BE';
14305          }
14306          // UTF-16 Little Endian Without BOM
14307          elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
14308          {
14309              if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
14310              {
14311                  $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
14312                  if ($parser->parse())
14313                  {
14314                      $encoding[] = $parser->encoding;
14315                  }
14316              }
14317              $encoding[] = 'UTF-16LE';
14318          }
14319          // US-ASCII (or superset)
14320          elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
14321          {
14322              if ($pos = strpos($data, "\x3F\x3E"))
14323              {
14324                  $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
14325                  if ($parser->parse())
14326                  {
14327                      $encoding[] = $parser->encoding;
14328                  }
14329              }
14330              $encoding[] = 'UTF-8';
14331          }
14332          // Fallback to UTF-8
14333          else
14334          {
14335              $encoding[] = 'UTF-8';
14336          }
14337          return $encoding;
14338      }
14339  
14340  	public static function output_javascript()
14341      {
14342          if (function_exists('ob_gzhandler'))
14343          {
14344              ob_start('ob_gzhandler');
14345          }
14346          header('Content-type: text/javascript; charset: UTF-8');
14347          header('Cache-Control: must-revalidate');
14348          header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
14349          ?>
14350  function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
14351      if (placeholder != '') {
14352          document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
14353      }
14354      else {
14355          document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
14356      }
14357  }
14358  
14359  function embed_flash(bgcolor, width, height, link, loop, type) {
14360      document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
14361  }
14362  
14363  function embed_flv(width, height, link, placeholder, loop, player) {
14364      document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
14365  }
14366  
14367  function embed_wmedia(width, height, link) {
14368      document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
14369  }
14370          <?php
14371      }
14372  
14373      /**
14374       * Get the SimplePie build timestamp
14375       *
14376       * Uses the git index if it exists, otherwise uses the modification time
14377       * of the newest file.
14378       */
14379  	public static function get_build()
14380      {
14381          $root = dirname(dirname(__FILE__));
14382          if (file_exists($root . '/.git/index'))
14383          {
14384              return filemtime($root . '/.git/index');
14385          }
14386          elseif (file_exists($root . '/SimplePie'))
14387          {
14388              $time = 0;
14389              foreach (glob($root . '/SimplePie/*.php') as $file)
14390              {
14391                  if (($mtime = filemtime($file)) > $time)
14392                  {
14393                      $time = $mtime;
14394                  }
14395              }
14396              return $time;
14397          }
14398          elseif (file_exists(dirname(__FILE__) . '/Core.php'))
14399          {
14400              return filemtime(dirname(__FILE__) . '/Core.php');
14401          }
14402          else
14403          {
14404              return filemtime(__FILE__);
14405          }
14406      }
14407  
14408      /**
14409       * Format debugging information
14410       */
14411  	public static function debug(&$sp)
14412      {
14413          $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
14414          $info .= 'PHP ' . PHP_VERSION . "\n";
14415          if ($sp->error() !== null)
14416          {
14417              $info .= 'Error occurred: ' . $sp->error() . "\n";
14418          }
14419          else
14420          {
14421              $info .= "No error found.\n";
14422          }
14423          $info .= "Extensions:\n";
14424          $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
14425          foreach ($extensions as $ext)
14426          {
14427              if (extension_loaded($ext))
14428              {
14429                  $info .= "    $ext loaded\n";
14430                  switch ($ext)
14431                  {
14432                      case 'pcre':
14433                          $info .= '      Version ' . PCRE_VERSION . "\n";
14434                          break;
14435                      case 'curl':
14436                          $version = curl_version();
14437                          $info .= '      Version ' . $version['version'] . "\n";
14438                          break;
14439                      case 'mbstring':
14440                          $info .= '      Overloading: ' . mb_get_info('func_overload') . "\n";
14441                          break;
14442                      case 'iconv':
14443                          $info .= '      Version ' . ICONV_VERSION . "\n";
14444                          break;
14445                      case 'xml':
14446                          $info .= '      Version ' . LIBXML_DOTTED_VERSION . "\n";
14447                          break;
14448                  }
14449              }
14450              else
14451              {
14452                  $info .= "    $ext not loaded\n";
14453              }
14454          }
14455          return $info;
14456      }
14457  
14458  	public static function silence_errors($num, $str)
14459      {
14460          // No-op
14461      }
14462  }
14463  
14464  /**
14465   * Class to validate and to work with IPv6 addresses.
14466   *
14467   * @package SimplePie
14468   * @subpackage HTTP
14469   * @copyright 2003-2005 The PHP Group
14470   * @license http://www.opensource.org/licenses/bsd-license.php
14471   * @link http://pear.php.net/package/Net_IPv6
14472   * @author Alexander Merz <alexander.merz@web.de>
14473   * @author elfrink at introweb dot nl
14474   * @author Josh Peck <jmp at joshpeck dot org>
14475   * @author Geoffrey Sneddon <geoffers@gmail.com>
14476   */
14477  class SimplePie_Net_IPv6
14478  {
14479      /**
14480       * Uncompresses an IPv6 address
14481       *
14482       * RFC 4291 allows you to compress concecutive zero pieces in an address to
14483       * '::'. This method expects a valid IPv6 address and expands the '::' to
14484       * the required number of zero pieces.
14485       *
14486       * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
14487       *           ::1         ->  0:0:0:0:0:0:0:1
14488       *
14489       * @author Alexander Merz <alexander.merz@web.de>
14490       * @author elfrink at introweb dot nl
14491       * @author Josh Peck <jmp at joshpeck dot org>
14492       * @copyright 2003-2005 The PHP Group
14493       * @license http://www.opensource.org/licenses/bsd-license.php
14494       * @param string $ip An IPv6 address
14495       * @return string The uncompressed IPv6 address
14496       */
14497  	public static function uncompress($ip)
14498      {
14499          $c1 = -1;
14500          $c2 = -1;
14501          if (substr_count($ip, '::') === 1)
14502          {
14503              list($ip1, $ip2) = explode('::', $ip);
14504              if ($ip1 === '')
14505              {
14506                  $c1 = -1;
14507              }
14508              else
14509              {
14510                  $c1 = substr_count($ip1, ':');
14511              }
14512              if ($ip2 === '')
14513              {
14514                  $c2 = -1;
14515              }
14516              else
14517              {
14518                  $c2 = substr_count($ip2, ':');
14519              }
14520              if (strpos($ip2, '.') !== false)
14521              {
14522                  $c2++;
14523              }
14524              // ::
14525              if ($c1 === -1 && $c2 === -1)
14526              {
14527                  $ip = '0:0:0:0:0:0:0:0';
14528              }
14529              // ::xxx
14530              else if ($c1 === -1)
14531              {
14532                  $fill = str_repeat('0:', 7 - $c2);
14533                  $ip = str_replace('::', $fill, $ip);
14534              }
14535              // xxx::
14536              else if ($c2 === -1)
14537              {
14538                  $fill = str_repeat(':0', 7 - $c1);
14539                  $ip = str_replace('::', $fill, $ip);
14540              }
14541              // xxx::xxx
14542              else
14543              {
14544                  $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
14545                  $ip = str_replace('::', $fill, $ip);
14546              }
14547          }
14548          return $ip;
14549      }
14550  
14551      /**
14552       * Compresses an IPv6 address
14553       *
14554       * RFC 4291 allows you to compress concecutive zero pieces in an address to
14555       * '::'. This method expects a valid IPv6 address and compresses consecutive
14556       * zero pieces to '::'.
14557       *
14558       * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
14559       *           0:0:0:0:0:0:0:1        ->  ::1
14560       *
14561       * @see uncompress()
14562       * @param string $ip An IPv6 address
14563       * @return string The compressed IPv6 address
14564       */
14565  	public static function compress($ip)
14566      {
14567          // Prepare the IP to be compressed
14568          $ip = self::uncompress($ip);
14569          $ip_parts = self::split_v6_v4($ip);
14570  
14571          // Replace all leading zeros
14572          $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
14573  
14574          // Find bunches of zeros
14575          if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
14576          {
14577              $max = 0;
14578              $pos = null;
14579              foreach ($matches[0] as $match)
14580              {
14581                  if (strlen($match[0]) > $max)
14582                  {
14583                      $max = strlen($match[0]);
14584                      $pos = $match[1];
14585                  }
14586              }
14587  
14588              $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
14589          }
14590  
14591          if ($ip_parts[1] !== '')
14592          {
14593              return implode(':', $ip_parts);
14594          }
14595          else
14596          {
14597              return $ip_parts[0];
14598          }
14599      }
14600  
14601      /**
14602       * Splits an IPv6 address into the IPv6 and IPv4 representation parts
14603       *
14604       * RFC 4291 allows you to represent the last two parts of an IPv6 address
14605       * using the standard IPv4 representation
14606       *
14607       * Example:  0:0:0:0:0:0:13.1.68.3
14608       *           0:0:0:0:0:FFFF:129.144.52.38
14609       *
14610       * @param string $ip An IPv6 address
14611       * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
14612       */
14613  	private static function split_v6_v4($ip)
14614      {
14615          if (strpos($ip, '.') !== false)
14616          {
14617              $pos = strrpos($ip, ':');
14618              $ipv6_part = substr($ip, 0, $pos);
14619              $ipv4_part = substr($ip, $pos + 1);
14620              return array($ipv6_part, $ipv4_part);
14621          }
14622          else
14623          {
14624              return array($ip, '');
14625          }
14626      }
14627  
14628      /**
14629       * Checks an IPv6 address
14630       *
14631       * Checks if the given IP is a valid IPv6 address
14632       *
14633       * @param string $ip An IPv6 address
14634       * @return bool true if $ip is a valid IPv6 address
14635       */
14636  	public static function check_ipv6($ip)
14637      {
14638          $ip = self::uncompress($ip);
14639          list($ipv6, $ipv4) = self::split_v6_v4($ip);
14640          $ipv6 = explode(':', $ipv6);
14641          $ipv4 = explode('.', $ipv4);
14642          if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
14643          {
14644              foreach ($ipv6 as $ipv6_part)
14645              {
14646                  // The section can't be empty
14647                  if ($ipv6_part === '')
14648                      return false;
14649  
14650                  // Nor can it be over four characters
14651                  if (strlen($ipv6_part) > 4)
14652                      return false;
14653  
14654                  // Remove leading zeros (this is safe because of the above)
14655                  $ipv6_part = ltrim($ipv6_part, '0');
14656                  if ($ipv6_part === '')
14657                      $ipv6_part = '0';
14658  
14659                  // Check the value is valid
14660                  $value = hexdec($ipv6_part);
14661                  if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
14662                      return false;
14663              }
14664              if (count($ipv4) === 4)
14665              {
14666                  foreach ($ipv4 as $ipv4_part)
14667                  {
14668                      $value = (int) $ipv4_part;
14669                      if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
14670                          return false;
14671                  }
14672              }
14673              return true;
14674          }
14675          else
14676          {
14677              return false;
14678          }
14679      }
14680  
14681      /**
14682       * Checks if the given IP is a valid IPv6 address
14683       *
14684       * @codeCoverageIgnore
14685       * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
14686       * @see check_ipv6
14687       * @param string $ip An IPv6 address
14688       * @return bool true if $ip is a valid IPv6 address
14689       */
14690  	public static function checkIPv6($ip)
14691      {
14692          return self::check_ipv6($ip);
14693      }
14694  }
14695  
14696  /**
14697   * Date Parser
14698   *
14699   * @package SimplePie
14700   * @subpackage Parsing
14701   */
14702  class SimplePie_Parse_Date
14703  {
14704      /**
14705       * Input data
14706       *
14707       * @access protected
14708       * @var string
14709       */
14710      var $date;
14711  
14712      /**
14713       * List of days, calendar day name => ordinal day number in the week
14714       *
14715       * @access protected
14716       * @var array
14717       */
14718      var $day = array(
14719          // English
14720          'mon' => 1,
14721          'monday' => 1,
14722          'tue' => 2,
14723          'tuesday' => 2,
14724          'wed' => 3,
14725          'wednesday' => 3,
14726          'thu' => 4,
14727          'thursday' => 4,
14728          'fri' => 5,
14729          'friday' => 5,
14730          'sat' => 6,
14731          'saturday' => 6,
14732          'sun' => 7,
14733          'sunday' => 7,
14734          // Dutch
14735          'maandag' => 1,
14736          'dinsdag' => 2,
14737          'woensdag' => 3,
14738          'donderdag' => 4,
14739          'vrijdag' => 5,
14740          'zaterdag' => 6,
14741          'zondag' => 7,
14742          // French
14743          'lundi' => 1,
14744          'mardi' => 2,
14745          'mercredi' => 3,
14746          'jeudi' => 4,
14747          'vendredi' => 5,
14748          'samedi' => 6,
14749          'dimanche' => 7,
14750          // German
14751          'montag' => 1,
14752          'dienstag' => 2,
14753          'mittwoch' => 3,
14754          'donnerstag' => 4,
14755          'freitag' => 5,
14756          'samstag' => 6,
14757          'sonnabend' => 6,
14758          'sonntag' => 7,
14759          // Italian
14760          'lunedì' => 1,
14761          'martedì' => 2,
14762          'mercoledì' => 3,
14763          'giovedì' => 4,
14764          'venerdì' => 5,
14765          'sabato' => 6,
14766          'domenica' => 7,
14767          // Spanish
14768          'lunes' => 1,
14769          'martes' => 2,
14770          'miércoles' => 3,
14771          'jueves' => 4,
14772          'viernes' => 5,
14773          'sábado' => 6,
14774          'domingo' => 7,
14775          // Finnish
14776          'maanantai' => 1,
14777          'tiistai' => 2,
14778          'keskiviikko' => 3,
14779          'torstai' => 4,
14780          'perjantai' => 5,
14781          'lauantai' => 6,
14782          'sunnuntai' => 7,
14783          // Hungarian
14784          'hétfő' => 1,
14785          'kedd' => 2,
14786          'szerda' => 3,
14787          'csütörtok' => 4,
14788          'péntek' => 5,
14789          'szombat' => 6,
14790          'vasárnap' => 7,
14791          // Greek
14792          'Δευ' => 1,
14793          'Τρι' => 2,
14794          'Τετ' => 3,
14795          'Πεμ' => 4,
14796          'Παρ' => 5,
14797          'Σαβ' => 6,
14798          'Κυρ' => 7,
14799      );
14800  
14801      /**
14802       * List of months, calendar month name => calendar month number
14803       *
14804       * @access protected
14805       * @var array
14806       */
14807      var $month = array(
14808          // English
14809          'jan' => 1,
14810          'january' => 1,
14811          'feb' => 2,
14812          'february' => 2,
14813          'mar' => 3,
14814          'march' => 3,
14815          'apr' => 4,
14816          'april' => 4,
14817          'may' => 5,
14818          // No long form of May
14819          'jun' => 6,
14820          'june' => 6,
14821          'jul' => 7,
14822          'july' => 7,
14823          'aug' => 8,
14824          'august' => 8,
14825          'sep' => 9,
14826          'september' => 8,
14827          'oct' => 10,
14828          'october' => 10,
14829          'nov' => 11,
14830          'november' => 11,
14831          'dec' => 12,
14832          'december' => 12,
14833          // Dutch
14834          'januari' => 1,
14835          'februari' => 2,
14836          'maart' => 3,
14837          'april' => 4,
14838          'mei' => 5,
14839          'juni' => 6,
14840          'juli' => 7,
14841          'augustus' => 8,
14842          'september' => 9,
14843          'oktober' => 10,
14844          'november' => 11,
14845          'december' => 12,
14846          // French
14847          'janvier' => 1,
14848          'février' => 2,
14849          'mars' => 3,
14850          'avril' => 4,
14851          'mai' => 5,
14852          'juin' => 6,
14853          'juillet' => 7,
14854          'août' => 8,
14855          'septembre' => 9,
14856          'octobre' => 10,
14857          'novembre' => 11,
14858          'décembre' => 12,
14859          // German
14860          'januar' => 1,
14861          'februar' => 2,
14862          'märz' => 3,
14863          'april' => 4,
14864          'mai' => 5,
14865          'juni' => 6,
14866          'juli' => 7,
14867          'august' => 8,
14868          'september' => 9,
14869          'oktober' => 10,
14870          'november' => 11,
14871          'dezember' => 12,
14872          // Italian
14873          'gennaio' => 1,
14874          'febbraio' => 2,
14875          'marzo' => 3,
14876          'aprile' => 4,
14877          'maggio' => 5,
14878          'giugno' => 6,
14879          'luglio' => 7,
14880          'agosto' => 8,
14881          'settembre' => 9,
14882          'ottobre' => 10,
14883          'novembre' => 11,
14884          'dicembre' => 12,
14885          // Spanish
14886          'enero' => 1,
14887          'febrero' => 2,
14888          'marzo' => 3,
14889          'abril' => 4,
14890          'mayo' => 5,
14891          'junio' => 6,
14892          'julio' => 7,
14893          'agosto' => 8,
14894          'septiembre' => 9,
14895          'setiembre' => 9,
14896          'octubre' => 10,
14897          'noviembre' => 11,
14898          'diciembre' => 12,
14899          // Finnish
14900          'tammikuu' => 1,
14901          'helmikuu' => 2,
14902          'maaliskuu' => 3,
14903          'huhtikuu' => 4,
14904          'toukokuu' => 5,
14905          'kesäkuu' => 6,
14906          'heinäkuu' => 7,
14907          'elokuu' => 8,
14908          'suuskuu' => 9,
14909          'lokakuu' => 10,
14910          'marras' => 11,
14911          'joulukuu' => 12,
14912          // Hungarian
14913          'január' => 1,
14914          'február' => 2,
14915          'március' => 3,
14916          'április' => 4,
14917          'május' => 5,
14918          'június' => 6,
14919          'július' => 7,
14920          'augusztus' => 8,
14921          'szeptember' => 9,
14922          'október' => 10,
14923          'november' => 11,
14924          'december' => 12,
14925          // Greek
14926          'Ιαν' => 1,
14927          'Φεβ' => 2,
14928          'Μάώ' => 3,
14929          'Μαώ' => 3,
14930          'Απρ' => 4,
14931          'Μάι' => 5,
14932          'Μαϊ' => 5,
14933          'Μαι' => 5,
14934          'Ιούν' => 6,
14935          'Ιον' => 6,
14936          'Ιούλ' => 7,
14937          'Ιολ' => 7,
14938          'Αύγ' => 8,
14939          'Αυγ' => 8,
14940          'Σεπ' => 9,
14941          'Οκτ' => 10,
14942          'Νοέ' => 11,
14943          'Δεκ' => 12,
14944      );
14945  
14946      /**
14947       * List of timezones, abbreviation => offset from UTC
14948       *
14949       * @access protected
14950       * @var array
14951       */
14952      var $timezone = array(
14953          'ACDT' => 37800,
14954          'ACIT' => 28800,
14955          'ACST' => 34200,
14956          'ACT' => -18000,
14957          'ACWDT' => 35100,
14958          'ACWST' => 31500,
14959          'AEDT' => 39600,
14960          'AEST' => 36000,
14961          'AFT' => 16200,
14962          'AKDT' => -28800,
14963          'AKST' => -32400,
14964          'AMDT' => 18000,
14965          'AMT' => -14400,
14966          'ANAST' => 46800,
14967          'ANAT' => 43200,
14968          'ART' => -10800,
14969          'AZOST' => -3600,
14970          'AZST' => 18000,
14971          'AZT' => 14400,
14972          'BIOT' => 21600,
14973          'BIT' => -43200,
14974          'BOT' => -14400,
14975          'BRST' => -7200,
14976          'BRT' => -10800,
14977          'BST' => 3600,
14978          'BTT' => 21600,
14979          'CAST' => 18000,
14980          'CAT' => 7200,
14981          'CCT' => 23400,
14982          'CDT' => -18000,
14983          'CEDT' => 7200,
14984          'CET' => 3600,
14985          'CGST' => -7200,
14986          'CGT' => -10800,
14987          'CHADT' => 49500,
14988          'CHAST' => 45900,
14989          'CIST' => -28800,
14990          'CKT' => -36000,
14991          'CLDT' => -10800,
14992          'CLST' => -14400,
14993          'COT' => -18000,
14994          'CST' => -21600,
14995          'CVT' => -3600,
14996          'CXT' => 25200,
14997          'DAVT' => 25200,
14998          'DTAT' => 36000,
14999          'EADT' => -18000,
15000          'EAST' => -21600,
15001          'EAT' => 10800,
15002          'ECT' => -18000,
15003          'EDT' => -14400,
15004          'EEST' => 10800,
15005          'EET' => 7200,
15006          'EGT' => -3600,
15007          'EKST' => 21600,
15008          'EST' => -18000,
15009          'FJT' => 43200,
15010          'FKDT' => -10800,
15011          'FKST' => -14400,
15012          'FNT' => -7200,
15013          'GALT' => -21600,
15014          'GEDT' => 14400,
15015          'GEST' => 10800,
15016          'GFT' => -10800,
15017          'GILT' => 43200,
15018          'GIT' => -32400,
15019          'GST' => 14400,
15020          'GST' => -7200,
15021          'GYT' => -14400,
15022          'HAA' => -10800,
15023          'HAC' => -18000,
15024          'HADT' => -32400,
15025          'HAE' => -14400,
15026          'HAP' => -25200,
15027          'HAR' => -21600,
15028          'HAST' => -36000,
15029          'HAT' => -9000,
15030          'HAY' => -28800,
15031          'HKST' => 28800,
15032          'HMT' => 18000,
15033          'HNA' => -14400,
15034          'HNC' => -21600,
15035          'HNE' => -18000,
15036          'HNP' => -28800,
15037          'HNR' => -25200,
15038          'HNT' => -12600,
15039          'HNY' => -32400,
15040          'IRDT' => 16200,
15041          'IRKST' => 32400,
15042          'IRKT' => 28800,
15043          'IRST' => 12600,
15044          'JFDT' => -10800,
15045          'JFST' => -14400,
15046          'JST' => 32400,
15047          'KGST' => 21600,
15048          'KGT' => 18000,
15049          'KOST' => 39600,
15050          'KOVST' => 28800,
15051          'KOVT' => 25200,
15052          'KRAST' => 28800,
15053          'KRAT' => 25200,
15054          'KST' => 32400,
15055          'LHDT' => 39600,
15056          'LHST' => 37800,
15057          'LINT' => 50400,
15058          'LKT' => 21600,
15059          'MAGST' => 43200,
15060          'MAGT' => 39600,
15061          'MAWT' => 21600,
15062          'MDT' => -21600,
15063          'MESZ' => 7200,
15064          'MEZ' => 3600,
15065          'MHT' => 43200,
15066          'MIT' => -34200,
15067          'MNST' => 32400,
15068          'MSDT' => 14400,
15069          'MSST' => 10800,
15070          'MST' => -25200,
15071          'MUT' => 14400,
15072          'MVT' => 18000,
15073          'MYT' => 28800,
15074          'NCT' => 39600,
15075          'NDT' => -9000,
15076          'NFT' => 41400,
15077          'NMIT' => 36000,
15078          'NOVST' => 25200,
15079          'NOVT' => 21600,
15080          'NPT' => 20700,
15081          'NRT' => 43200,
15082          'NST' => -12600,
15083          'NUT' => -39600,
15084          'NZDT' => 46800,
15085          'NZST' => 43200,
15086          'OMSST' => 25200,
15087          'OMST' => 21600,
15088          'PDT' => -25200,
15089          'PET' => -18000,
15090          'PETST' => 46800,
15091          'PETT' => 43200,
15092          'PGT' => 36000,
15093          'PHOT' => 46800,
15094          'PHT' => 28800,
15095          'PKT' => 18000,
15096          'PMDT' => -7200,
15097          'PMST' => -10800,
15098          'PONT' => 39600,
15099          'PST' => -28800,
15100          'PWT' => 32400,
15101          'PYST' => -10800,
15102          'PYT' => -14400,
15103          'RET' => 14400,
15104          'ROTT' => -10800,
15105          'SAMST' => 18000,
15106          'SAMT' => 14400,
15107          'SAST' => 7200,
15108          'SBT' => 39600,
15109          'SCDT' => 46800,
15110          'SCST' => 43200,
15111          'SCT' => 14400,
15112          'SEST' => 3600,
15113          'SGT' => 28800,
15114          'SIT' => 28800,
15115          'SRT' => -10800,
15116          'SST' => -39600,
15117          'SYST' => 10800,
15118          'SYT' => 7200,
15119          'TFT' => 18000,
15120          'THAT' => -36000,
15121          'TJT' => 18000,
15122          'TKT' => -36000,
15123          'TMT' => 18000,
15124          'TOT' => 46800,
15125          'TPT' => 32400,
15126          'TRUT' => 36000,
15127          'TVT' => 43200,
15128          'TWT' => 28800,
15129          'UYST' => -7200,
15130          'UYT' => -10800,
15131          'UZT' => 18000,
15132          'VET' => -14400,
15133          'VLAST' => 39600,
15134          'VLAT' => 36000,
15135          'VOST' => 21600,
15136          'VUT' => 39600,
15137          'WAST' => 7200,
15138          'WAT' => 3600,
15139          'WDT' => 32400,
15140          'WEST' => 3600,
15141          'WFT' => 43200,
15142          'WIB' => 25200,
15143          'WIT' => 32400,
15144          'WITA' => 28800,
15145          'WKST' => 18000,
15146          'WST' => 28800,
15147          'YAKST' => 36000,
15148          'YAKT' => 32400,
15149          'YAPT' => 36000,
15150          'YEKST' => 21600,
15151          'YEKT' => 18000,
15152      );
15153  
15154      /**
15155       * Cached PCRE for SimplePie_Parse_Date::$day
15156       *
15157       * @access protected
15158       * @var string
15159       */
15160      var $day_pcre;
15161  
15162      /**
15163       * Cached PCRE for SimplePie_Parse_Date::$month
15164       *
15165       * @access protected
15166       * @var string
15167       */
15168      var $month_pcre;
15169  
15170      /**
15171       * Array of user-added callback methods
15172       *
15173       * @access private
15174       * @var array
15175       */
15176      var $built_in = array();
15177  
15178      /**
15179       * Array of user-added callback methods
15180       *
15181       * @access private
15182       * @var array
15183       */
15184      var $user = array();
15185  
15186      /**
15187       * Create new SimplePie_Parse_Date object, and set self::day_pcre,
15188       * self::month_pcre, and self::built_in
15189       *
15190       * @access private
15191       */
15192  	public function __construct()
15193      {
15194          $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
15195          $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
15196  
15197          static $cache;
15198          if (!isset($cache[get_class($this)]))
15199          {
15200              $all_methods = get_class_methods($this);
15201  
15202              foreach ($all_methods as $method)
15203              {
15204                  if (strtolower(substr($method, 0, 5)) === 'date_')
15205                  {
15206                      $cache[get_class($this)][] = $method;
15207                  }
15208              }
15209          }
15210  
15211          foreach ($cache[get_class($this)] as $method)
15212          {
15213              $this->built_in[] = $method;
15214          }
15215      }
15216  
15217      /**
15218       * Get the object
15219       *
15220       * @access public
15221       */
15222  	public static function get()
15223      {
15224          static $object;
15225          if (!$object)
15226          {
15227              $object = new SimplePie_Parse_Date;
15228          }
15229          return $object;
15230      }
15231  
15232      /**
15233       * Parse a date
15234       *
15235       * @final
15236       * @access public
15237       * @param string $date Date to parse
15238       * @return int Timestamp corresponding to date string, or false on failure
15239       */
15240  	public function parse($date)
15241      {
15242          foreach ($this->user as $method)
15243          {
15244              if (($returned = call_user_func($method, $date)) !== false)
15245              {
15246                  return $returned;
15247              }
15248          }
15249  
15250          foreach ($this->built_in as $method)
15251          {
15252              if (($returned = call_user_func(array($this, $method), $date)) !== false)
15253              {
15254                  return $returned;
15255              }
15256          }
15257  
15258          return false;
15259      }
15260  
15261      /**
15262       * Add a callback method to parse a date
15263       *
15264       * @final
15265       * @access public
15266       * @param callback $callback
15267       */
15268  	public function add_callback($callback)
15269      {
15270          if (is_callable($callback))
15271          {
15272              $this->user[] = $callback;
15273          }
15274          else
15275          {
15276              trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
15277          }
15278      }
15279  
15280      /**
15281       * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
15282       * well as allowing any of upper or lower case "T", horizontal tabs, or
15283       * spaces to be used as the time seperator (including more than one))
15284       *
15285       * @access protected
15286       * @return int Timestamp
15287       */
15288  	public function date_w3cdtf($date)
15289      {
15290          static $pcre;
15291          if (!$pcre)
15292          {
15293              $year = '([0-9]{4})';
15294              $month = $day = $hour = $minute = $second = '([0-9]{2})';
15295              $decimal = '([0-9]*)';
15296              $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
15297              $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
15298          }
15299          if (preg_match($pcre, $date, $match))
15300          {
15301              /*
15302              Capturing subpatterns:
15303              1: Year
15304              2: Month
15305              3: Day
15306              4: Hour
15307              5: Minute
15308              6: Second
15309              7: Decimal fraction of a second
15310              8: Zulu
15311              9: Timezone ±
15312              10: Timezone hours
15313              11: Timezone minutes
15314              */
15315  
15316              // Fill in empty matches
15317              for ($i = count($match); $i <= 3; $i++)
15318              {
15319                  $match[$i] = '1';
15320              }
15321  
15322              for ($i = count($match); $i <= 7; $i++)
15323              {
15324                  $match[$i] = '0';
15325              }
15326  
15327              // Numeric timezone
15328              if (isset($match[9]) && $match[9] !== '')
15329              {
15330                  $timezone = $match[10] * 3600;
15331                  $timezone += $match[11] * 60;
15332                  if ($match[9] === '-')
15333                  {
15334                      $timezone = 0 - $timezone;
15335                  }
15336              }
15337              else
15338              {
15339                  $timezone = 0;
15340              }
15341  
15342              // Convert the number of seconds to an integer, taking decimals into account
15343              $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
15344  
15345              return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
15346          }
15347          else
15348          {
15349              return false;
15350          }
15351      }
15352  
15353      /**
15354       * Remove RFC822 comments
15355       *
15356       * @access protected
15357       * @param string $data Data to strip comments from
15358       * @return string Comment stripped string
15359       */
15360  	public function remove_rfc2822_comments($string)
15361      {
15362          $string = (string) $string;
15363          $position = 0;
15364          $length = strlen($string);
15365          $depth = 0;
15366  
15367          $output = '';
15368  
15369          while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
15370          {
15371              $output .= substr($string, $position, $pos - $position);
15372              $position = $pos + 1;
15373              if ($string[$pos - 1] !== '\\')
15374              {
15375                  $depth++;
15376                  while ($depth && $position < $length)
15377                  {
15378                      $position += strcspn($string, '()', $position);
15379                      if ($string[$position - 1] === '\\')
15380                      {
15381                          $position++;
15382                          continue;
15383                      }
15384                      elseif (isset($string[$position]))
15385                      {
15386                          switch ($string[$position])
15387                          {
15388                              case '(':
15389                                  $depth++;
15390                                  break;
15391  
15392                              case ')':
15393                                  $depth--;
15394                                  break;
15395                          }
15396                          $position++;
15397                      }
15398                      else
15399                      {
15400                          break;
15401                      }
15402                  }
15403              }
15404              else
15405              {
15406                  $output .= '(';
15407              }
15408          }
15409          $output .= substr($string, $position);
15410  
15411          return $output;
15412      }
15413  
15414      /**
15415       * Parse RFC2822's date format
15416       *
15417       * @access protected
15418       * @return int Timestamp
15419       */
15420  	public function date_rfc2822($date)
15421      {
15422          static $pcre;
15423          if (!$pcre)
15424          {
15425              $wsp = '[\x09\x20]';
15426              $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
15427              $optional_fws = $fws . '?';
15428              $day_name = $this->day_pcre;
15429              $month = $this->month_pcre;
15430              $day = '([0-9]{1,2})';
15431              $hour = $minute = $second = '([0-9]{2})';
15432              $year = '([0-9]{2,4})';
15433              $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
15434              $character_zone = '([A-Z]{1,5})';
15435              $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
15436              $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
15437          }
15438          if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
15439          {
15440              /*
15441              Capturing subpatterns:
15442              1: Day name
15443              2: Day
15444              3: Month
15445              4: Year
15446              5: Hour
15447              6: Minute
15448              7: Second
15449              8: Timezone ±
15450              9: Timezone hours
15451              10: Timezone minutes
15452              11: Alphabetic timezone
15453              */
15454  
15455              // Find the month number
15456              $month = $this->month[strtolower($match[3])];
15457  
15458              // Numeric timezone
15459              if ($match[8] !== '')
15460              {
15461                  $timezone = $match[9] * 3600;
15462                  $timezone += $match[10] * 60;
15463                  if ($match[8] === '-')
15464                  {
15465                      $timezone = 0 - $timezone;
15466                  }
15467              }
15468              // Character timezone
15469              elseif (isset($this->timezone[strtoupper($match[11])]))
15470              {
15471                  $timezone = $this->timezone[strtoupper($match[11])];
15472              }
15473              // Assume everything else to be -0000
15474              else
15475              {
15476                  $timezone = 0;
15477              }
15478  
15479              // Deal with 2/3 digit years
15480              if ($match[4] < 50)
15481              {
15482                  $match[4] += 2000;
15483              }
15484              elseif ($match[4] < 1000)
15485              {
15486                  $match[4] += 1900;
15487              }
15488  
15489              // Second is optional, if it is empty set it to zero
15490              if ($match[7] !== '')
15491              {
15492                  $second = $match[7];
15493              }
15494              else
15495              {
15496                  $second = 0;
15497              }
15498  
15499              return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
15500          }
15501          else
15502          {
15503              return false;
15504          }
15505      }
15506  
15507      /**
15508       * Parse RFC850's date format
15509       *
15510       * @access protected
15511       * @return int Timestamp
15512       */
15513  	public function date_rfc850($date)
15514      {
15515          static $pcre;
15516          if (!$pcre)
15517          {
15518              $space = '[\x09\x20]+';
15519              $day_name = $this->day_pcre;
15520              $month = $this->month_pcre;
15521              $day = '([0-9]{1,2})';
15522              $year = $hour = $minute = $second = '([0-9]{2})';
15523              $zone = '([A-Z]{1,5})';
15524              $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
15525          }
15526          if (preg_match($pcre, $date, $match))
15527          {
15528              /*
15529              Capturing subpatterns:
15530              1: Day name
15531              2: Day
15532              3: Month
15533              4: Year
15534              5: Hour
15535              6: Minute
15536              7: Second
15537              8: Timezone
15538              */
15539  
15540              // Month
15541              $month = $this->month[strtolower($match[3])];
15542  
15543              // Character timezone
15544              if (isset($this->timezone[strtoupper($match[8])]))
15545              {
15546                  $timezone = $this->timezone[strtoupper($match[8])];
15547              }
15548              // Assume everything else to be -0000
15549              else
15550              {
15551                  $timezone = 0;
15552              }
15553  
15554              // Deal with 2 digit year
15555              if ($match[4] < 50)
15556              {
15557                  $match[4] += 2000;
15558              }
15559              else
15560              {
15561                  $match[4] += 1900;
15562              }
15563  
15564              return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
15565          }
15566          else
15567          {
15568              return false;
15569          }
15570      }
15571  
15572      /**
15573       * Parse C99's asctime()'s date format
15574       *
15575       * @access protected
15576       * @return int Timestamp
15577       */
15578  	public function date_asctime($date)
15579      {
15580          static $pcre;
15581          if (!$pcre)
15582          {
15583              $space = '[\x09\x20]+';
15584              $wday_name = $this->day_pcre;
15585              $mon_name = $this->month_pcre;
15586              $day = '([0-9]{1,2})';
15587              $hour = $sec = $min = '([0-9]{2})';
15588              $year = '([0-9]{4})';
15589              $terminator = '\x0A?\x00?';
15590              $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
15591          }
15592          if (preg_match($pcre, $date, $match))
15593          {
15594              /*
15595              Capturing subpatterns:
15596              1: Day name
15597              2: Month
15598              3: Day
15599              4: Hour
15600              5: Minute
15601              6: Second
15602              7: Year
15603              */
15604  
15605              $month = $this->month[strtolower($match[2])];
15606              return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
15607          }
15608          else
15609          {
15610              return false;
15611          }
15612      }
15613  
15614      /**
15615       * Parse dates using strtotime()
15616       *
15617       * @access protected
15618       * @return int Timestamp
15619       */
15620  	public function date_strtotime($date)
15621      {
15622          $strtotime = strtotime($date);
15623          if ($strtotime === -1 || $strtotime === false)
15624          {
15625              return false;
15626          }
15627          else
15628          {
15629              return $strtotime;
15630          }
15631      }
15632  }
15633  
15634  /**
15635   * Parses XML into something sane
15636   *
15637   *
15638   * This class can be overloaded with {@see SimplePie::set_parser_class()}
15639   *
15640   * @package SimplePie
15641   * @subpackage Parsing
15642   */
15643  class SimplePie_Parser
15644  {
15645      var $error_code;
15646      var $error_string;
15647      var $current_line;
15648      var $current_column;
15649      var $current_byte;
15650      var $separator = ' ';
15651      var $namespace = array('');
15652      var $element = array('');
15653      var $xml_base = array('');
15654      var $xml_base_explicit = array(false);
15655      var $xml_lang = array('');
15656      var $data = array();
15657      var $datas = array(array());
15658      var $current_xhtml_construct = -1;
15659      var $encoding;
15660      protected $registry;
15661  
15662  	public function set_registry(SimplePie_Registry $registry)
15663      {
15664          $this->registry = $registry;
15665      }
15666  
15667  	public function parse(&$data, $encoding)
15668      {
15669          // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
15670          if (strtoupper($encoding) === 'US-ASCII')
15671          {
15672              $this->encoding = 'UTF-8';
15673          }
15674          else
15675          {
15676              $this->encoding = $encoding;
15677          }
15678  
15679          // Strip BOM:
15680          // UTF-32 Big Endian BOM
15681          if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
15682          {
15683              $data = substr($data, 4);
15684          }
15685          // UTF-32 Little Endian BOM
15686          elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
15687          {
15688              $data = substr($data, 4);
15689          }
15690          // UTF-16 Big Endian BOM
15691          elseif (substr($data, 0, 2) === "\xFE\xFF")
15692          {
15693              $data = substr($data, 2);
15694          }
15695          // UTF-16 Little Endian BOM
15696          elseif (substr($data, 0, 2) === "\xFF\xFE")
15697          {
15698              $data = substr($data, 2);
15699          }
15700          // UTF-8 BOM
15701          elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
15702          {
15703              $data = substr($data, 3);
15704          }
15705  
15706          if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
15707          {
15708              $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
15709              if ($declaration->parse())
15710              {
15711                  $data = substr($data, $pos + 2);
15712                  $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
15713              }
15714              else
15715              {
15716                  $this->error_string = 'SimplePie bug! Please report this!';
15717                  return false;
15718              }
15719          }
15720  
15721          $return = true;
15722  
15723          static $xml_is_sane = null;
15724          if ($xml_is_sane === null)
15725          {
15726              $parser_check = xml_parser_create();
15727              xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
15728              xml_parser_free($parser_check);
15729              $xml_is_sane = isset($values[0]['value']);
15730          }
15731  
15732          // Create the parser
15733          if ($xml_is_sane)
15734          {
15735              $xml = xml_parser_create_ns($this->encoding, $this->separator);
15736              xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
15737              xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
15738              xml_set_object($xml, $this);
15739              xml_set_character_data_handler($xml, 'cdata');
15740              xml_set_element_handler($xml, 'tag_open', 'tag_close');
15741  
15742              // Parse!
15743              if (!xml_parse($xml, $data, true))
15744              {
15745                  $this->error_code = xml_get_error_code($xml);
15746                  $this->error_string = xml_error_string($this->error_code);
15747                  $return = false;
15748              }
15749              $this->current_line = xml_get_current_line_number($xml);
15750              $this->current_column = xml_get_current_column_number($xml);
15751              $this->current_byte = xml_get_current_byte_index($xml);
15752              xml_parser_free($xml);
15753              return $return;
15754          }
15755          else
15756          {
15757              libxml_clear_errors();
15758              $xml = new XMLReader();
15759              $xml->xml($data);
15760              while (@$xml->read())
15761              {
15762                  switch ($xml->nodeType)
15763                  {
15764  
15765                      case constant('XMLReader::END_ELEMENT'):
15766                          if ($xml->namespaceURI !== '')
15767                          {
15768                              $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15769                          }
15770                          else
15771                          {
15772                              $tagName = $xml->localName;
15773                          }
15774                          $this->tag_close(null, $tagName);
15775                          break;
15776                      case constant('XMLReader::ELEMENT'):
15777                          $empty = $xml->isEmptyElement;
15778                          if ($xml->namespaceURI !== '')
15779                          {
15780                              $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
15781                          }
15782                          else
15783                          {
15784                              $tagName = $xml->localName;
15785                          }
15786                          $attributes = array();
15787                          while ($xml->moveToNextAttribute())
15788                          {
15789                              if ($xml->namespaceURI !== '')
15790                              {
15791                                  $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
15792                              }
15793                              else
15794                              {
15795                                  $attrName = $xml->localName;
15796                              }
15797                              $attributes[$attrName] = $xml->value;
15798                          }
15799                          $this->tag_open(null, $tagName, $attributes);
15800                          if ($empty)
15801                          {
15802                              $this->tag_close(null, $tagName);
15803                          }
15804                          break;
15805                      case constant('XMLReader::TEXT'):
15806  
15807                      case constant('XMLReader::CDATA'):
15808                          $this->cdata(null, $xml->value);
15809                          break;
15810                  }
15811              }
15812              if ($error = libxml_get_last_error())
15813              {
15814                  $this->error_code = $error->code;
15815                  $this->error_string = $error->message;
15816                  $this->current_line = $error->line;
15817                  $this->current_column = $error->column;
15818                  return false;
15819              }
15820              else
15821              {
15822                  return true;
15823              }
15824          }
15825      }
15826  
15827  	public function get_error_code()
15828      {
15829          return $this->error_code;
15830      }
15831  
15832  	public function get_error_string()
15833      {
15834          return $this->error_string;
15835      }
15836  
15837  	public function get_current_line()
15838      {
15839          return $this->current_line;
15840      }
15841  
15842  	public function get_current_column()
15843      {
15844          return $this->current_column;
15845      }
15846  
15847  	public function get_current_byte()
15848      {
15849          return $this->current_byte;
15850      }
15851  
15852  	public function get_data()
15853      {
15854          return $this->data;
15855      }
15856  
15857  	public function tag_open($parser, $tag, $attributes)
15858      {
15859          list($this->namespace[], $this->element[]) = $this->split_ns($tag);
15860  
15861          $attribs = array();
15862          foreach ($attributes as $name => $value)
15863          {
15864              list($attrib_namespace, $attribute) = $this->split_ns($name);
15865              $attribs[$attrib_namespace][$attribute] = $value;
15866          }
15867  
15868          if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
15869          {
15870              $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
15871              if ($base !== false)
15872              {
15873                  $this->xml_base[] = $base;
15874                  $this->xml_base_explicit[] = true;
15875              }
15876          }
15877          else
15878          {
15879              $this->xml_base[] = end($this->xml_base);
15880              $this->xml_base_explicit[] = end($this->xml_base_explicit);
15881          }
15882  
15883          if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
15884          {
15885              $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
15886          }
15887          else
15888          {
15889              $this->xml_lang[] = end($this->xml_lang);
15890          }
15891  
15892          if ($this->current_xhtml_construct >= 0)
15893          {
15894              $this->current_xhtml_construct++;
15895              if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
15896              {
15897                  $this->data['data'] .= '<' . end($this->element);
15898                  if (isset($attribs['']))
15899                  {
15900                      foreach ($attribs[''] as $name => $value)
15901                      {
15902                          $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
15903                      }
15904                  }
15905                  $this->data['data'] .= '>';
15906              }
15907          }
15908          else
15909          {
15910              $this->datas[] =& $this->data;
15911              $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
15912              $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
15913              if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
15914              || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')
15915              || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
15916              || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
15917              || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
15918              {
15919                  $this->current_xhtml_construct = 0;
15920              }
15921          }
15922      }
15923  
15924  	public function cdata($parser, $cdata)
15925      {
15926          if ($this->current_xhtml_construct >= 0)
15927          {
15928              $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
15929          }
15930          else
15931          {
15932              $this->data['data'] .= $cdata;
15933          }
15934      }
15935  
15936  	public function tag_close($parser, $tag)
15937      {
15938          if ($this->current_xhtml_construct >= 0)
15939          {
15940              $this->current_xhtml_construct--;
15941              if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
15942              {
15943                  $this->data['data'] .= '</' . end($this->element) . '>';
15944              }
15945          }
15946          if ($this->current_xhtml_construct === -1)
15947          {
15948              $this->data =& $this->datas[count($this->datas) - 1];
15949              array_pop($this->datas);
15950          }
15951  
15952          array_pop($this->element);
15953          array_pop($this->namespace);
15954          array_pop($this->xml_base);
15955          array_pop($this->xml_base_explicit);
15956          array_pop($this->xml_lang);
15957      }
15958  
15959  	public function split_ns($string)
15960      {
15961          static $cache = array();
15962          if (!isset($cache[$string]))
15963          {
15964              if ($pos = strpos($string, $this->separator))
15965              {
15966                  static $separator_length;
15967                  if (!$separator_length)
15968                  {
15969                      $separator_length = strlen($this->separator);
15970                  }
15971                  $namespace = substr($string, 0, $pos);
15972                  $local_name = substr($string, $pos + $separator_length);
15973                  if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
15974                  {
15975                      $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
15976                  }
15977  
15978                  // Normalize the Media RSS namespaces
15979                  if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
15980                      $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
15981                      $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
15982                      $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
15983                      $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
15984                  {
15985                      $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
15986                  }
15987                  $cache[$string] = array($namespace, $local_name);
15988              }
15989              else
15990              {
15991                  $cache[$string] = array('', $string);
15992              }
15993          }
15994          return $cache[$string];
15995      }
15996  }
15997  
15998  /**
15999   * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
16000   *
16001   * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
16002   *
16003   * This class can be overloaded with {@see SimplePie::set_rating_class()}
16004   *
16005   * @package SimplePie
16006   * @subpackage API
16007   */
16008  class SimplePie_Rating
16009  {
16010      /**
16011       * Rating scheme
16012       *
16013       * @var string
16014       * @see get_scheme()
16015       */
16016      var $scheme;
16017  
16018      /**
16019       * Rating value
16020       *
16021       * @var string
16022       * @see get_value()
16023       */
16024      var $value;
16025  
16026      /**
16027       * Constructor, used to input the data
16028       *
16029       * For documentation on all the parameters, see the corresponding
16030       * properties and their accessors
16031       */
16032  	public function __construct($scheme = null, $value = null)
16033      {
16034          $this->scheme = $scheme;
16035          $this->value = $value;
16036      }
16037  
16038      /**
16039       * String-ified version
16040       *
16041       * @return string
16042       */
16043  	public function __toString()
16044      {
16045          // There is no $this->data here
16046          return md5(serialize($this));
16047      }
16048  
16049      /**
16050       * Get the organizational scheme for the rating
16051       *
16052       * @return string|null
16053       */
16054  	public function get_scheme()
16055      {
16056          if ($this->scheme !== null)
16057          {
16058              return $this->scheme;
16059          }
16060          else
16061          {
16062              return null;
16063          }
16064      }
16065  
16066      /**
16067       * Get the value of the rating
16068       *
16069       * @return string|null
16070       */
16071  	public function get_value()
16072      {
16073          if ($this->value !== null)
16074          {
16075              return $this->value;
16076          }
16077          else
16078          {
16079              return null;
16080          }
16081      }
16082  }
16083  
16084  /**
16085   * Handles creating objects and calling methods
16086   *
16087   * Access this via {@see SimplePie::get_registry()}
16088   *
16089   * @package SimplePie
16090   */
16091  class SimplePie_Registry
16092  {
16093      /**
16094       * Default class mapping
16095       *
16096       * Overriding classes *must* subclass these.
16097       *
16098       * @var array
16099       */
16100      protected $default = array(
16101          'Cache' => 'SimplePie_Cache',
16102          'Locator' => 'SimplePie_Locator',
16103          'Parser' => 'SimplePie_Parser',
16104          'File' => 'SimplePie_File',
16105          'Sanitize' => 'SimplePie_Sanitize',
16106          'Item' => 'SimplePie_Item',
16107          'Author' => 'SimplePie_Author',
16108          'Category' => 'SimplePie_Category',
16109          'Enclosure' => 'SimplePie_Enclosure',
16110          'Caption' => 'SimplePie_Caption',
16111          'Copyright' => 'SimplePie_Copyright',
16112          'Credit' => 'SimplePie_Credit',
16113          'Rating' => 'SimplePie_Rating',
16114          'Restriction' => 'SimplePie_Restriction',
16115          'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
16116          'Source' => 'SimplePie_Source',
16117          'Misc' => 'SimplePie_Misc',
16118          'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
16119          'Parse_Date' => 'SimplePie_Parse_Date',
16120      );
16121  
16122      /**
16123       * Class mapping
16124       *
16125       * @see register()
16126       * @var array
16127       */
16128      protected $classes = array();
16129  
16130      /**
16131       * Legacy classes
16132       *
16133       * @see register()
16134       * @var array
16135       */
16136      protected $legacy = array();
16137  
16138      /**
16139       * Constructor
16140       *
16141       * No-op
16142       */
16143  	public function __construct() { }
16144  
16145      /**
16146       * Register a class
16147       *
16148       * @param string $type See {@see $default} for names
16149       * @param string $class Class name, must subclass the corresponding default
16150       * @param bool $legacy Whether to enable legacy support for this class
16151       * @return bool Successfulness
16152       */
16153  	public function register($type, $class, $legacy = false)
16154      {
16155          if (!is_subclass_of($class, $this->default[$type]))
16156          {
16157              return false;
16158          }
16159  
16160          $this->classes[$type] = $class;
16161  
16162          if ($legacy)
16163          {
16164              $this->legacy[] = $class;
16165          }
16166  
16167          return true;
16168      }
16169  
16170      /**
16171       * Get the class registered for a type
16172       *
16173       * Where possible, use {@see create()} or {@see call()} instead
16174       *
16175       * @param string $type
16176       * @return string|null
16177       */
16178  	public function get_class($type)
16179      {
16180          if (!empty($this->classes[$type]))
16181          {
16182              return $this->classes[$type];
16183          }
16184          if (!empty($this->default[$type]))
16185          {
16186              return $this->default[$type];
16187          }
16188  
16189          return null;
16190      }
16191  
16192      /**
16193       * Create a new instance of a given type
16194       *
16195       * @param string $type
16196       * @param array $parameters Parameters to pass to the constructor
16197       * @return object Instance of class
16198       */
16199      public function &create($type, $parameters = array())
16200      {
16201          $class = $this->get_class($type);
16202  
16203          if (in_array($class, $this->legacy))
16204          {
16205              switch ($type)
16206              {
16207                  case 'locator':
16208                      // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
16209                      // Specified: file, timeout, useragent, max_checked_feeds
16210                      $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
16211                      array_splice($parameters, 3, 1, $replacement);
16212                      break;
16213              }
16214          }
16215  
16216          if (!method_exists($class, '__construct'))
16217          {
16218              $instance = new $class;
16219          }
16220          else
16221          {
16222              $reflector = new ReflectionClass($class);
16223              $instance = $reflector->newInstanceArgs($parameters);
16224          }
16225  
16226          if (method_exists($instance, 'set_registry'))
16227          {
16228              $instance->set_registry($this);
16229          }
16230          return $instance;
16231      }
16232  
16233      /**
16234       * Call a static method for a type
16235       *
16236       * @param string $type
16237       * @param string $method
16238       * @param array $parameters
16239       * @return mixed
16240       */
16241      public function &call($type, $method, $parameters = array())
16242      {
16243          $class = $this->get_class($type);
16244  
16245          if (in_array($class, $this->legacy))
16246          {
16247              switch ($type)
16248              {
16249                  case 'Cache':
16250                      // For backwards compatibility with old non-static
16251                      // Cache::create() methods
16252                      if ($method === 'get_handler')
16253                      {
16254                          $result = @call_user_func_array(array($class, 'create'), $parameters);
16255                          return $result;
16256                      }
16257                      break;
16258              }
16259          }
16260  
16261          $result = call_user_func_array(array($class, $method), $parameters);
16262          return $result;
16263      }
16264  }
16265  
16266  /**
16267   * Handles `<media:restriction>` as defined in Media RSS
16268   *
16269   * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
16270   *
16271   * This class can be overloaded with {@see SimplePie::set_restriction_class()}
16272   *
16273   * @package SimplePie
16274   * @subpackage API
16275   */
16276  class SimplePie_Restriction
16277  {
16278      /**
16279       * Relationship ('allow'/'deny')
16280       *
16281       * @var string
16282       * @see get_relationship()
16283       */
16284      var $relationship;
16285  
16286      /**
16287       * Type of restriction
16288       *
16289       * @var string
16290       * @see get_type()
16291       */
16292      var $type;
16293  
16294      /**
16295       * Restricted values
16296       *
16297       * @var string
16298       * @see get_value()
16299       */
16300      var $value;
16301  
16302      /**
16303       * Constructor, used to input the data
16304       *
16305       * For documentation on all the parameters, see the corresponding
16306       * properties and their accessors
16307       */
16308  	public function __construct($relationship = null, $type = null, $value = null)
16309      {
16310          $this->relationship = $relationship;
16311          $this->type = $type;
16312          $this->value = $value;
16313      }
16314  
16315      /**
16316       * String-ified version
16317       *
16318       * @return string
16319       */
16320  	public function __toString()
16321      {
16322          // There is no $this->data here
16323          return md5(serialize($this));
16324      }
16325  
16326      /**
16327       * Get the relationship
16328       *
16329       * @return string|null Either 'allow' or 'deny'
16330       */
16331  	public function get_relationship()
16332      {
16333          if ($this->relationship !== null)
16334          {
16335              return $this->relationship;
16336          }
16337          else
16338          {
16339              return null;
16340          }
16341      }
16342  
16343      /**
16344       * Get the type
16345       *
16346       * @return string|null
16347       */
16348  	public function get_type()
16349      {
16350          if ($this->type !== null)
16351          {
16352              return $this->type;
16353          }
16354          else
16355          {
16356              return null;
16357          }
16358      }
16359  
16360      /**
16361       * Get the list of restricted things
16362       *
16363       * @return string|null
16364       */
16365  	public function get_value()
16366      {
16367          if ($this->value !== null)
16368          {
16369              return $this->value;
16370          }
16371          else
16372          {
16373              return null;
16374          }
16375      }
16376  }
16377  
16378  /**
16379   * Used for data cleanup and post-processing
16380   *
16381   *
16382   * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
16383   *
16384   * @package SimplePie
16385   * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
16386   */
16387  class SimplePie_Sanitize
16388  {
16389      // Private vars
16390      var $base;
16391  
16392      // Options
16393      var $remove_div = true;
16394      var $image_handler = '';
16395      var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
16396      var $encode_instead_of_strip = false;
16397      var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
16398      var $strip_comments = false;
16399      var $output_encoding = 'UTF-8';
16400      var $enable_cache = true;
16401      var $cache_location = './cache';
16402      var $cache_name_function = 'md5';
16403      var $timeout = 10;
16404      var $useragent = '';
16405      var $force_fsockopen = false;
16406      var $replace_url_attributes = null;
16407  
16408  	public function __construct()
16409      {
16410          // Set defaults
16411          $this->set_url_replacements(null);
16412      }
16413  
16414  	public function remove_div($enable = true)
16415      {
16416          $this->remove_div = (bool) $enable;
16417      }
16418  
16419  	public function set_image_handler($page = false)
16420      {
16421          if ($page)
16422          {
16423              $this->image_handler = (string) $page;
16424          }
16425          else
16426          {
16427              $this->image_handler = false;
16428          }
16429      }
16430  
16431  	public function set_registry(SimplePie_Registry $registry)
16432      {
16433          $this->registry = $registry;
16434      }
16435  
16436  	public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
16437      {
16438          if (isset($enable_cache))
16439          {
16440              $this->enable_cache = (bool) $enable_cache;
16441          }
16442  
16443          if ($cache_location)
16444          {
16445              $this->cache_location = (string) $cache_location;
16446          }
16447  
16448          if ($cache_name_function)
16449          {
16450              $this->cache_name_function = (string) $cache_name_function;
16451          }
16452      }
16453  
16454  	public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
16455      {
16456          if ($timeout)
16457          {
16458              $this->timeout = (string) $timeout;
16459          }
16460  
16461          if ($useragent)
16462          {
16463              $this->useragent = (string) $useragent;
16464          }
16465  
16466          if ($force_fsockopen)
16467          {
16468              $this->force_fsockopen = (string) $force_fsockopen;
16469          }
16470      }
16471  
16472  	public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
16473      {
16474          if ($tags)
16475          {
16476              if (is_array($tags))
16477              {
16478                  $this->strip_htmltags = $tags;
16479              }
16480              else
16481              {
16482                  $this->strip_htmltags = explode(',', $tags);
16483              }
16484          }
16485          else
16486          {
16487              $this->strip_htmltags = false;
16488          }
16489      }
16490  
16491  	public function encode_instead_of_strip($encode = false)
16492      {
16493          $this->encode_instead_of_strip = (bool) $encode;
16494      }
16495  
16496  	public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
16497      {
16498          if ($attribs)
16499          {
16500              if (is_array($attribs))
16501              {
16502                  $this->strip_attributes = $attribs;
16503              }
16504              else
16505              {
16506                  $this->strip_attributes = explode(',', $attribs);
16507              }
16508          }
16509          else
16510          {
16511              $this->strip_attributes = false;
16512          }
16513      }
16514  
16515  	public function strip_comments($strip = false)
16516      {
16517          $this->strip_comments = (bool) $strip;
16518      }
16519  
16520  	public function set_output_encoding($encoding = 'UTF-8')
16521      {
16522          $this->output_encoding = (string) $encoding;
16523      }
16524  
16525      /**
16526       * Set element/attribute key/value pairs of HTML attributes
16527       * containing URLs that need to be resolved relative to the feed
16528       *
16529       * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
16530       * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
16531       * |q|@cite
16532       *
16533       * @since 1.0
16534       * @param array|null $element_attribute Element/attribute key/value pairs, null for default
16535       */
16536  	public function set_url_replacements($element_attribute = null)
16537      {
16538          if ($element_attribute === null)
16539          {
16540              $element_attribute = array(
16541                  'a' => 'href',
16542                  'area' => 'href',
16543                  'blockquote' => 'cite',
16544                  'del' => 'cite',
16545                  'form' => 'action',
16546                  'img' => array(
16547                      'longdesc',
16548                      'src'
16549                  ),
16550                  'input' => 'src',
16551                  'ins' => 'cite',
16552                  'q' => 'cite'
16553              );
16554          }
16555          $this->replace_url_attributes = (array) $element_attribute;
16556      }
16557  
16558  	public function sanitize($data, $type, $base = '')
16559      {
16560          $data = trim($data);
16561          if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
16562          {
16563              if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
16564              {
16565                  if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
16566                  {
16567                      $type |= SIMPLEPIE_CONSTRUCT_HTML;
16568                  }
16569                  else
16570                  {
16571                      $type |= SIMPLEPIE_CONSTRUCT_TEXT;
16572                  }
16573              }
16574  
16575              if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
16576              {
16577                  $data = base64_decode($data);
16578              }
16579  
16580              if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
16581              {
16582                  if (!class_exists('DOMDocument'))
16583                  {
16584                      $this->registry->call('Misc', 'error', array('DOMDocument not found, unable to use sanitizer', E_USER_WARNING, __FILE__, __LINE__));
16585                      return '';
16586                  }
16587                  $document = new DOMDocument();
16588                  $document->encoding = 'UTF-8';
16589                  $data = $this->preprocess($data, $type);
16590  
16591                  set_error_handler(array('SimplePie_Misc', 'silence_errors'));
16592                  $document->loadHTML($data);
16593                  restore_error_handler();
16594  
16595                  // Strip comments
16596                  if ($this->strip_comments)
16597                  {
16598                      $xpath = new DOMXPath($document);
16599                      $comments = $xpath->query('//comment()');
16600  
16601                      foreach ($comments as $comment)
16602                      {
16603                          $comment->parentNode->removeChild($comment);
16604                      }
16605                  }
16606  
16607                  // Strip out HTML tags and attributes that might cause various security problems.
16608                  // Based on recommendations by Mark Pilgrim at:
16609                  // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
16610                  if ($this->strip_htmltags)
16611                  {
16612                      foreach ($this->strip_htmltags as $tag)
16613                      {
16614                          $this->strip_tag($tag, $document, $type);
16615                      }
16616                  }
16617  
16618                  if ($this->strip_attributes)
16619                  {
16620                      foreach ($this->strip_attributes as $attrib)
16621                      {
16622                          $this->strip_attr($attrib, $document);
16623                      }
16624                  }
16625  
16626                  // Replace relative URLs
16627                  $this->base = $base;
16628                  foreach ($this->replace_url_attributes as $element => $attributes)
16629                  {
16630                      $this->replace_urls($document, $element, $attributes);
16631                  }
16632  
16633                  // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
16634                  if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
16635                  {
16636                      $images = $document->getElementsByTagName('img');
16637                      foreach ($images as $img)
16638                      {
16639                          if ($img->hasAttribute('src'))
16640                          {
16641                              $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
16642                              $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
16643  
16644                              if ($cache->load())
16645                              {
16646                                  $img->setAttribute('src', $this->image_handler . $image_url);
16647                              }
16648                              else
16649                              {
16650                                  $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
16651                                  $headers = $file->headers;
16652  
16653                                  if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
16654                                  {
16655                                      if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
16656                                      {
16657                                          $img->setAttribute('src', $this->image_handler . $image_url);
16658                                      }
16659                                      else
16660                                      {
16661                                          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);
16662                                      }
16663                                  }
16664                              }
16665                          }
16666                      }
16667                  }
16668  
16669                  // Remove the DOCTYPE
16670                  // Seems to cause segfaulting if we don't do this
16671                  if ($document->firstChild instanceof DOMDocumentType)
16672                  {
16673                      $document->removeChild($document->firstChild);
16674                  }
16675  
16676                  // Move everything from the body to the root
16677                  $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
16678                  $document->replaceChild($real_body, $document->firstChild);
16679  
16680                  // Finally, convert to a HTML string
16681                  $data = trim($document->saveHTML());
16682  
16683                  if ($this->remove_div)
16684                  {
16685                      $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
16686                      $data = preg_replace('/<\/div>$/', '', $data);
16687                  }
16688                  else
16689                  {
16690                      $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
16691                  }
16692              }
16693  
16694              if ($type & SIMPLEPIE_CONSTRUCT_IRI)
16695              {
16696                  $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
16697                  if ($absolute !== false)
16698                  {
16699                      $data = $absolute;
16700                  }
16701              }
16702  
16703              if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
16704              {
16705                  $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
16706              }
16707  
16708              if ($this->output_encoding !== 'UTF-8')
16709              {
16710                  $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
16711              }
16712          }
16713          return $data;
16714      }
16715  
16716  	protected function preprocess($html, $type)
16717      {
16718          $ret = '';
16719          if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
16720          {
16721              // Atom XHTML constructs are wrapped with a div by default
16722              // Note: No protection if $html contains a stray </div>!
16723              $html = '<div>' . $html . '</div>';
16724              $ret .= '<!DOCTYPE html>';
16725              $content_type = 'text/html';
16726          }
16727          else
16728          {
16729              $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
16730              $content_type = 'application/xhtml+xml';
16731          }
16732  
16733          $ret .= '<html><head>';
16734          $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
16735          $ret .= '</head><body>' . $html . '</body></html>';
16736          return $ret;
16737      }
16738  
16739  	public function replace_urls($document, $tag, $attributes)
16740      {
16741          if (!is_array($attributes))
16742          {
16743              $attributes = array($attributes);
16744          }
16745  
16746          if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
16747          {
16748              $elements = $document->getElementsByTagName($tag);
16749              foreach ($elements as $element)
16750              {
16751                  foreach ($attributes as $attribute)
16752                  {
16753                      if ($element->hasAttribute($attribute))
16754                      {
16755                          $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
16756                          if ($value !== false)
16757                          {
16758                              $element->setAttribute($attribute, $value);
16759                          }
16760                      }
16761                  }
16762              }
16763          }
16764      }
16765  
16766  	public function do_strip_htmltags($match)
16767      {
16768          if ($this->encode_instead_of_strip)
16769          {
16770              if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
16771              {
16772                  $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
16773                  $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
16774                  return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
16775              }
16776              else
16777              {
16778                  return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
16779              }
16780          }
16781          elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
16782          {
16783              return $match[4];
16784          }
16785          else
16786          {
16787              return '';
16788          }
16789      }
16790  
16791  	protected function strip_tag($tag, $document, $type)
16792      {
16793          $xpath = new DOMXPath($document);
16794          $elements = $xpath->query('body//' . $tag);
16795          if ($this->encode_instead_of_strip)
16796          {
16797              foreach ($elements as $element)
16798              {
16799                  $fragment = $document->createDocumentFragment();
16800  
16801                  // For elements which aren't script or style, include the tag itself
16802                  if (!in_array($tag, array('script', 'style')))
16803                  {
16804                      $text = '<' . $tag;
16805                      if ($element->hasAttributes())
16806                      {
16807                          $attrs = array();
16808                          foreach ($element->attributes as $name => $attr)
16809                          {
16810                              $value = $attr->value;
16811  
16812                              // In XHTML, empty values should never exist, so we repeat the value
16813                              if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
16814                              {
16815                                  $value = $name;
16816                              }
16817                              // For HTML, empty is fine
16818                              elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
16819                              {
16820                                  $attrs[] = $name;
16821                                  continue;
16822                              }
16823  
16824                              // Standard attribute text
16825                              $attrs[] = $name . '="' . $attr->value . '"';
16826                          }
16827                          $text .= ' ' . implode(' ', $attrs);
16828                      }
16829                      $text .= '>';
16830                      $fragment->appendChild(new DOMText($text));
16831                  }
16832  
16833                  $number = $element->childNodes->length;
16834                  for ($i = $number; $i > 0; $i--)
16835                  {
16836                      $child = $element->childNodes->item(0);
16837                      $fragment->appendChild($child);
16838                  }
16839  
16840                  if (!in_array($tag, array('script', 'style')))
16841                  {
16842                      $fragment->appendChild(new DOMText('</' . $tag . '>'));
16843                  }
16844  
16845                  $element->parentNode->replaceChild($fragment, $element);
16846              }
16847  
16848              return;
16849          }
16850          elseif (in_array($tag, array('script', 'style')))
16851          {
16852              foreach ($elements as $element)
16853              {
16854                  $element->parentNode->removeChild($element);
16855              }
16856  
16857              return;
16858          }
16859          else
16860          {
16861              foreach ($elements as $element)
16862              {
16863                  $fragment = $document->createDocumentFragment();
16864                  $number = $element->childNodes->length;
16865                  for ($i = $number; $i > 0; $i--)
16866                  {
16867                      $child = $element->childNodes->item(0);
16868                      $fragment->appendChild($child);
16869                  }
16870  
16871                  $element->parentNode->replaceChild($fragment, $element);
16872              }
16873          }
16874      }
16875  
16876  	protected function strip_attr($attrib, $document)
16877      {
16878          $xpath = new DOMXPath($document);
16879          $elements = $xpath->query('//*[@' . $attrib . ']');
16880  
16881          foreach ($elements as $element)
16882          {
16883              $element->removeAttribute($attrib);
16884          }
16885      }
16886  }
16887  
16888  /**
16889   * Handles `<atom:source>`
16890   *
16891   * Used by {@see SimplePie_Item::get_source()}
16892   *
16893   * This class can be overloaded with {@see SimplePie::set_source_class()}
16894   *
16895   * @package SimplePie
16896   * @subpackage API
16897   */
16898  class SimplePie_Source
16899  {
16900      var $item;
16901      var $data = array();
16902      protected $registry;
16903  
16904  	public function __construct($item, $data)
16905      {
16906          $this->item = $item;
16907          $this->data = $data;
16908      }
16909  
16910  	public function set_registry(SimplePie_Registry $registry)
16911      {
16912          $this->registry = $registry;
16913      }
16914  
16915  	public function __toString()
16916      {
16917          return md5(serialize($this->data));
16918      }
16919  
16920  	public function get_source_tags($namespace, $tag)
16921      {
16922          if (isset($this->data['child'][$namespace][$tag]))
16923          {
16924              return $this->data['child'][$namespace][$tag];
16925          }
16926          else
16927          {
16928              return null;
16929          }
16930      }
16931  
16932  	public function get_base($element = array())
16933      {
16934          return $this->item->get_base($element);
16935      }
16936  
16937  	public function sanitize($data, $type, $base = '')
16938      {
16939          return $this->item->sanitize($data, $type, $base);
16940      }
16941  
16942  	public function get_item()
16943      {
16944          return $this->item;
16945      }
16946  
16947  	public function get_title()
16948      {
16949          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
16950          {
16951              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16952          }
16953          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
16954          {
16955              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
16956          }
16957          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
16958          {
16959              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16960          }
16961          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
16962          {
16963              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16964          }
16965          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
16966          {
16967              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
16968          }
16969          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
16970          {
16971              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16972          }
16973          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
16974          {
16975              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
16976          }
16977          else
16978          {
16979              return null;
16980          }
16981      }
16982  
16983  	public function get_category($key = 0)
16984      {
16985          $categories = $this->get_categories();
16986          if (isset($categories[$key]))
16987          {
16988              return $categories[$key];
16989          }
16990          else
16991          {
16992              return null;
16993          }
16994      }
16995  
16996  	public function get_categories()
16997      {
16998          $categories = array();
16999  
17000          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
17001          {
17002              $term = null;
17003              $scheme = null;
17004              $label = null;
17005              if (isset($category['attribs']['']['term']))
17006              {
17007                  $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
17008              }
17009              if (isset($category['attribs']['']['scheme']))
17010              {
17011                  $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
17012              }
17013              if (isset($category['attribs']['']['label']))
17014              {
17015                  $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
17016              }
17017              $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
17018          }
17019          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
17020          {
17021              // This is really the label, but keep this as the term also for BC.
17022              // Label will also work on retrieving because that falls back to term.
17023              $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17024              if (isset($category['attribs']['']['domain']))
17025              {
17026                  $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
17027              }
17028              else
17029              {
17030                  $scheme = null;
17031              }
17032              $categories[] = $this->registry->create('Category', array($term, $scheme, null));
17033          }
17034          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
17035          {
17036              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17037          }
17038          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
17039          {
17040              $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17041          }
17042  
17043          if (!empty($categories))
17044          {
17045              return array_unique($categories);
17046          }
17047          else
17048          {
17049              return null;
17050          }
17051      }
17052  
17053  	public function get_author($key = 0)
17054      {
17055          $authors = $this->get_authors();
17056          if (isset($authors[$key]))
17057          {
17058              return $authors[$key];
17059          }
17060          else
17061          {
17062              return null;
17063          }
17064      }
17065  
17066  	public function get_authors()
17067      {
17068          $authors = array();
17069          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
17070          {
17071              $name = null;
17072              $uri = null;
17073              $email = null;
17074              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
17075              {
17076                  $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17077              }
17078              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
17079              {
17080                  $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]));
17081              }
17082              if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17083              {
17084                  $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17085              }
17086              if ($name !== null || $email !== null || $uri !== null)
17087              {
17088                  $authors[] = $this->registry->create('Author', array($name, $uri, $email));
17089              }
17090          }
17091          if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
17092          {
17093              $name = null;
17094              $url = null;
17095              $email = null;
17096              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17097              {
17098                  $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17099              }
17100              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
17101              {
17102                  $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]));
17103              }
17104              if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17105              {
17106                  $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17107              }
17108              if ($name !== null || $email !== null || $url !== null)
17109              {
17110                  $authors[] = $this->registry->create('Author', array($name, $url, $email));
17111              }
17112          }
17113          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
17114          {
17115              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17116          }
17117          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
17118          {
17119              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17120          }
17121          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
17122          {
17123              $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
17124          }
17125  
17126          if (!empty($authors))
17127          {
17128              return array_unique($authors);
17129          }
17130          else
17131          {
17132              return null;
17133          }
17134      }
17135  
17136  	public function get_contributor($key = 0)
17137      {
17138          $contributors = $this->get_contributors();
17139          if (isset($contributors[$key]))
17140          {
17141              return $contributors[$key];
17142          }
17143          else
17144          {
17145              return null;
17146          }
17147      }
17148  
17149  	public function get_contributors()
17150      {
17151          $contributors = array();
17152          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
17153          {
17154              $name = null;
17155              $uri = null;
17156              $email = null;
17157              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
17158              {
17159                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17160              }
17161              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
17162              {
17163                  $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]));
17164              }
17165              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
17166              {
17167                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17168              }
17169              if ($name !== null || $email !== null || $uri !== null)
17170              {
17171                  $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
17172              }
17173          }
17174          foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
17175          {
17176              $name = null;
17177              $url = null;
17178              $email = null;
17179              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
17180              {
17181                  $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17182              }
17183              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
17184              {
17185                  $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]));
17186              }
17187              if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
17188              {
17189                  $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17190              }
17191              if ($name !== null || $email !== null || $url !== null)
17192              {
17193                  $contributors[] = $this->registry->create('Author', array($name, $url, $email));
17194              }
17195          }
17196  
17197          if (!empty($contributors))
17198          {
17199              return array_unique($contributors);
17200          }
17201          else
17202          {
17203              return null;
17204          }
17205      }
17206  
17207  	public function get_link($key = 0, $rel = 'alternate')
17208      {
17209          $links = $this->get_links($rel);
17210          if (isset($links[$key]))
17211          {
17212              return $links[$key];
17213          }
17214          else
17215          {
17216              return null;
17217          }
17218      }
17219  
17220      /**
17221       * Added for parity between the parent-level and the item/entry-level.
17222       */
17223  	public function get_permalink()
17224      {
17225          return $this->get_link(0);
17226      }
17227  
17228  	public function get_links($rel = 'alternate')
17229      {
17230          if (!isset($this->data['links']))
17231          {
17232              $this->data['links'] = array();
17233              if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
17234              {
17235                  foreach ($links as $link)
17236                  {
17237                      if (isset($link['attribs']['']['href']))
17238                      {
17239                          $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
17240                          $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
17241                      }
17242                  }
17243              }
17244              if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
17245              {
17246                  foreach ($links as $link)
17247                  {
17248                      if (isset($link['attribs']['']['href']))
17249                      {
17250                          $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
17251                          $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
17252  
17253                      }
17254                  }
17255              }
17256              if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
17257              {
17258                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17259              }
17260              if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
17261              {
17262                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17263              }
17264              if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
17265              {
17266                  $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
17267              }
17268  
17269              $keys = array_keys($this->data['links']);
17270              foreach ($keys as $key)
17271              {
17272                  if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
17273                  {
17274                      if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
17275                      {
17276                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
17277                          $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
17278                      }
17279                      else
17280                      {
17281                          $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
17282                      }
17283                  }
17284                  elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
17285                  {
17286                      $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
17287                  }
17288                  $this->data['links'][$key] = array_unique($this->data['links'][$key]);
17289              }
17290          }
17291  
17292          if (isset($this->data['links'][$rel]))
17293          {
17294              return $this->data['links'][$rel];
17295          }
17296          else
17297          {
17298              return null;
17299          }
17300      }
17301  
17302  	public function get_description()
17303      {
17304          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
17305          {
17306              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17307          }
17308          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
17309          {
17310              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17311          }
17312          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
17313          {
17314              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17315          }
17316          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
17317          {
17318              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17319          }
17320          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
17321          {
17322              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
17323          }
17324          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
17325          {
17326              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17327          }
17328          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
17329          {
17330              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17331          }
17332          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
17333          {
17334              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17335          }
17336          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
17337          {
17338              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
17339          }
17340          else
17341          {
17342              return null;
17343          }
17344      }
17345  
17346  	public function get_copyright()
17347      {
17348          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
17349          {
17350              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17351          }
17352          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
17353          {
17354              return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
17355          }
17356          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
17357          {
17358              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17359          }
17360          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
17361          {
17362              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17363          }
17364          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
17365          {
17366              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17367          }
17368          else
17369          {
17370              return null;
17371          }
17372      }
17373  
17374  	public function get_language()
17375      {
17376          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
17377          {
17378              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17379          }
17380          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
17381          {
17382              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17383          }
17384          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
17385          {
17386              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
17387          }
17388          elseif (isset($this->data['xml_lang']))
17389          {
17390              return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
17391          }
17392          else
17393          {
17394              return null;
17395          }
17396      }
17397  
17398  	public function get_latitude()
17399      {
17400          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
17401          {
17402              return (float) $return[0]['data'];
17403          }
17404          elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
17405          {
17406              return (float) $match[1];
17407          }
17408          else
17409          {
17410              return null;
17411          }
17412      }
17413  
17414  	public function get_longitude()
17415      {
17416          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
17417          {
17418              return (float) $return[0]['data'];
17419          }
17420          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
17421          {
17422              return (float) $return[0]['data'];
17423          }
17424          elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
17425          {
17426              return (float) $match[2];
17427          }
17428          else
17429          {
17430              return null;
17431          }
17432      }
17433  
17434  	public function get_image_url()
17435      {
17436          if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
17437          {
17438              return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
17439          }
17440          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
17441          {
17442              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17443          }
17444          elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
17445          {
17446              return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
17447          }
17448          else
17449          {
17450              return null;
17451          }
17452      }
17453  }
17454  
17455  /**
17456   * Parses the XML Declaration
17457   *
17458   * @package SimplePie
17459   * @subpackage Parsing
17460   */
17461  class SimplePie_XML_Declaration_Parser
17462  {
17463      /**
17464       * XML Version
17465       *
17466       * @access public
17467       * @var string
17468       */
17469      var $version = '1.0';
17470  
17471      /**
17472       * Encoding
17473       *
17474       * @access public
17475       * @var string
17476       */
17477      var $encoding = 'UTF-8';
17478  
17479      /**
17480       * Standalone
17481       *
17482       * @access public
17483       * @var bool
17484       */
17485      var $standalone = false;
17486  
17487      /**
17488       * Current state of the state machine
17489       *
17490       * @access private
17491       * @var string
17492       */
17493      var $state = 'before_version_name';
17494  
17495      /**
17496       * Input data
17497       *
17498       * @access private
17499       * @var string
17500       */
17501      var $data = '';
17502  
17503      /**
17504       * Input data length (to avoid calling strlen() everytime this is needed)
17505       *
17506       * @access private
17507       * @var int
17508       */
17509      var $data_length = 0;
17510  
17511      /**
17512       * Current position of the pointer
17513       *
17514       * @var int
17515       * @access private
17516       */
17517      var $position = 0;
17518  
17519      /**
17520       * Create an instance of the class with the input data
17521       *
17522       * @access public
17523       * @param string $data Input data
17524       */
17525  	public function __construct($data)
17526      {
17527          $this->data = $data;
17528          $this->data_length = strlen($this->data);
17529      }
17530  
17531      /**
17532       * Parse the input data
17533       *
17534       * @access public
17535       * @return bool true on success, false on failure
17536       */
17537  	public function parse()
17538      {
17539          while ($this->state && $this->state !== 'emit' && $this->has_data())
17540          {
17541              $state = $this->state;
17542              $this->$state();
17543          }
17544          $this->data = '';
17545          if ($this->state === 'emit')
17546          {
17547              return true;
17548          }
17549          else
17550          {
17551              $this->version = '';
17552              $this->encoding = '';
17553              $this->standalone = '';
17554              return false;
17555          }
17556      }
17557  
17558      /**
17559       * Check whether there is data beyond the pointer
17560       *
17561       * @access private
17562       * @return bool true if there is further data, false if not
17563       */
17564  	public function has_data()
17565      {
17566          return (bool) ($this->position < $this->data_length);
17567      }
17568  
17569      /**
17570       * Advance past any whitespace
17571       *
17572       * @return int Number of whitespace characters passed
17573       */
17574  	public function skip_whitespace()
17575      {
17576          $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
17577          $this->position += $whitespace;
17578          return $whitespace;
17579      }
17580  
17581      /**
17582       * Read value
17583       */
17584  	public function get_value()
17585      {
17586          $quote = substr($this->data, $this->position, 1);
17587          if ($quote === '"' || $quote === "'")
17588          {
17589              $this->position++;
17590              $len = strcspn($this->data, $quote, $this->position);
17591              if ($this->has_data())
17592              {
17593                  $value = substr($this->data, $this->position, $len);
17594                  $this->position += $len + 1;
17595                  return $value;
17596              }
17597          }
17598          return false;
17599      }
17600  
17601  	public function before_version_name()
17602      {
17603          if ($this->skip_whitespace())
17604          {
17605              $this->state = 'version_name';
17606          }
17607          else
17608          {
17609              $this->state = false;
17610          }
17611      }
17612  
17613  	public function version_name()
17614      {
17615          if (substr($this->data, $this->position, 7) === 'version')
17616          {
17617              $this->position += 7;
17618              $this->skip_whitespace();
17619              $this->state = 'version_equals';
17620          }
17621          else
17622          {
17623              $this->state = false;
17624          }
17625      }
17626  
17627  	public function version_equals()
17628      {
17629          if (substr($this->data, $this->position, 1) === '=')
17630          {
17631              $this->position++;
17632              $this->skip_whitespace();
17633              $this->state = 'version_value';
17634          }
17635          else
17636          {
17637              $this->state = false;
17638          }
17639      }
17640  
17641  	public function version_value()
17642      {
17643          if ($this->version = $this->get_value())
17644          {
17645              $this->skip_whitespace();
17646              if ($this->has_data())
17647              {
17648                  $this->state = 'encoding_name';
17649              }
17650              else
17651              {
17652                  $this->state = 'emit';
17653              }
17654          }
17655          else
17656          {
17657              $this->state = false;
17658          }
17659      }
17660  
17661  	public function encoding_name()
17662      {
17663          if (substr($this->data, $this->position, 8) === 'encoding')
17664          {
17665              $this->position += 8;
17666              $this->skip_whitespace();
17667              $this->state = 'encoding_equals';
17668          }
17669          else
17670          {
17671              $this->state = 'standalone_name';
17672          }
17673      }
17674  
17675  	public function encoding_equals()
17676      {
17677          if (substr($this->data, $this->position, 1) === '=')
17678          {
17679              $this->position++;
17680              $this->skip_whitespace();
17681              $this->state = 'encoding_value';
17682          }
17683          else
17684          {
17685              $this->state = false;
17686          }
17687      }
17688  
17689  	public function encoding_value()
17690      {
17691          if ($this->encoding = $this->get_value())
17692          {
17693              $this->skip_whitespace();
17694              if ($this->has_data())
17695              {
17696                  $this->state = 'standalone_name';
17697              }
17698              else
17699              {
17700                  $this->state = 'emit';
17701              }
17702          }
17703          else
17704          {
17705              $this->state = false;
17706          }
17707      }
17708  
17709  	public function standalone_name()
17710      {
17711          if (substr($this->data, $this->position, 10) === 'standalone')
17712          {
17713              $this->position += 10;
17714              $this->skip_whitespace();
17715              $this->state = 'standalone_equals';
17716          }
17717          else
17718          {
17719              $this->state = false;
17720          }
17721      }
17722  
17723  	public function standalone_equals()
17724      {
17725          if (substr($this->data, $this->position, 1) === '=')
17726          {
17727              $this->position++;
17728              $this->skip_whitespace();
17729              $this->state = 'standalone_value';
17730          }
17731          else
17732          {
17733              $this->state = false;
17734          }
17735      }
17736  
17737  	public function standalone_value()
17738      {
17739          if ($standalone = $this->get_value())
17740          {
17741              switch ($standalone)
17742              {
17743                  case 'yes':
17744                      $this->standalone = true;
17745                      break;
17746  
17747                  case 'no':
17748                      $this->standalone = false;
17749                      break;
17750  
17751                  default:
17752                      $this->state = false;
17753                      return;
17754              }
17755  
17756              $this->skip_whitespace();
17757              if ($this->has_data())
17758              {
17759                  $this->state = false;
17760              }
17761              else
17762              {
17763                  $this->state = 'emit';
17764              }
17765          }
17766          else
17767          {
17768              $this->state = false;
17769          }
17770      }
17771  }
17772