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