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