[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * SimplePie 4 * 5 * A PHP-Based RSS and Atom Feed Framework. 6 * Takes the hard work out of managing a complete RSS/Atom solution. 7 * 8 * Please note: This file is automatically generated by a build script. The 9 * full original source is always available from http://simplepie.org/ 10 * 11 * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without modification, are 15 * permitted provided that the following conditions are met: 16 * 17 * * Redistributions of source code must retain the above copyright notice, this list of 18 * conditions and the following disclaimer. 19 * 20 * * Redistributions in binary form must reproduce the above copyright notice, this list 21 * of conditions and the following disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * * Neither the name of the SimplePie Team nor the names of its contributors may be used 25 * to endorse or promote products derived from this software without specific prior 26 * written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 29 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 30 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 31 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 * 38 * @package SimplePie 39 * @version 1.3.1 40 * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue 41 * @author Ryan Parman 42 * @author Geoffrey Sneddon 43 * @author Ryan McCue 44 * @link http://simplepie.org/ SimplePie 45 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 46 */ 47 48 /** 49 * SimplePie Name 50 */ 51 define('SIMPLEPIE_NAME', 'SimplePie'); 52 53 /** 54 * SimplePie Version 55 */ 56 define('SIMPLEPIE_VERSION', '1.3.1'); 57 58 /** 59 * SimplePie Build 60 * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc) 61 */ 62 define('SIMPLEPIE_BUILD', '20121030175911'); 63 64 /** 65 * SimplePie Website URL 66 */ 67 define('SIMPLEPIE_URL', 'http://simplepie.org'); 68 69 /** 70 * SimplePie Useragent 71 * @see SimplePie::set_useragent() 72 */ 73 define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD); 74 75 /** 76 * SimplePie Linkback 77 */ 78 define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>'); 79 80 /** 81 * No Autodiscovery 82 * @see SimplePie::set_autodiscovery_level() 83 */ 84 define('SIMPLEPIE_LOCATOR_NONE', 0); 85 86 /** 87 * Feed Link Element Autodiscovery 88 * @see SimplePie::set_autodiscovery_level() 89 */ 90 define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1); 91 92 /** 93 * Local Feed Extension Autodiscovery 94 * @see SimplePie::set_autodiscovery_level() 95 */ 96 define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2); 97 98 /** 99 * Local Feed Body Autodiscovery 100 * @see SimplePie::set_autodiscovery_level() 101 */ 102 define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4); 103 104 /** 105 * Remote Feed Extension Autodiscovery 106 * @see SimplePie::set_autodiscovery_level() 107 */ 108 define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8); 109 110 /** 111 * Remote Feed Body Autodiscovery 112 * @see SimplePie::set_autodiscovery_level() 113 */ 114 define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16); 115 116 /** 117 * All Feed Autodiscovery 118 * @see SimplePie::set_autodiscovery_level() 119 */ 120 define('SIMPLEPIE_LOCATOR_ALL', 31); 121 122 /** 123 * No known feed type 124 */ 125 define('SIMPLEPIE_TYPE_NONE', 0); 126 127 /** 128 * RSS 0.90 129 */ 130 define('SIMPLEPIE_TYPE_RSS_090', 1); 131 132 /** 133 * RSS 0.91 (Netscape) 134 */ 135 define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2); 136 137 /** 138 * RSS 0.91 (Userland) 139 */ 140 define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4); 141 142 /** 143 * RSS 0.91 (both Netscape and Userland) 144 */ 145 define('SIMPLEPIE_TYPE_RSS_091', 6); 146 147 /** 148 * RSS 0.92 149 */ 150 define('SIMPLEPIE_TYPE_RSS_092', 8); 151 152 /** 153 * RSS 0.93 154 */ 155 define('SIMPLEPIE_TYPE_RSS_093', 16); 156 157 /** 158 * RSS 0.94 159 */ 160 define('SIMPLEPIE_TYPE_RSS_094', 32); 161 162 /** 163 * RSS 1.0 164 */ 165 define('SIMPLEPIE_TYPE_RSS_10', 64); 166 167 /** 168 * RSS 2.0 169 */ 170 define('SIMPLEPIE_TYPE_RSS_20', 128); 171 172 /** 173 * RDF-based RSS 174 */ 175 define('SIMPLEPIE_TYPE_RSS_RDF', 65); 176 177 /** 178 * Non-RDF-based RSS (truly intended as syndication format) 179 */ 180 define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190); 181 182 /** 183 * All RSS 184 */ 185 define('SIMPLEPIE_TYPE_RSS_ALL', 255); 186 187 /** 188 * Atom 0.3 189 */ 190 define('SIMPLEPIE_TYPE_ATOM_03', 256); 191 192 /** 193 * Atom 1.0 194 */ 195 define('SIMPLEPIE_TYPE_ATOM_10', 512); 196 197 /** 198 * All Atom 199 */ 200 define('SIMPLEPIE_TYPE_ATOM_ALL', 768); 201 202 /** 203 * All feed types 204 */ 205 define('SIMPLEPIE_TYPE_ALL', 1023); 206 207 /** 208 * No construct 209 */ 210 define('SIMPLEPIE_CONSTRUCT_NONE', 0); 211 212 /** 213 * Text construct 214 */ 215 define('SIMPLEPIE_CONSTRUCT_TEXT', 1); 216 217 /** 218 * HTML construct 219 */ 220 define('SIMPLEPIE_CONSTRUCT_HTML', 2); 221 222 /** 223 * XHTML construct 224 */ 225 define('SIMPLEPIE_CONSTRUCT_XHTML', 4); 226 227 /** 228 * base64-encoded construct 229 */ 230 define('SIMPLEPIE_CONSTRUCT_BASE64', 8); 231 232 /** 233 * IRI construct 234 */ 235 define('SIMPLEPIE_CONSTRUCT_IRI', 16); 236 237 /** 238 * A construct that might be HTML 239 */ 240 define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32); 241 242 /** 243 * All constructs 244 */ 245 define('SIMPLEPIE_CONSTRUCT_ALL', 63); 246 247 /** 248 * Don't change case 249 */ 250 define('SIMPLEPIE_SAME_CASE', 1); 251 252 /** 253 * Change to lowercase 254 */ 255 define('SIMPLEPIE_LOWERCASE', 2); 256 257 /** 258 * Change to uppercase 259 */ 260 define('SIMPLEPIE_UPPERCASE', 4); 261 262 /** 263 * PCRE for HTML attributes 264 */ 265 define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*'); 266 267 /** 268 * PCRE for XML attributes 269 */ 270 define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*'); 271 272 /** 273 * XML Namespace 274 */ 275 define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace'); 276 277 /** 278 * Atom 1.0 Namespace 279 */ 280 define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom'); 281 282 /** 283 * Atom 0.3 Namespace 284 */ 285 define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#'); 286 287 /** 288 * RDF Namespace 289 */ 290 define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'); 291 292 /** 293 * RSS 0.90 Namespace 294 */ 295 define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/'); 296 297 /** 298 * RSS 1.0 Namespace 299 */ 300 define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/'); 301 302 /** 303 * RSS 1.0 Content Module Namespace 304 */ 305 define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/'); 306 307 /** 308 * RSS 2.0 Namespace 309 * (Stupid, I know, but I'm certain it will confuse people less with support.) 310 */ 311 define('SIMPLEPIE_NAMESPACE_RSS_20', ''); 312 313 /** 314 * DC 1.0 Namespace 315 */ 316 define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/'); 317 318 /** 319 * DC 1.1 Namespace 320 */ 321 define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/'); 322 323 /** 324 * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace 325 */ 326 define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#'); 327 328 /** 329 * GeoRSS Namespace 330 */ 331 define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss'); 332 333 /** 334 * Media RSS Namespace 335 */ 336 define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/'); 337 338 /** 339 * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec. 340 */ 341 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss'); 342 343 /** 344 * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5. 345 */ 346 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss'); 347 348 /** 349 * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace. 350 */ 351 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/'); 352 353 /** 354 * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace. 355 */ 356 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss'); 357 358 /** 359 * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL. 360 */ 361 define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/'); 362 363 /** 364 * iTunes RSS Namespace 365 */ 366 define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd'); 367 368 /** 369 * XHTML Namespace 370 */ 371 define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml'); 372 373 /** 374 * IANA Link Relations Registry 375 */ 376 define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/'); 377 378 /** 379 * No file source 380 */ 381 define('SIMPLEPIE_FILE_SOURCE_NONE', 0); 382 383 /** 384 * Remote file source 385 */ 386 define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1); 387 388 /** 389 * Local file source 390 */ 391 define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2); 392 393 /** 394 * fsockopen() file source 395 */ 396 define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4); 397 398 /** 399 * cURL file source 400 */ 401 define('SIMPLEPIE_FILE_SOURCE_CURL', 8); 402 403 /** 404 * file_get_contents() file source 405 */ 406 define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16); 407 408 /** 409 * SimplePie 410 * 411 * @package SimplePie 412 * @subpackage API 413 */ 414 class SimplePie 415 { 416 /** 417 * @var array Raw data 418 * @access private 419 */ 420 public $data = array(); 421 422 /** 423 * @var mixed Error string 424 * @access private 425 */ 426 public $error; 427 428 /** 429 * @var object Instance of SimplePie_Sanitize (or other class) 430 * @see SimplePie::set_sanitize_class() 431 * @access private 432 */ 433 public $sanitize; 434 435 /** 436 * @var string SimplePie Useragent 437 * @see SimplePie::set_useragent() 438 * @access private 439 */ 440 public $useragent = SIMPLEPIE_USERAGENT; 441 442 /** 443 * @var string Feed URL 444 * @see SimplePie::set_feed_url() 445 * @access private 446 */ 447 public $feed_url; 448 449 /** 450 * @var object Instance of SimplePie_File to use as a feed 451 * @see SimplePie::set_file() 452 * @access private 453 */ 454 public $file; 455 456 /** 457 * @var string Raw feed data 458 * @see SimplePie::set_raw_data() 459 * @access private 460 */ 461 public $raw_data; 462 463 /** 464 * @var int Timeout for fetching remote files 465 * @see SimplePie::set_timeout() 466 * @access private 467 */ 468 public $timeout = 10; 469 470 /** 471 * @var bool Forces fsockopen() to be used for remote files instead 472 * of cURL, even if a new enough version is installed 473 * @see SimplePie::force_fsockopen() 474 * @access private 475 */ 476 public $force_fsockopen = false; 477 478 /** 479 * @var bool Force the given data/URL to be treated as a feed no matter what 480 * it appears like 481 * @see SimplePie::force_feed() 482 * @access private 483 */ 484 public $force_feed = false; 485 486 /** 487 * @var bool Enable/Disable Caching 488 * @see SimplePie::enable_cache() 489 * @access private 490 */ 491 public $cache = true; 492 493 /** 494 * @var int Cache duration (in seconds) 495 * @see SimplePie::set_cache_duration() 496 * @access private 497 */ 498 public $cache_duration = 3600; 499 500 /** 501 * @var int Auto-discovery cache duration (in seconds) 502 * @see SimplePie::set_autodiscovery_cache_duration() 503 * @access private 504 */ 505 public $autodiscovery_cache_duration = 604800; // 7 Days. 506 507 /** 508 * @var string Cache location (relative to executing script) 509 * @see SimplePie::set_cache_location() 510 * @access private 511 */ 512 public $cache_location = './cache'; 513 514 /** 515 * @var string Function that creates the cache filename 516 * @see SimplePie::set_cache_name_function() 517 * @access private 518 */ 519 public $cache_name_function = 'md5'; 520 521 /** 522 * @var bool Reorder feed by date descending 523 * @see SimplePie::enable_order_by_date() 524 * @access private 525 */ 526 public $order_by_date = true; 527 528 /** 529 * @var mixed Force input encoding to be set to the follow value 530 * (false, or anything type-cast to false, disables this feature) 531 * @see SimplePie::set_input_encoding() 532 * @access private 533 */ 534 public $input_encoding = false; 535 536 /** 537 * @var int Feed Autodiscovery Level 538 * @see SimplePie::set_autodiscovery_level() 539 * @access private 540 */ 541 public $autodiscovery = SIMPLEPIE_LOCATOR_ALL; 542 543 /** 544 * Class registry object 545 * 546 * @var SimplePie_Registry 547 */ 548 public $registry; 549 550 /** 551 * @var int Maximum number of feeds to check with autodiscovery 552 * @see SimplePie::set_max_checked_feeds() 553 * @access private 554 */ 555 public $max_checked_feeds = 10; 556 557 /** 558 * @var array All the feeds found during the autodiscovery process 559 * @see SimplePie::get_all_discovered_feeds() 560 * @access private 561 */ 562 public $all_discovered_feeds = array(); 563 564 /** 565 * @var string Web-accessible path to the handler_image.php file. 566 * @see SimplePie::set_image_handler() 567 * @access private 568 */ 569 public $image_handler = ''; 570 571 /** 572 * @var array Stores the URLs when multiple feeds are being initialized. 573 * @see SimplePie::set_feed_url() 574 * @access private 575 */ 576 public $multifeed_url = array(); 577 578 /** 579 * @var array Stores SimplePie objects when multiple feeds initialized. 580 * @access private 581 */ 582 public $multifeed_objects = array(); 583 584 /** 585 * @var array Stores the get_object_vars() array for use with multifeeds. 586 * @see SimplePie::set_feed_url() 587 * @access private 588 */ 589 public $config_settings = null; 590 591 /** 592 * @var integer Stores the number of items to return per-feed with multifeeds. 593 * @see SimplePie::set_item_limit() 594 * @access private 595 */ 596 public $item_limit = 0; 597 598 /** 599 * @var array Stores the default attributes to be stripped by strip_attributes(). 600 * @see SimplePie::strip_attributes() 601 * @access private 602 */ 603 public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); 604 605 /** 606 * @var array Stores the default tags to be stripped by strip_htmltags(). 607 * @see SimplePie::strip_htmltags() 608 * @access private 609 */ 610 public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); 611 612 /** 613 * The SimplePie class contains feed level data and options 614 * 615 * To use SimplePie, create the SimplePie object with no parameters. You can 616 * then set configuration options using the provided methods. After setting 617 * them, you must initialise the feed using $feed->init(). At that point the 618 * object's methods and properties will be available to you. 619 * 620 * Previously, it was possible to pass in the feed URL along with cache 621 * options directly into the constructor. This has been removed as of 1.3 as 622 * it caused a lot of confusion. 623 * 624 * @since 1.0 Preview Release 625 */ 626 public function __construct() 627 { 628 if (version_compare(PHP_VERSION, '5.2', '<')) 629 { 630 trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.'); 631 die(); 632 } 633 634 // Other objects, instances created here so we can set options on them 635 $this->sanitize = new SimplePie_Sanitize(); 636 $this->registry = new SimplePie_Registry(); 637 638 if (func_num_args() > 0) 639 { 640 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING; 641 trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level); 642 643 $args = func_get_args(); 644 switch (count($args)) { 645 case 3: 646 $this->set_cache_duration($args[2]); 647 case 2: 648 $this->set_cache_location($args[1]); 649 case 1: 650 $this->set_feed_url($args[0]); 651 $this->init(); 652 } 653 } 654 } 655 656 /** 657 * Used for converting object to a string 658 */ 659 public function __toString() 660 { 661 return md5(serialize($this->data)); 662 } 663 664 /** 665 * Remove items that link back to this before destroying this object 666 */ 667 public function __destruct() 668 { 669 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode')) 670 { 671 if (!empty($this->data['items'])) 672 { 673 foreach ($this->data['items'] as $item) 674 { 675 $item->__destruct(); 676 } 677 unset($item, $this->data['items']); 678 } 679 if (!empty($this->data['ordered_items'])) 680 { 681 foreach ($this->data['ordered_items'] as $item) 682 { 683 $item->__destruct(); 684 } 685 unset($item, $this->data['ordered_items']); 686 } 687 } 688 } 689 690 /** 691 * Force the given data/URL to be treated as a feed 692 * 693 * This tells SimplePie to ignore the content-type provided by the server. 694 * Be careful when using this option, as it will also disable autodiscovery. 695 * 696 * @since 1.1 697 * @param bool $enable Force the given data/URL to be treated as a feed 698 */ 699 public function force_feed($enable = false) 700 { 701 $this->force_feed = (bool) $enable; 702 } 703 704 /** 705 * Set the URL of the feed you want to parse 706 * 707 * This allows you to enter the URL of the feed you want to parse, or the 708 * website you want to try to use auto-discovery on. This takes priority 709 * over any set raw data. 710 * 711 * You can set multiple feeds to mash together by passing an array instead 712 * of a string for the $url. Remember that with each additional feed comes 713 * additional processing and resources. 714 * 715 * @since 1.0 Preview Release 716 * @see set_raw_data() 717 * @param string|array $url This is the URL (or array of URLs) that you want to parse. 718 */ 719 public function set_feed_url($url) 720 { 721 $this->multifeed_url = array(); 722 if (is_array($url)) 723 { 724 foreach ($url as $value) 725 { 726 $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1)); 727 } 728 } 729 else 730 { 731 $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1)); 732 } 733 } 734 735 /** 736 * Set an instance of {@see SimplePie_File} to use as a feed 737 * 738 * @param SimplePie_File &$file 739 * @return bool True on success, false on failure 740 */ 741 public function set_file(&$file) 742 { 743 if ($file instanceof SimplePie_File) 744 { 745 $this->feed_url = $file->url; 746 $this->file =& $file; 747 return true; 748 } 749 return false; 750 } 751 752 /** 753 * Set the raw XML data to parse 754 * 755 * Allows you to use a string of RSS/Atom data instead of a remote feed. 756 * 757 * If you have a feed available as a string in PHP, you can tell SimplePie 758 * to parse that data string instead of a remote feed. Any set feed URL 759 * takes precedence. 760 * 761 * @since 1.0 Beta 3 762 * @param string $data RSS or Atom data as a string. 763 * @see set_feed_url() 764 */ 765 public function set_raw_data($data) 766 { 767 $this->raw_data = $data; 768 } 769 770 /** 771 * Set the the default timeout for fetching remote feeds 772 * 773 * This allows you to change the maximum time the feed's server to respond 774 * and send the feed back. 775 * 776 * @since 1.0 Beta 3 777 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed. 778 */ 779 public function set_timeout($timeout = 10) 780 { 781 $this->timeout = (int) $timeout; 782 } 783 784 /** 785 * Force SimplePie to use fsockopen() instead of cURL 786 * 787 * @since 1.0 Beta 3 788 * @param bool $enable Force fsockopen() to be used 789 */ 790 public function force_fsockopen($enable = false) 791 { 792 $this->force_fsockopen = (bool) $enable; 793 } 794 795 /** 796 * Enable/disable caching in SimplePie. 797 * 798 * This option allows you to disable caching all-together in SimplePie. 799 * However, disabling the cache can lead to longer load times. 800 * 801 * @since 1.0 Preview Release 802 * @param bool $enable Enable caching 803 */ 804 public function enable_cache($enable = true) 805 { 806 $this->cache = (bool) $enable; 807 } 808 809 /** 810 * Set the length of time (in seconds) that the contents of a feed will be 811 * cached 812 * 813 * @param int $seconds The feed content cache duration 814 */ 815 public function set_cache_duration($seconds = 3600) 816 { 817 $this->cache_duration = (int) $seconds; 818 } 819 820 /** 821 * Set the length of time (in seconds) that the autodiscovered feed URL will 822 * be cached 823 * 824 * @param int $seconds The autodiscovered feed URL cache duration. 825 */ 826 public function set_autodiscovery_cache_duration($seconds = 604800) 827 { 828 $this->autodiscovery_cache_duration = (int) $seconds; 829 } 830 831 /** 832 * Set the file system location where the cached files should be stored 833 * 834 * @param string $location The file system location. 835 */ 836 public function set_cache_location($location = './cache') 837 { 838 $this->cache_location = (string) $location; 839 } 840 841 /** 842 * Set whether feed items should be sorted into reverse chronological order 843 * 844 * @param bool $enable Sort as reverse chronological order. 845 */ 846 public function enable_order_by_date($enable = true) 847 { 848 $this->order_by_date = (bool) $enable; 849 } 850 851 /** 852 * Set the character encoding used to parse the feed 853 * 854 * This overrides the encoding reported by the feed, however it will fall 855 * back to the normal encoding detection if the override fails 856 * 857 * @param string $encoding Character encoding 858 */ 859 public function set_input_encoding($encoding = false) 860 { 861 if ($encoding) 862 { 863 $this->input_encoding = (string) $encoding; 864 } 865 else 866 { 867 $this->input_encoding = false; 868 } 869 } 870 871 /** 872 * Set how much feed autodiscovery to do 873 * 874 * @see SIMPLEPIE_LOCATOR_NONE 875 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY 876 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION 877 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY 878 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION 879 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY 880 * @see SIMPLEPIE_LOCATOR_ALL 881 * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator) 882 */ 883 public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL) 884 { 885 $this->autodiscovery = (int) $level; 886 } 887 888 /** 889 * Get the class registry 890 * 891 * Use this to override SimplePie's default classes 892 * @see SimplePie_Registry 893 * @return SimplePie_Registry 894 */ 895 public function &get_registry() 896 { 897 return $this->registry; 898 } 899 900 /**#@+ 901 * Useful when you are overloading or extending SimplePie's default classes. 902 * 903 * @deprecated Use {@see get_registry()} instead 904 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation 905 * @param string $class Name of custom class 906 * @return boolean True on success, false otherwise 907 */ 908 /** 909 * Set which class SimplePie uses for caching 910 */ 911 public function set_cache_class($class = 'SimplePie_Cache') 912 { 913 return $this->registry->register('Cache', $class, true); 914 } 915 916 /** 917 * Set which class SimplePie uses for auto-discovery 918 */ 919 public function set_locator_class($class = 'SimplePie_Locator') 920 { 921 return $this->registry->register('Locator', $class, true); 922 } 923 924 /** 925 * Set which class SimplePie uses for XML parsing 926 */ 927 public function set_parser_class($class = 'SimplePie_Parser') 928 { 929 return $this->registry->register('Parser', $class, true); 930 } 931 932 /** 933 * Set which class SimplePie uses for remote file fetching 934 */ 935 public function set_file_class($class = 'SimplePie_File') 936 { 937 return $this->registry->register('File', $class, true); 938 } 939 940 /** 941 * Set which class SimplePie uses for data sanitization 942 */ 943 public function set_sanitize_class($class = 'SimplePie_Sanitize') 944 { 945 return $this->registry->register('Sanitize', $class, true); 946 } 947 948 /** 949 * Set which class SimplePie uses for handling feed items 950 */ 951 public function set_item_class($class = 'SimplePie_Item') 952 { 953 return $this->registry->register('Item', $class, true); 954 } 955 956 /** 957 * Set which class SimplePie uses for handling author data 958 */ 959 public function set_author_class($class = 'SimplePie_Author') 960 { 961 return $this->registry->register('Author', $class, true); 962 } 963 964 /** 965 * Set which class SimplePie uses for handling category data 966 */ 967 public function set_category_class($class = 'SimplePie_Category') 968 { 969 return $this->registry->register('Category', $class, true); 970 } 971 972 /** 973 * Set which class SimplePie uses for feed enclosures 974 */ 975 public function set_enclosure_class($class = 'SimplePie_Enclosure') 976 { 977 return $this->registry->register('Enclosure', $class, true); 978 } 979 980 /** 981 * Set which class SimplePie uses for `<media:text>` captions 982 */ 983 public function set_caption_class($class = 'SimplePie_Caption') 984 { 985 return $this->registry->register('Caption', $class, true); 986 } 987 988 /** 989 * Set which class SimplePie uses for `<media:copyright>` 990 */ 991 public function set_copyright_class($class = 'SimplePie_Copyright') 992 { 993 return $this->registry->register('Copyright', $class, true); 994 } 995 996 /** 997 * Set which class SimplePie uses for `<media:credit>` 998 */ 999 public function set_credit_class($class = 'SimplePie_Credit') 1000 { 1001 return $this->registry->register('Credit', $class, true); 1002 } 1003 1004 /** 1005 * Set which class SimplePie uses for `<media:rating>` 1006 */ 1007 public function set_rating_class($class = 'SimplePie_Rating') 1008 { 1009 return $this->registry->register('Rating', $class, true); 1010 } 1011 1012 /** 1013 * Set which class SimplePie uses for `<media:restriction>` 1014 */ 1015 public function set_restriction_class($class = 'SimplePie_Restriction') 1016 { 1017 return $this->registry->register('Restriction', $class, true); 1018 } 1019 1020 /** 1021 * Set which class SimplePie uses for content-type sniffing 1022 */ 1023 public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer') 1024 { 1025 return $this->registry->register('Content_Type_Sniffer', $class, true); 1026 } 1027 1028 /** 1029 * Set which class SimplePie uses item sources 1030 */ 1031 public function set_source_class($class = 'SimplePie_Source') 1032 { 1033 return $this->registry->register('Source', $class, true); 1034 } 1035 /**#@-*/ 1036 1037 /** 1038 * Set the user agent string 1039 * 1040 * @param string $ua New user agent string. 1041 */ 1042 public function set_useragent($ua = SIMPLEPIE_USERAGENT) 1043 { 1044 $this->useragent = (string) $ua; 1045 } 1046 1047 /** 1048 * Set callback function to create cache filename with 1049 * 1050 * @param mixed $function Callback function 1051 */ 1052 public function set_cache_name_function($function = 'md5') 1053 { 1054 if (is_callable($function)) 1055 { 1056 $this->cache_name_function = $function; 1057 } 1058 } 1059 1060 /** 1061 * Set options to make SP as fast as possible 1062 * 1063 * Forgoes a substantial amount of data sanitization in favor of speed. This 1064 * turns SimplePie into a dumb parser of feeds. 1065 * 1066 * @param bool $set Whether to set them or not 1067 */ 1068 public function set_stupidly_fast($set = false) 1069 { 1070 if ($set) 1071 { 1072 $this->enable_order_by_date(false); 1073 $this->remove_div(false); 1074 $this->strip_comments(false); 1075 $this->strip_htmltags(false); 1076 $this->strip_attributes(false); 1077 $this->set_image_handler(false); 1078 } 1079 } 1080 1081 /** 1082 * Set maximum number of feeds to check with autodiscovery 1083 * 1084 * @param int $max Maximum number of feeds to check 1085 */ 1086 public function set_max_checked_feeds($max = 10) 1087 { 1088 $this->max_checked_feeds = (int) $max; 1089 } 1090 1091 public function remove_div($enable = true) 1092 { 1093 $this->sanitize->remove_div($enable); 1094 } 1095 1096 public function strip_htmltags($tags = '', $encode = null) 1097 { 1098 if ($tags === '') 1099 { 1100 $tags = $this->strip_htmltags; 1101 } 1102 $this->sanitize->strip_htmltags($tags); 1103 if ($encode !== null) 1104 { 1105 $this->sanitize->encode_instead_of_strip($tags); 1106 } 1107 } 1108 1109 public function encode_instead_of_strip($enable = true) 1110 { 1111 $this->sanitize->encode_instead_of_strip($enable); 1112 } 1113 1114 public function strip_attributes($attribs = '') 1115 { 1116 if ($attribs === '') 1117 { 1118 $attribs = $this->strip_attributes; 1119 } 1120 $this->sanitize->strip_attributes($attribs); 1121 } 1122 1123 /** 1124 * Set the output encoding 1125 * 1126 * Allows you to override SimplePie's output to match that of your webpage. 1127 * This is useful for times when your webpages are not being served as 1128 * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and 1129 * is similar to {@see set_input_encoding()}. 1130 * 1131 * It should be noted, however, that not all character encodings can support 1132 * all characters. If your page is being served as ISO-8859-1 and you try 1133 * to display a Japanese feed, you'll likely see garbled characters. 1134 * Because of this, it is highly recommended to ensure that your webpages 1135 * are served as UTF-8. 1136 * 1137 * The number of supported character encodings depends on whether your web 1138 * host supports {@link http://php.net/mbstring mbstring}, 1139 * {@link http://php.net/iconv iconv}, or both. See 1140 * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for 1141 * more information. 1142 * 1143 * @param string $encoding 1144 */ 1145 public function set_output_encoding($encoding = 'UTF-8') 1146 { 1147 $this->sanitize->set_output_encoding($encoding); 1148 } 1149 1150 public function strip_comments($strip = false) 1151 { 1152 $this->sanitize->strip_comments($strip); 1153 } 1154 1155 /** 1156 * Set element/attribute key/value pairs of HTML attributes 1157 * containing URLs that need to be resolved relative to the feed 1158 * 1159 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite, 1160 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite, 1161 * |q|@cite 1162 * 1163 * @since 1.0 1164 * @param array|null $element_attribute Element/attribute key/value pairs, null for default 1165 */ 1166 public function set_url_replacements($element_attribute = null) 1167 { 1168 $this->sanitize->set_url_replacements($element_attribute); 1169 } 1170 1171 /** 1172 * Set the handler to enable the display of cached images. 1173 * 1174 * @param str $page Web-accessible path to the handler_image.php file. 1175 * @param str $qs The query string that the value should be passed to. 1176 */ 1177 public function set_image_handler($page = false, $qs = 'i') 1178 { 1179 if ($page !== false) 1180 { 1181 $this->sanitize->set_image_handler($page . '?' . $qs . '='); 1182 } 1183 else 1184 { 1185 $this->image_handler = ''; 1186 } 1187 } 1188 1189 /** 1190 * Set the limit for items returned per-feed with multifeeds 1191 * 1192 * @param integer $limit The maximum number of items to return. 1193 */ 1194 public function set_item_limit($limit = 0) 1195 { 1196 $this->item_limit = (int) $limit; 1197 } 1198 1199 /** 1200 * Initialize the feed object 1201 * 1202 * This is what makes everything happen. Period. This is where all of the 1203 * configuration options get processed, feeds are fetched, cached, and 1204 * parsed, and all of that other good stuff. 1205 * 1206 * @return boolean True if successful, false otherwise 1207 */ 1208 public function init() 1209 { 1210 // Check absolute bare minimum requirements. 1211 if (!extension_loaded('xml') || !extension_loaded('pcre')) 1212 { 1213 return false; 1214 } 1215 // Then check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader. 1216 elseif (!extension_loaded('xmlreader')) 1217 { 1218 static $xml_is_sane = null; 1219 if ($xml_is_sane === null) 1220 { 1221 $parser_check = xml_parser_create(); 1222 xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); 1223 xml_parser_free($parser_check); 1224 $xml_is_sane = isset($values[0]['value']); 1225 } 1226 if (!$xml_is_sane) 1227 { 1228 return false; 1229 } 1230 } 1231 1232 if (method_exists($this->sanitize, 'set_registry')) 1233 { 1234 $this->sanitize->set_registry($this->registry); 1235 } 1236 1237 // Pass whatever was set with config options over to the sanitizer. 1238 // Pass the classes in for legacy support; new classes should use the registry instead 1239 $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache')); 1240 $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen); 1241 1242 if (!empty($this->multifeed_url)) 1243 { 1244 $i = 0; 1245 $success = 0; 1246 $this->multifeed_objects = array(); 1247 $this->error = array(); 1248 foreach ($this->multifeed_url as $url) 1249 { 1250 $this->multifeed_objects[$i] = clone $this; 1251 $this->multifeed_objects[$i]->set_feed_url($url); 1252 $single_success = $this->multifeed_objects[$i]->init(); 1253 $success |= $single_success; 1254 if (!$single_success) 1255 { 1256 $this->error[$i] = $this->multifeed_objects[$i]->error(); 1257 } 1258 $i++; 1259 } 1260 return (bool) $success; 1261 } 1262 elseif ($this->feed_url === null && $this->raw_data === null) 1263 { 1264 return false; 1265 } 1266 1267 $this->error = null; 1268 $this->data = array(); 1269 $this->multifeed_objects = array(); 1270 $cache = false; 1271 1272 if ($this->feed_url !== null) 1273 { 1274 $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url)); 1275 1276 // Decide whether to enable caching 1277 if ($this->cache && $parsed_feed_url['scheme'] !== '') 1278 { 1279 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc')); 1280 } 1281 1282 // Fetch the data via SimplePie_File into $this->raw_data 1283 if (($fetched = $this->fetch_data($cache)) === true) 1284 { 1285 return true; 1286 } 1287 elseif ($fetched === false) { 1288 return false; 1289 } 1290 1291 list($headers, $sniffed) = $fetched; 1292 } 1293 1294 // Set up array of possible encodings 1295 $encodings = array(); 1296 1297 // First check to see if input has been overridden. 1298 if ($this->input_encoding !== false) 1299 { 1300 $encodings[] = $this->input_encoding; 1301 } 1302 1303 $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity'); 1304 $text_types = array('text/xml', 'text/xml-external-parsed-entity'); 1305 1306 // RFC 3023 (only applies to sniffed content) 1307 if (isset($sniffed)) 1308 { 1309 if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml') 1310 { 1311 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) 1312 { 1313 $encodings[] = strtoupper($charset[1]); 1314 } 1315 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry))); 1316 $encodings[] = 'UTF-8'; 1317 } 1318 elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml') 1319 { 1320 if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset)) 1321 { 1322 $encodings[] = $charset[1]; 1323 } 1324 $encodings[] = 'US-ASCII'; 1325 } 1326 // Text MIME-type default 1327 elseif (substr($sniffed, 0, 5) === 'text/') 1328 { 1329 $encodings[] = 'US-ASCII'; 1330 } 1331 } 1332 1333 // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1 1334 $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry))); 1335 $encodings[] = 'UTF-8'; 1336 $encodings[] = 'ISO-8859-1'; 1337 1338 // There's no point in trying an encoding twice 1339 $encodings = array_unique($encodings); 1340 1341 // Loop through each possible encoding, till we return something, or run out of possibilities 1342 foreach ($encodings as $encoding) 1343 { 1344 // Change the encoding to UTF-8 (as we always use UTF-8 internally) 1345 if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8'))) 1346 { 1347 // Create new parser 1348 $parser = $this->registry->create('Parser'); 1349 1350 // If it's parsed fine 1351 if ($parser->parse($utf8_data, 'UTF-8')) 1352 { 1353 $this->data = $parser->get_data(); 1354 if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE)) 1355 { 1356 $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed."; 1357 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__)); 1358 return false; 1359 } 1360 1361 if (isset($headers)) 1362 { 1363 $this->data['headers'] = $headers; 1364 } 1365 $this->data['build'] = SIMPLEPIE_BUILD; 1366 1367 // Cache the file if caching is enabled 1368 if ($cache && !$cache->save($this)) 1369 { 1370 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); 1371 } 1372 return true; 1373 } 1374 } 1375 } 1376 1377 if (isset($parser)) 1378 { 1379 // We have an error, just set SimplePie_Misc::error to it and quit 1380 $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column()); 1381 } 1382 else 1383 { 1384 $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.'; 1385 } 1386 1387 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__)); 1388 1389 return false; 1390 } 1391 1392 /** 1393 * Fetch the data via SimplePie_File 1394 * 1395 * If the data is already cached, attempt to fetch it from there instead 1396 * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache 1397 * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type 1398 */ 1399 protected function fetch_data(&$cache) 1400 { 1401 // If it's enabled, use the cache 1402 if ($cache) 1403 { 1404 // Load the Cache 1405 $this->data = $cache->load(); 1406 if (!empty($this->data)) 1407 { 1408 // If the cache is for an outdated build of SimplePie 1409 if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD) 1410 { 1411 $cache->unlink(); 1412 $this->data = array(); 1413 } 1414 // If we've hit a collision just rerun it with caching disabled 1415 elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url) 1416 { 1417 $cache = false; 1418 $this->data = array(); 1419 } 1420 // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL. 1421 elseif (isset($this->data['feed_url'])) 1422 { 1423 // If the autodiscovery cache is still valid use it. 1424 if ($cache->mtime() + $this->autodiscovery_cache_duration > time()) 1425 { 1426 // Do not need to do feed autodiscovery yet. 1427 if ($this->data['feed_url'] !== $this->data['url']) 1428 { 1429 $this->set_feed_url($this->data['feed_url']); 1430 return $this->init(); 1431 } 1432 1433 $cache->unlink(); 1434 $this->data = array(); 1435 } 1436 } 1437 // Check if the cache has been updated 1438 elseif ($cache->mtime() + $this->cache_duration < time()) 1439 { 1440 // If we have last-modified and/or etag set 1441 if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) 1442 { 1443 $headers = array( 1444 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 1445 ); 1446 if (isset($this->data['headers']['last-modified'])) 1447 { 1448 $headers['if-modified-since'] = $this->data['headers']['last-modified']; 1449 } 1450 if (isset($this->data['headers']['etag'])) 1451 { 1452 $headers['if-none-match'] = $this->data['headers']['etag']; 1453 } 1454 1455 $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen)); 1456 1457 if ($file->success) 1458 { 1459 if ($file->status_code === 304) 1460 { 1461 $cache->touch(); 1462 return true; 1463 } 1464 } 1465 else 1466 { 1467 unset($file); 1468 } 1469 } 1470 } 1471 // If the cache is still valid, just return true 1472 else 1473 { 1474 $this->raw_data = false; 1475 return true; 1476 } 1477 } 1478 // If the cache is empty, delete it 1479 else 1480 { 1481 $cache->unlink(); 1482 $this->data = array(); 1483 } 1484 } 1485 // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it. 1486 if (!isset($file)) 1487 { 1488 if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url) 1489 { 1490 $file =& $this->file; 1491 } 1492 else 1493 { 1494 $headers = array( 1495 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 1496 ); 1497 $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen)); 1498 } 1499 } 1500 // If the file connection has an error, set SimplePie::error to that and quit 1501 if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) 1502 { 1503 $this->error = $file->error; 1504 return !empty($this->data); 1505 } 1506 1507 if (!$this->force_feed) 1508 { 1509 // Check if the supplied URL is a feed, if it isn't, look for it. 1510 $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds)); 1511 1512 if (!$locate->is_feed($file)) 1513 { 1514 // We need to unset this so that if SimplePie::set_file() has been called that object is untouched 1515 unset($file); 1516 try 1517 { 1518 if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds))) 1519 { 1520 $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed."; 1521 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__)); 1522 return false; 1523 } 1524 } 1525 catch (SimplePie_Exception $e) 1526 { 1527 // This is usually because DOMDocument doesn't exist 1528 $this->error = $e->getMessage(); 1529 $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine())); 1530 return false; 1531 } 1532 if ($cache) 1533 { 1534 $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD); 1535 if (!$cache->save($this)) 1536 { 1537 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); 1538 } 1539 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc')); 1540 } 1541 $this->feed_url = $file->url; 1542 } 1543 $locate = null; 1544 } 1545 1546 $this->raw_data = $file->body; 1547 1548 $headers = $file->headers; 1549 $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file)); 1550 $sniffed = $sniffer->get_type(); 1551 1552 return array($headers, $sniffed); 1553 } 1554 1555 /** 1556 * Get the error message for the occured error 1557 * 1558 * @return string|array Error message, or array of messages for multifeeds 1559 */ 1560 public function error() 1561 { 1562 return $this->error; 1563 } 1564 1565 /** 1566 * Get the raw XML 1567 * 1568 * This is the same as the old `$feed->enable_xml_dump(true)`, but returns 1569 * the data instead of printing it. 1570 * 1571 * @return string|boolean Raw XML data, false if the cache is used 1572 */ 1573 public function get_raw_data() 1574 { 1575 return $this->raw_data; 1576 } 1577 1578 /** 1579 * Get the character encoding used for output 1580 * 1581 * @since Preview Release 1582 * @return string 1583 */ 1584 public function get_encoding() 1585 { 1586 return $this->sanitize->output_encoding; 1587 } 1588 1589 /** 1590 * Send the content-type header with correct encoding 1591 * 1592 * This method ensures that the SimplePie-enabled page is being served with 1593 * the correct {@link http://www.iana.org/assignments/media-types/ mime-type} 1594 * and character encoding HTTP headers (character encoding determined by the 1595 * {@see set_output_encoding} config option). 1596 * 1597 * This won't work properly if any content or whitespace has already been 1598 * sent to the browser, because it relies on PHP's 1599 * {@link http://php.net/header header()} function, and these are the 1600 * circumstances under which the function works. 1601 * 1602 * Because it's setting these settings for the entire page (as is the nature 1603 * of HTTP headers), this should only be used once per page (again, at the 1604 * top). 1605 * 1606 * @param string $mime MIME type to serve the page as 1607 */ 1608 public function handle_content_type($mime = 'text/html') 1609 { 1610 if (!headers_sent()) 1611 { 1612 $header = "Content-type: $mime;"; 1613 if ($this->get_encoding()) 1614 { 1615 $header .= ' charset=' . $this->get_encoding(); 1616 } 1617 else 1618 { 1619 $header .= ' charset=UTF-8'; 1620 } 1621 header($header); 1622 } 1623 } 1624 1625 /** 1626 * Get the type of the feed 1627 * 1628 * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against 1629 * using {@link http://php.net/language.operators.bitwise bitwise operators} 1630 * 1631 * @since 0.8 (usage changed to using constants in 1.0) 1632 * @see SIMPLEPIE_TYPE_NONE Unknown. 1633 * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90. 1634 * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape). 1635 * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland). 1636 * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91. 1637 * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92. 1638 * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93. 1639 * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94. 1640 * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0. 1641 * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x. 1642 * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS. 1643 * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format). 1644 * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS. 1645 * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3. 1646 * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0. 1647 * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom. 1648 * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type. 1649 * @return int SIMPLEPIE_TYPE_* constant 1650 */ 1651 public function get_type() 1652 { 1653 if (!isset($this->data['type'])) 1654 { 1655 $this->data['type'] = SIMPLEPIE_TYPE_ALL; 1656 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'])) 1657 { 1658 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10; 1659 } 1660 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'])) 1661 { 1662 $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03; 1663 } 1664 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'])) 1665 { 1666 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel']) 1667 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image']) 1668 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']) 1669 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput'])) 1670 { 1671 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10; 1672 } 1673 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel']) 1674 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image']) 1675 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']) 1676 || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput'])) 1677 { 1678 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090; 1679 } 1680 } 1681 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'])) 1682 { 1683 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL; 1684 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version'])) 1685 { 1686 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version'])) 1687 { 1688 case '0.91': 1689 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091; 1690 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data'])) 1691 { 1692 switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data'])) 1693 { 1694 case '0': 1695 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE; 1696 break; 1697 1698 case '24': 1699 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND; 1700 break; 1701 } 1702 } 1703 break; 1704 1705 case '0.92': 1706 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092; 1707 break; 1708 1709 case '0.93': 1710 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093; 1711 break; 1712 1713 case '0.94': 1714 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094; 1715 break; 1716 1717 case '2.0': 1718 $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20; 1719 break; 1720 } 1721 } 1722 } 1723 else 1724 { 1725 $this->data['type'] = SIMPLEPIE_TYPE_NONE; 1726 } 1727 } 1728 return $this->data['type']; 1729 } 1730 1731 /** 1732 * Get the URL for the feed 1733 * 1734 * May or may not be different from the URL passed to {@see set_feed_url()}, 1735 * depending on whether auto-discovery was used. 1736 * 1737 * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.) 1738 * @todo If we have a perm redirect we should return the new URL 1739 * @todo When we make the above change, let's support <itunes:new-feed-url> as well 1740 * @todo Also, |atom:link|@rel=self 1741 * @return string|null 1742 */ 1743 public function subscribe_url() 1744 { 1745 if ($this->feed_url !== null) 1746 { 1747 return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI); 1748 } 1749 else 1750 { 1751 return null; 1752 } 1753 } 1754 1755 /** 1756 * Get data for an feed-level element 1757 * 1758 * This method allows you to get access to ANY element/attribute that is a 1759 * sub-element of the opening feed tag. 1760 * 1761 * The return value is an indexed array of elements matching the given 1762 * namespace and tag name. Each element has `attribs`, `data` and `child` 1763 * subkeys. For `attribs` and `child`, these contain namespace subkeys. 1764 * `attribs` then has one level of associative name => value data (where 1765 * `value` is a string) after the namespace. `child` has tag-indexed keys 1766 * after the namespace, each member of which is an indexed array matching 1767 * this same format. 1768 * 1769 * For example: 1770 * <pre> 1771 * // This is probably a bad example because we already support 1772 * // <media:content> natively, but it shows you how to parse through 1773 * // the nodes. 1774 * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group'); 1775 * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']; 1776 * $file = $content[0]['attribs']['']['url']; 1777 * echo $file; 1778 * </pre> 1779 * 1780 * @since 1.0 1781 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces 1782 * @param string $namespace The URL of the XML namespace of the elements you're trying to access 1783 * @param string $tag Tag name 1784 * @return array 1785 */ 1786 public function get_feed_tags($namespace, $tag) 1787 { 1788 $type = $this->get_type(); 1789 if ($type & SIMPLEPIE_TYPE_ATOM_10) 1790 { 1791 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag])) 1792 { 1793 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]; 1794 } 1795 } 1796 if ($type & SIMPLEPIE_TYPE_ATOM_03) 1797 { 1798 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag])) 1799 { 1800 return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]; 1801 } 1802 } 1803 if ($type & SIMPLEPIE_TYPE_RSS_RDF) 1804 { 1805 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag])) 1806 { 1807 return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]; 1808 } 1809 } 1810 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) 1811 { 1812 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag])) 1813 { 1814 return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]; 1815 } 1816 } 1817 return null; 1818 } 1819 1820 /** 1821 * Get data for an channel-level element 1822 * 1823 * This method allows you to get access to ANY element/attribute in the 1824 * channel/header section of the feed. 1825 * 1826 * See {@see SimplePie::get_feed_tags()} for a description of the return value 1827 * 1828 * @since 1.0 1829 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces 1830 * @param string $namespace The URL of the XML namespace of the elements you're trying to access 1831 * @param string $tag Tag name 1832 * @return array 1833 */ 1834 public function get_channel_tags($namespace, $tag) 1835 { 1836 $type = $this->get_type(); 1837 if ($type & SIMPLEPIE_TYPE_ATOM_ALL) 1838 { 1839 if ($return = $this->get_feed_tags($namespace, $tag)) 1840 { 1841 return $return; 1842 } 1843 } 1844 if ($type & SIMPLEPIE_TYPE_RSS_10) 1845 { 1846 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel')) 1847 { 1848 if (isset($channel[0]['child'][$namespace][$tag])) 1849 { 1850 return $channel[0]['child'][$namespace][$tag]; 1851 } 1852 } 1853 } 1854 if ($type & SIMPLEPIE_TYPE_RSS_090) 1855 { 1856 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel')) 1857 { 1858 if (isset($channel[0]['child'][$namespace][$tag])) 1859 { 1860 return $channel[0]['child'][$namespace][$tag]; 1861 } 1862 } 1863 } 1864 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) 1865 { 1866 if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel')) 1867 { 1868 if (isset($channel[0]['child'][$namespace][$tag])) 1869 { 1870 return $channel[0]['child'][$namespace][$tag]; 1871 } 1872 } 1873 } 1874 return null; 1875 } 1876 1877 /** 1878 * Get data for an channel-level element 1879 * 1880 * This method allows you to get access to ANY element/attribute in the 1881 * image/logo section of the feed. 1882 * 1883 * See {@see SimplePie::get_feed_tags()} for a description of the return value 1884 * 1885 * @since 1.0 1886 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces 1887 * @param string $namespace The URL of the XML namespace of the elements you're trying to access 1888 * @param string $tag Tag name 1889 * @return array 1890 */ 1891 public function get_image_tags($namespace, $tag) 1892 { 1893 $type = $this->get_type(); 1894 if ($type & SIMPLEPIE_TYPE_RSS_10) 1895 { 1896 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image')) 1897 { 1898 if (isset($image[0]['child'][$namespace][$tag])) 1899 { 1900 return $image[0]['child'][$namespace][$tag]; 1901 } 1902 } 1903 } 1904 if ($type & SIMPLEPIE_TYPE_RSS_090) 1905 { 1906 if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image')) 1907 { 1908 if (isset($image[0]['child'][$namespace][$tag])) 1909 { 1910 return $image[0]['child'][$namespace][$tag]; 1911 } 1912 } 1913 } 1914 if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION) 1915 { 1916 if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image')) 1917 { 1918 if (isset($image[0]['child'][$namespace][$tag])) 1919 { 1920 return $image[0]['child'][$namespace][$tag]; 1921 } 1922 } 1923 } 1924 return null; 1925 } 1926 1927 /** 1928 * Get the base URL value from the feed 1929 * 1930 * Uses `<xml:base>` if available, otherwise uses the first link in the 1931 * feed, or failing that, the URL of the feed itself. 1932 * 1933 * @see get_link 1934 * @see subscribe_url 1935 * 1936 * @param array $element 1937 * @return string 1938 */ 1939 public function get_base($element = array()) 1940 { 1941 if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base'])) 1942 { 1943 return $element['xml_base']; 1944 } 1945 elseif ($this->get_link() !== null) 1946 { 1947 return $this->get_link(); 1948 } 1949 else 1950 { 1951 return $this->subscribe_url(); 1952 } 1953 } 1954 1955 /** 1956 * Sanitize feed data 1957 * 1958 * @access private 1959 * @see SimplePie_Sanitize::sanitize() 1960 * @param string $data Data to sanitize 1961 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants 1962 * @param string $base Base URL to resolve URLs against 1963 * @return string Sanitized data 1964 */ 1965 public function sanitize($data, $type, $base = '') 1966 { 1967 return $this->sanitize->sanitize($data, $type, $base); 1968 } 1969 1970 /** 1971 * Get the title of the feed 1972 * 1973 * Uses `<atom:title>`, `<title>` or `<dc:title>` 1974 * 1975 * @since 1.0 (previously called `get_feed_title` since 0.8) 1976 * @return string|null 1977 */ 1978 public function get_title() 1979 { 1980 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) 1981 { 1982 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 1983 } 1984 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) 1985 { 1986 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 1987 } 1988 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) 1989 { 1990 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 1991 } 1992 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) 1993 { 1994 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 1995 } 1996 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) 1997 { 1998 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 1999 } 2000 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) 2001 { 2002 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2003 } 2004 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) 2005 { 2006 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2007 } 2008 else 2009 { 2010 return null; 2011 } 2012 } 2013 2014 /** 2015 * Get a category for the feed 2016 * 2017 * @since Unknown 2018 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 2019 * @return SimplePie_Category|null 2020 */ 2021 public function get_category($key = 0) 2022 { 2023 $categories = $this->get_categories(); 2024 if (isset($categories[$key])) 2025 { 2026 return $categories[$key]; 2027 } 2028 else 2029 { 2030 return null; 2031 } 2032 } 2033 2034 /** 2035 * Get all categories for the feed 2036 * 2037 * Uses `<atom:category>`, `<category>` or `<dc:subject>` 2038 * 2039 * @since Unknown 2040 * @return array|null List of {@see SimplePie_Category} objects 2041 */ 2042 public function get_categories() 2043 { 2044 $categories = array(); 2045 2046 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) 2047 { 2048 $term = null; 2049 $scheme = null; 2050 $label = null; 2051 if (isset($category['attribs']['']['term'])) 2052 { 2053 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); 2054 } 2055 if (isset($category['attribs']['']['scheme'])) 2056 { 2057 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 2058 } 2059 if (isset($category['attribs']['']['label'])) 2060 { 2061 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 2062 } 2063 $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); 2064 } 2065 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) 2066 { 2067 // This is really the label, but keep this as the term also for BC. 2068 // Label will also work on retrieving because that falls back to term. 2069 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2070 if (isset($category['attribs']['']['domain'])) 2071 { 2072 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); 2073 } 2074 else 2075 { 2076 $scheme = null; 2077 } 2078 $categories[] = $this->registry->create('Category', array($term, $scheme, null)); 2079 } 2080 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) 2081 { 2082 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 2083 } 2084 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) 2085 { 2086 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 2087 } 2088 2089 if (!empty($categories)) 2090 { 2091 return array_unique($categories); 2092 } 2093 else 2094 { 2095 return null; 2096 } 2097 } 2098 2099 /** 2100 * Get an author for the feed 2101 * 2102 * @since 1.1 2103 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 2104 * @return SimplePie_Author|null 2105 */ 2106 public function get_author($key = 0) 2107 { 2108 $authors = $this->get_authors(); 2109 if (isset($authors[$key])) 2110 { 2111 return $authors[$key]; 2112 } 2113 else 2114 { 2115 return null; 2116 } 2117 } 2118 2119 /** 2120 * Get all authors for the feed 2121 * 2122 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>` 2123 * 2124 * @since 1.1 2125 * @return array|null List of {@see SimplePie_Author} objects 2126 */ 2127 public function get_authors() 2128 { 2129 $authors = array(); 2130 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) 2131 { 2132 $name = null; 2133 $uri = null; 2134 $email = null; 2135 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) 2136 { 2137 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2138 } 2139 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) 2140 { 2141 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); 2142 } 2143 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) 2144 { 2145 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2146 } 2147 if ($name !== null || $email !== null || $uri !== null) 2148 { 2149 $authors[] = $this->registry->create('Author', array($name, $uri, $email)); 2150 } 2151 } 2152 if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) 2153 { 2154 $name = null; 2155 $url = null; 2156 $email = null; 2157 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) 2158 { 2159 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2160 } 2161 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) 2162 { 2163 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); 2164 } 2165 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) 2166 { 2167 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2168 } 2169 if ($name !== null || $email !== null || $url !== null) 2170 { 2171 $authors[] = $this->registry->create('Author', array($name, $url, $email)); 2172 } 2173 } 2174 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) 2175 { 2176 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 2177 } 2178 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) 2179 { 2180 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 2181 } 2182 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) 2183 { 2184 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 2185 } 2186 2187 if (!empty($authors)) 2188 { 2189 return array_unique($authors); 2190 } 2191 else 2192 { 2193 return null; 2194 } 2195 } 2196 2197 /** 2198 * Get a contributor for the feed 2199 * 2200 * @since 1.1 2201 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 2202 * @return SimplePie_Author|null 2203 */ 2204 public function get_contributor($key = 0) 2205 { 2206 $contributors = $this->get_contributors(); 2207 if (isset($contributors[$key])) 2208 { 2209 return $contributors[$key]; 2210 } 2211 else 2212 { 2213 return null; 2214 } 2215 } 2216 2217 /** 2218 * Get all contributors for the feed 2219 * 2220 * Uses `<atom:contributor>` 2221 * 2222 * @since 1.1 2223 * @return array|null List of {@see SimplePie_Author} objects 2224 */ 2225 public function get_contributors() 2226 { 2227 $contributors = array(); 2228 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) 2229 { 2230 $name = null; 2231 $uri = null; 2232 $email = null; 2233 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) 2234 { 2235 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2236 } 2237 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) 2238 { 2239 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); 2240 } 2241 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) 2242 { 2243 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2244 } 2245 if ($name !== null || $email !== null || $uri !== null) 2246 { 2247 $contributors[] = $this->registry->create('Author', array($name, $uri, $email)); 2248 } 2249 } 2250 foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) 2251 { 2252 $name = null; 2253 $url = null; 2254 $email = null; 2255 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) 2256 { 2257 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2258 } 2259 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) 2260 { 2261 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); 2262 } 2263 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) 2264 { 2265 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2266 } 2267 if ($name !== null || $email !== null || $url !== null) 2268 { 2269 $contributors[] = $this->registry->create('Author', array($name, $url, $email)); 2270 } 2271 } 2272 2273 if (!empty($contributors)) 2274 { 2275 return array_unique($contributors); 2276 } 2277 else 2278 { 2279 return null; 2280 } 2281 } 2282 2283 /** 2284 * Get a single link for the feed 2285 * 2286 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8) 2287 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 2288 * @param string $rel The relationship of the link to return 2289 * @return string|null Link URL 2290 */ 2291 public function get_link($key = 0, $rel = 'alternate') 2292 { 2293 $links = $this->get_links($rel); 2294 if (isset($links[$key])) 2295 { 2296 return $links[$key]; 2297 } 2298 else 2299 { 2300 return null; 2301 } 2302 } 2303 2304 /** 2305 * Get the permalink for the item 2306 * 2307 * Returns the first link available with a relationship of "alternate". 2308 * Identical to {@see get_link()} with key 0 2309 * 2310 * @see get_link 2311 * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8) 2312 * @internal Added for parity between the parent-level and the item/entry-level. 2313 * @return string|null Link URL 2314 */ 2315 public function get_permalink() 2316 { 2317 return $this->get_link(0); 2318 } 2319 2320 /** 2321 * Get all links for the feed 2322 * 2323 * Uses `<atom:link>` or `<link>` 2324 * 2325 * @since Beta 2 2326 * @param string $rel The relationship of links to return 2327 * @return array|null Links found for the feed (strings) 2328 */ 2329 public function get_links($rel = 'alternate') 2330 { 2331 if (!isset($this->data['links'])) 2332 { 2333 $this->data['links'] = array(); 2334 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) 2335 { 2336 foreach ($links as $link) 2337 { 2338 if (isset($link['attribs']['']['href'])) 2339 { 2340 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; 2341 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 2342 } 2343 } 2344 } 2345 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) 2346 { 2347 foreach ($links as $link) 2348 { 2349 if (isset($link['attribs']['']['href'])) 2350 { 2351 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; 2352 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 2353 2354 } 2355 } 2356 } 2357 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) 2358 { 2359 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 2360 } 2361 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) 2362 { 2363 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 2364 } 2365 if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) 2366 { 2367 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 2368 } 2369 2370 $keys = array_keys($this->data['links']); 2371 foreach ($keys as $key) 2372 { 2373 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key))) 2374 { 2375 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) 2376 { 2377 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); 2378 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; 2379 } 2380 else 2381 { 2382 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; 2383 } 2384 } 2385 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) 2386 { 2387 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; 2388 } 2389 $this->data['links'][$key] = array_unique($this->data['links'][$key]); 2390 } 2391 } 2392 2393 if (isset($this->data['links'][$rel])) 2394 { 2395 return $this->data['links'][$rel]; 2396 } 2397 else 2398 { 2399 return null; 2400 } 2401 } 2402 2403 public function get_all_discovered_feeds() 2404 { 2405 return $this->all_discovered_feeds; 2406 } 2407 2408 /** 2409 * Get the content for the item 2410 * 2411 * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`, 2412 * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>` 2413 * 2414 * @since 1.0 (previously called `get_feed_description()` since 0.8) 2415 * @return string|null 2416 */ 2417 public function get_description() 2418 { 2419 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) 2420 { 2421 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 2422 } 2423 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline')) 2424 { 2425 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 2426 } 2427 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) 2428 { 2429 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 2430 } 2431 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) 2432 { 2433 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 2434 } 2435 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) 2436 { 2437 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 2438 } 2439 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) 2440 { 2441 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2442 } 2443 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) 2444 { 2445 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2446 } 2447 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) 2448 { 2449 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 2450 } 2451 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) 2452 { 2453 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 2454 } 2455 else 2456 { 2457 return null; 2458 } 2459 } 2460 2461 /** 2462 * Get the copyright info for the feed 2463 * 2464 * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>` 2465 * 2466 * @since 1.0 (previously called `get_feed_copyright()` since 0.8) 2467 * @return string|null 2468 */ 2469 public function get_copyright() 2470 { 2471 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) 2472 { 2473 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 2474 } 2475 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) 2476 { 2477 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 2478 } 2479 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright')) 2480 { 2481 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2482 } 2483 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) 2484 { 2485 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2486 } 2487 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) 2488 { 2489 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2490 } 2491 else 2492 { 2493 return null; 2494 } 2495 } 2496 2497 /** 2498 * Get the language for the feed 2499 * 2500 * Uses `<language>`, `<dc:language>`, or @xml_lang 2501 * 2502 * @since 1.0 (previously called `get_feed_language()` since 0.8) 2503 * @return string|null 2504 */ 2505 public function get_language() 2506 { 2507 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language')) 2508 { 2509 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2510 } 2511 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language')) 2512 { 2513 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2514 } 2515 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language')) 2516 { 2517 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2518 } 2519 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'])) 2520 { 2521 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); 2522 } 2523 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'])) 2524 { 2525 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); 2526 } 2527 elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'])) 2528 { 2529 return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); 2530 } 2531 elseif (isset($this->data['headers']['content-language'])) 2532 { 2533 return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT); 2534 } 2535 else 2536 { 2537 return null; 2538 } 2539 } 2540 2541 /** 2542 * Get the latitude coordinates for the item 2543 * 2544 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications 2545 * 2546 * Uses `<geo:lat>` or `<georss:point>` 2547 * 2548 * @since 1.0 2549 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo 2550 * @link http://www.georss.org/ GeoRSS 2551 * @return string|null 2552 */ 2553 public function get_latitude() 2554 { 2555 2556 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) 2557 { 2558 return (float) $return[0]['data']; 2559 } 2560 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) 2561 { 2562 return (float) $match[1]; 2563 } 2564 else 2565 { 2566 return null; 2567 } 2568 } 2569 2570 /** 2571 * Get the longitude coordinates for the feed 2572 * 2573 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications 2574 * 2575 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>` 2576 * 2577 * @since 1.0 2578 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo 2579 * @link http://www.georss.org/ GeoRSS 2580 * @return string|null 2581 */ 2582 public function get_longitude() 2583 { 2584 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) 2585 { 2586 return (float) $return[0]['data']; 2587 } 2588 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) 2589 { 2590 return (float) $return[0]['data']; 2591 } 2592 elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) 2593 { 2594 return (float) $match[2]; 2595 } 2596 else 2597 { 2598 return null; 2599 } 2600 } 2601 2602 /** 2603 * Get the feed logo's title 2604 * 2605 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title. 2606 * 2607 * Uses `<image><title>` or `<image><dc:title>` 2608 * 2609 * @return string|null 2610 */ 2611 public function get_image_title() 2612 { 2613 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) 2614 { 2615 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2616 } 2617 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) 2618 { 2619 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2620 } 2621 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) 2622 { 2623 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2624 } 2625 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) 2626 { 2627 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2628 } 2629 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) 2630 { 2631 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 2632 } 2633 else 2634 { 2635 return null; 2636 } 2637 } 2638 2639 /** 2640 * Get the feed logo's URL 2641 * 2642 * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to 2643 * have a "feed logo" URL. This points directly to the image itself. 2644 * 2645 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`, 2646 * `<image><title>` or `<image><dc:title>` 2647 * 2648 * @return string|null 2649 */ 2650 public function get_image_url() 2651 { 2652 if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) 2653 { 2654 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); 2655 } 2656 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) 2657 { 2658 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2659 } 2660 elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) 2661 { 2662 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2663 } 2664 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url')) 2665 { 2666 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2667 } 2668 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url')) 2669 { 2670 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2671 } 2672 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url')) 2673 { 2674 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2675 } 2676 else 2677 { 2678 return null; 2679 } 2680 } 2681 2682 /** 2683 * Get the feed logo's link 2684 * 2685 * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This 2686 * points to a human-readable page that the image should link to. 2687 * 2688 * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`, 2689 * `<image><title>` or `<image><dc:title>` 2690 * 2691 * @return string|null 2692 */ 2693 public function get_image_link() 2694 { 2695 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) 2696 { 2697 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2698 } 2699 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) 2700 { 2701 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2702 } 2703 elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) 2704 { 2705 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 2706 } 2707 else 2708 { 2709 return null; 2710 } 2711 } 2712 2713 /** 2714 * Get the feed logo's link 2715 * 2716 * RSS 2.0 feeds are allowed to have a "feed logo" width. 2717 * 2718 * Uses `<image><width>` or defaults to 88.0 if no width is specified and 2719 * the feed is an RSS 2.0 feed. 2720 * 2721 * @return int|float|null 2722 */ 2723 public function get_image_width() 2724 { 2725 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width')) 2726 { 2727 return round($return[0]['data']); 2728 } 2729 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url')) 2730 { 2731 return 88.0; 2732 } 2733 else 2734 { 2735 return null; 2736 } 2737 } 2738 2739 /** 2740 * Get the feed logo's height 2741 * 2742 * RSS 2.0 feeds are allowed to have a "feed logo" height. 2743 * 2744 * Uses `<image><height>` or defaults to 31.0 if no height is specified and 2745 * the feed is an RSS 2.0 feed. 2746 * 2747 * @return int|float|null 2748 */ 2749 public function get_image_height() 2750 { 2751 if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height')) 2752 { 2753 return round($return[0]['data']); 2754 } 2755 elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url')) 2756 { 2757 return 31.0; 2758 } 2759 else 2760 { 2761 return null; 2762 } 2763 } 2764 2765 /** 2766 * Get the number of items in the feed 2767 * 2768 * This is well-suited for {@link http://php.net/for for()} loops with 2769 * {@see get_item()} 2770 * 2771 * @param int $max Maximum value to return. 0 for no limit 2772 * @return int Number of items in the feed 2773 */ 2774 public function get_item_quantity($max = 0) 2775 { 2776 $max = (int) $max; 2777 $qty = count($this->get_items()); 2778 if ($max === 0) 2779 { 2780 return $qty; 2781 } 2782 else 2783 { 2784 return ($qty > $max) ? $max : $qty; 2785 } 2786 } 2787 2788 /** 2789 * Get a single item from the feed 2790 * 2791 * This is better suited for {@link http://php.net/for for()} loops, whereas 2792 * {@see get_items()} is better suited for 2793 * {@link http://php.net/foreach foreach()} loops. 2794 * 2795 * @see get_item_quantity() 2796 * @since Beta 2 2797 * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1 2798 * @return SimplePie_Item|null 2799 */ 2800 public function get_item($key = 0) 2801 { 2802 $items = $this->get_items(); 2803 if (isset($items[$key])) 2804 { 2805 return $items[$key]; 2806 } 2807 else 2808 { 2809 return null; 2810 } 2811 } 2812 2813 /** 2814 * Get all items from the feed 2815 * 2816 * This is better suited for {@link http://php.net/for for()} loops, whereas 2817 * {@see get_items()} is better suited for 2818 * {@link http://php.net/foreach foreach()} loops. 2819 * 2820 * @see get_item_quantity 2821 * @since Beta 2 2822 * @param int $start Index to start at 2823 * @param int $end Number of items to return. 0 for all items after `$start` 2824 * @return array|null List of {@see SimplePie_Item} objects 2825 */ 2826 public function get_items($start = 0, $end = 0) 2827 { 2828 if (!isset($this->data['items'])) 2829 { 2830 if (!empty($this->multifeed_objects)) 2831 { 2832 $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit); 2833 } 2834 else 2835 { 2836 $this->data['items'] = array(); 2837 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry')) 2838 { 2839 $keys = array_keys($items); 2840 foreach ($keys as $key) 2841 { 2842 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key])); 2843 } 2844 } 2845 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry')) 2846 { 2847 $keys = array_keys($items); 2848 foreach ($keys as $key) 2849 { 2850 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key])); 2851 } 2852 } 2853 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item')) 2854 { 2855 $keys = array_keys($items); 2856 foreach ($keys as $key) 2857 { 2858 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key])); 2859 } 2860 } 2861 if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item')) 2862 { 2863 $keys = array_keys($items); 2864 foreach ($keys as $key) 2865 { 2866 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key])); 2867 } 2868 } 2869 if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item')) 2870 { 2871 $keys = array_keys($items); 2872 foreach ($keys as $key) 2873 { 2874 $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key])); 2875 } 2876 } 2877 } 2878 } 2879 2880 if (!empty($this->data['items'])) 2881 { 2882 // If we want to order it by date, check if all items have a date, and then sort it 2883 if ($this->order_by_date && empty($this->multifeed_objects)) 2884 { 2885 if (!isset($this->data['ordered_items'])) 2886 { 2887 $do_sort = true; 2888 foreach ($this->data['items'] as $item) 2889 { 2890 if (!$item->get_date('U')) 2891 { 2892 $do_sort = false; 2893 break; 2894 } 2895 } 2896 $item = null; 2897 $this->data['ordered_items'] = $this->data['items']; 2898 if ($do_sort) 2899 { 2900 usort($this->data['ordered_items'], array(get_class($this), 'sort_items')); 2901 } 2902 } 2903 $items = $this->data['ordered_items']; 2904 } 2905 else 2906 { 2907 $items = $this->data['items']; 2908 } 2909 2910 // Slice the data as desired 2911 if ($end === 0) 2912 { 2913 return array_slice($items, $start); 2914 } 2915 else 2916 { 2917 return array_slice($items, $start, $end); 2918 } 2919 } 2920 else 2921 { 2922 return array(); 2923 } 2924 } 2925 2926 /** 2927 * Set the favicon handler 2928 * 2929 * @deprecated Use your own favicon handling instead 2930 */ 2931 public function set_favicon_handler($page = false, $qs = 'i') 2932 { 2933 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING; 2934 trigger_error('Favicon handling has been removed, please use your own handling', $level); 2935 return false; 2936 } 2937 2938 /** 2939 * Get the favicon for the current feed 2940 * 2941 * @deprecated Use your own favicon handling instead 2942 */ 2943 public function get_favicon() 2944 { 2945 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING; 2946 trigger_error('Favicon handling has been removed, please use your own handling', $level); 2947 2948 if (($url = $this->get_link()) !== null) 2949 { 2950 return 'http://g.etfv.co/' . urlencode($url); 2951 } 2952 2953 return false; 2954 } 2955 2956 /** 2957 * Magic method handler 2958 * 2959 * @param string $method Method name 2960 * @param array $args Arguments to the method 2961 * @return mixed 2962 */ 2963 public function __call($method, $args) 2964 { 2965 if (strpos($method, 'subscribe_') === 0) 2966 { 2967 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING; 2968 trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level); 2969 return ''; 2970 } 2971 if ($method === 'enable_xml_dump') 2972 { 2973 $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING; 2974 trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level); 2975 return false; 2976 } 2977 2978 $class = get_class($this); 2979 $trace = debug_backtrace(); 2980 $file = $trace[0]['file']; 2981 $line = $trace[0]['line']; 2982 trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR); 2983 } 2984 2985 /** 2986 * Sorting callback for items 2987 * 2988 * @access private 2989 * @param SimplePie $a 2990 * @param SimplePie $b 2991 * @return boolean 2992 */ 2993 public static function sort_items($a, $b) 2994 { 2995 return $a->get_date('U') <= $b->get_date('U'); 2996 } 2997 2998 /** 2999 * Merge items from several feeds into one 3000 * 3001 * If you're merging multiple feeds together, they need to all have dates 3002 * for the items or else SimplePie will refuse to sort them. 3003 * 3004 * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings 3005 * @param array $urls List of SimplePie feed objects to merge 3006 * @param int $start Starting item 3007 * @param int $end Number of items to return 3008 * @param int $limit Maximum number of items per feed 3009 * @return array 3010 */ 3011 public static function merge_items($urls, $start = 0, $end = 0, $limit = 0) 3012 { 3013 if (is_array($urls) && sizeof($urls) > 0) 3014 { 3015 $items = array(); 3016 foreach ($urls as $arg) 3017 { 3018 if ($arg instanceof SimplePie) 3019 { 3020 $items = array_merge($items, $arg->get_items(0, $limit)); 3021 } 3022 else 3023 { 3024 trigger_error('Arguments must be SimplePie objects', E_USER_WARNING); 3025 } 3026 } 3027 3028 $do_sort = true; 3029 foreach ($items as $item) 3030 { 3031 if (!$item->get_date('U')) 3032 { 3033 $do_sort = false; 3034 break; 3035 } 3036 } 3037 $item = null; 3038 if ($do_sort) 3039 { 3040 usort($items, array(get_class($urls[0]), 'sort_items')); 3041 } 3042 3043 if ($end === 0) 3044 { 3045 return array_slice($items, $start); 3046 } 3047 else 3048 { 3049 return array_slice($items, $start, $end); 3050 } 3051 } 3052 else 3053 { 3054 trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING); 3055 return array(); 3056 } 3057 } 3058 } 3059 3060 /** 3061 * Manages all author-related data 3062 * 3063 * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()} 3064 * 3065 * This class can be overloaded with {@see SimplePie::set_author_class()} 3066 * 3067 * @package SimplePie 3068 * @subpackage API 3069 */ 3070 class SimplePie_Author 3071 { 3072 /** 3073 * Author's name 3074 * 3075 * @var string 3076 * @see get_name() 3077 */ 3078 var $name; 3079 3080 /** 3081 * Author's link 3082 * 3083 * @var string 3084 * @see get_link() 3085 */ 3086 var $link; 3087 3088 /** 3089 * Author's email address 3090 * 3091 * @var string 3092 * @see get_email() 3093 */ 3094 var $email; 3095 3096 /** 3097 * Constructor, used to input the data 3098 * 3099 * @param string $name 3100 * @param string $link 3101 * @param string $email 3102 */ 3103 public function __construct($name = null, $link = null, $email = null) 3104 { 3105 $this->name = $name; 3106 $this->link = $link; 3107 $this->email = $email; 3108 } 3109 3110 /** 3111 * String-ified version 3112 * 3113 * @return string 3114 */ 3115 public function __toString() 3116 { 3117 // There is no $this->data here 3118 return md5(serialize($this)); 3119 } 3120 3121 /** 3122 * Author's name 3123 * 3124 * @return string|null 3125 */ 3126 public function get_name() 3127 { 3128 if ($this->name !== null) 3129 { 3130 return $this->name; 3131 } 3132 else 3133 { 3134 return null; 3135 } 3136 } 3137 3138 /** 3139 * Author's link 3140 * 3141 * @return string|null 3142 */ 3143 public function get_link() 3144 { 3145 if ($this->link !== null) 3146 { 3147 return $this->link; 3148 } 3149 else 3150 { 3151 return null; 3152 } 3153 } 3154 3155 /** 3156 * Author's email address 3157 * 3158 * @return string|null 3159 */ 3160 public function get_email() 3161 { 3162 if ($this->email !== null) 3163 { 3164 return $this->email; 3165 } 3166 else 3167 { 3168 return null; 3169 } 3170 } 3171 } 3172 3173 /** 3174 * Base for cache objects 3175 * 3176 * Classes to be used with {@see SimplePie_Cache::register()} are expected 3177 * to implement this interface. 3178 * 3179 * @package SimplePie 3180 * @subpackage Caching 3181 */ 3182 interface SimplePie_Cache_Base 3183 { 3184 /** 3185 * Feed cache type 3186 * 3187 * @var string 3188 */ 3189 const TYPE_FEED = 'spc'; 3190 3191 /** 3192 * Image cache type 3193 * 3194 * @var string 3195 */ 3196 const TYPE_IMAGE = 'spi'; 3197 3198 /** 3199 * Create a new cache object 3200 * 3201 * @param string $location Location string (from SimplePie::$cache_location) 3202 * @param string $name Unique ID for the cache 3203 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data 3204 */ 3205 public function __construct($location, $name, $type); 3206 3207 /** 3208 * Save data to the cache 3209 * 3210 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property 3211 * @return bool Successfulness 3212 */ 3213 public function save($data); 3214 3215 /** 3216 * Retrieve the data saved to the cache 3217 * 3218 * @return array Data for SimplePie::$data 3219 */ 3220 public function load(); 3221 3222 /** 3223 * Retrieve the last modified time for the cache 3224 * 3225 * @return int Timestamp 3226 */ 3227 public function mtime(); 3228 3229 /** 3230 * Set the last modified time to the current time 3231 * 3232 * @return bool Success status 3233 */ 3234 public function touch(); 3235 3236 /** 3237 * Remove the cache 3238 * 3239 * @return bool Success status 3240 */ 3241 public function unlink(); 3242 } 3243 3244 /** 3245 * Base class for database-based caches 3246 * 3247 * @package SimplePie 3248 * @subpackage Caching 3249 */ 3250 abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base 3251 { 3252 /** 3253 * Helper for database conversion 3254 * 3255 * Converts a given {@see SimplePie} object into data to be stored 3256 * 3257 * @param SimplePie $data 3258 * @return array First item is the serialized data for storage, second item is the unique ID for this item 3259 */ 3260 protected static function prepare_simplepie_object_for_cache($data) 3261 { 3262 $items = $data->get_items(); 3263 $items_by_id = array(); 3264 3265 if (!empty($items)) 3266 { 3267 foreach ($items as $item) 3268 { 3269 $items_by_id[$item->get_id()] = $item; 3270 } 3271 3272 if (count($items_by_id) !== count($items)) 3273 { 3274 $items_by_id = array(); 3275 foreach ($items as $item) 3276 { 3277 $items_by_id[$item->get_id(true)] = $item; 3278 } 3279 } 3280 3281 if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0])) 3282 { 3283 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]; 3284 } 3285 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0])) 3286 { 3287 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]; 3288 } 3289 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0])) 3290 { 3291 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]; 3292 } 3293 elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0])) 3294 { 3295 $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]; 3296 } 3297 else 3298 { 3299 $channel = null; 3300 } 3301 3302 if ($channel !== null) 3303 { 3304 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'])) 3305 { 3306 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']); 3307 } 3308 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry'])) 3309 { 3310 unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']); 3311 } 3312 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])) 3313 { 3314 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']); 3315 } 3316 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])) 3317 { 3318 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']); 3319 } 3320 if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item'])) 3321 { 3322 unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']); 3323 } 3324 } 3325 if (isset($data->data['items'])) 3326 { 3327 unset($data->data['items']); 3328 } 3329 if (isset($data->data['ordered_items'])) 3330 { 3331 unset($data->data['ordered_items']); 3332 } 3333 } 3334 return array(serialize($data->data), $items_by_id); 3335 } 3336 } 3337 3338 /** 3339 * Caches data to the filesystem 3340 * 3341 * @package SimplePie 3342 * @subpackage Caching 3343 */ 3344 class SimplePie_Cache_File implements SimplePie_Cache_Base 3345 { 3346 /** 3347 * Location string 3348 * 3349 * @see SimplePie::$cache_location 3350 * @var string 3351 */ 3352 protected $location; 3353 3354 /** 3355 * Filename 3356 * 3357 * @var string 3358 */ 3359 protected $filename; 3360 3361 /** 3362 * File extension 3363 * 3364 * @var string 3365 */ 3366 protected $extension; 3367 3368 /** 3369 * File path 3370 * 3371 * @var string 3372 */ 3373 protected $name; 3374 3375 /** 3376 * Create a new cache object 3377 * 3378 * @param string $location Location string (from SimplePie::$cache_location) 3379 * @param string $name Unique ID for the cache 3380 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data 3381 */ 3382 public function __construct($location, $name, $type) 3383 { 3384 $this->location = $location; 3385 $this->filename = $name; 3386 $this->extension = $type; 3387 $this->name = "$this->location/$this->filename.$this->extension"; 3388 } 3389 3390 /** 3391 * Save data to the cache 3392 * 3393 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property 3394 * @return bool Successfulness 3395 */ 3396 public function save($data) 3397 { 3398 if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location)) 3399 { 3400 if ($data instanceof SimplePie) 3401 { 3402 $data = $data->data; 3403 } 3404 3405 $data = serialize($data); 3406 return (bool) file_put_contents($this->name, $data); 3407 } 3408 return false; 3409 } 3410 3411 /** 3412 * Retrieve the data saved to the cache 3413 * 3414 * @return array Data for SimplePie::$data 3415 */ 3416 public function load() 3417 { 3418 if (file_exists($this->name) && is_readable($this->name)) 3419 { 3420 return unserialize(file_get_contents($this->name)); 3421 } 3422 return false; 3423 } 3424 3425 /** 3426 * Retrieve the last modified time for the cache 3427 * 3428 * @return int Timestamp 3429 */ 3430 public function mtime() 3431 { 3432 if (file_exists($this->name)) 3433 { 3434 return filemtime($this->name); 3435 } 3436 return false; 3437 } 3438 3439 /** 3440 * Set the last modified time to the current time 3441 * 3442 * @return bool Success status 3443 */ 3444 public function touch() 3445 { 3446 if (file_exists($this->name)) 3447 { 3448 return touch($this->name); 3449 } 3450 return false; 3451 } 3452 3453 /** 3454 * Remove the cache 3455 * 3456 * @return bool Success status 3457 */ 3458 public function unlink() 3459 { 3460 if (file_exists($this->name)) 3461 { 3462 return unlink($this->name); 3463 } 3464 return false; 3465 } 3466 } 3467 3468 /** 3469 * Caches data to memcache 3470 * 3471 * Registered for URLs with the "memcache" protocol 3472 * 3473 * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will 3474 * connect to memcache on `localhost` on port 11211. All tables will be 3475 * prefixed with `sp_` and data will expire after 3600 seconds 3476 * 3477 * @package SimplePie 3478 * @subpackage Caching 3479 * @uses Memcache 3480 */ 3481 class SimplePie_Cache_Memcache implements SimplePie_Cache_Base 3482 { 3483 /** 3484 * Memcache instance 3485 * 3486 * @var Memcache 3487 */ 3488 protected $cache; 3489 3490 /** 3491 * Options 3492 * 3493 * @var array 3494 */ 3495 protected $options; 3496 3497 /** 3498 * Cache name 3499 * 3500 * @var string 3501 */ 3502 protected $name; 3503 3504 /** 3505 * Create a new cache object 3506 * 3507 * @param string $location Location string (from SimplePie::$cache_location) 3508 * @param string $name Unique ID for the cache 3509 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data 3510 */ 3511 public function __construct($location, $name, $type) 3512 { 3513 $this->options = array( 3514 'host' => '127.0.0.1', 3515 'port' => 11211, 3516 'extras' => array( 3517 'timeout' => 3600, // one hour 3518 'prefix' => 'simplepie_', 3519 ), 3520 ); 3521 $parsed = SimplePie_Cache::parse_URL($location); 3522 $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host']; 3523 $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port']; 3524 $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']); 3525 $this->name = $this->options['extras']['prefix'] . md5("$name:$type"); 3526 3527 $this->cache = new Memcache(); 3528 $this->cache->addServer($this->options['host'], (int) $this->options['port']); 3529 } 3530 3531 /** 3532 * Save data to the cache 3533 * 3534 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property 3535 * @return bool Successfulness 3536 */ 3537 public function save($data) 3538 { 3539 if ($data instanceof SimplePie) 3540 { 3541 $data = $data->data; 3542 } 3543 return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']); 3544 } 3545 3546 /** 3547 * Retrieve the data saved to the cache 3548 * 3549 * @return array Data for SimplePie::$data 3550 */ 3551 public function load() 3552 { 3553 $data = $this->cache->get($this->name); 3554 3555 if ($data !== false) 3556 { 3557 return unserialize($data); 3558 } 3559 return false; 3560 } 3561 3562 /** 3563 * Retrieve the last modified time for the cache 3564 * 3565 * @return int Timestamp 3566 */ 3567 public function mtime() 3568 { 3569 $data = $this->cache->get($this->name); 3570 3571 if ($data !== false) 3572 { 3573 // essentially ignore the mtime because Memcache expires on it's own 3574 return time(); 3575 } 3576 3577 return false; 3578 } 3579 3580 /** 3581 * Set the last modified time to the current time 3582 * 3583 * @return bool Success status 3584 */ 3585 public function touch() 3586 { 3587 $data = $this->cache->get($this->name); 3588 3589 if ($data !== false) 3590 { 3591 return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration); 3592 } 3593 3594 return false; 3595 } 3596 3597 /** 3598 * Remove the cache 3599 * 3600 * @return bool Success status 3601 */ 3602 public function unlink() 3603 { 3604 return $this->cache->delete($this->name, 0); 3605 } 3606 } 3607 3608 /** 3609 * Caches data to a MySQL database 3610 * 3611 * Registered for URLs with the "mysql" protocol 3612 * 3613 * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will 3614 * connect to the `mydb` database on `localhost` on port 3306, with the user 3615 * `root` and the password `password`. All tables will be prefixed with `sp_` 3616 * 3617 * @package SimplePie 3618 * @subpackage Caching 3619 */ 3620 class SimplePie_Cache_MySQL extends SimplePie_Cache_DB 3621 { 3622 /** 3623 * PDO instance 3624 * 3625 * @var PDO 3626 */ 3627 protected $mysql; 3628 3629 /** 3630 * Options 3631 * 3632 * @var array 3633 */ 3634 protected $options; 3635 3636 /** 3637 * Cache ID 3638 * 3639 * @var string 3640 */ 3641 protected $id; 3642 3643 /** 3644 * Create a new cache object 3645 * 3646 * @param string $location Location string (from SimplePie::$cache_location) 3647 * @param string $name Unique ID for the cache 3648 * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data 3649 */ 3650 public function __construct($location, $name, $type) 3651 { 3652 $this->options = array( 3653 'user' => null, 3654 'pass' => null, 3655 'host' => '127.0.0.1', 3656 'port' => '3306', 3657 'path' => '', 3658 'extras' => array( 3659 'prefix' => '', 3660 ), 3661 ); 3662 $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location)); 3663 3664 // Path is prefixed with a "/" 3665 $this->options['dbname'] = substr($this->options['path'], 1); 3666 3667 try 3668 { 3669 $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')); 3670 } 3671 catch (PDOException $e) 3672 { 3673 $this->mysql = null; 3674 return; 3675 } 3676 3677 $this->id = $name . $type; 3678 3679 if (!$query = $this->mysql->query('SHOW TABLES')) 3680 { 3681 $this->mysql = null; 3682 return; 3683 } 3684 3685 $db = array(); 3686 while ($row = $query->fetchColumn()) 3687 { 3688 $db[] = $row; 3689 } 3690 3691 if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db)) 3692 { 3693 $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))'); 3694 if ($query === false) 3695 { 3696 $this->mysql = null; 3697 } 3698 } 3699 3700 if (!in_array($this->options['extras']['prefix'] . 'items', $db)) 3701 { 3702 $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))'); 3703 if ($query === false) 3704 { 3705 $this->mysql = null; 3706 } 3707 } 3708 } 3709 3710 /** 3711 * Save data to the cache 3712 * 3713 * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property 3714 * @return bool Successfulness 3715 */ 3716 public function save($data) 3717 { 3718 if ($this->mysql === null) 3719 { 3720 return false; 3721 } 3722 3723 if ($data instanceof SimplePie) 3724 { 3725 $data = clone $data; 3726 3727 $prepared = self::prepare_simplepie_object_for_cache($data); 3728 3729 $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed'); 3730 $query->bindValue(':feed', $this->id); 3731 if ($query->execute()) 3732 { 3733 if ($query->fetchColumn() > 0) 3734 { 3735 $items = count($prepared[1]); 3736 if ($items) 3737 { 3738 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed'; 3739 $query = $this->mysql->prepare($sql); 3740 $query->bindValue(':items', $items); 3741 } 3742 else 3743 { 3744 $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed'; 3745 $query = $this->mysql->prepare($sql); 3746 } 3747 3748 $query->bindValue(':data', $prepared[0]); 3749 $query->bindValue(':time', time()); 3750 $query->bindValue(':feed', $this->id); 3751 if (!$query->execute()) 3752 { 3753 return false; 3754 } 3755 } 3756 else 3757 { 3758 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)'); 3759 $query->bindValue(':feed', $this->id); 3760 $query->bindValue(':count', count($prepared[1])); 3761 $query->bindValue(':data', $prepared[0]); 3762 $query->bindValue(':time', time()); 3763 if (!$query->execute()) 3764 { 3765 return false; 3766 } 3767 } 3768 3769 $ids = array_keys($prepared[1]); 3770 if (!empty($ids)) 3771 { 3772 foreach ($ids as $id) 3773 { 3774 $database_ids[] = $this->mysql->quote($id); 3775 } 3776 3777 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed'); 3778 $query->bindValue(':feed', $this->id); 3779 3780 if ($query->execute()) 3781 { 3782 $existing_ids = array(); 3783 while ($row = $query->fetchColumn()) 3784 { 3785 $existing_ids[] = $row; 3786 } 3787 3788 $new_ids = array_diff($ids, $existing_ids); 3789 3790 foreach ($new_ids as $new_id) 3791 { 3792 if (!($date = $prepared[1][$new_id]->get_date('U'))) 3793 { 3794 $date = time(); 3795 } 3796 3797 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)'); 3798 $query->bindValue(':feed', $this->id); 3799 $query->bindValue(':id', $new_id); 3800 $query->bindValue(':data', serialize($prepared[1][$new_id]->data)); 3801 $query->bindValue(':date', $date); 3802 if (!$query->execute()) 3803 { 3804 return false; 3805 } 3806 } 3807 return true; 3808 } 3809 } 3810 else 3811 { 3812 return true; 3813 } 3814 } 3815 } 3816 else 3817 { 3818 $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed'); 3819 $query->bindValue(':feed', $this->id); 3820 if ($query->execute()) 3821 { 3822 if ($query->rowCount() > 0) 3823 { 3824 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed'); 3825 $query->bindValue(':data', serialize($data)); 3826 $query->bindValue(':time', time()); 3827 $query->bindValue(':feed', $this->id); 3828 if ($this->execute()) 3829 { 3830 return true; 3831 } 3832 } 3833 else 3834 { 3835 $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)'); 3836 $query->bindValue(':id', $this->id); 3837 $query->bindValue(':data', serialize($data)); 3838 $query->bindValue(':time', time()); 3839 if ($query->execute()) 3840 { 3841 return true; 3842 } 3843 } 3844 } 3845 } 3846 return false; 3847 } 3848 3849 /** 3850 * Retrieve the data saved to the cache 3851 * 3852 * @return array Data for SimplePie::$data 3853 */ 3854 public function load() 3855 { 3856 if ($this->mysql === null) 3857 { 3858 return false; 3859 } 3860 3861 $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); 3862 $query->bindValue(':id', $this->id); 3863 if ($query->execute() && ($row = $query->fetch())) 3864 { 3865 $data = unserialize($row[1]); 3866 3867 if (isset($this->options['items'][0])) 3868 { 3869 $items = (int) $this->options['items'][0]; 3870 } 3871 else 3872 { 3873 $items = (int) $row[0]; 3874 } 3875 3876 if ($items !== 0) 3877 { 3878 if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0])) 3879 { 3880 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]; 3881 } 3882 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0])) 3883 { 3884 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]; 3885 } 3886 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0])) 3887 { 3888 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]; 3889 } 3890 elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0])) 3891 { 3892 $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]; 3893 } 3894 else 3895 { 3896 $feed = null; 3897 } 3898 3899 if ($feed !== null) 3900 { 3901 $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC'; 3902 if ($items > 0) 3903 { 3904 $sql .= ' LIMIT ' . $items; 3905 } 3906 3907 $query = $this->mysql->prepare($sql); 3908 $query->bindValue(':feed', $this->id); 3909 if ($query->execute()) 3910 { 3911 while ($row = $query->fetchColumn()) 3912 { 3913 $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row); 3914 } 3915 } 3916 else 3917 { 3918 return false; 3919 } 3920 } 3921 } 3922 return $data; 3923 } 3924 return false; 3925 } 3926 3927 /** 3928 * Retrieve the last modified time for the cache 3929 * 3930 * @return int Timestamp 3931 */ 3932 public function mtime() 3933 { 3934 if ($this->mysql === null) 3935 { 3936 return false; 3937 } 3938 3939 $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); 3940 $query->bindValue(':id', $this->id); 3941 if ($query->execute() && ($time = $query->fetchColumn())) 3942 { 3943 return $time; 3944 } 3945 else 3946 { 3947 return false; 3948 } 3949 } 3950 3951 /** 3952 * Set the last modified time to the current time 3953 * 3954 * @return bool Success status 3955 */ 3956 public function touch() 3957 { 3958 if ($this->mysql === null) 3959 { 3960 return false; 3961 } 3962 3963 $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id'); 3964 $query->bindValue(':time', time()); 3965 $query->bindValue(':id', $this->id); 3966 if ($query->execute() && $query->rowCount() > 0) 3967 { 3968 return true; 3969 } 3970 else 3971 { 3972 return false; 3973 } 3974 } 3975 3976 /** 3977 * Remove the cache 3978 * 3979 * @return bool Success status 3980 */ 3981 public function unlink() 3982 { 3983 if ($this->mysql === null) 3984 { 3985 return false; 3986 } 3987 3988 $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id'); 3989 $query->bindValue(':id', $this->id); 3990 $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id'); 3991 $query2->bindValue(':id', $this->id); 3992 if ($query->execute() && $query2->execute()) 3993 { 3994 return true; 3995 } 3996 else 3997 { 3998 return false; 3999 } 4000 } 4001 } 4002 4003 /** 4004 * Used to create cache objects 4005 * 4006 * This class can be overloaded with {@see SimplePie::set_cache_class()}, 4007 * although the preferred way is to create your own handler 4008 * via {@see register()} 4009 * 4010 * @package SimplePie 4011 * @subpackage Caching 4012 */ 4013 class SimplePie_Cache 4014 { 4015 /** 4016 * Cache handler classes 4017 * 4018 * These receive 3 parameters to their constructor, as documented in 4019 * {@see register()} 4020 * @var array 4021 */ 4022 protected static $handlers = array( 4023 'mysql' => 'SimplePie_Cache_MySQL', 4024 'memcache' => 'SimplePie_Cache_Memcache', 4025 ); 4026 4027 /** 4028 * Don't call the constructor. Please. 4029 */ 4030 private function __construct() { } 4031 4032 /** 4033 * Create a new SimplePie_Cache object 4034 * 4035 * @param string $location URL location (scheme is used to determine handler) 4036 * @param string $filename Unique identifier for cache object 4037 * @param string $extension 'spi' or 'spc' 4038 * @return SimplePie_Cache_Base Type of object depends on scheme of `$location` 4039 */ 4040 public static function get_handler($location, $filename, $extension) 4041 { 4042 $type = explode(':', $location, 2); 4043 $type = $type[0]; 4044 if (!empty(self::$handlers[$type])) 4045 { 4046 $class = self::$handlers[$type]; 4047 return new $class($location, $filename, $extension); 4048 } 4049 4050 return new SimplePie_Cache_File($location, $filename, $extension); 4051 } 4052 4053 /** 4054 * Create a new SimplePie_Cache object 4055 * 4056 * @deprecated Use {@see get_handler} instead 4057 */ 4058 public function create($location, $filename, $extension) 4059 { 4060 trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED); 4061 return self::get_handler($location, $filename, $extension); 4062 } 4063 4064 /** 4065 * Register a handler 4066 * 4067 * @param string $type DSN type to register for 4068 * @param string $class Name of handler class. Must implement SimplePie_Cache_Base 4069 */ 4070 public static function register($type, $class) 4071 { 4072 self::$handlers[$type] = $class; 4073 } 4074 4075 /** 4076 * Parse a URL into an array 4077 * 4078 * @param string $url 4079 * @return array 4080 */ 4081 public static function parse_URL($url) 4082 { 4083 $params = parse_url($url); 4084 $params['extras'] = array(); 4085 if (isset($params['query'])) 4086 { 4087 parse_str($params['query'], $params['extras']); 4088 } 4089 return $params; 4090 } 4091 } 4092 4093 /** 4094 * Handles `<media:text>` captions as defined in Media RSS. 4095 * 4096 * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()} 4097 * 4098 * This class can be overloaded with {@see SimplePie::set_caption_class()} 4099 * 4100 * @package SimplePie 4101 * @subpackage API 4102 */ 4103 class SimplePie_Caption 4104 { 4105 /** 4106 * Content type 4107 * 4108 * @var string 4109 * @see get_type() 4110 */ 4111 var $type; 4112 4113 /** 4114 * Language 4115 * 4116 * @var string 4117 * @see get_language() 4118 */ 4119 var $lang; 4120 4121 /** 4122 * Start time 4123 * 4124 * @var string 4125 * @see get_starttime() 4126 */ 4127 var $startTime; 4128 4129 /** 4130 * End time 4131 * 4132 * @var string 4133 * @see get_endtime() 4134 */ 4135 var $endTime; 4136 4137 /** 4138 * Caption text 4139 * 4140 * @var string 4141 * @see get_text() 4142 */ 4143 var $text; 4144 4145 /** 4146 * Constructor, used to input the data 4147 * 4148 * For documentation on all the parameters, see the corresponding 4149 * properties and their accessors 4150 */ 4151 public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null) 4152 { 4153 $this->type = $type; 4154 $this->lang = $lang; 4155 $this->startTime = $startTime; 4156 $this->endTime = $endTime; 4157 $this->text = $text; 4158 } 4159 4160 /** 4161 * String-ified version 4162 * 4163 * @return string 4164 */ 4165 public function __toString() 4166 { 4167 // There is no $this->data here 4168 return md5(serialize($this)); 4169 } 4170 4171 /** 4172 * Get the end time 4173 * 4174 * @return string|null Time in the format 'hh:mm:ss.SSS' 4175 */ 4176 public function get_endtime() 4177 { 4178 if ($this->endTime !== null) 4179 { 4180 return $this->endTime; 4181 } 4182 else 4183 { 4184 return null; 4185 } 4186 } 4187 4188 /** 4189 * Get the language 4190 * 4191 * @link http://tools.ietf.org/html/rfc3066 4192 * @return string|null Language code as per RFC 3066 4193 */ 4194 public function get_language() 4195 { 4196 if ($this->lang !== null) 4197 { 4198 return $this->lang; 4199 } 4200 else 4201 { 4202 return null; 4203 } 4204 } 4205 4206 /** 4207 * Get the start time 4208 * 4209 * @return string|null Time in the format 'hh:mm:ss.SSS' 4210 */ 4211 public function get_starttime() 4212 { 4213 if ($this->startTime !== null) 4214 { 4215 return $this->startTime; 4216 } 4217 else 4218 { 4219 return null; 4220 } 4221 } 4222 4223 /** 4224 * Get the text of the caption 4225 * 4226 * @return string|null 4227 */ 4228 public function get_text() 4229 { 4230 if ($this->text !== null) 4231 { 4232 return $this->text; 4233 } 4234 else 4235 { 4236 return null; 4237 } 4238 } 4239 4240 /** 4241 * Get the content type (not MIME type) 4242 * 4243 * @return string|null Either 'text' or 'html' 4244 */ 4245 public function get_type() 4246 { 4247 if ($this->type !== null) 4248 { 4249 return $this->type; 4250 } 4251 else 4252 { 4253 return null; 4254 } 4255 } 4256 } 4257 4258 /** 4259 * Manages all category-related data 4260 * 4261 * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()} 4262 * 4263 * This class can be overloaded with {@see SimplePie::set_category_class()} 4264 * 4265 * @package SimplePie 4266 * @subpackage API 4267 */ 4268 class SimplePie_Category 4269 { 4270 /** 4271 * Category identifier 4272 * 4273 * @var string 4274 * @see get_term 4275 */ 4276 var $term; 4277 4278 /** 4279 * Categorization scheme identifier 4280 * 4281 * @var string 4282 * @see get_scheme() 4283 */ 4284 var $scheme; 4285 4286 /** 4287 * Human readable label 4288 * 4289 * @var string 4290 * @see get_label() 4291 */ 4292 var $label; 4293 4294 /** 4295 * Constructor, used to input the data 4296 * 4297 * @param string $term 4298 * @param string $scheme 4299 * @param string $label 4300 */ 4301 public function __construct($term = null, $scheme = null, $label = null) 4302 { 4303 $this->term = $term; 4304 $this->scheme = $scheme; 4305 $this->label = $label; 4306 } 4307 4308 /** 4309 * String-ified version 4310 * 4311 * @return string 4312 */ 4313 public function __toString() 4314 { 4315 // There is no $this->data here 4316 return md5(serialize($this)); 4317 } 4318 4319 /** 4320 * Get the category identifier 4321 * 4322 * @return string|null 4323 */ 4324 public function get_term() 4325 { 4326 if ($this->term !== null) 4327 { 4328 return $this->term; 4329 } 4330 else 4331 { 4332 return null; 4333 } 4334 } 4335 4336 /** 4337 * Get the categorization scheme identifier 4338 * 4339 * @return string|null 4340 */ 4341 public function get_scheme() 4342 { 4343 if ($this->scheme !== null) 4344 { 4345 return $this->scheme; 4346 } 4347 else 4348 { 4349 return null; 4350 } 4351 } 4352 4353 /** 4354 * Get the human readable label 4355 * 4356 * @return string|null 4357 */ 4358 public function get_label() 4359 { 4360 if ($this->label !== null) 4361 { 4362 return $this->label; 4363 } 4364 else 4365 { 4366 return $this->get_term(); 4367 } 4368 } 4369 } 4370 4371 /** 4372 * Content-type sniffing 4373 * 4374 * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06 4375 * 4376 * This is used since we can't always trust Content-Type headers, and is based 4377 * upon the HTML5 parsing rules. 4378 * 4379 * 4380 * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()} 4381 * 4382 * @package SimplePie 4383 * @subpackage HTTP 4384 */ 4385 class SimplePie_Content_Type_Sniffer 4386 { 4387 /** 4388 * File object 4389 * 4390 * @var SimplePie_File 4391 */ 4392 var $file; 4393 4394 /** 4395 * Create an instance of the class with the input file 4396 * 4397 * @param SimplePie_Content_Type_Sniffer $file Input file 4398 */ 4399 public function __construct($file) 4400 { 4401 $this->file = $file; 4402 } 4403 4404 /** 4405 * Get the Content-Type of the specified file 4406 * 4407 * @return string Actual Content-Type 4408 */ 4409 public function get_type() 4410 { 4411 if (isset($this->file->headers['content-type'])) 4412 { 4413 if (!isset($this->file->headers['content-encoding']) 4414 && ($this->file->headers['content-type'] === 'text/plain' 4415 || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' 4416 || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1' 4417 || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8')) 4418 { 4419 return $this->text_or_binary(); 4420 } 4421 4422 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) 4423 { 4424 $official = substr($this->file->headers['content-type'], 0, $pos); 4425 } 4426 else 4427 { 4428 $official = $this->file->headers['content-type']; 4429 } 4430 $official = trim(strtolower($official)); 4431 4432 if ($official === 'unknown/unknown' 4433 || $official === 'application/unknown') 4434 { 4435 return $this->unknown(); 4436 } 4437 elseif (substr($official, -4) === '+xml' 4438 || $official === 'text/xml' 4439 || $official === 'application/xml') 4440 { 4441 return $official; 4442 } 4443 elseif (substr($official, 0, 6) === 'image/') 4444 { 4445 if ($return = $this->image()) 4446 { 4447 return $return; 4448 } 4449 else 4450 { 4451 return $official; 4452 } 4453 } 4454 elseif ($official === 'text/html') 4455 { 4456 return $this->feed_or_html(); 4457 } 4458 else 4459 { 4460 return $official; 4461 } 4462 } 4463 else 4464 { 4465 return $this->unknown(); 4466 } 4467 } 4468 4469 /** 4470 * Sniff text or binary 4471 * 4472 * @return string Actual Content-Type 4473 */ 4474 public function text_or_binary() 4475 { 4476 if (substr($this->file->body, 0, 2) === "\xFE\xFF" 4477 || substr($this->file->body, 0, 2) === "\xFF\xFE" 4478 || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" 4479 || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") 4480 { 4481 return 'text/plain'; 4482 } 4483 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) 4484 { 4485 return 'application/octect-stream'; 4486 } 4487 else 4488 { 4489 return 'text/plain'; 4490 } 4491 } 4492 4493 /** 4494 * Sniff unknown 4495 * 4496 * @return string Actual Content-Type 4497 */ 4498 public function unknown() 4499 { 4500 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); 4501 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html' 4502 || strtolower(substr($this->file->body, $ws, 5)) === '<html' 4503 || strtolower(substr($this->file->body, $ws, 7)) === '<script') 4504 { 4505 return 'text/html'; 4506 } 4507 elseif (substr($this->file->body, 0, 5) === '%PDF-') 4508 { 4509 return 'application/pdf'; 4510 } 4511 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') 4512 { 4513 return 'application/postscript'; 4514 } 4515 elseif (substr($this->file->body, 0, 6) === 'GIF87a' 4516 || substr($this->file->body, 0, 6) === 'GIF89a') 4517 { 4518 return 'image/gif'; 4519 } 4520 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") 4521 { 4522 return 'image/png'; 4523 } 4524 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") 4525 { 4526 return 'image/jpeg'; 4527 } 4528 elseif (substr($this->file->body, 0, 2) === "\x42\x4D") 4529 { 4530 return 'image/bmp'; 4531 } 4532 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") 4533 { 4534 return 'image/vnd.microsoft.icon'; 4535 } 4536 else 4537 { 4538 return $this->text_or_binary(); 4539 } 4540 } 4541 4542 /** 4543 * Sniff images 4544 * 4545 * @return string Actual Content-Type 4546 */ 4547 public function image() 4548 { 4549 if (substr($this->file->body, 0, 6) === 'GIF87a' 4550 || substr($this->file->body, 0, 6) === 'GIF89a') 4551 { 4552 return 'image/gif'; 4553 } 4554 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") 4555 { 4556 return 'image/png'; 4557 } 4558 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") 4559 { 4560 return 'image/jpeg'; 4561 } 4562 elseif (substr($this->file->body, 0, 2) === "\x42\x4D") 4563 { 4564 return 'image/bmp'; 4565 } 4566 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") 4567 { 4568 return 'image/vnd.microsoft.icon'; 4569 } 4570 else 4571 { 4572 return false; 4573 } 4574 } 4575 4576 /** 4577 * Sniff HTML 4578 * 4579 * @return string Actual Content-Type 4580 */ 4581 public function feed_or_html() 4582 { 4583 $len = strlen($this->file->body); 4584 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20"); 4585 4586 while ($pos < $len) 4587 { 4588 switch ($this->file->body[$pos]) 4589 { 4590 case "\x09": 4591 case "\x0A": 4592 case "\x0D": 4593 case "\x20": 4594 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); 4595 continue 2; 4596 4597 case '<': 4598 $pos++; 4599 break; 4600 4601 default: 4602 return 'text/html'; 4603 } 4604 4605 if (substr($this->file->body, $pos, 3) === '!--') 4606 { 4607 $pos += 3; 4608 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) 4609 { 4610 $pos += 3; 4611 } 4612 else 4613 { 4614 return 'text/html'; 4615 } 4616 } 4617 elseif (substr($this->file->body, $pos, 1) === '!') 4618 { 4619 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) 4620 { 4621 $pos++; 4622 } 4623 else 4624 { 4625 return 'text/html'; 4626 } 4627 } 4628 elseif (substr($this->file->body, $pos, 1) === '?') 4629 { 4630 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) 4631 { 4632 $pos += 2; 4633 } 4634 else 4635 { 4636 return 'text/html'; 4637 } 4638 } 4639 elseif (substr($this->file->body, $pos, 3) === 'rss' 4640 || substr($this->file->body, $pos, 7) === 'rdf:RDF') 4641 { 4642 return 'application/rss+xml'; 4643 } 4644 elseif (substr($this->file->body, $pos, 4) === 'feed') 4645 { 4646 return 'application/atom+xml'; 4647 } 4648 else 4649 { 4650 return 'text/html'; 4651 } 4652 } 4653 4654 return 'text/html'; 4655 } 4656 } 4657 4658 /** 4659 * Manages `<media:copyright>` copyright tags as defined in Media RSS 4660 * 4661 * Used by {@see SimplePie_Enclosure::get_copyright()} 4662 * 4663 * This class can be overloaded with {@see SimplePie::set_copyright_class()} 4664 * 4665 * @package SimplePie 4666 * @subpackage API 4667 */ 4668 class SimplePie_Copyright 4669 { 4670 /** 4671 * Copyright URL 4672 * 4673 * @var string 4674 * @see get_url() 4675 */ 4676 var $url; 4677 4678 /** 4679 * Attribution 4680 * 4681 * @var string 4682 * @see get_attribution() 4683 */ 4684 var $label; 4685 4686 /** 4687 * Constructor, used to input the data 4688 * 4689 * For documentation on all the parameters, see the corresponding 4690 * properties and their accessors 4691 */ 4692 public function __construct($url = null, $label = null) 4693 { 4694 $this->url = $url; 4695 $this->label = $label; 4696 } 4697 4698 /** 4699 * String-ified version 4700 * 4701 * @return string 4702 */ 4703 public function __toString() 4704 { 4705 // There is no $this->data here 4706 return md5(serialize($this)); 4707 } 4708 4709 /** 4710 * Get the copyright URL 4711 * 4712 * @return string|null URL to copyright information 4713 */ 4714 public function get_url() 4715 { 4716 if ($this->url !== null) 4717 { 4718 return $this->url; 4719 } 4720 else 4721 { 4722 return null; 4723 } 4724 } 4725 4726 /** 4727 * Get the attribution text 4728 * 4729 * @return string|null 4730 */ 4731 public function get_attribution() 4732 { 4733 if ($this->label !== null) 4734 { 4735 return $this->label; 4736 } 4737 else 4738 { 4739 return null; 4740 } 4741 } 4742 } 4743 4744 /** 4745 * SimplePie class. 4746 * 4747 * Class for backward compatibility. 4748 * 4749 * @deprecated Use {@see SimplePie} directly 4750 * @package SimplePie 4751 * @subpackage API 4752 */ 4753 class SimplePie_Core extends SimplePie 4754 { 4755 4756 } 4757 4758 /** 4759 * Handles `<media:credit>` as defined in Media RSS 4760 * 4761 * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()} 4762 * 4763 * This class can be overloaded with {@see SimplePie::set_credit_class()} 4764 * 4765 * @package SimplePie 4766 * @subpackage API 4767 */ 4768 class SimplePie_Credit 4769 { 4770 /** 4771 * Credited role 4772 * 4773 * @var string 4774 * @see get_role() 4775 */ 4776 var $role; 4777 4778 /** 4779 * Organizational scheme 4780 * 4781 * @var string 4782 * @see get_scheme() 4783 */ 4784 var $scheme; 4785 4786 /** 4787 * Credited name 4788 * 4789 * @var string 4790 * @see get_name() 4791 */ 4792 var $name; 4793 4794 /** 4795 * Constructor, used to input the data 4796 * 4797 * For documentation on all the parameters, see the corresponding 4798 * properties and their accessors 4799 */ 4800 public function __construct($role = null, $scheme = null, $name = null) 4801 { 4802 $this->role = $role; 4803 $this->scheme = $scheme; 4804 $this->name = $name; 4805 } 4806 4807 /** 4808 * String-ified version 4809 * 4810 * @return string 4811 */ 4812 public function __toString() 4813 { 4814 // There is no $this->data here 4815 return md5(serialize($this)); 4816 } 4817 4818 /** 4819 * Get the role of the person receiving credit 4820 * 4821 * @return string|null 4822 */ 4823 public function get_role() 4824 { 4825 if ($this->role !== null) 4826 { 4827 return $this->role; 4828 } 4829 else 4830 { 4831 return null; 4832 } 4833 } 4834 4835 /** 4836 * Get the organizational scheme 4837 * 4838 * @return string|null 4839 */ 4840 public function get_scheme() 4841 { 4842 if ($this->scheme !== null) 4843 { 4844 return $this->scheme; 4845 } 4846 else 4847 { 4848 return null; 4849 } 4850 } 4851 4852 /** 4853 * Get the credited person/entity's name 4854 * 4855 * @return string|null 4856 */ 4857 public function get_name() 4858 { 4859 if ($this->name !== null) 4860 { 4861 return $this->name; 4862 } 4863 else 4864 { 4865 return null; 4866 } 4867 } 4868 } 4869 4870 /** 4871 * Decode HTML Entities 4872 * 4873 * This implements HTML5 as of revision 967 (2007-06-28) 4874 * 4875 * @deprecated Use DOMDocument instead! 4876 * @package SimplePie 4877 */ 4878 class SimplePie_Decode_HTML_Entities 4879 { 4880 /** 4881 * Data to be parsed 4882 * 4883 * @access private 4884 * @var string 4885 */ 4886 var $data = ''; 4887 4888 /** 4889 * Currently consumed bytes 4890 * 4891 * @access private 4892 * @var string 4893 */ 4894 var $consumed = ''; 4895 4896 /** 4897 * Position of the current byte being parsed 4898 * 4899 * @access private 4900 * @var int 4901 */ 4902 var $position = 0; 4903 4904 /** 4905 * Create an instance of the class with the input data 4906 * 4907 * @access public 4908 * @param string $data Input data 4909 */ 4910 public function __construct($data) 4911 { 4912 $this->data = $data; 4913 } 4914 4915 /** 4916 * Parse the input data 4917 * 4918 * @access public 4919 * @return string Output data 4920 */ 4921 public function parse() 4922 { 4923 while (($this->position = strpos($this->data, '&', $this->position)) !== false) 4924 { 4925 $this->consume(); 4926 $this->entity(); 4927 $this->consumed = ''; 4928 } 4929 return $this->data; 4930 } 4931 4932 /** 4933 * Consume the next byte 4934 * 4935 * @access private 4936 * @return mixed The next byte, or false, if there is no more data 4937 */ 4938 public function consume() 4939 { 4940 if (isset($this->data[$this->position])) 4941 { 4942 $this->consumed .= $this->data[$this->position]; 4943 return $this->data[$this->position++]; 4944 } 4945 else 4946 { 4947 return false; 4948 } 4949 } 4950 4951 /** 4952 * Consume a range of characters 4953 * 4954 * @access private 4955 * @param string $chars Characters to consume 4956 * @return mixed A series of characters that match the range, or false 4957 */ 4958 public function consume_range($chars) 4959 { 4960 if ($len = strspn($this->data, $chars, $this->position)) 4961 { 4962 $data = substr($this->data, $this->position, $len); 4963 $this->consumed .= $data; 4964 $this->position += $len; 4965 return $data; 4966 } 4967 else 4968 { 4969 return false; 4970 } 4971 } 4972 4973 /** 4974 * Unconsume one byte 4975 * 4976 * @access private 4977 */ 4978 public function unconsume() 4979 { 4980 $this->consumed = substr($this->consumed, 0, -1); 4981 $this->position--; 4982 } 4983 4984 /** 4985 * Decode an entity 4986 * 4987 * @access private 4988 */ 4989 public function entity() 4990 { 4991 switch ($this->consume()) 4992 { 4993 case "\x09": 4994 case "\x0A": 4995 case "\x0B": 4996 case "\x0B": 4997 case "\x0C": 4998 case "\x20": 4999 case "\x3C": 5000 case "\x26": 5001 case false: 5002 break; 5003 5004 case "\x23": 5005 switch ($this->consume()) 5006 { 5007 case "\x78": 5008 case "\x58": 5009 $range = '0123456789ABCDEFabcdef'; 5010 $hex = true; 5011 break; 5012 5013 default: 5014 $range = '0123456789'; 5015 $hex = false; 5016 $this->unconsume(); 5017 break; 5018 } 5019 5020 if ($codepoint = $this->consume_range($range)) 5021 { 5022 static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8"); 5023 5024 if ($hex) 5025 { 5026 $codepoint = hexdec($codepoint); 5027 } 5028 else 5029 { 5030 $codepoint = intval($codepoint); 5031 } 5032 5033 if (isset($windows_1252_specials[$codepoint])) 5034 { 5035 $replacement = $windows_1252_specials[$codepoint]; 5036 } 5037 else 5038 { 5039 $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint); 5040 } 5041 5042 if (!in_array($this->consume(), array(';', false), true)) 5043 { 5044 $this->unconsume(); 5045 } 5046 5047 $consumed_length = strlen($this->consumed); 5048 $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length); 5049 $this->position += strlen($replacement) - $consumed_length; 5050 } 5051 break; 5052 5053 default: 5054 static $entities = array( 5055 'Aacute' => "\xC3\x81", 5056 'aacute' => "\xC3\xA1", 5057 'Aacute;' => "\xC3\x81", 5058 'aacute;' => "\xC3\xA1", 5059 'Acirc' => "\xC3\x82", 5060 'acirc' => "\xC3\xA2", 5061 'Acirc;' => "\xC3\x82", 5062 'acirc;' => "\xC3\xA2", 5063 'acute' => "\xC2\xB4", 5064 'acute;' => "\xC2\xB4", 5065 'AElig' => "\xC3\x86", 5066 'aelig' => "\xC3\xA6", 5067 'AElig;' => "\xC3\x86", 5068 'aelig;' => "\xC3\xA6", 5069 'Agrave' => "\xC3\x80", 5070 'agrave' => "\xC3\xA0", 5071 'Agrave;' => "\xC3\x80", 5072 'agrave;' => "\xC3\xA0", 5073 'alefsym;' => "\xE2\x84\xB5", 5074 'Alpha;' => "\xCE\x91", 5075 'alpha;' => "\xCE\xB1", 5076 'AMP' => "\x26", 5077 'amp' => "\x26", 5078 'AMP;' => "\x26", 5079 'amp;' => "\x26", 5080 'and;' => "\xE2\x88\xA7", 5081 'ang;' => "\xE2\x88\xA0", 5082 'apos;' => "\x27", 5083 'Aring' => "\xC3\x85", 5084 'aring' => "\xC3\xA5", 5085 'Aring;' => "\xC3\x85", 5086 'aring;' => "\xC3\xA5", 5087 'asymp;' => "\xE2\x89\x88", 5088 'Atilde' => "\xC3\x83", 5089 'atilde' => "\xC3\xA3", 5090 'Atilde;' => "\xC3\x83", 5091 'atilde;' => "\xC3\xA3", 5092 'Auml' => "\xC3\x84", 5093 'auml' => "\xC3\xA4", 5094 'Auml;' => "\xC3\x84", 5095 'auml;' => "\xC3\xA4", 5096 'bdquo;' => "\xE2\x80\x9E", 5097 'Beta;' => "\xCE\x92", 5098 'beta;' => "\xCE\xB2", 5099 'brvbar' => "\xC2\xA6", 5100 'brvbar;' => "\xC2\xA6", 5101 'bull;' => "\xE2\x80\xA2", 5102 'cap;' => "\xE2\x88\xA9", 5103 'Ccedil' => "\xC3\x87", 5104 'ccedil' => "\xC3\xA7", 5105 'Ccedil;' => "\xC3\x87", 5106 'ccedil;' => "\xC3\xA7", 5107 'cedil' => "\xC2\xB8", 5108 'cedil;' => "\xC2\xB8", 5109 'cent' => "\xC2\xA2", 5110 'cent;' => "\xC2\xA2", 5111 'Chi;' => "\xCE\xA7", 5112 'chi;' => "\xCF\x87", 5113 'circ;' => "\xCB\x86", 5114 'clubs;' => "\xE2\x99\xA3", 5115 'cong;' => "\xE2\x89\x85", 5116 'COPY' => "\xC2\xA9", 5117 'copy' => "\xC2\xA9", 5118 'COPY;' => "\xC2\xA9", 5119 'copy;' => "\xC2\xA9", 5120 'crarr;' => "\xE2\x86\xB5", 5121 'cup;' => "\xE2\x88\xAA", 5122 'curren' => "\xC2\xA4", 5123 'curren;' => "\xC2\xA4", 5124 'Dagger;' => "\xE2\x80\xA1", 5125 'dagger;' => "\xE2\x80\xA0", 5126 'dArr;' => "\xE2\x87\x93", 5127 'darr;' => "\xE2\x86\x93", 5128 'deg' => "\xC2\xB0", 5129 'deg;' => "\xC2\xB0", 5130 'Delta;' => "\xCE\x94", 5131 'delta;' => "\xCE\xB4", 5132 'diams;' => "\xE2\x99\xA6", 5133 'divide' => "\xC3\xB7", 5134 'divide;' => "\xC3\xB7", 5135 'Eacute' => "\xC3\x89", 5136 'eacute' => "\xC3\xA9", 5137 'Eacute;' => "\xC3\x89", 5138 'eacute;' => "\xC3\xA9", 5139 'Ecirc' => "\xC3\x8A", 5140 'ecirc' => "\xC3\xAA", 5141 'Ecirc;' => "\xC3\x8A", 5142 'ecirc;' => "\xC3\xAA", 5143 'Egrave' => "\xC3\x88", 5144 'egrave' => "\xC3\xA8", 5145 'Egrave;' => "\xC3\x88", 5146 'egrave;' => "\xC3\xA8", 5147 'empty;' => "\xE2\x88\x85", 5148 'emsp;' => "\xE2\x80\x83", 5149 'ensp;' => "\xE2\x80\x82", 5150 'Epsilon;' => "\xCE\x95", 5151 'epsilon;' => "\xCE\xB5", 5152 'equiv;' => "\xE2\x89\xA1", 5153 'Eta;' => "\xCE\x97", 5154 'eta;' => "\xCE\xB7", 5155 'ETH' => "\xC3\x90", 5156 'eth' => "\xC3\xB0", 5157 'ETH;' => "\xC3\x90", 5158 'eth;' => "\xC3\xB0", 5159 'Euml' => "\xC3\x8B", 5160 'euml' => "\xC3\xAB", 5161 'Euml;' => "\xC3\x8B", 5162 'euml;' => "\xC3\xAB", 5163 'euro;' => "\xE2\x82\xAC", 5164 'exist;' => "\xE2\x88\x83", 5165 'fnof;' => "\xC6\x92", 5166 'forall;' => "\xE2\x88\x80", 5167 'frac12' => "\xC2\xBD", 5168 'frac12;' => "\xC2\xBD", 5169 'frac14' => "\xC2\xBC", 5170 'frac14;' => "\xC2\xBC", 5171 'frac34' => "\xC2\xBE", 5172 'frac34;' => "\xC2\xBE", 5173 'frasl;' => "\xE2\x81\x84", 5174 'Gamma;' => "\xCE\x93", 5175 'gamma;' => "\xCE\xB3", 5176 'ge;' => "\xE2\x89\xA5", 5177 'GT' => "\x3E", 5178 'gt' => "\x3E", 5179 'GT;' => "\x3E", 5180 'gt;' => "\x3E", 5181 'hArr;' => "\xE2\x87\x94", 5182 'harr;' => "\xE2\x86\x94", 5183 'hearts;' => "\xE2\x99\xA5", 5184 'hellip;' => "\xE2\x80\xA6", 5185 'Iacute' => "\xC3\x8D", 5186 'iacute' => "\xC3\xAD", 5187 'Iacute;' => "\xC3\x8D", 5188 'iacute;' => "\xC3\xAD", 5189 'Icirc' => "\xC3\x8E", 5190 'icirc' => "\xC3\xAE", 5191 'Icirc;' => "\xC3\x8E", 5192 'icirc;' => "\xC3\xAE", 5193 'iexcl' => "\xC2\xA1", 5194 'iexcl;' => "\xC2\xA1", 5195 'Igrave' => "\xC3\x8C", 5196 'igrave' => "\xC3\xAC", 5197 'Igrave;' => "\xC3\x8C", 5198 'igrave;' => "\xC3\xAC", 5199 'image;' => "\xE2\x84\x91", 5200 'infin;' => "\xE2\x88\x9E", 5201 'int;' => "\xE2\x88\xAB", 5202 'Iota;' => "\xCE\x99", 5203 'iota;' => "\xCE\xB9", 5204 'iquest' => "\xC2\xBF", 5205 'iquest;' => "\xC2\xBF", 5206 'isin;' => "\xE2\x88\x88", 5207 'Iuml' => "\xC3\x8F", 5208 'iuml' => "\xC3\xAF", 5209 'Iuml;' => "\xC3\x8F", 5210 'iuml;' => "\xC3\xAF", 5211 'Kappa;' => "\xCE\x9A", 5212 'kappa;' => "\xCE\xBA", 5213 'Lambda;' => "\xCE\x9B", 5214 'lambda;' => "\xCE\xBB", 5215 'lang;' => "\xE3\x80\x88", 5216 'laquo' => "\xC2\xAB", 5217 'laquo;' => "\xC2\xAB", 5218 'lArr;' => "\xE2\x87\x90", 5219 'larr;' => "\xE2\x86\x90", 5220 'lceil;' => "\xE2\x8C\x88", 5221 'ldquo;' => "\xE2\x80\x9C", 5222 'le;' => "\xE2\x89\xA4", 5223 'lfloor;' => "\xE2\x8C\x8A", 5224 'lowast;' => "\xE2\x88\x97", 5225 'loz;' => "\xE2\x97\x8A", 5226 'lrm;' => "\xE2\x80\x8E", 5227 'lsaquo;' => "\xE2\x80\xB9", 5228 'lsquo;' => "\xE2\x80\x98", 5229 'LT' => "\x3C", 5230 'lt' => "\x3C", 5231 'LT;' => "\x3C", 5232 'lt;' => "\x3C", 5233 'macr' => "\xC2\xAF", 5234 'macr;' => "\xC2\xAF", 5235 'mdash;' => "\xE2\x80\x94", 5236 'micro' => "\xC2\xB5", 5237 'micro;' => "\xC2\xB5", 5238 'middot' => "\xC2\xB7", 5239 'middot;' => "\xC2\xB7", 5240 'minus;' => "\xE2\x88\x92", 5241 'Mu;' => "\xCE\x9C", 5242 'mu;' => "\xCE\xBC", 5243 'nabla;' => "\xE2\x88\x87", 5244 'nbsp' => "\xC2\xA0", 5245 'nbsp;' => "\xC2\xA0", 5246 'ndash;' => "\xE2\x80\x93", 5247 'ne;' => "\xE2\x89\xA0", 5248 'ni;' => "\xE2\x88\x8B", 5249 'not' => "\xC2\xAC", 5250 'not;' => "\xC2\xAC", 5251 'notin;' => "\xE2\x88\x89", 5252 'nsub;' => "\xE2\x8A\x84", 5253 'Ntilde' => "\xC3\x91", 5254 'ntilde' => "\xC3\xB1", 5255 'Ntilde;' => "\xC3\x91", 5256 'ntilde;' => "\xC3\xB1", 5257 'Nu;' => "\xCE\x9D", 5258 'nu;' => "\xCE\xBD", 5259 'Oacute' => "\xC3\x93", 5260 'oacute' => "\xC3\xB3", 5261 'Oacute;' => "\xC3\x93", 5262 'oacute;' => "\xC3\xB3", 5263 'Ocirc' => "\xC3\x94", 5264 'ocirc' => "\xC3\xB4", 5265 'Ocirc;' => "\xC3\x94", 5266 'ocirc;' => "\xC3\xB4", 5267 'OElig;' => "\xC5\x92", 5268 'oelig;' => "\xC5\x93", 5269 'Ograve' => "\xC3\x92", 5270 'ograve' => "\xC3\xB2", 5271 'Ograve;' => "\xC3\x92", 5272 'ograve;' => "\xC3\xB2", 5273 'oline;' => "\xE2\x80\xBE", 5274 'Omega;' => "\xCE\xA9", 5275 'omega;' => "\xCF\x89", 5276 'Omicron;' => "\xCE\x9F", 5277 'omicron;' => "\xCE\xBF", 5278 'oplus;' => "\xE2\x8A\x95", 5279 'or;' => "\xE2\x88\xA8", 5280 'ordf' => "\xC2\xAA", 5281 'ordf;' => "\xC2\xAA", 5282 'ordm' => "\xC2\xBA", 5283 'ordm;' => "\xC2\xBA", 5284 'Oslash' => "\xC3\x98", 5285 'oslash' => "\xC3\xB8", 5286 'Oslash;' => "\xC3\x98", 5287 'oslash;' => "\xC3\xB8", 5288 'Otilde' => "\xC3\x95", 5289 'otilde' => "\xC3\xB5", 5290 'Otilde;' => "\xC3\x95", 5291 'otilde;' => "\xC3\xB5", 5292 'otimes;' => "\xE2\x8A\x97", 5293 'Ouml' => "\xC3\x96", 5294 'ouml' => "\xC3\xB6", 5295 'Ouml;' => "\xC3\x96", 5296 'ouml;' => "\xC3\xB6", 5297 'para' => "\xC2\xB6", 5298 'para;' => "\xC2\xB6", 5299 'part;' => "\xE2\x88\x82", 5300 'permil;' => "\xE2\x80\xB0", 5301 'perp;' => "\xE2\x8A\xA5", 5302 'Phi;' => "\xCE\xA6", 5303 'phi;' => "\xCF\x86", 5304 'Pi;' => "\xCE\xA0", 5305 'pi;' => "\xCF\x80", 5306 'piv;' => "\xCF\x96", 5307 'plusmn' => "\xC2\xB1", 5308 'plusmn;' => "\xC2\xB1", 5309 'pound' => "\xC2\xA3", 5310 'pound;' => "\xC2\xA3", 5311 'Prime;' => "\xE2\x80\xB3", 5312 'prime;' => "\xE2\x80\xB2", 5313 'prod;' => "\xE2\x88\x8F", 5314 'prop;' => "\xE2\x88\x9D", 5315 'Psi;' => "\xCE\xA8", 5316 'psi;' => "\xCF\x88", 5317 'QUOT' => "\x22", 5318 'quot' => "\x22", 5319 'QUOT;' => "\x22", 5320 'quot;' => "\x22", 5321 'radic;' => "\xE2\x88\x9A", 5322 'rang;' => "\xE3\x80\x89", 5323 'raquo' => "\xC2\xBB", 5324 'raquo;' => "\xC2\xBB", 5325 'rArr;' => "\xE2\x87\x92", 5326 'rarr;' => "\xE2\x86\x92", 5327 'rceil;' => "\xE2\x8C\x89", 5328 'rdquo;' => "\xE2\x80\x9D", 5329 'real;' => "\xE2\x84\x9C", 5330 'REG' => "\xC2\xAE", 5331 'reg' => "\xC2\xAE", 5332 'REG;' => "\xC2\xAE", 5333 'reg;' => "\xC2\xAE", 5334 'rfloor;' => "\xE2\x8C\x8B", 5335 'Rho;' => "\xCE\xA1", 5336 'rho;' => "\xCF\x81", 5337 'rlm;' => "\xE2\x80\x8F", 5338 'rsaquo;' => "\xE2\x80\xBA", 5339 'rsquo;' => "\xE2\x80\x99", 5340 'sbquo;' => "\xE2\x80\x9A", 5341 'Scaron;' => "\xC5\xA0", 5342 'scaron;' => "\xC5\xA1", 5343 'sdot;' => "\xE2\x8B\x85", 5344 'sect' => "\xC2\xA7", 5345 'sect;' => "\xC2\xA7", 5346 'shy' => "\xC2\xAD", 5347 'shy;' => "\xC2\xAD", 5348 'Sigma;' => "\xCE\xA3", 5349 'sigma;' => "\xCF\x83", 5350 'sigmaf;' => "\xCF\x82", 5351 'sim;' => "\xE2\x88\xBC", 5352 'spades;' => "\xE2\x99\xA0", 5353 'sub;' => "\xE2\x8A\x82", 5354 'sube;' => "\xE2\x8A\x86", 5355 'sum;' => "\xE2\x88\x91", 5356 'sup;' => "\xE2\x8A\x83", 5357 'sup1' => "\xC2\xB9", 5358 'sup1;' => "\xC2\xB9", 5359 'sup2' => "\xC2\xB2", 5360 'sup2;' => "\xC2\xB2", 5361 'sup3' => "\xC2\xB3", 5362 'sup3;' => "\xC2\xB3", 5363 'supe;' => "\xE2\x8A\x87", 5364 'szlig' => "\xC3\x9F", 5365 'szlig;' => "\xC3\x9F", 5366 'Tau;' => "\xCE\xA4", 5367 'tau;' => "\xCF\x84", 5368 'there4;' => "\xE2\x88\xB4", 5369 'Theta;' => "\xCE\x98", 5370 'theta;' => "\xCE\xB8", 5371 'thetasym;' => "\xCF\x91", 5372 'thinsp;' => "\xE2\x80\x89", 5373 'THORN' => "\xC3\x9E", 5374 'thorn' => "\xC3\xBE", 5375 'THORN;' => "\xC3\x9E", 5376 'thorn;' => "\xC3\xBE", 5377 'tilde;' => "\xCB\x9C", 5378 'times' => "\xC3\x97", 5379 'times;' => "\xC3\x97", 5380 'TRADE;' => "\xE2\x84\xA2", 5381 'trade;' => "\xE2\x84\xA2", 5382 'Uacute' => "\xC3\x9A", 5383 'uacute' => "\xC3\xBA", 5384 'Uacute;' => "\xC3\x9A", 5385 'uacute;' => "\xC3\xBA", 5386 'uArr;' => "\xE2\x87\x91", 5387 'uarr;' => "\xE2\x86\x91", 5388 'Ucirc' => "\xC3\x9B", 5389 'ucirc' => "\xC3\xBB", 5390 'Ucirc;' => "\xC3\x9B", 5391 'ucirc;' => "\xC3\xBB", 5392 'Ugrave' => "\xC3\x99", 5393 'ugrave' => "\xC3\xB9", 5394 'Ugrave;' => "\xC3\x99", 5395 'ugrave;' => "\xC3\xB9", 5396 'uml' => "\xC2\xA8", 5397 'uml;' => "\xC2\xA8", 5398 'upsih;' => "\xCF\x92", 5399 'Upsilon;' => "\xCE\xA5", 5400 'upsilon;' => "\xCF\x85", 5401 'Uuml' => "\xC3\x9C", 5402 'uuml' => "\xC3\xBC", 5403 'Uuml;' => "\xC3\x9C", 5404 'uuml;' => "\xC3\xBC", 5405 'weierp;' => "\xE2\x84\x98", 5406 'Xi;' => "\xCE\x9E", 5407 'xi;' => "\xCE\xBE", 5408 'Yacute' => "\xC3\x9D", 5409 'yacute' => "\xC3\xBD", 5410 'Yacute;' => "\xC3\x9D", 5411 'yacute;' => "\xC3\xBD", 5412 'yen' => "\xC2\xA5", 5413 'yen;' => "\xC2\xA5", 5414 'yuml' => "\xC3\xBF", 5415 'Yuml;' => "\xC5\xB8", 5416 'yuml;' => "\xC3\xBF", 5417 'Zeta;' => "\xCE\x96", 5418 'zeta;' => "\xCE\xB6", 5419 'zwj;' => "\xE2\x80\x8D", 5420 'zwnj;' => "\xE2\x80\x8C" 5421 ); 5422 5423 for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++) 5424 { 5425 $consumed = substr($this->consumed, 1); 5426 if (isset($entities[$consumed])) 5427 { 5428 $match = $consumed; 5429 } 5430 } 5431 5432 if ($match !== null) 5433 { 5434 $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1); 5435 $this->position += strlen($entities[$match]) - strlen($consumed) - 1; 5436 } 5437 break; 5438 } 5439 } 5440 } 5441 5442 /** 5443 * Handles everything related to enclosures (including Media RSS and iTunes RSS) 5444 * 5445 * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()} 5446 * 5447 * This class can be overloaded with {@see SimplePie::set_enclosure_class()} 5448 * 5449 * @package SimplePie 5450 * @subpackage API 5451 */ 5452 class SimplePie_Enclosure 5453 { 5454 /** 5455 * @var string 5456 * @see get_bitrate() 5457 */ 5458 var $bitrate; 5459 5460 /** 5461 * @var array 5462 * @see get_captions() 5463 */ 5464 var $captions; 5465 5466 /** 5467 * @var array 5468 * @see get_categories() 5469 */ 5470 var $categories; 5471 5472 /** 5473 * @var int 5474 * @see get_channels() 5475 */ 5476 var $channels; 5477 5478 /** 5479 * @var SimplePie_Copyright 5480 * @see get_copyright() 5481 */ 5482 var $copyright; 5483 5484 /** 5485 * @var array 5486 * @see get_credits() 5487 */ 5488 var $credits; 5489 5490 /** 5491 * @var string 5492 * @see get_description() 5493 */ 5494 var $description; 5495 5496 /** 5497 * @var int 5498 * @see get_duration() 5499 */ 5500 var $duration; 5501 5502 /** 5503 * @var string 5504 * @see get_expression() 5505 */ 5506 var $expression; 5507 5508 /** 5509 * @var string 5510 * @see get_framerate() 5511 */ 5512 var $framerate; 5513 5514 /** 5515 * @var string 5516 * @see get_handler() 5517 */ 5518 var $handler; 5519 5520 /** 5521 * @var array 5522 * @see get_hashes() 5523 */ 5524 var $hashes; 5525 5526 /** 5527 * @var string 5528 * @see get_height() 5529 */ 5530 var $height; 5531 5532 /** 5533 * @deprecated 5534 * @var null 5535 */ 5536 var $javascript; 5537 5538 /** 5539 * @var array 5540 * @see get_keywords() 5541 */ 5542 var $keywords; 5543 5544 /** 5545 * @var string 5546 * @see get_language() 5547 */ 5548 var $lang; 5549 5550 /** 5551 * @var string 5552 * @see get_length() 5553 */ 5554 var $length; 5555 5556 /** 5557 * @var string 5558 * @see get_link() 5559 */ 5560 var $link; 5561 5562 /** 5563 * @var string 5564 * @see get_medium() 5565 */ 5566 var $medium; 5567 5568 /** 5569 * @var string 5570 * @see get_player() 5571 */ 5572 var $player; 5573 5574 /** 5575 * @var array 5576 * @see get_ratings() 5577 */ 5578 var $ratings; 5579 5580 /** 5581 * @var array 5582 * @see get_restrictions() 5583 */ 5584 var $restrictions; 5585 5586 /** 5587 * @var string 5588 * @see get_sampling_rate() 5589 */ 5590 var $samplingrate; 5591 5592 /** 5593 * @var array 5594 * @see get_thumbnails() 5595 */ 5596 var $thumbnails; 5597 5598 /** 5599 * @var string 5600 * @see get_title() 5601 */ 5602 var $title; 5603 5604 /** 5605 * @var string 5606 * @see get_type() 5607 */ 5608 var $type; 5609 5610 /** 5611 * @var string 5612 * @see get_width() 5613 */ 5614 var $width; 5615 5616 /** 5617 * Constructor, used to input the data 5618 * 5619 * For documentation on all the parameters, see the corresponding 5620 * properties and their accessors 5621 * 5622 * @uses idna_convert If available, this will convert an IDN 5623 */ 5624 public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null) 5625 { 5626 $this->bitrate = $bitrate; 5627 $this->captions = $captions; 5628 $this->categories = $categories; 5629 $this->channels = $channels; 5630 $this->copyright = $copyright; 5631 $this->credits = $credits; 5632 $this->description = $description; 5633 $this->duration = $duration; 5634 $this->expression = $expression; 5635 $this->framerate = $framerate; 5636 $this->hashes = $hashes; 5637 $this->height = $height; 5638 $this->keywords = $keywords; 5639 $this->lang = $lang; 5640 $this->length = $length; 5641 $this->link = $link; 5642 $this->medium = $medium; 5643 $this->player = $player; 5644 $this->ratings = $ratings; 5645 $this->restrictions = $restrictions; 5646 $this->samplingrate = $samplingrate; 5647 $this->thumbnails = $thumbnails; 5648 $this->title = $title; 5649 $this->type = $type; 5650 $this->width = $width; 5651 5652 if (class_exists('idna_convert')) 5653 { 5654 $idn = new idna_convert(); 5655 $parsed = SimplePie_Misc::parse_url($link); 5656 $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); 5657 } 5658 $this->handler = $this->get_handler(); // Needs to load last 5659 } 5660 5661 /** 5662 * String-ified version 5663 * 5664 * @return string 5665 */ 5666 public function __toString() 5667 { 5668 // There is no $this->data here 5669 return md5(serialize($this)); 5670 } 5671 5672 /** 5673 * Get the bitrate 5674 * 5675 * @return string|null 5676 */ 5677 public function get_bitrate() 5678 { 5679 if ($this->bitrate !== null) 5680 { 5681 return $this->bitrate; 5682 } 5683 else 5684 { 5685 return null; 5686 } 5687 } 5688 5689 /** 5690 * Get a single caption 5691 * 5692 * @param int $key 5693 * @return SimplePie_Caption|null 5694 */ 5695 public function get_caption($key = 0) 5696 { 5697 $captions = $this->get_captions(); 5698 if (isset($captions[$key])) 5699 { 5700 return $captions[$key]; 5701 } 5702 else 5703 { 5704 return null; 5705 } 5706 } 5707 5708 /** 5709 * Get all captions 5710 * 5711 * @return array|null Array of {@see SimplePie_Caption} objects 5712 */ 5713 public function get_captions() 5714 { 5715 if ($this->captions !== null) 5716 { 5717 return $this->captions; 5718 } 5719 else 5720 { 5721 return null; 5722 } 5723 } 5724 5725 /** 5726 * Get a single category 5727 * 5728 * @param int $key 5729 * @return SimplePie_Category|null 5730 */ 5731 public function get_category($key = 0) 5732 { 5733 $categories = $this->get_categories(); 5734 if (isset($categories[$key])) 5735 { 5736 return $categories[$key]; 5737 } 5738 else 5739 { 5740 return null; 5741 } 5742 } 5743 5744 /** 5745 * Get all categories 5746 * 5747 * @return array|null Array of {@see SimplePie_Category} objects 5748 */ 5749 public function get_categories() 5750 { 5751 if ($this->categories !== null) 5752 { 5753 return $this->categories; 5754 } 5755 else 5756 { 5757 return null; 5758 } 5759 } 5760 5761 /** 5762 * Get the number of audio channels 5763 * 5764 * @return int|null 5765 */ 5766 public function get_channels() 5767 { 5768 if ($this->channels !== null) 5769 { 5770 return $this->channels; 5771 } 5772 else 5773 { 5774 return null; 5775 } 5776 } 5777 5778 /** 5779 * Get the copyright information 5780 * 5781 * @return SimplePie_Copyright|null 5782 */ 5783 public function get_copyright() 5784 { 5785 if ($this->copyright !== null) 5786 { 5787 return $this->copyright; 5788 } 5789 else 5790 { 5791 return null; 5792 } 5793 } 5794 5795 /** 5796 * Get a single credit 5797 * 5798 * @param int $key 5799 * @return SimplePie_Credit|null 5800 */ 5801 public function get_credit($key = 0) 5802 { 5803 $credits = $this->get_credits(); 5804 if (isset($credits[$key])) 5805 { 5806 return $credits[$key]; 5807 } 5808 else 5809 { 5810 return null; 5811 } 5812 } 5813 5814 /** 5815 * Get all credits 5816 * 5817 * @return array|null Array of {@see SimplePie_Credit} objects 5818 */ 5819 public function get_credits() 5820 { 5821 if ($this->credits !== null) 5822 { 5823 return $this->credits; 5824 } 5825 else 5826 { 5827 return null; 5828 } 5829 } 5830 5831 /** 5832 * Get the description of the enclosure 5833 * 5834 * @return string|null 5835 */ 5836 public function get_description() 5837 { 5838 if ($this->description !== null) 5839 { 5840 return $this->description; 5841 } 5842 else 5843 { 5844 return null; 5845 } 5846 } 5847 5848 /** 5849 * Get the duration of the enclosure 5850 * 5851 * @param string $convert Convert seconds into hh:mm:ss 5852 * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found) 5853 */ 5854 public function get_duration($convert = false) 5855 { 5856 if ($this->duration !== null) 5857 { 5858 if ($convert) 5859 { 5860 $time = SimplePie_Misc::time_hms($this->duration); 5861 return $time; 5862 } 5863 else 5864 { 5865 return $this->duration; 5866 } 5867 } 5868 else 5869 { 5870 return null; 5871 } 5872 } 5873 5874 /** 5875 * Get the expression 5876 * 5877 * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full' 5878 */ 5879 public function get_expression() 5880 { 5881 if ($this->expression !== null) 5882 { 5883 return $this->expression; 5884 } 5885 else 5886 { 5887 return 'full'; 5888 } 5889 } 5890 5891 /** 5892 * Get the file extension 5893 * 5894 * @return string|null 5895 */ 5896 public function get_extension() 5897 { 5898 if ($this->link !== null) 5899 { 5900 $url = SimplePie_Misc::parse_url($this->link); 5901 if ($url['path'] !== '') 5902 { 5903 return pathinfo($url['path'], PATHINFO_EXTENSION); 5904 } 5905 } 5906 return null; 5907 } 5908 5909 /** 5910 * Get the framerate (in frames-per-second) 5911 * 5912 * @return string|null 5913 */ 5914 public function get_framerate() 5915 { 5916 if ($this->framerate !== null) 5917 { 5918 return $this->framerate; 5919 } 5920 else 5921 { 5922 return null; 5923 } 5924 } 5925 5926 /** 5927 * Get the preferred handler 5928 * 5929 * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3' 5930 */ 5931 public function get_handler() 5932 { 5933 return $this->get_real_type(true); 5934 } 5935 5936 /** 5937 * Get a single hash 5938 * 5939 * @link http://www.rssboard.org/media-rss#media-hash 5940 * @param int $key 5941 * @return string|null Hash as per `media:hash`, prefixed with "$algo:" 5942 */ 5943 public function get_hash($key = 0) 5944 { 5945 $hashes = $this->get_hashes(); 5946 if (isset($hashes[$key])) 5947 { 5948 return $hashes[$key]; 5949 } 5950 else 5951 { 5952 return null; 5953 } 5954 } 5955 5956 /** 5957 * Get all credits 5958 * 5959 * @return array|null Array of strings, see {@see get_hash()} 5960 */ 5961 public function get_hashes() 5962 { 5963 if ($this->hashes !== null) 5964 { 5965 return $this->hashes; 5966 } 5967 else 5968 { 5969 return null; 5970 } 5971 } 5972 5973 /** 5974 * Get the height 5975 * 5976 * @return string|null 5977 */ 5978 public function get_height() 5979 { 5980 if ($this->height !== null) 5981 { 5982 return $this->height; 5983 } 5984 else 5985 { 5986 return null; 5987 } 5988 } 5989 5990 /** 5991 * Get the language 5992 * 5993 * @link http://tools.ietf.org/html/rfc3066 5994 * @return string|null Language code as per RFC 3066 5995 */ 5996 public function get_language() 5997 { 5998 if ($this->lang !== null) 5999 { 6000 return $this->lang; 6001 } 6002 else 6003 { 6004 return null; 6005 } 6006 } 6007 6008 /** 6009 * Get a single keyword 6010 * 6011 * @param int $key 6012 * @return string|null 6013 */ 6014 public function get_keyword($key = 0) 6015 { 6016 $keywords = $this->get_keywords(); 6017 if (isset($keywords[$key])) 6018 { 6019 return $keywords[$key]; 6020 } 6021 else 6022 { 6023 return null; 6024 } 6025 } 6026 6027 /** 6028 * Get all keywords 6029 * 6030 * @return array|null Array of strings 6031 */ 6032 public function get_keywords() 6033 { 6034 if ($this->keywords !== null) 6035 { 6036 return $this->keywords; 6037 } 6038 else 6039 { 6040 return null; 6041 } 6042 } 6043 6044 /** 6045 * Get length 6046 * 6047 * @return float Length in bytes 6048 */ 6049 public function get_length() 6050 { 6051 if ($this->length !== null) 6052 { 6053 return $this->length; 6054 } 6055 else 6056 { 6057 return null; 6058 } 6059 } 6060 6061 /** 6062 * Get the URL 6063 * 6064 * @return string|null 6065 */ 6066 public function get_link() 6067 { 6068 if ($this->link !== null) 6069 { 6070 return urldecode($this->link); 6071 } 6072 else 6073 { 6074 return null; 6075 } 6076 } 6077 6078 /** 6079 * Get the medium 6080 * 6081 * @link http://www.rssboard.org/media-rss#media-content 6082 * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable' 6083 */ 6084 public function get_medium() 6085 { 6086 if ($this->medium !== null) 6087 { 6088 return $this->medium; 6089 } 6090 else 6091 { 6092 return null; 6093 } 6094 } 6095 6096 /** 6097 * Get the player URL 6098 * 6099 * Typically the same as {@see get_permalink()} 6100 * @return string|null Player URL 6101 */ 6102 public function get_player() 6103 { 6104 if ($this->player !== null) 6105 { 6106 return $this->player; 6107 } 6108 else 6109 { 6110 return null; 6111 } 6112 } 6113 6114 /** 6115 * Get a single rating 6116 * 6117 * @param int $key 6118 * @return SimplePie_Rating|null 6119 */ 6120 public function get_rating($key = 0) 6121 { 6122 $ratings = $this->get_ratings(); 6123 if (isset($ratings[$key])) 6124 { 6125 return $ratings[$key]; 6126 } 6127 else 6128 { 6129 return null; 6130 } 6131 } 6132 6133 /** 6134 * Get all ratings 6135 * 6136 * @return array|null Array of {@see SimplePie_Rating} objects 6137 */ 6138 public function get_ratings() 6139 { 6140 if ($this->ratings !== null) 6141 { 6142 return $this->ratings; 6143 } 6144 else 6145 { 6146 return null; 6147 } 6148 } 6149 6150 /** 6151 * Get a single restriction 6152 * 6153 * @param int $key 6154 * @return SimplePie_Restriction|null 6155 */ 6156 public function get_restriction($key = 0) 6157 { 6158 $restrictions = $this->get_restrictions(); 6159 if (isset($restrictions[$key])) 6160 { 6161 return $restrictions[$key]; 6162 } 6163 else 6164 { 6165 return null; 6166 } 6167 } 6168 6169 /** 6170 * Get all restrictions 6171 * 6172 * @return array|null Array of {@see SimplePie_Restriction} objects 6173 */ 6174 public function get_restrictions() 6175 { 6176 if ($this->restrictions !== null) 6177 { 6178 return $this->restrictions; 6179 } 6180 else 6181 { 6182 return null; 6183 } 6184 } 6185 6186 /** 6187 * Get the sampling rate (in kHz) 6188 * 6189 * @return string|null 6190 */ 6191 public function get_sampling_rate() 6192 { 6193 if ($this->samplingrate !== null) 6194 { 6195 return $this->samplingrate; 6196 } 6197 else 6198 { 6199 return null; 6200 } 6201 } 6202 6203 /** 6204 * Get the file size (in MiB) 6205 * 6206 * @return float|null File size in mebibytes (1048 bytes) 6207 */ 6208 public function get_size() 6209 { 6210 $length = $this->get_length(); 6211 if ($length !== null) 6212 { 6213 return round($length/1048576, 2); 6214 } 6215 else 6216 { 6217 return null; 6218 } 6219 } 6220 6221 /** 6222 * Get a single thumbnail 6223 * 6224 * @param int $key 6225 * @return string|null Thumbnail URL 6226 */ 6227 public function get_thumbnail($key = 0) 6228 { 6229 $thumbnails = $this->get_thumbnails(); 6230 if (isset($thumbnails[$key])) 6231 { 6232 return $thumbnails[$key]; 6233 } 6234 else 6235 { 6236 return null; 6237 } 6238 } 6239 6240 /** 6241 * Get all thumbnails 6242 * 6243 * @return array|null Array of thumbnail URLs 6244 */ 6245 public function get_thumbnails() 6246 { 6247 if ($this->thumbnails !== null) 6248 { 6249 return $this->thumbnails; 6250 } 6251 else 6252 { 6253 return null; 6254 } 6255 } 6256 6257 /** 6258 * Get the title 6259 * 6260 * @return string|null 6261 */ 6262 public function get_title() 6263 { 6264 if ($this->title !== null) 6265 { 6266 return $this->title; 6267 } 6268 else 6269 { 6270 return null; 6271 } 6272 } 6273 6274 /** 6275 * Get mimetype of the enclosure 6276 * 6277 * @see get_real_type() 6278 * @return string|null MIME type 6279 */ 6280 public function get_type() 6281 { 6282 if ($this->type !== null) 6283 { 6284 return $this->type; 6285 } 6286 else 6287 { 6288 return null; 6289 } 6290 } 6291 6292 /** 6293 * Get the width 6294 * 6295 * @return string|null 6296 */ 6297 public function get_width() 6298 { 6299 if ($this->width !== null) 6300 { 6301 return $this->width; 6302 } 6303 else 6304 { 6305 return null; 6306 } 6307 } 6308 6309 /** 6310 * Embed the enclosure using `<embed>` 6311 * 6312 * @deprecated Use the second parameter to {@see embed} instead 6313 * 6314 * @param array|string $options See first paramter to {@see embed} 6315 * @return string HTML string to output 6316 */ 6317 public function native_embed($options='') 6318 { 6319 return $this->embed($options, true); 6320 } 6321 6322 /** 6323 * Embed the enclosure using Javascript 6324 * 6325 * `$options` is an array or comma-separated key:value string, with the 6326 * following properties: 6327 * 6328 * - `alt` (string): Alternate content for when an end-user does not have 6329 * the appropriate handler installed or when a file type is 6330 * unsupported. Can be any text or HTML. Defaults to blank. 6331 * - `altclass` (string): If a file type is unsupported, the end-user will 6332 * see the alt text (above) linked directly to the content. That link 6333 * will have this value as its class name. Defaults to blank. 6334 * - `audio` (string): This is an image that should be used as a 6335 * placeholder for audio files before they're loaded (QuickTime-only). 6336 * Can be any relative or absolute URL. Defaults to blank. 6337 * - `bgcolor` (string): The background color for the media, if not 6338 * already transparent. Defaults to `#ffffff`. 6339 * - `height` (integer): The height of the embedded media. Accepts any 6340 * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`, 6341 * and it is recommended that you use this default. 6342 * - `loop` (boolean): Do you want the media to loop when its done? 6343 * Defaults to `false`. 6344 * - `mediaplayer` (string): The location of the included 6345 * `mediaplayer.swf` file. This allows for the playback of Flash Video 6346 * (`.flv`) files, and is the default handler for non-Odeo MP3's. 6347 * Defaults to blank. 6348 * - `video` (string): This is an image that should be used as a 6349 * placeholder for video files before they're loaded (QuickTime-only). 6350 * Can be any relative or absolute URL. Defaults to blank. 6351 * - `width` (integer): The width of the embedded media. Accepts any 6352 * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`, 6353 * and it is recommended that you use this default. 6354 * - `widescreen` (boolean): Is the enclosure widescreen or standard? 6355 * This applies only to video enclosures, and will automatically resize 6356 * the content appropriately. Defaults to `false`, implying 4:3 mode. 6357 * 6358 * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto` 6359 * will default to 480x360 video resolution. Widescreen (16:9) mode with 6360 * `width` and `height` set to `auto` will default to 480x270 video resolution. 6361 * 6362 * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'. 6363 * @param array|string $options Comma-separated key:value list, or array 6364 * @param bool $native Use `<embed>` 6365 * @return string HTML string to output 6366 */ 6367 public function embed($options = '', $native = false) 6368 { 6369 // Set up defaults 6370 $audio = ''; 6371 $video = ''; 6372 $alt = ''; 6373 $altclass = ''; 6374 $loop = 'false'; 6375 $width = 'auto'; 6376 $height = 'auto'; 6377 $bgcolor = '#ffffff'; 6378 $mediaplayer = ''; 6379 $widescreen = false; 6380 $handler = $this->get_handler(); 6381 $type = $this->get_real_type(); 6382 6383 // Process options and reassign values as necessary 6384 if (is_array($options)) 6385 { 6386 extract($options); 6387 } 6388 else 6389 { 6390 $options = explode(',', $options); 6391 foreach($options as $option) 6392 { 6393 $opt = explode(':', $option, 2); 6394 if (isset($opt[0], $opt[1])) 6395 { 6396 $opt[0] = trim($opt[0]); 6397 $opt[1] = trim($opt[1]); 6398 switch ($opt[0]) 6399 { 6400 case 'audio': 6401 $audio = $opt[1]; 6402 break; 6403 6404 case 'video': 6405 $video = $opt[1]; 6406 break; 6407 6408 case 'alt': 6409 $alt = $opt[1]; 6410 break; 6411 6412 case 'altclass': 6413 $altclass = $opt[1]; 6414 break; 6415 6416 case 'loop': 6417 $loop = $opt[1]; 6418 break; 6419 6420 case 'width': 6421 $width = $opt[1]; 6422 break; 6423 6424 case 'height': 6425 $height = $opt[1]; 6426 break; 6427 6428 case 'bgcolor': 6429 $bgcolor = $opt[1]; 6430 break; 6431 6432 case 'mediaplayer': 6433 $mediaplayer = $opt[1]; 6434 break; 6435 6436 case 'widescreen': 6437 $widescreen = $opt[1]; 6438 break; 6439 } 6440 } 6441 } 6442 } 6443 6444 $mime = explode('/', $type, 2); 6445 $mime = $mime[0]; 6446 6447 // Process values for 'auto' 6448 if ($width === 'auto') 6449 { 6450 if ($mime === 'video') 6451 { 6452 if ($height === 'auto') 6453 { 6454 $width = 480; 6455 } 6456 elseif ($widescreen) 6457 { 6458 $width = round((intval($height)/9)*16); 6459 } 6460 else 6461 { 6462 $width = round((intval($height)/3)*4); 6463 } 6464 } 6465 else 6466 { 6467 $width = '100%'; 6468 } 6469 } 6470 6471 if ($height === 'auto') 6472 { 6473 if ($mime === 'audio') 6474 { 6475 $height = 0; 6476 } 6477 elseif ($mime === 'video') 6478 { 6479 if ($width === 'auto') 6480 { 6481 if ($widescreen) 6482 { 6483 $height = 270; 6484 } 6485 else 6486 { 6487 $height = 360; 6488 } 6489 } 6490 elseif ($widescreen) 6491 { 6492 $height = round((intval($width)/16)*9); 6493 } 6494 else 6495 { 6496 $height = round((intval($width)/4)*3); 6497 } 6498 } 6499 else 6500 { 6501 $height = 376; 6502 } 6503 } 6504 elseif ($mime === 'audio') 6505 { 6506 $height = 0; 6507 } 6508 6509 // Set proper placeholder value 6510 if ($mime === 'audio') 6511 { 6512 $placeholder = $audio; 6513 } 6514 elseif ($mime === 'video') 6515 { 6516 $placeholder = $video; 6517 } 6518 6519 $embed = ''; 6520 6521 // Flash 6522 if ($handler === 'flash') 6523 { 6524 if ($native) 6525 { 6526 $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>"; 6527 } 6528 else 6529 { 6530 $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>"; 6531 } 6532 } 6533 6534 // Flash Media Player file types. 6535 // Preferred handler for MP3 file types. 6536 elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== '')) 6537 { 6538 $height += 20; 6539 if ($native) 6540 { 6541 $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>"; 6542 } 6543 else 6544 { 6545 $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>"; 6546 } 6547 } 6548 6549 // QuickTime 7 file types. Need to test with QuickTime 6. 6550 // Only handle MP3's if the Flash Media Player is not present. 6551 elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === '')) 6552 { 6553 $height += 16; 6554 if ($native) 6555 { 6556 if ($placeholder !== '') 6557 { 6558 $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>"; 6559 } 6560 else 6561 { 6562 $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>"; 6563 } 6564 } 6565 else 6566 { 6567 $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>"; 6568 } 6569 } 6570 6571 // Windows Media 6572 elseif ($handler === 'wmedia') 6573 { 6574 $height += 45; 6575 if ($native) 6576 { 6577 $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>"; 6578 } 6579 else 6580 { 6581 $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>"; 6582 } 6583 } 6584 6585 // Everything else 6586 else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>'; 6587 6588 return $embed; 6589 } 6590 6591 /** 6592 * Get the real media type 6593 * 6594 * Often, feeds lie to us, necessitating a bit of deeper inspection. This 6595 * converts types to their canonical representations based on the file 6596 * extension 6597 * 6598 * @see get_type() 6599 * @param bool $find_handler Internal use only, use {@see get_handler()} instead 6600 * @return string MIME type 6601 */ 6602 public function get_real_type($find_handler = false) 6603 { 6604 // Mime-types by handler. 6605 $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash 6606 $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player 6607 $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime 6608 $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media 6609 $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3 6610 6611 if ($this->get_type() !== null) 6612 { 6613 $type = strtolower($this->type); 6614 } 6615 else 6616 { 6617 $type = null; 6618 } 6619 6620 // If we encounter an unsupported mime-type, check the file extension and guess intelligently. 6621 if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3))) 6622 { 6623 switch (strtolower($this->get_extension())) 6624 { 6625 // Audio mime-types 6626 case 'aac': 6627 case 'adts': 6628 $type = 'audio/acc'; 6629 break; 6630 6631 case 'aif': 6632 case 'aifc': 6633 case 'aiff': 6634 case 'cdda': 6635 $type = 'audio/aiff'; 6636 break; 6637 6638 case 'bwf': 6639 $type = 'audio/wav'; 6640 break; 6641 6642 case 'kar': 6643 case 'mid': 6644 case 'midi': 6645 case 'smf': 6646 $type = 'audio/midi'; 6647 break; 6648 6649 case 'm4a': 6650 $type = 'audio/x-m4a'; 6651 break; 6652 6653 case 'mp3': 6654 case 'swa': 6655 $type = 'audio/mp3'; 6656 break; 6657 6658 case 'wav': 6659 $type = 'audio/wav'; 6660 break; 6661 6662 case 'wax': 6663 $type = 'audio/x-ms-wax'; 6664 break; 6665 6666 case 'wma': 6667 $type = 'audio/x-ms-wma'; 6668 break; 6669 6670 // Video mime-types 6671 case '3gp': 6672 case '3gpp': 6673 $type = 'video/3gpp'; 6674 break; 6675 6676 case '3g2': 6677 case '3gp2': 6678 $type = 'video/3gpp2'; 6679 break; 6680 6681 case 'asf': 6682 $type = 'video/x-ms-asf'; 6683 break; 6684 6685 case 'flv': 6686 $type = 'video/x-flv'; 6687 break; 6688 6689 case 'm1a': 6690 case 'm1s': 6691 case 'm1v': 6692 case 'm15': 6693 case 'm75': 6694 case 'mp2': 6695 case 'mpa': 6696 case 'mpeg': 6697 case 'mpg': 6698 case 'mpm': 6699 case 'mpv': 6700 $type = 'video/mpeg'; 6701 break; 6702 6703 case 'm4v': 6704 $type = 'video/x-m4v'; 6705 break; 6706 6707 case 'mov': 6708 case 'qt': 6709 $type = 'video/quicktime'; 6710 break; 6711 6712 case 'mp4': 6713 case 'mpg4': 6714 $type = 'video/mp4'; 6715 break; 6716 6717 case 'sdv': 6718 $type = 'video/sd-video'; 6719 break; 6720 6721 case 'wm': 6722 $type = 'video/x-ms-wm'; 6723 break; 6724 6725 case 'wmv': 6726 $type = 'video/x-ms-wmv'; 6727 break; 6728 6729 case 'wvx': 6730 $type = 'video/x-ms-wvx'; 6731 break; 6732 6733 // Flash mime-types 6734 case 'spl': 6735 $type = 'application/futuresplash'; 6736 break; 6737 6738 case 'swf': 6739 $type = 'application/x-shockwave-flash'; 6740 break; 6741 } 6742 } 6743 6744 if ($find_handler) 6745 { 6746 if (in_array($type, $types_flash)) 6747 { 6748 return 'flash'; 6749 } 6750 elseif (in_array($type, $types_fmedia)) 6751 { 6752 return 'fmedia'; 6753 } 6754 elseif (in_array($type, $types_quicktime)) 6755 { 6756 return 'quicktime'; 6757 } 6758 elseif (in_array($type, $types_wmedia)) 6759 { 6760 return 'wmedia'; 6761 } 6762 elseif (in_array($type, $types_mp3)) 6763 { 6764 return 'mp3'; 6765 } 6766 else 6767 { 6768 return null; 6769 } 6770 } 6771 else 6772 { 6773 return $type; 6774 } 6775 } 6776 } 6777 6778 /** 6779 * General SimplePie exception class 6780 * 6781 * @package SimplePie 6782 */ 6783 class SimplePie_Exception extends Exception 6784 { 6785 } 6786 6787 /** 6788 * Used for fetching remote files and reading local files 6789 * 6790 * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support 6791 * 6792 * This class can be overloaded with {@see SimplePie::set_file_class()} 6793 * 6794 * @package SimplePie 6795 * @subpackage HTTP 6796 * @todo Move to properly supporting RFC2616 (HTTP/1.1) 6797 */ 6798 class SimplePie_File 6799 { 6800 var $url; 6801 var $useragent; 6802 var $success = true; 6803 var $headers = array(); 6804 var $body; 6805 var $status_code; 6806 var $redirects = 0; 6807 var $error; 6808 var $method = SIMPLEPIE_FILE_SOURCE_NONE; 6809 6810 public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) 6811 { 6812 if (class_exists('idna_convert')) 6813 { 6814 $idn = new idna_convert(); 6815 $parsed = SimplePie_Misc::parse_url($url); 6816 $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']); 6817 } 6818 $this->url = $url; 6819 $this->useragent = $useragent; 6820 if (preg_match('/^http(s)?:\/\//i', $url)) 6821 { 6822 if ($useragent === null) 6823 { 6824 $useragent = ini_get('user_agent'); 6825 $this->useragent = $useragent; 6826 } 6827 if (!is_array($headers)) 6828 { 6829 $headers = array(); 6830 } 6831 if (!$force_fsockopen && function_exists('curl_exec')) 6832 { 6833 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL; 6834 $fp = curl_init(); 6835 $headers2 = array(); 6836 foreach ($headers as $key => $value) 6837 { 6838 $headers2[] = "$key: $value"; 6839 } 6840 if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=')) 6841 { 6842 curl_setopt($fp, CURLOPT_ENCODING, ''); 6843 } 6844 curl_setopt($fp, CURLOPT_URL, $url); 6845 curl_setopt($fp, CURLOPT_HEADER, 1); 6846 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1); 6847 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout); 6848 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout); 6849 curl_setopt($fp, CURLOPT_REFERER, $url); 6850 curl_setopt($fp, CURLOPT_USERAGENT, $useragent); 6851 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2); 6852 if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>=')) 6853 { 6854 curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1); 6855 curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects); 6856 } 6857 6858 $this->headers = curl_exec($fp); 6859 if (curl_errno($fp) === 23 || curl_errno($fp) === 61) 6860 { 6861 curl_setopt($fp, CURLOPT_ENCODING, 'none'); 6862 $this->headers = curl_exec($fp); 6863 } 6864 if (curl_errno($fp)) 6865 { 6866 $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp); 6867 $this->success = false; 6868 } 6869 else 6870 { 6871 $info = curl_getinfo($fp); 6872 curl_close($fp); 6873 $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1); 6874 $this->headers = array_pop($this->headers); 6875 $parser = new SimplePie_HTTP_Parser($this->headers); 6876 if ($parser->parse()) 6877 { 6878 $this->headers = $parser->headers; 6879 $this->body = $parser->body; 6880 $this->status_code = $parser->status_code; 6881 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) 6882 { 6883 $this->redirects++; 6884 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); 6885 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); 6886 } 6887 } 6888 } 6889 } 6890 else 6891 { 6892 $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN; 6893 $url_parts = parse_url($url); 6894 $socket_host = $url_parts['host']; 6895 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') 6896 { 6897 $socket_host = "ssl://$url_parts[host]"; 6898 $url_parts['port'] = 443; 6899 } 6900 if (!isset($url_parts['port'])) 6901 { 6902 $url_parts['port'] = 80; 6903 } 6904 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout); 6905 if (!$fp) 6906 { 6907 $this->error = 'fsockopen error: ' . $errstr; 6908 $this->success = false; 6909 } 6910 else 6911 { 6912 stream_set_timeout($fp, $timeout); 6913 if (isset($url_parts['path'])) 6914 { 6915 if (isset($url_parts['query'])) 6916 { 6917 $get = "$url_parts[path]?$url_parts[query]"; 6918 } 6919 else 6920 { 6921 $get = $url_parts['path']; 6922 } 6923 } 6924 else 6925 { 6926 $get = '/'; 6927 } 6928 $out = "GET $get HTTP/1.1\r\n"; 6929 $out .= "Host: $url_parts[host]\r\n"; 6930 $out .= "User-Agent: $useragent\r\n"; 6931 if (extension_loaded('zlib')) 6932 { 6933 $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n"; 6934 } 6935 6936 if (isset($url_parts['user']) && isset($url_parts['pass'])) 6937 { 6938 $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n"; 6939 } 6940 foreach ($headers as $key => $value) 6941 { 6942 $out .= "$key: $value\r\n"; 6943 } 6944 $out .= "Connection: Close\r\n\r\n"; 6945 fwrite($fp, $out); 6946 6947 $info = stream_get_meta_data($fp); 6948 6949 $this->headers = ''; 6950 while (!$info['eof'] && !$info['timed_out']) 6951 { 6952 $this->headers .= fread($fp, 1160); 6953 $info = stream_get_meta_data($fp); 6954 } 6955 if (!$info['timed_out']) 6956 { 6957 $parser = new SimplePie_HTTP_Parser($this->headers); 6958 if ($parser->parse()) 6959 { 6960 $this->headers = $parser->headers; 6961 $this->body = $parser->body; 6962 $this->status_code = $parser->status_code; 6963 if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) 6964 { 6965 $this->redirects++; 6966 $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url); 6967 return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen); 6968 } 6969 if (isset($this->headers['content-encoding'])) 6970 { 6971 // Hey, we act dumb elsewhere, so let's do that here too 6972 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) 6973 { 6974 case 'gzip': 6975 case 'x-gzip': 6976 $decoder = new SimplePie_gzdecode($this->body); 6977 if (!$decoder->parse()) 6978 { 6979 $this->error = 'Unable to decode HTTP "gzip" stream'; 6980 $this->success = false; 6981 } 6982 else 6983 { 6984 $this->body = $decoder->data; 6985 } 6986 break; 6987 6988 case 'deflate': 6989 if (($decompressed = gzinflate($this->body)) !== false) 6990 { 6991 $this->body = $decompressed; 6992 } 6993 else if (($decompressed = gzuncompress($this->body)) !== false) 6994 { 6995 $this->body = $decompressed; 6996 } 6997 else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false) 6998 { 6999 $this->body = $decompressed; 7000 } 7001 else 7002 { 7003 $this->error = 'Unable to decode HTTP "deflate" stream'; 7004 $this->success = false; 7005 } 7006 break; 7007 7008 default: 7009 $this->error = 'Unknown content coding'; 7010 $this->success = false; 7011 } 7012 } 7013 } 7014 } 7015 else 7016 { 7017 $this->error = 'fsocket timed out'; 7018 $this->success = false; 7019 } 7020 fclose($fp); 7021 } 7022 } 7023 } 7024 else 7025 { 7026 $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS; 7027 if (!$this->body = file_get_contents($url)) 7028 { 7029 $this->error = 'file_get_contents could not read the file'; 7030 $this->success = false; 7031 } 7032 } 7033 } 7034 } 7035 7036 /** 7037 * Decode 'gzip' encoded HTTP data 7038 * 7039 * @package SimplePie 7040 * @subpackage HTTP 7041 * @link http://www.gzip.org/format.txt 7042 */ 7043 class SimplePie_gzdecode 7044 { 7045 /** 7046 * Compressed data 7047 * 7048 * @access private 7049 * @var string 7050 * @see gzdecode::$data 7051 */ 7052 var $compressed_data; 7053 7054 /** 7055 * Size of compressed data 7056 * 7057 * @access private 7058 * @var int 7059 */ 7060 var $compressed_size; 7061 7062 /** 7063 * Minimum size of a valid gzip string 7064 * 7065 * @access private 7066 * @var int 7067 */ 7068 var $min_compressed_size = 18; 7069 7070 /** 7071 * Current position of pointer 7072 * 7073 * @access private 7074 * @var int 7075 */ 7076 var $position = 0; 7077 7078 /** 7079 * Flags (FLG) 7080 * 7081 * @access private 7082 * @var int 7083 */ 7084 var $flags; 7085 7086 /** 7087 * Uncompressed data 7088 * 7089 * @access public 7090 * @see gzdecode::$compressed_data 7091 * @var string 7092 */ 7093 var $data; 7094 7095 /** 7096 * Modified time 7097 * 7098 * @access public 7099 * @var int 7100 */ 7101 var $MTIME; 7102 7103 /** 7104 * Extra Flags 7105 * 7106 * @access public 7107 * @var int 7108 */ 7109 var $XFL; 7110 7111 /** 7112 * Operating System 7113 * 7114 * @access public 7115 * @var int 7116 */ 7117 var $OS; 7118 7119 /** 7120 * Subfield ID 1 7121 * 7122 * @access public 7123 * @see gzdecode::$extra_field 7124 * @see gzdecode::$SI2 7125 * @var string 7126 */ 7127 var $SI1; 7128 7129 /** 7130 * Subfield ID 2 7131 * 7132 * @access public 7133 * @see gzdecode::$extra_field 7134 * @see gzdecode::$SI1 7135 * @var string 7136 */ 7137 var $SI2; 7138 7139 /** 7140 * Extra field content 7141 * 7142 * @access public 7143 * @see gzdecode::$SI1 7144 * @see gzdecode::$SI2 7145 * @var string 7146 */ 7147 var $extra_field; 7148 7149 /** 7150 * Original filename 7151 * 7152 * @access public 7153 * @var string 7154 */ 7155 var $filename; 7156 7157 /** 7158 * Human readable comment 7159 * 7160 * @access public 7161 * @var string 7162 */ 7163 var $comment; 7164 7165 /** 7166 * Don't allow anything to be set 7167 * 7168 * @param string $name 7169 * @param mixed $value 7170 */ 7171 public function __set($name, $value) 7172 { 7173 trigger_error("Cannot write property $name", E_USER_ERROR); 7174 } 7175 7176 /** 7177 * Set the compressed string and related properties 7178 * 7179 * @param string $data 7180 */ 7181 public function __construct($data) 7182 { 7183 $this->compressed_data = $data; 7184 $this->compressed_size = strlen($data); 7185 } 7186 7187 /** 7188 * Decode the GZIP stream 7189 * 7190 * @return bool Successfulness 7191 */ 7192 public function parse() 7193 { 7194 if ($this->compressed_size >= $this->min_compressed_size) 7195 { 7196 // Check ID1, ID2, and CM 7197 if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08") 7198 { 7199 return false; 7200 } 7201 7202 // Get the FLG (FLaGs) 7203 $this->flags = ord($this->compressed_data[3]); 7204 7205 // FLG bits above (1 << 4) are reserved 7206 if ($this->flags > 0x1F) 7207 { 7208 return false; 7209 } 7210 7211 // Advance the pointer after the above 7212 $this->position += 4; 7213 7214 // MTIME 7215 $mtime = substr($this->compressed_data, $this->position, 4); 7216 // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness 7217 if (current(unpack('S', "\x00\x01")) === 1) 7218 { 7219 $mtime = strrev($mtime); 7220 } 7221 $this->MTIME = current(unpack('l', $mtime)); 7222 $this->position += 4; 7223 7224 // Get the XFL (eXtra FLags) 7225 $this->XFL = ord($this->compressed_data[$this->position++]); 7226 7227 // Get the OS (Operating System) 7228 $this->OS = ord($this->compressed_data[$this->position++]); 7229 7230 // Parse the FEXTRA 7231 if ($this->flags & 4) 7232 { 7233 // Read subfield IDs 7234 $this->SI1 = $this->compressed_data[$this->position++]; 7235 $this->SI2 = $this->compressed_data[$this->position++]; 7236 7237 // SI2 set to zero is reserved for future use 7238 if ($this->SI2 === "\x00") 7239 { 7240 return false; 7241 } 7242 7243 // Get the length of the extra field 7244 $len = current(unpack('v', substr($this->compressed_data, $this->position, 2))); 7245 $this->position += 2; 7246 7247 // Check the length of the string is still valid 7248 $this->min_compressed_size += $len + 4; 7249 if ($this->compressed_size >= $this->min_compressed_size) 7250 { 7251 // Set the extra field to the given data 7252 $this->extra_field = substr($this->compressed_data, $this->position, $len); 7253 $this->position += $len; 7254 } 7255 else 7256 { 7257 return false; 7258 } 7259 } 7260 7261 // Parse the FNAME 7262 if ($this->flags & 8) 7263 { 7264 // Get the length of the filename 7265 $len = strcspn($this->compressed_data, "\x00", $this->position); 7266 7267 // Check the length of the string is still valid 7268 $this->min_compressed_size += $len + 1; 7269 if ($this->compressed_size >= $this->min_compressed_size) 7270 { 7271 // Set the original filename to the given string 7272 $this->filename = substr($this->compressed_data, $this->position, $len); 7273 $this->position += $len + 1; 7274 } 7275 else 7276 { 7277 return false; 7278 } 7279 } 7280 7281 // Parse the FCOMMENT 7282 if ($this->flags & 16) 7283 { 7284 // Get the length of the comment 7285 $len = strcspn($this->compressed_data, "\x00", $this->position); 7286 7287 // Check the length of the string is still valid 7288 $this->min_compressed_size += $len + 1; 7289 if ($this->compressed_size >= $this->min_compressed_size) 7290 { 7291 // Set the original comment to the given string 7292 $this->comment = substr($this->compressed_data, $this->position, $len); 7293 $this->position += $len + 1; 7294 } 7295 else 7296 { 7297 return false; 7298 } 7299 } 7300 7301 // Parse the FHCRC 7302 if ($this->flags & 2) 7303 { 7304 // Check the length of the string is still valid 7305 $this->min_compressed_size += $len + 2; 7306 if ($this->compressed_size >= $this->min_compressed_size) 7307 { 7308 // Read the CRC 7309 $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2))); 7310 7311 // Check the CRC matches 7312 if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc) 7313 { 7314 $this->position += 2; 7315 } 7316 else 7317 { 7318 return false; 7319 } 7320 } 7321 else 7322 { 7323 return false; 7324 } 7325 } 7326 7327 // Decompress the actual data 7328 if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false) 7329 { 7330 return false; 7331 } 7332 else 7333 { 7334 $this->position = $this->compressed_size - 8; 7335 } 7336 7337 // Check CRC of data 7338 $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4))); 7339 $this->position += 4; 7340 /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc)) 7341 { 7342 return false; 7343 }*/ 7344 7345 // Check ISIZE of data 7346 $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4))); 7347 $this->position += 4; 7348 if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize)) 7349 { 7350 return false; 7351 } 7352 7353 // Wow, against all odds, we've actually got a valid gzip string 7354 return true; 7355 } 7356 else 7357 { 7358 return false; 7359 } 7360 } 7361 } 7362 7363 /** 7364 * HTTP Response Parser 7365 * 7366 * @package SimplePie 7367 * @subpackage HTTP 7368 */ 7369 class SimplePie_HTTP_Parser 7370 { 7371 /** 7372 * HTTP Version 7373 * 7374 * @var float 7375 */ 7376 public $http_version = 0.0; 7377 7378 /** 7379 * Status code 7380 * 7381 * @var int 7382 */ 7383 public $status_code = 0; 7384 7385 /** 7386 * Reason phrase 7387 * 7388 * @var string 7389 */ 7390 public $reason = ''; 7391 7392 /** 7393 * Key/value pairs of the headers 7394 * 7395 * @var array 7396 */ 7397 public $headers = array(); 7398 7399 /** 7400 * Body of the response 7401 * 7402 * @var string 7403 */ 7404 public $body = ''; 7405 7406 /** 7407 * Current state of the state machine 7408 * 7409 * @var string 7410 */ 7411 protected $state = 'http_version'; 7412 7413 /** 7414 * Input data 7415 * 7416 * @var string 7417 */ 7418 protected $data = ''; 7419 7420 /** 7421 * Input data length (to avoid calling strlen() everytime this is needed) 7422 * 7423 * @var int 7424 */ 7425 protected $data_length = 0; 7426 7427 /** 7428 * Current position of the pointer 7429 * 7430 * @var int 7431 */ 7432 protected $position = 0; 7433 7434 /** 7435 * Name of the hedaer currently being parsed 7436 * 7437 * @var string 7438 */ 7439 protected $name = ''; 7440 7441 /** 7442 * Value of the hedaer currently being parsed 7443 * 7444 * @var string 7445 */ 7446 protected $value = ''; 7447 7448 /** 7449 * Create an instance of the class with the input data 7450 * 7451 * @param string $data Input data 7452 */ 7453 public function __construct($data) 7454 { 7455 $this->data = $data; 7456 $this->data_length = strlen($this->data); 7457 } 7458 7459 /** 7460 * Parse the input data 7461 * 7462 * @return bool true on success, false on failure 7463 */ 7464 public function parse() 7465 { 7466 while ($this->state && $this->state !== 'emit' && $this->has_data()) 7467 { 7468 $state = $this->state; 7469 $this->$state(); 7470 } 7471 $this->data = ''; 7472 if ($this->state === 'emit' || $this->state === 'body') 7473 { 7474 return true; 7475 } 7476 else 7477 { 7478 $this->http_version = ''; 7479 $this->status_code = ''; 7480 $this->reason = ''; 7481 $this->headers = array(); 7482 $this->body = ''; 7483 return false; 7484 } 7485 } 7486 7487 /** 7488 * Check whether there is data beyond the pointer 7489 * 7490 * @return bool true if there is further data, false if not 7491 */ 7492 protected function has_data() 7493 { 7494 return (bool) ($this->position < $this->data_length); 7495 } 7496 7497 /** 7498 * See if the next character is LWS 7499 * 7500 * @return bool true if the next character is LWS, false if not 7501 */ 7502 protected function is_linear_whitespace() 7503 { 7504 return (bool) ($this->data[$this->position] === "\x09" 7505 || $this->data[$this->position] === "\x20" 7506 || ($this->data[$this->position] === "\x0A" 7507 && isset($this->data[$this->position + 1]) 7508 && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20"))); 7509 } 7510 7511 /** 7512 * Parse the HTTP version 7513 */ 7514 protected function http_version() 7515 { 7516 if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/') 7517 { 7518 $len = strspn($this->data, '0123456789.', 5); 7519 $this->http_version = substr($this->data, 5, $len); 7520 $this->position += 5 + $len; 7521 if (substr_count($this->http_version, '.') <= 1) 7522 { 7523 $this->http_version = (float) $this->http_version; 7524 $this->position += strspn($this->data, "\x09\x20", $this->position); 7525 $this->state = 'status'; 7526 } 7527 else 7528 { 7529 $this->state = false; 7530 } 7531 } 7532 else 7533 { 7534 $this->state = false; 7535 } 7536 } 7537 7538 /** 7539 * Parse the status code 7540 */ 7541 protected function status() 7542 { 7543 if ($len = strspn($this->data, '0123456789', $this->position)) 7544 { 7545 $this->status_code = (int) substr($this->data, $this->position, $len); 7546 $this->position += $len; 7547 $this->state = 'reason'; 7548 } 7549 else 7550 { 7551 $this->state = false; 7552 } 7553 } 7554 7555 /** 7556 * Parse the reason phrase 7557 */ 7558 protected function reason() 7559 { 7560 $len = strcspn($this->data, "\x0A", $this->position); 7561 $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20"); 7562 $this->position += $len + 1; 7563 $this->state = 'new_line'; 7564 } 7565 7566 /** 7567 * Deal with a new line, shifting data around as needed 7568 */ 7569 protected function new_line() 7570 { 7571 $this->value = trim($this->value, "\x0D\x20"); 7572 if ($this->name !== '' && $this->value !== '') 7573 { 7574 $this->name = strtolower($this->name); 7575 // We should only use the last Content-Type header. c.f. issue #1 7576 if (isset($this->headers[$this->name]) && $this->name !== 'content-type') 7577 { 7578 $this->headers[$this->name] .= ', ' . $this->value; 7579 } 7580 else 7581 { 7582 $this->headers[$this->name] = $this->value; 7583 } 7584 } 7585 $this->name = ''; 7586 $this->value = ''; 7587 if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A") 7588 { 7589 $this->position += 2; 7590 $this->state = 'body'; 7591 } 7592 elseif ($this->data[$this->position] === "\x0A") 7593 { 7594 $this->position++; 7595 $this->state = 'body'; 7596 } 7597 else 7598 { 7599 $this->state = 'name'; 7600 } 7601 } 7602 7603 /** 7604 * Parse a header name 7605 */ 7606 protected function name() 7607 { 7608 $len = strcspn($this->data, "\x0A:", $this->position); 7609 if (isset($this->data[$this->position + $len])) 7610 { 7611 if ($this->data[$this->position + $len] === "\x0A") 7612 { 7613 $this->position += $len; 7614 $this->state = 'new_line'; 7615 } 7616 else 7617 { 7618 $this->name = substr($this->data, $this->position, $len); 7619 $this->position += $len + 1; 7620 $this->state = 'value'; 7621 } 7622 } 7623 else 7624 { 7625 $this->state = false; 7626 } 7627 } 7628 7629 /** 7630 * Parse LWS, replacing consecutive LWS characters with a single space 7631 */ 7632 protected function linear_whitespace() 7633 { 7634 do 7635 { 7636 if (substr($this->data, $this->position, 2) === "\x0D\x0A") 7637 { 7638 $this->position += 2; 7639 } 7640 elseif ($this->data[$this->position] === "\x0A") 7641 { 7642 $this->position++; 7643 } 7644 $this->position += strspn($this->data, "\x09\x20", $this->position); 7645 } while ($this->has_data() && $this->is_linear_whitespace()); 7646 $this->value .= "\x20"; 7647 } 7648 7649 /** 7650 * See what state to move to while within non-quoted header values 7651 */ 7652 protected function value() 7653 { 7654 if ($this->is_linear_whitespace()) 7655 { 7656 $this->linear_whitespace(); 7657 } 7658 else 7659 { 7660 switch ($this->data[$this->position]) 7661 { 7662 case '"': 7663 // Workaround for ETags: we have to include the quotes as 7664 // part of the tag. 7665 if (strtolower($this->name) === 'etag') 7666 { 7667 $this->value .= '"'; 7668 $this->position++; 7669 $this->state = 'value_char'; 7670 break; 7671 } 7672 $this->position++; 7673 $this->state = 'quote'; 7674 break; 7675 7676 case "\x0A": 7677 $this->position++; 7678 $this->state = 'new_line'; 7679 break; 7680 7681 default: 7682 $this->state = 'value_char'; 7683 break; 7684 } 7685 } 7686 } 7687 7688 /** 7689 * Parse a header value while outside quotes 7690 */ 7691 protected function value_char() 7692 { 7693 $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position); 7694 $this->value .= substr($this->data, $this->position, $len); 7695 $this->position += $len; 7696 $this->state = 'value'; 7697 } 7698 7699 /** 7700 * See what state to move to while within quoted header values 7701 */ 7702 protected function quote() 7703 { 7704 if ($this->is_linear_whitespace()) 7705 { 7706 $this->linear_whitespace(); 7707 } 7708 else 7709 { 7710 switch ($this->data[$this->position]) 7711 { 7712 case '"': 7713 $this->position++; 7714 $this->state = 'value'; 7715 break; 7716 7717 case "\x0A": 7718 $this->position++; 7719 $this->state = 'new_line'; 7720 break; 7721 7722 case '\\': 7723 $this->position++; 7724 $this->state = 'quote_escaped'; 7725 break; 7726 7727 default: 7728 $this->state = 'quote_char'; 7729 break; 7730 } 7731 } 7732 } 7733 7734 /** 7735 * Parse a header value while within quotes 7736 */ 7737 protected function quote_char() 7738 { 7739 $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position); 7740 $this->value .= substr($this->data, $this->position, $len); 7741 $this->position += $len; 7742 $this->state = 'value'; 7743 } 7744 7745 /** 7746 * Parse an escaped character within quotes 7747 */ 7748 protected function quote_escaped() 7749 { 7750 $this->value .= $this->data[$this->position]; 7751 $this->position++; 7752 $this->state = 'quote'; 7753 } 7754 7755 /** 7756 * Parse the body 7757 */ 7758 protected function body() 7759 { 7760 $this->body = substr($this->data, $this->position); 7761 if (!empty($this->headers['transfer-encoding'])) 7762 { 7763 unset($this->headers['transfer-encoding']); 7764 $this->state = 'chunked'; 7765 } 7766 else 7767 { 7768 $this->state = 'emit'; 7769 } 7770 } 7771 7772 /** 7773 * Parsed a "Transfer-Encoding: chunked" body 7774 */ 7775 protected function chunked() 7776 { 7777 if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body))) 7778 { 7779 $this->state = 'emit'; 7780 return; 7781 } 7782 7783 $decoded = ''; 7784 $encoded = $this->body; 7785 7786 while (true) 7787 { 7788 $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches ); 7789 if (!$is_chunked) 7790 { 7791 // Looks like it's not chunked after all 7792 $this->state = 'emit'; 7793 return; 7794 } 7795 7796 $length = hexdec(trim($matches[1])); 7797 if ($length === 0) 7798 { 7799 // Ignore trailer headers 7800 $this->state = 'emit'; 7801 $this->body = $decoded; 7802 return; 7803 } 7804 7805 $chunk_length = strlen($matches[0]); 7806 $decoded .= $part = substr($encoded, $chunk_length, $length); 7807 $encoded = substr($encoded, $chunk_length + $length + 2); 7808 7809 if (trim($encoded) === '0' || empty($encoded)) 7810 { 7811 $this->state = 'emit'; 7812 $this->body = $decoded; 7813 return; 7814 } 7815 } 7816 } 7817 } 7818 7819 /** 7820 * IRI parser/serialiser/normaliser 7821 * 7822 * @package SimplePie 7823 * @subpackage HTTP 7824 * @author Geoffrey Sneddon 7825 * @author Steve Minutillo 7826 * @author Ryan McCue 7827 * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue 7828 * @license http://www.opensource.org/licenses/bsd-license.php 7829 */ 7830 class SimplePie_IRI 7831 { 7832 /** 7833 * Scheme 7834 * 7835 * @var string 7836 */ 7837 protected $scheme = null; 7838 7839 /** 7840 * User Information 7841 * 7842 * @var string 7843 */ 7844 protected $iuserinfo = null; 7845 7846 /** 7847 * ihost 7848 * 7849 * @var string 7850 */ 7851 protected $ihost = null; 7852 7853 /** 7854 * Port 7855 * 7856 * @var string 7857 */ 7858 protected $port = null; 7859 7860 /** 7861 * ipath 7862 * 7863 * @var string 7864 */ 7865 protected $ipath = ''; 7866 7867 /** 7868 * iquery 7869 * 7870 * @var string 7871 */ 7872 protected $iquery = null; 7873 7874 /** 7875 * ifragment 7876 * 7877 * @var string 7878 */ 7879 protected $ifragment = null; 7880 7881 /** 7882 * Normalization database 7883 * 7884 * Each key is the scheme, each value is an array with each key as the IRI 7885 * part and value as the default value for that part. 7886 */ 7887 protected $normalization = array( 7888 'acap' => array( 7889 'port' => 674 7890 ), 7891 'dict' => array( 7892 'port' => 2628 7893 ), 7894 'file' => array( 7895 'ihost' => 'localhost' 7896 ), 7897 'http' => array( 7898 'port' => 80, 7899 'ipath' => '/' 7900 ), 7901 'https' => array( 7902 'port' => 443, 7903 'ipath' => '/' 7904 ), 7905 ); 7906 7907 /** 7908 * Return the entire IRI when you try and read the object as a string 7909 * 7910 * @return string 7911 */ 7912 public function __toString() 7913 { 7914 return $this->get_iri(); 7915 } 7916 7917 /** 7918 * Overload __set() to provide access via properties 7919 * 7920 * @param string $name Property name 7921 * @param mixed $value Property value 7922 */ 7923 public function __set($name, $value) 7924 { 7925 if (method_exists($this, 'set_' . $name)) 7926 { 7927 call_user_func(array($this, 'set_' . $name), $value); 7928 } 7929 elseif ( 7930 $name === 'iauthority' 7931 || $name === 'iuserinfo' 7932 || $name === 'ihost' 7933 || $name === 'ipath' 7934 || $name === 'iquery' 7935 || $name === 'ifragment' 7936 ) 7937 { 7938 call_user_func(array($this, 'set_' . substr($name, 1)), $value); 7939 } 7940 } 7941 7942 /** 7943 * Overload __get() to provide access via properties 7944 * 7945 * @param string $name Property name 7946 * @return mixed 7947 */ 7948 public function __get($name) 7949 { 7950 // isset() returns false for null, we don't want to do that 7951 // Also why we use array_key_exists below instead of isset() 7952 $props = get_object_vars($this); 7953 7954 if ( 7955 $name === 'iri' || 7956 $name === 'uri' || 7957 $name === 'iauthority' || 7958 $name === 'authority' 7959 ) 7960 { 7961 $return = $this->{"get_$name"}(); 7962 } 7963 elseif (array_key_exists($name, $props)) 7964 { 7965 $return = $this->$name; 7966 } 7967 // host -> ihost 7968 elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) 7969 { 7970 $name = $prop; 7971 $return = $this->$prop; 7972 } 7973 // ischeme -> scheme 7974 elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) 7975 { 7976 $name = $prop; 7977 $return = $this->$prop; 7978 } 7979 else 7980 { 7981 trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); 7982 $return = null; 7983 } 7984 7985 if ($return === null && isset($this->normalization[$this->scheme][$name])) 7986 { 7987 return $this->normalization[$this->scheme][$name]; 7988 } 7989 else 7990 { 7991 return $return; 7992 } 7993 } 7994 7995 /** 7996 * Overload __isset() to provide access via properties 7997 * 7998 * @param string $name Property name 7999 * @return bool 8000 */ 8001 public function __isset($name) 8002 { 8003 if (method_exists($this, 'get_' . $name) || isset($this->$name)) 8004 { 8005 return true; 8006 } 8007 else 8008 { 8009 return false; 8010 } 8011 } 8012 8013 /** 8014 * Overload __unset() to provide access via properties 8015 * 8016 * @param string $name Property name 8017 */ 8018 public function __unset($name) 8019 { 8020 if (method_exists($this, 'set_' . $name)) 8021 { 8022 call_user_func(array($this, 'set_' . $name), ''); 8023 } 8024 } 8025 8026 /** 8027 * Create a new IRI object, from a specified string 8028 * 8029 * @param string $iri 8030 */ 8031 public function __construct($iri = null) 8032 { 8033 $this->set_iri($iri); 8034 } 8035 8036 /** 8037 * Create a new IRI object by resolving a relative IRI 8038 * 8039 * Returns false if $base is not absolute, otherwise an IRI. 8040 * 8041 * @param IRI|string $base (Absolute) Base IRI 8042 * @param IRI|string $relative Relative IRI 8043 * @return IRI|false 8044 */ 8045 public static function absolutize($base, $relative) 8046 { 8047 if (!($relative instanceof SimplePie_IRI)) 8048 { 8049 $relative = new SimplePie_IRI($relative); 8050 } 8051 if (!$relative->is_valid()) 8052 { 8053 return false; 8054 } 8055 elseif ($relative->scheme !== null) 8056 { 8057 return clone $relative; 8058 } 8059 else 8060 { 8061 if (!($base instanceof SimplePie_IRI)) 8062 { 8063 $base = new SimplePie_IRI($base); 8064 } 8065 if ($base->scheme !== null && $base->is_valid()) 8066 { 8067 if ($relative->get_iri() !== '') 8068 { 8069 if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) 8070 { 8071 $target = clone $relative; 8072 $target->scheme = $base->scheme; 8073 } 8074 else 8075 { 8076 $target = new SimplePie_IRI; 8077 $target->scheme = $base->scheme; 8078 $target->iuserinfo = $base->iuserinfo; 8079 $target->ihost = $base->ihost; 8080 $target->port = $base->port; 8081 if ($relative->ipath !== '') 8082 { 8083 if ($relative->ipath[0] === '/') 8084 { 8085 $target->ipath = $relative->ipath; 8086 } 8087 elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') 8088 { 8089 $target->ipath = '/' . $relative->ipath; 8090 } 8091 elseif (($last_segment = strrpos($base->ipath, '/')) !== false) 8092 { 8093 $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; 8094 } 8095 else 8096 { 8097 $target->ipath = $relative->ipath; 8098 } 8099 $target->ipath = $target->remove_dot_segments($target->ipath); 8100 $target->iquery = $relative->iquery; 8101 } 8102 else 8103 { 8104 $target->ipath = $base->ipath; 8105 if ($relative->iquery !== null) 8106 { 8107 $target->iquery = $relative->iquery; 8108 } 8109 elseif ($base->iquery !== null) 8110 { 8111 $target->iquery = $base->iquery; 8112 } 8113 } 8114 $target->ifragment = $relative->ifragment; 8115 } 8116 } 8117 else 8118 { 8119 $target = clone $base; 8120 $target->ifragment = null; 8121 } 8122 $target->scheme_normalization(); 8123 return $target; 8124 } 8125 else 8126 { 8127 return false; 8128 } 8129 } 8130 } 8131 8132 /** 8133 * Parse an IRI into scheme/authority/path/query/fragment segments 8134 * 8135 * @param string $iri 8136 * @return array 8137 */ 8138 protected function parse_iri($iri) 8139 { 8140 $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); 8141 if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match)) 8142 { 8143 if ($match[1] === '') 8144 { 8145 $match['scheme'] = null; 8146 } 8147 if (!isset($match[3]) || $match[3] === '') 8148 { 8149 $match['authority'] = null; 8150 } 8151 if (!isset($match[5])) 8152 { 8153 $match['path'] = ''; 8154 } 8155 if (!isset($match[6]) || $match[6] === '') 8156 { 8157 $match['query'] = null; 8158 } 8159 if (!isset($match[8]) || $match[8] === '') 8160 { 8161 $match['fragment'] = null; 8162 } 8163 return $match; 8164 } 8165 else 8166 { 8167 // This can occur when a paragraph is accidentally parsed as a URI 8168 return false; 8169 } 8170 } 8171 8172 /** 8173 * Remove dot segments from a path 8174 * 8175 * @param string $input 8176 * @return string 8177 */ 8178 protected function remove_dot_segments($input) 8179 { 8180 $output = ''; 8181 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') 8182 { 8183 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, 8184 if (strpos($input, '../') === 0) 8185 { 8186 $input = substr($input, 3); 8187 } 8188 elseif (strpos($input, './') === 0) 8189 { 8190 $input = substr($input, 2); 8191 } 8192 // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, 8193 elseif (strpos($input, '/./') === 0) 8194 { 8195 $input = substr($input, 2); 8196 } 8197 elseif ($input === '/.') 8198 { 8199 $input = '/'; 8200 } 8201 // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, 8202 elseif (strpos($input, '/../') === 0) 8203 { 8204 $input = substr($input, 3); 8205 $output = substr_replace($output, '', strrpos($output, '/')); 8206 } 8207 elseif ($input === '/..') 8208 { 8209 $input = '/'; 8210 $output = substr_replace($output, '', strrpos($output, '/')); 8211 } 8212 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, 8213 elseif ($input === '.' || $input === '..') 8214 { 8215 $input = ''; 8216 } 8217 // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer 8218 elseif (($pos = strpos($input, '/', 1)) !== false) 8219 { 8220 $output .= substr($input, 0, $pos); 8221 $input = substr_replace($input, '', 0, $pos); 8222 } 8223 else 8224 { 8225 $output .= $input; 8226 $input = ''; 8227 } 8228 } 8229 return $output . $input; 8230 } 8231 8232 /** 8233 * Replace invalid character with percent encoding 8234 * 8235 * @param string $string Input string 8236 * @param string $extra_chars Valid characters not in iunreserved or 8237 * iprivate (this is ASCII-only) 8238 * @param bool $iprivate Allow iprivate 8239 * @return string 8240 */ 8241 protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) 8242 { 8243 // Normalize as many pct-encoded sections as possible 8244 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string); 8245 8246 // Replace invalid percent characters 8247 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); 8248 8249 // Add unreserved and % to $extra_chars (the latter is safe because all 8250 // pct-encoded sections are now valid). 8251 $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; 8252 8253 // Now replace any bytes that aren't allowed with their pct-encoded versions 8254 $position = 0; 8255 $strlen = strlen($string); 8256 while (($position += strspn($string, $extra_chars, $position)) < $strlen) 8257 { 8258 $value = ord($string[$position]); 8259 8260 // Start position 8261 $start = $position; 8262 8263 // By default we are valid 8264 $valid = true; 8265 8266 // No one byte sequences are valid due to the while. 8267 // Two byte sequence: 8268 if (($value & 0xE0) === 0xC0) 8269 { 8270 $character = ($value & 0x1F) << 6; 8271 $length = 2; 8272 $remaining = 1; 8273 } 8274 // Three byte sequence: 8275 elseif (($value & 0xF0) === 0xE0) 8276 { 8277 $character = ($value & 0x0F) << 12; 8278 $length = 3; 8279 $remaining = 2; 8280 } 8281 // Four byte sequence: 8282 elseif (($value & 0xF8) === 0xF0) 8283 { 8284 $character = ($value & 0x07) << 18; 8285 $length = 4; 8286 $remaining = 3; 8287 } 8288 // Invalid byte: 8289 else 8290 { 8291 $valid = false; 8292 $length = 1; 8293 $remaining = 0; 8294 } 8295 8296 if ($remaining) 8297 { 8298 if ($position + $length <= $strlen) 8299 { 8300 for ($position++; $remaining; $position++) 8301 { 8302 $value = ord($string[$position]); 8303 8304 // Check that the byte is valid, then add it to the character: 8305 if (($value & 0xC0) === 0x80) 8306 { 8307 $character |= ($value & 0x3F) << (--$remaining * 6); 8308 } 8309 // If it is invalid, count the sequence as invalid and reprocess the current byte: 8310 else 8311 { 8312 $valid = false; 8313 $position--; 8314 break; 8315 } 8316 } 8317 } 8318 else 8319 { 8320 $position = $strlen - 1; 8321 $valid = false; 8322 } 8323 } 8324 8325 // Percent encode anything invalid or not in ucschar 8326 if ( 8327 // Invalid sequences 8328 !$valid 8329 // Non-shortest form sequences are invalid 8330 || $length > 1 && $character <= 0x7F 8331 || $length > 2 && $character <= 0x7FF 8332 || $length > 3 && $character <= 0xFFFF 8333 // Outside of range of ucschar codepoints 8334 // Noncharacters 8335 || ($character & 0xFFFE) === 0xFFFE 8336 || $character >= 0xFDD0 && $character <= 0xFDEF 8337 || ( 8338 // Everything else not in ucschar 8339 $character > 0xD7FF && $character < 0xF900 8340 || $character < 0xA0 8341 || $character > 0xEFFFD 8342 ) 8343 && ( 8344 // Everything not in iprivate, if it applies 8345 !$iprivate 8346 || $character < 0xE000 8347 || $character > 0x10FFFD 8348 ) 8349 ) 8350 { 8351 // If we were a character, pretend we weren't, but rather an error. 8352 if ($valid) 8353 $position--; 8354 8355 for ($j = $start; $j <= $position; $j++) 8356 { 8357 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); 8358 $j += 2; 8359 $position += 2; 8360 $strlen += 2; 8361 } 8362 } 8363 } 8364 8365 return $string; 8366 } 8367 8368 /** 8369 * Callback function for preg_replace_callback. 8370 * 8371 * Removes sequences of percent encoded bytes that represent UTF-8 8372 * encoded characters in iunreserved 8373 * 8374 * @param array $match PCRE match 8375 * @return string Replacement 8376 */ 8377 protected function remove_iunreserved_percent_encoded($match) 8378 { 8379 // As we just have valid percent encoded sequences we can just explode 8380 // and ignore the first member of the returned array (an empty string). 8381 $bytes = explode('%', $match[0]); 8382 8383 // Initialize the new string (this is what will be returned) and that 8384 // there are no bytes remaining in the current sequence (unsurprising 8385 // at the first byte!). 8386 $string = ''; 8387 $remaining = 0; 8388 8389 // Loop over each and every byte, and set $value to its value 8390 for ($i = 1, $len = count($bytes); $i < $len; $i++) 8391 { 8392 $value = hexdec($bytes[$i]); 8393 8394 // If we're the first byte of sequence: 8395 if (!$remaining) 8396 { 8397 // Start position 8398 $start = $i; 8399 8400 // By default we are valid 8401 $valid = true; 8402 8403 // One byte sequence: 8404 if ($value <= 0x7F) 8405 { 8406 $character = $value; 8407 $length = 1; 8408 } 8409 // Two byte sequence: 8410 elseif (($value & 0xE0) === 0xC0) 8411 { 8412 $character = ($value & 0x1F) << 6; 8413 $length = 2; 8414 $remaining = 1; 8415 } 8416 // Three byte sequence: 8417 elseif (($value & 0xF0) === 0xE0) 8418 { 8419 $character = ($value & 0x0F) << 12; 8420 $length = 3; 8421 $remaining = 2; 8422 } 8423 // Four byte sequence: 8424 elseif (($value & 0xF8) === 0xF0) 8425 { 8426 $character = ($value & 0x07) << 18; 8427 $length = 4; 8428 $remaining = 3; 8429 } 8430 // Invalid byte: 8431 else 8432 { 8433 $valid = false; 8434 $remaining = 0; 8435 } 8436 } 8437 // Continuation byte: 8438 else 8439 { 8440 // Check that the byte is valid, then add it to the character: 8441 if (($value & 0xC0) === 0x80) 8442 { 8443 $remaining--; 8444 $character |= ($value & 0x3F) << ($remaining * 6); 8445 } 8446 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: 8447 else 8448 { 8449 $valid = false; 8450 $remaining = 0; 8451 $i--; 8452 } 8453 } 8454 8455 // If we've reached the end of the current byte sequence, append it to Unicode::$data 8456 if (!$remaining) 8457 { 8458 // Percent encode anything invalid or not in iunreserved 8459 if ( 8460 // Invalid sequences 8461 !$valid 8462 // Non-shortest form sequences are invalid 8463 || $length > 1 && $character <= 0x7F 8464 || $length > 2 && $character <= 0x7FF 8465 || $length > 3 && $character <= 0xFFFF 8466 // Outside of range of iunreserved codepoints 8467 || $character < 0x2D 8468 || $character > 0xEFFFD 8469 // Noncharacters 8470 || ($character & 0xFFFE) === 0xFFFE 8471 || $character >= 0xFDD0 && $character <= 0xFDEF 8472 // Everything else not in iunreserved (this is all BMP) 8473 || $character === 0x2F 8474 || $character > 0x39 && $character < 0x41 8475 || $character > 0x5A && $character < 0x61 8476 || $character > 0x7A && $character < 0x7E 8477 || $character > 0x7E && $character < 0xA0 8478 || $character > 0xD7FF && $character < 0xF900 8479 ) 8480 { 8481 for ($j = $start; $j <= $i; $j++) 8482 { 8483 $string .= '%' . strtoupper($bytes[$j]); 8484 } 8485 } 8486 else 8487 { 8488 for ($j = $start; $j <= $i; $j++) 8489 { 8490 $string .= chr(hexdec($bytes[$j])); 8491 } 8492 } 8493 } 8494 } 8495 8496 // If we have any bytes left over they are invalid (i.e., we are 8497 // mid-way through a multi-byte sequence) 8498 if ($remaining) 8499 { 8500 for ($j = $start; $j < $len; $j++) 8501 { 8502 $string .= '%' . strtoupper($bytes[$j]); 8503 } 8504 } 8505 8506 return $string; 8507 } 8508 8509 protected function scheme_normalization() 8510 { 8511 if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) 8512 { 8513 $this->iuserinfo = null; 8514 } 8515 if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) 8516 { 8517 $this->ihost = null; 8518 } 8519 if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) 8520 { 8521 $this->port = null; 8522 } 8523 if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) 8524 { 8525 $this->ipath = ''; 8526 } 8527 if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) 8528 { 8529 $this->iquery = null; 8530 } 8531 if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) 8532 { 8533 $this->ifragment = null; 8534 } 8535 } 8536 8537 /** 8538 * Check if the object represents a valid IRI. This needs to be done on each 8539 * call as some things change depending on another part of the IRI. 8540 * 8541 * @return bool 8542 */ 8543 public function is_valid() 8544 { 8545 $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; 8546 if ($this->ipath !== '' && 8547 ( 8548 $isauthority && ( 8549 $this->ipath[0] !== '/' || 8550 substr($this->ipath, 0, 2) === '//' 8551 ) || 8552 ( 8553 $this->scheme === null && 8554 !$isauthority && 8555 strpos($this->ipath, ':') !== false && 8556 (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) 8557 ) 8558 ) 8559 ) 8560 { 8561 return false; 8562 } 8563 8564 return true; 8565 } 8566 8567 /** 8568 * Set the entire IRI. Returns true on success, false on failure (if there 8569 * are any invalid characters). 8570 * 8571 * @param string $iri 8572 * @return bool 8573 */ 8574 public function set_iri($iri) 8575 { 8576 static $cache; 8577 if (!$cache) 8578 { 8579 $cache = array(); 8580 } 8581 8582 if ($iri === null) 8583 { 8584 return true; 8585 } 8586 elseif (isset($cache[$iri])) 8587 { 8588 list($this->scheme, 8589 $this->iuserinfo, 8590 $this->ihost, 8591 $this->port, 8592 $this->ipath, 8593 $this->iquery, 8594 $this->ifragment, 8595 $return) = $cache[$iri]; 8596 return $return; 8597 } 8598 else 8599 { 8600 $parsed = $this->parse_iri((string) $iri); 8601 if (!$parsed) 8602 { 8603 return false; 8604 } 8605 8606 $return = $this->set_scheme($parsed['scheme']) 8607 && $this->set_authority($parsed['authority']) 8608 && $this->set_path($parsed['path']) 8609 && $this->set_query($parsed['query']) 8610 && $this->set_fragment($parsed['fragment']); 8611 8612 $cache[$iri] = array($this->scheme, 8613 $this->iuserinfo, 8614 $this->ihost, 8615 $this->port, 8616 $this->ipath, 8617 $this->iquery, 8618 $this->ifragment, 8619 $return); 8620 return $return; 8621 } 8622 } 8623 8624 /** 8625 * Set the scheme. Returns true on success, false on failure (if there are 8626 * any invalid characters). 8627 * 8628 * @param string $scheme 8629 * @return bool 8630 */ 8631 public function set_scheme($scheme) 8632 { 8633 if ($scheme === null) 8634 { 8635 $this->scheme = null; 8636 } 8637 elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) 8638 { 8639 $this->scheme = null; 8640 return false; 8641 } 8642 else 8643 { 8644 $this->scheme = strtolower($scheme); 8645 } 8646 return true; 8647 } 8648 8649 /** 8650 * Set the authority. Returns true on success, false on failure (if there are 8651 * any invalid characters). 8652 * 8653 * @param string $authority 8654 * @return bool 8655 */ 8656 public function set_authority($authority) 8657 { 8658 static $cache; 8659 if (!$cache) 8660 $cache = array(); 8661 8662 if ($authority === null) 8663 { 8664 $this->iuserinfo = null; 8665 $this->ihost = null; 8666 $this->port = null; 8667 return true; 8668 } 8669 elseif (isset($cache[$authority])) 8670 { 8671 list($this->iuserinfo, 8672 $this->ihost, 8673 $this->port, 8674 $return) = $cache[$authority]; 8675 8676 return $return; 8677 } 8678 else 8679 { 8680 $remaining = $authority; 8681 if (($iuserinfo_end = strrpos($remaining, '@')) !== false) 8682 { 8683 $iuserinfo = substr($remaining, 0, $iuserinfo_end); 8684 $remaining = substr($remaining, $iuserinfo_end + 1); 8685 } 8686 else 8687 { 8688 $iuserinfo = null; 8689 } 8690 if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) 8691 { 8692 if (($port = substr($remaining, $port_start + 1)) === false) 8693 { 8694 $port = null; 8695 } 8696 $remaining = substr($remaining, 0, $port_start); 8697 } 8698 else 8699 { 8700 $port = null; 8701 } 8702 8703 $return = $this->set_userinfo($iuserinfo) && 8704 $this->set_host($remaining) && 8705 $this->set_port($port); 8706 8707 $cache[$authority] = array($this->iuserinfo, 8708 $this->ihost, 8709 $this->port, 8710 $return); 8711 8712 return $return; 8713 } 8714 } 8715 8716 /** 8717 * Set the iuserinfo. 8718 * 8719 * @param string $iuserinfo 8720 * @return bool 8721 */ 8722 public function set_userinfo($iuserinfo) 8723 { 8724 if ($iuserinfo === null) 8725 { 8726 $this->iuserinfo = null; 8727 } 8728 else 8729 { 8730 $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:'); 8731 $this->scheme_normalization(); 8732 } 8733 8734 return true; 8735 } 8736 8737 /** 8738 * Set the ihost. Returns true on success, false on failure (if there are 8739 * any invalid characters). 8740 * 8741 * @param string $ihost 8742 * @return bool 8743 */ 8744 public function set_host($ihost) 8745 { 8746 if ($ihost === null) 8747 { 8748 $this->ihost = null; 8749 return true; 8750 } 8751 elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') 8752 { 8753 if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1))) 8754 { 8755 $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']'; 8756 } 8757 else 8758 { 8759 $this->ihost = null; 8760 return false; 8761 } 8762 } 8763 else 8764 { 8765 $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;='); 8766 8767 // Lowercase, but ignore pct-encoded sections (as they should 8768 // remain uppercase). This must be done after the previous step 8769 // as that can add unescaped characters. 8770 $position = 0; 8771 $strlen = strlen($ihost); 8772 while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) 8773 { 8774 if ($ihost[$position] === '%') 8775 { 8776 $position += 3; 8777 } 8778 else 8779 { 8780 $ihost[$position] = strtolower($ihost[$position]); 8781 $position++; 8782 } 8783 } 8784 8785 $this->ihost = $ihost; 8786 } 8787 8788 $this->scheme_normalization(); 8789 8790 return true; 8791 } 8792 8793 /** 8794 * Set the port. Returns true on success, false on failure (if there are 8795 * any invalid characters). 8796 * 8797 * @param string $port 8798 * @return bool 8799 */ 8800 public function set_port($port) 8801 { 8802 if ($port === null) 8803 { 8804 $this->port = null; 8805 return true; 8806 } 8807 elseif (strspn($port, '0123456789') === strlen($port)) 8808 { 8809 $this->port = (int) $port; 8810 $this->scheme_normalization(); 8811 return true; 8812 } 8813 else 8814 { 8815 $this->port = null; 8816 return false; 8817 } 8818 } 8819 8820 /** 8821 * Set the ipath. 8822 * 8823 * @param string $ipath 8824 * @return bool 8825 */ 8826 public function set_path($ipath) 8827 { 8828 static $cache; 8829 if (!$cache) 8830 { 8831 $cache = array(); 8832 } 8833 8834 $ipath = (string) $ipath; 8835 8836 if (isset($cache[$ipath])) 8837 { 8838 $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; 8839 } 8840 else 8841 { 8842 $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/'); 8843 $removed = $this->remove_dot_segments($valid); 8844 8845 $cache[$ipath] = array($valid, $removed); 8846 $this->ipath = ($this->scheme !== null) ? $removed : $valid; 8847 } 8848 8849 $this->scheme_normalization(); 8850 return true; 8851 } 8852 8853 /** 8854 * Set the iquery. 8855 * 8856 * @param string $iquery 8857 * @return bool 8858 */ 8859 public function set_query($iquery) 8860 { 8861 if ($iquery === null) 8862 { 8863 $this->iquery = null; 8864 } 8865 else 8866 { 8867 $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true); 8868 $this->scheme_normalization(); 8869 } 8870 return true; 8871 } 8872 8873 /** 8874 * Set the ifragment. 8875 * 8876 * @param string $ifragment 8877 * @return bool 8878 */ 8879 public function set_fragment($ifragment) 8880 { 8881 if ($ifragment === null) 8882 { 8883 $this->ifragment = null; 8884 } 8885 else 8886 { 8887 $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?'); 8888 $this->scheme_normalization(); 8889 } 8890 return true; 8891 } 8892 8893 /** 8894 * Convert an IRI to a URI (or parts thereof) 8895 * 8896 * @return string 8897 */ 8898 public function to_uri($string) 8899 { 8900 static $non_ascii; 8901 if (!$non_ascii) 8902 { 8903 $non_ascii = implode('', range("\x80", "\xFF")); 8904 } 8905 8906 $position = 0; 8907 $strlen = strlen($string); 8908 while (($position += strcspn($string, $non_ascii, $position)) < $strlen) 8909 { 8910 $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); 8911 $position += 3; 8912 $strlen += 2; 8913 } 8914 8915 return $string; 8916 } 8917 8918 /** 8919 * Get the complete IRI 8920 * 8921 * @return string 8922 */ 8923 public function get_iri() 8924 { 8925 if (!$this->is_valid()) 8926 { 8927 return false; 8928 } 8929 8930 $iri = ''; 8931 if ($this->scheme !== null) 8932 { 8933 $iri .= $this->scheme . ':'; 8934 } 8935 if (($iauthority = $this->get_iauthority()) !== null) 8936 { 8937 $iri .= '//' . $iauthority; 8938 } 8939 if ($this->ipath !== '') 8940 { 8941 $iri .= $this->ipath; 8942 } 8943 elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '') 8944 { 8945 $iri .= $this->normalization[$this->scheme]['ipath']; 8946 } 8947 if ($this->iquery !== null) 8948 { 8949 $iri .= '?' . $this->iquery; 8950 } 8951 if ($this->ifragment !== null) 8952 { 8953 $iri .= '#' . $this->ifragment; 8954 } 8955 8956 return $iri; 8957 } 8958 8959 /** 8960 * Get the complete URI 8961 * 8962 * @return string 8963 */ 8964 public function get_uri() 8965 { 8966 return $this->to_uri($this->get_iri()); 8967 } 8968 8969 /** 8970 * Get the complete iauthority 8971 * 8972 * @return string 8973 */ 8974 protected function get_iauthority() 8975 { 8976 if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null) 8977 { 8978 $iauthority = ''; 8979 if ($this->iuserinfo !== null) 8980 { 8981 $iauthority .= $this->iuserinfo . '@'; 8982 } 8983 if ($this->ihost !== null) 8984 { 8985 $iauthority .= $this->ihost; 8986 } 8987 if ($this->port !== null) 8988 { 8989 $iauthority .= ':' . $this->port; 8990 } 8991 return $iauthority; 8992 } 8993 else 8994 { 8995 return null; 8996 } 8997 } 8998 8999 /** 9000 * Get the complete authority 9001 * 9002 * @return string 9003 */ 9004 protected function get_authority() 9005 { 9006 $iauthority = $this->get_iauthority(); 9007 if (is_string($iauthority)) 9008 return $this->to_uri($iauthority); 9009 else 9010 return $iauthority; 9011 } 9012 } 9013 9014 /** 9015 * Manages all item-related data 9016 * 9017 * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()} 9018 * 9019 * This class can be overloaded with {@see SimplePie::set_item_class()} 9020 * 9021 * @package SimplePie 9022 * @subpackage API 9023 */ 9024 class SimplePie_Item 9025 { 9026 /** 9027 * Parent feed 9028 * 9029 * @access private 9030 * @var SimplePie 9031 */ 9032 var $feed; 9033 9034 /** 9035 * Raw data 9036 * 9037 * @access private 9038 * @var array 9039 */ 9040 var $data = array(); 9041 9042 /** 9043 * Registry object 9044 * 9045 * @see set_registry 9046 * @var SimplePie_Registry 9047 */ 9048 protected $registry; 9049 9050 /** 9051 * Create a new item object 9052 * 9053 * This is usually used by {@see SimplePie::get_items} and 9054 * {@see SimplePie::get_item}. Avoid creating this manually. 9055 * 9056 * @param SimplePie $feed Parent feed 9057 * @param array $data Raw data 9058 */ 9059 public function __construct($feed, $data) 9060 { 9061 $this->feed = $feed; 9062 $this->data = $data; 9063 } 9064 9065 /** 9066 * Set the registry handler 9067 * 9068 * This is usually used by {@see SimplePie_Registry::create} 9069 * 9070 * @since 1.3 9071 * @param SimplePie_Registry $registry 9072 */ 9073 public function set_registry(SimplePie_Registry $registry) 9074 { 9075 $this->registry = $registry; 9076 } 9077 9078 /** 9079 * Get a string representation of the item 9080 * 9081 * @return string 9082 */ 9083 public function __toString() 9084 { 9085 return md5(serialize($this->data)); 9086 } 9087 9088 /** 9089 * Remove items that link back to this before destroying this object 9090 */ 9091 public function __destruct() 9092 { 9093 if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode')) 9094 { 9095 unset($this->feed); 9096 } 9097 } 9098 9099 /** 9100 * Get data for an item-level element 9101 * 9102 * This method allows you to get access to ANY element/attribute that is a 9103 * sub-element of the item/entry tag. 9104 * 9105 * See {@see SimplePie::get_feed_tags()} for a description of the return value 9106 * 9107 * @since 1.0 9108 * @see http://simplepie.org/wiki/faq/supported_xml_namespaces 9109 * @param string $namespace The URL of the XML namespace of the elements you're trying to access 9110 * @param string $tag Tag name 9111 * @return array 9112 */ 9113 public function get_item_tags($namespace, $tag) 9114 { 9115 if (isset($this->data['child'][$namespace][$tag])) 9116 { 9117 return $this->data['child'][$namespace][$tag]; 9118 } 9119 else 9120 { 9121 return null; 9122 } 9123 } 9124 9125 /** 9126 * Get the base URL value from the parent feed 9127 * 9128 * Uses `<xml:base>` 9129 * 9130 * @param array $element 9131 * @return string 9132 */ 9133 public function get_base($element = array()) 9134 { 9135 return $this->feed->get_base($element); 9136 } 9137 9138 /** 9139 * Sanitize feed data 9140 * 9141 * @access private 9142 * @see SimplePie::sanitize() 9143 * @param string $data Data to sanitize 9144 * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants 9145 * @param string $base Base URL to resolve URLs against 9146 * @return string Sanitized data 9147 */ 9148 public function sanitize($data, $type, $base = '') 9149 { 9150 return $this->feed->sanitize($data, $type, $base); 9151 } 9152 9153 /** 9154 * Get the parent feed 9155 * 9156 * Note: this may not work as you think for multifeeds! 9157 * 9158 * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed 9159 * @since 1.0 9160 * @return SimplePie 9161 */ 9162 public function get_feed() 9163 { 9164 return $this->feed; 9165 } 9166 9167 /** 9168 * Get the unique identifier for the item 9169 * 9170 * This is usually used when writing code to check for new items in a feed. 9171 * 9172 * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute 9173 * for RDF. If none of these are supplied (or `$hash` is true), creates an 9174 * MD5 hash based on the permalink and title. If either of those are not 9175 * supplied, creates a hash based on the full feed data. 9176 * 9177 * @since Beta 2 9178 * @param boolean $hash Should we force using a hash instead of the supplied ID? 9179 * @return string 9180 */ 9181 public function get_id($hash = false) 9182 { 9183 if (!$hash) 9184 { 9185 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id')) 9186 { 9187 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9188 } 9189 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id')) 9190 { 9191 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9192 } 9193 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid')) 9194 { 9195 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9196 } 9197 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier')) 9198 { 9199 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9200 } 9201 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier')) 9202 { 9203 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9204 } 9205 elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'])) 9206 { 9207 return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT); 9208 } 9209 elseif (($return = $this->get_permalink()) !== null) 9210 { 9211 return $return; 9212 } 9213 elseif (($return = $this->get_title()) !== null) 9214 { 9215 return $return; 9216 } 9217 } 9218 if ($this->get_permalink() !== null || $this->get_title() !== null) 9219 { 9220 return md5($this->get_permalink() . $this->get_title()); 9221 } 9222 else 9223 { 9224 return md5(serialize($this->data)); 9225 } 9226 } 9227 9228 /** 9229 * Get the title of the item 9230 * 9231 * Uses `<atom:title>`, `<title>` or `<dc:title>` 9232 * 9233 * @since Beta 2 (previously called `get_item_title` since 0.8) 9234 * @return string|null 9235 */ 9236 public function get_title() 9237 { 9238 if (!isset($this->data['title'])) 9239 { 9240 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) 9241 { 9242 $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9243 } 9244 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) 9245 { 9246 $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9247 } 9248 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) 9249 { 9250 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 9251 } 9252 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) 9253 { 9254 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 9255 } 9256 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) 9257 { 9258 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 9259 } 9260 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) 9261 { 9262 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9263 } 9264 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) 9265 { 9266 $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9267 } 9268 else 9269 { 9270 $this->data['title'] = null; 9271 } 9272 } 9273 return $this->data['title']; 9274 } 9275 9276 /** 9277 * Get the content for the item 9278 * 9279 * Prefers summaries over full content , but will return full content if a 9280 * summary does not exist. 9281 * 9282 * To prefer full content instead, use {@see get_content} 9283 * 9284 * Uses `<atom:summary>`, `<description>`, `<dc:description>` or 9285 * `<itunes:subtitle>` 9286 * 9287 * @since 0.8 9288 * @param boolean $description_only Should we avoid falling back to the content? 9289 * @return string|null 9290 */ 9291 public function get_description($description_only = false) 9292 { 9293 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary')) 9294 { 9295 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9296 } 9297 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary')) 9298 { 9299 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9300 } 9301 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) 9302 { 9303 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 9304 } 9305 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) 9306 { 9307 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 9308 } 9309 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) 9310 { 9311 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9312 } 9313 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) 9314 { 9315 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9316 } 9317 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) 9318 { 9319 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 9320 } 9321 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) 9322 { 9323 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9324 } 9325 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) 9326 { 9327 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML); 9328 } 9329 9330 elseif (!$description_only) 9331 { 9332 return $this->get_content(true); 9333 } 9334 else 9335 { 9336 return null; 9337 } 9338 } 9339 9340 /** 9341 * Get the content for the item 9342 * 9343 * Prefers full content over summaries, but will return a summary if full 9344 * content does not exist. 9345 * 9346 * To prefer summaries instead, use {@see get_description} 9347 * 9348 * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module) 9349 * 9350 * @since 1.0 9351 * @param boolean $content_only Should we avoid falling back to the description? 9352 * @return string|null 9353 */ 9354 public function get_content($content_only = false) 9355 { 9356 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content')) 9357 { 9358 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9359 } 9360 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content')) 9361 { 9362 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9363 } 9364 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded')) 9365 { 9366 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 9367 } 9368 elseif (!$content_only) 9369 { 9370 return $this->get_description(true); 9371 } 9372 else 9373 { 9374 return null; 9375 } 9376 } 9377 9378 /** 9379 * Get a category for the item 9380 * 9381 * @since Beta 3 (previously called `get_categories()` since Beta 2) 9382 * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1 9383 * @return SimplePie_Category|null 9384 */ 9385 public function get_category($key = 0) 9386 { 9387 $categories = $this->get_categories(); 9388 if (isset($categories[$key])) 9389 { 9390 return $categories[$key]; 9391 } 9392 else 9393 { 9394 return null; 9395 } 9396 } 9397 9398 /** 9399 * Get all categories for the item 9400 * 9401 * Uses `<atom:category>`, `<category>` or `<dc:subject>` 9402 * 9403 * @since Beta 3 9404 * @return array|null List of {@see SimplePie_Category} objects 9405 */ 9406 public function get_categories() 9407 { 9408 $categories = array(); 9409 9410 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) 9411 { 9412 $term = null; 9413 $scheme = null; 9414 $label = null; 9415 if (isset($category['attribs']['']['term'])) 9416 { 9417 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); 9418 } 9419 if (isset($category['attribs']['']['scheme'])) 9420 { 9421 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 9422 } 9423 if (isset($category['attribs']['']['label'])) 9424 { 9425 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 9426 } 9427 $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); 9428 } 9429 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) 9430 { 9431 // This is really the label, but keep this as the term also for BC. 9432 // Label will also work on retrieving because that falls back to term. 9433 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9434 if (isset($category['attribs']['']['domain'])) 9435 { 9436 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); 9437 } 9438 else 9439 { 9440 $scheme = null; 9441 } 9442 $categories[] = $this->registry->create('Category', array($term, $scheme, null)); 9443 } 9444 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) 9445 { 9446 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 9447 } 9448 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) 9449 { 9450 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 9451 } 9452 9453 if (!empty($categories)) 9454 { 9455 return array_unique($categories); 9456 } 9457 else 9458 { 9459 return null; 9460 } 9461 } 9462 9463 /** 9464 * Get an author for the item 9465 * 9466 * @since Beta 2 9467 * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1 9468 * @return SimplePie_Author|null 9469 */ 9470 public function get_author($key = 0) 9471 { 9472 $authors = $this->get_authors(); 9473 if (isset($authors[$key])) 9474 { 9475 return $authors[$key]; 9476 } 9477 else 9478 { 9479 return null; 9480 } 9481 } 9482 9483 /** 9484 * Get a contributor for the item 9485 * 9486 * @since 1.1 9487 * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1 9488 * @return SimplePie_Author|null 9489 */ 9490 public function get_contributor($key = 0) 9491 { 9492 $contributors = $this->get_contributors(); 9493 if (isset($contributors[$key])) 9494 { 9495 return $contributors[$key]; 9496 } 9497 else 9498 { 9499 return null; 9500 } 9501 } 9502 9503 /** 9504 * Get all contributors for the item 9505 * 9506 * Uses `<atom:contributor>` 9507 * 9508 * @since 1.1 9509 * @return array|null List of {@see SimplePie_Author} objects 9510 */ 9511 public function get_contributors() 9512 { 9513 $contributors = array(); 9514 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) 9515 { 9516 $name = null; 9517 $uri = null; 9518 $email = null; 9519 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) 9520 { 9521 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9522 } 9523 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) 9524 { 9525 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); 9526 } 9527 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) 9528 { 9529 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9530 } 9531 if ($name !== null || $email !== null || $uri !== null) 9532 { 9533 $contributors[] = $this->registry->create('Author', array($name, $uri, $email)); 9534 } 9535 } 9536 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) 9537 { 9538 $name = null; 9539 $url = null; 9540 $email = null; 9541 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) 9542 { 9543 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9544 } 9545 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) 9546 { 9547 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); 9548 } 9549 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) 9550 { 9551 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9552 } 9553 if ($name !== null || $email !== null || $url !== null) 9554 { 9555 $contributors[] = $this->registry->create('Author', array($name, $url, $email)); 9556 } 9557 } 9558 9559 if (!empty($contributors)) 9560 { 9561 return array_unique($contributors); 9562 } 9563 else 9564 { 9565 return null; 9566 } 9567 } 9568 9569 /** 9570 * Get all authors for the item 9571 * 9572 * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>` 9573 * 9574 * @since Beta 2 9575 * @return array|null List of {@see SimplePie_Author} objects 9576 */ 9577 public function get_authors() 9578 { 9579 $authors = array(); 9580 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) 9581 { 9582 $name = null; 9583 $uri = null; 9584 $email = null; 9585 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) 9586 { 9587 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9588 } 9589 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) 9590 { 9591 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); 9592 } 9593 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) 9594 { 9595 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9596 } 9597 if ($name !== null || $email !== null || $uri !== null) 9598 { 9599 $authors[] = $this->registry->create('Author', array($name, $uri, $email)); 9600 } 9601 } 9602 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) 9603 { 9604 $name = null; 9605 $url = null; 9606 $email = null; 9607 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) 9608 { 9609 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9610 } 9611 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) 9612 { 9613 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); 9614 } 9615 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) 9616 { 9617 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9618 } 9619 if ($name !== null || $email !== null || $url !== null) 9620 { 9621 $authors[] = $this->registry->create('Author', array($name, $url, $email)); 9622 } 9623 } 9624 if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author')) 9625 { 9626 $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT))); 9627 } 9628 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) 9629 { 9630 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 9631 } 9632 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) 9633 { 9634 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 9635 } 9636 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) 9637 { 9638 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 9639 } 9640 9641 if (!empty($authors)) 9642 { 9643 return array_unique($authors); 9644 } 9645 elseif (($source = $this->get_source()) && ($authors = $source->get_authors())) 9646 { 9647 return $authors; 9648 } 9649 elseif ($authors = $this->feed->get_authors()) 9650 { 9651 return $authors; 9652 } 9653 else 9654 { 9655 return null; 9656 } 9657 } 9658 9659 /** 9660 * Get the copyright info for the item 9661 * 9662 * Uses `<atom:rights>` or `<dc:rights>` 9663 * 9664 * @since 1.1 9665 * @return string 9666 */ 9667 public function get_copyright() 9668 { 9669 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) 9670 { 9671 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 9672 } 9673 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) 9674 { 9675 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9676 } 9677 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) 9678 { 9679 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 9680 } 9681 else 9682 { 9683 return null; 9684 } 9685 } 9686 9687 /** 9688 * Get the posting date/time for the item 9689 * 9690 * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`, 9691 * `<atom:modified>`, `<pubDate>` or `<dc:date>` 9692 * 9693 * Note: obeys PHP's timezone setting. To get a UTC date/time, use 9694 * {@see get_gmdate} 9695 * 9696 * @since Beta 2 (previously called `get_item_date` since 0.8) 9697 * 9698 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data) 9699 * @return int|string|null 9700 */ 9701 public function get_date($date_format = 'j F Y, g:i a') 9702 { 9703 if (!isset($this->data['date'])) 9704 { 9705 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published')) 9706 { 9707 $this->data['date']['raw'] = $return[0]['data']; 9708 } 9709 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated')) 9710 { 9711 $this->data['date']['raw'] = $return[0]['data']; 9712 } 9713 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued')) 9714 { 9715 $this->data['date']['raw'] = $return[0]['data']; 9716 } 9717 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created')) 9718 { 9719 $this->data['date']['raw'] = $return[0]['data']; 9720 } 9721 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified')) 9722 { 9723 $this->data['date']['raw'] = $return[0]['data']; 9724 } 9725 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate')) 9726 { 9727 $this->data['date']['raw'] = $return[0]['data']; 9728 } 9729 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date')) 9730 { 9731 $this->data['date']['raw'] = $return[0]['data']; 9732 } 9733 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date')) 9734 { 9735 $this->data['date']['raw'] = $return[0]['data']; 9736 } 9737 9738 if (!empty($this->data['date']['raw'])) 9739 { 9740 $parser = $this->registry->call('Parse_Date', 'get'); 9741 $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']); 9742 } 9743 else 9744 { 9745 $this->data['date'] = null; 9746 } 9747 } 9748 if ($this->data['date']) 9749 { 9750 $date_format = (string) $date_format; 9751 switch ($date_format) 9752 { 9753 case '': 9754 return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT); 9755 9756 case 'U': 9757 return $this->data['date']['parsed']; 9758 9759 default: 9760 return date($date_format, $this->data['date']['parsed']); 9761 } 9762 } 9763 else 9764 { 9765 return null; 9766 } 9767 } 9768 9769 /** 9770 * Get the update date/time for the item 9771 * 9772 * Uses `<atom:updated>` 9773 * 9774 * Note: obeys PHP's timezone setting. To get a UTC date/time, use 9775 * {@see get_gmdate} 9776 * 9777 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data) 9778 * @return int|string|null 9779 */ 9780 public function get_updated_date($date_format = 'j F Y, g:i a') 9781 { 9782 if (!isset($this->data['updated'])) 9783 { 9784 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated')) 9785 { 9786 $this->data['updated']['raw'] = $return[0]['data']; 9787 } 9788 9789 if (!empty($this->data['updated']['raw'])) 9790 { 9791 $parser = $this->registry->call('Parse_Date', 'get'); 9792 $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']); 9793 } 9794 else 9795 { 9796 $this->data['updated'] = null; 9797 } 9798 } 9799 if ($this->data['updated']) 9800 { 9801 $date_format = (string) $date_format; 9802 switch ($date_format) 9803 { 9804 case '': 9805 return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT); 9806 9807 case 'U': 9808 return $this->data['updated']['parsed']; 9809 9810 default: 9811 return date($date_format, $this->data['updated']['parsed']); 9812 } 9813 } 9814 else 9815 { 9816 return null; 9817 } 9818 } 9819 9820 /** 9821 * Get the localized posting date/time for the item 9822 * 9823 * Returns the date formatted in the localized language. To display in 9824 * languages other than the server's default, you need to change the locale 9825 * with {@link http://php.net/setlocale setlocale()}. The available 9826 * localizations depend on which ones are installed on your web server. 9827 * 9828 * @since 1.0 9829 * 9830 * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data) 9831 * @return int|string|null 9832 */ 9833 public function get_local_date($date_format = '%c') 9834 { 9835 if (!$date_format) 9836 { 9837 return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT); 9838 } 9839 elseif (($date = $this->get_date('U')) !== null && $date !== false) 9840 { 9841 return strftime($date_format, $date); 9842 } 9843 else 9844 { 9845 return null; 9846 } 9847 } 9848 9849 /** 9850 * Get the posting date/time for the item (UTC time) 9851 * 9852 * @see get_date 9853 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} 9854 * @return int|string|null 9855 */ 9856 public function get_gmdate($date_format = 'j F Y, g:i a') 9857 { 9858 $date = $this->get_date('U'); 9859 if ($date === null) 9860 { 9861 return null; 9862 } 9863 9864 return gmdate($date_format, $date); 9865 } 9866 9867 /** 9868 * Get the update date/time for the item (UTC time) 9869 * 9870 * @see get_updated_date 9871 * @param string $date_format Supports any PHP date format from {@see http://php.net/date} 9872 * @return int|string|null 9873 */ 9874 public function get_updated_gmdate($date_format = 'j F Y, g:i a') 9875 { 9876 $date = $this->get_updated_date('U'); 9877 if ($date === null) 9878 { 9879 return null; 9880 } 9881 9882 return gmdate($date_format, $date); 9883 } 9884 9885 /** 9886 * Get the permalink for the item 9887 * 9888 * Returns the first link available with a relationship of "alternate". 9889 * Identical to {@see get_link()} with key 0 9890 * 9891 * @see get_link 9892 * @since 0.8 9893 * @return string|null Permalink URL 9894 */ 9895 public function get_permalink() 9896 { 9897 $link = $this->get_link(); 9898 $enclosure = $this->get_enclosure(0); 9899 if ($link !== null) 9900 { 9901 return $link; 9902 } 9903 elseif ($enclosure !== null) 9904 { 9905 return $enclosure->get_link(); 9906 } 9907 else 9908 { 9909 return null; 9910 } 9911 } 9912 9913 /** 9914 * Get a single link for the item 9915 * 9916 * @since Beta 3 9917 * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1 9918 * @param string $rel The relationship of the link to return 9919 * @return string|null Link URL 9920 */ 9921 public function get_link($key = 0, $rel = 'alternate') 9922 { 9923 $links = $this->get_links($rel); 9924 if ($links[$key] !== null) 9925 { 9926 return $links[$key]; 9927 } 9928 else 9929 { 9930 return null; 9931 } 9932 } 9933 9934 /** 9935 * Get all links for the item 9936 * 9937 * Uses `<atom:link>`, `<link>` or `<guid>` 9938 * 9939 * @since Beta 2 9940 * @param string $rel The relationship of links to return 9941 * @return array|null Links found for the item (strings) 9942 */ 9943 public function get_links($rel = 'alternate') 9944 { 9945 if (!isset($this->data['links'])) 9946 { 9947 $this->data['links'] = array(); 9948 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) 9949 { 9950 if (isset($link['attribs']['']['href'])) 9951 { 9952 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; 9953 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 9954 9955 } 9956 } 9957 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) 9958 { 9959 if (isset($link['attribs']['']['href'])) 9960 { 9961 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; 9962 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 9963 } 9964 } 9965 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) 9966 { 9967 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 9968 } 9969 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) 9970 { 9971 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 9972 } 9973 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) 9974 { 9975 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 9976 } 9977 if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid')) 9978 { 9979 if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true') 9980 { 9981 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 9982 } 9983 } 9984 9985 $keys = array_keys($this->data['links']); 9986 foreach ($keys as $key) 9987 { 9988 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key))) 9989 { 9990 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) 9991 { 9992 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); 9993 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; 9994 } 9995 else 9996 { 9997 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; 9998 } 9999 } 10000 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) 10001 { 10002 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; 10003 } 10004 $this->data['links'][$key] = array_unique($this->data['links'][$key]); 10005 } 10006 } 10007 if (isset($this->data['links'][$rel])) 10008 { 10009 return $this->data['links'][$rel]; 10010 } 10011 else 10012 { 10013 return null; 10014 } 10015 } 10016 10017 /** 10018 * Get an enclosure from the item 10019 * 10020 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS. 10021 * 10022 * @since Beta 2 10023 * @todo Add ability to prefer one type of content over another (in a media group). 10024 * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1 10025 * @return SimplePie_Enclosure|null 10026 */ 10027 public function get_enclosure($key = 0, $prefer = null) 10028 { 10029 $enclosures = $this->get_enclosures(); 10030 if (isset($enclosures[$key])) 10031 { 10032 return $enclosures[$key]; 10033 } 10034 else 10035 { 10036 return null; 10037 } 10038 } 10039 10040 /** 10041 * Get all available enclosures (podcasts, etc.) 10042 * 10043 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS. 10044 * 10045 * At this point, we're pretty much assuming that all enclosures for an item 10046 * are the same content. Anything else is too complicated to 10047 * properly support. 10048 * 10049 * @since Beta 2 10050 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4). 10051 * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists). 10052 * @return array|null List of SimplePie_Enclosure items 10053 */ 10054 public function get_enclosures() 10055 { 10056 if (!isset($this->data['enclosures'])) 10057 { 10058 $this->data['enclosures'] = array(); 10059 10060 // Elements 10061 $captions_parent = null; 10062 $categories_parent = null; 10063 $copyrights_parent = null; 10064 $credits_parent = null; 10065 $description_parent = null; 10066 $duration_parent = null; 10067 $hashes_parent = null; 10068 $keywords_parent = null; 10069 $player_parent = null; 10070 $ratings_parent = null; 10071 $restrictions_parent = null; 10072 $thumbnails_parent = null; 10073 $title_parent = null; 10074 10075 // Let's do the channel and item-level ones first, and just re-use them if we need to. 10076 $parent = $this->get_feed(); 10077 10078 // CAPTIONS 10079 if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text')) 10080 { 10081 foreach ($captions as $caption) 10082 { 10083 $caption_type = null; 10084 $caption_lang = null; 10085 $caption_startTime = null; 10086 $caption_endTime = null; 10087 $caption_text = null; 10088 if (isset($caption['attribs']['']['type'])) 10089 { 10090 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10091 } 10092 if (isset($caption['attribs']['']['lang'])) 10093 { 10094 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 10095 } 10096 if (isset($caption['attribs']['']['start'])) 10097 { 10098 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); 10099 } 10100 if (isset($caption['attribs']['']['end'])) 10101 { 10102 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); 10103 } 10104 if (isset($caption['data'])) 10105 { 10106 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10107 } 10108 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); 10109 } 10110 } 10111 elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text')) 10112 { 10113 foreach ($captions as $caption) 10114 { 10115 $caption_type = null; 10116 $caption_lang = null; 10117 $caption_startTime = null; 10118 $caption_endTime = null; 10119 $caption_text = null; 10120 if (isset($caption['attribs']['']['type'])) 10121 { 10122 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10123 } 10124 if (isset($caption['attribs']['']['lang'])) 10125 { 10126 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 10127 } 10128 if (isset($caption['attribs']['']['start'])) 10129 { 10130 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); 10131 } 10132 if (isset($caption['attribs']['']['end'])) 10133 { 10134 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); 10135 } 10136 if (isset($caption['data'])) 10137 { 10138 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10139 } 10140 $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); 10141 } 10142 } 10143 if (is_array($captions_parent)) 10144 { 10145 $captions_parent = array_values(array_unique($captions_parent)); 10146 } 10147 10148 // CATEGORIES 10149 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category) 10150 { 10151 $term = null; 10152 $scheme = null; 10153 $label = null; 10154 if (isset($category['data'])) 10155 { 10156 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10157 } 10158 if (isset($category['attribs']['']['scheme'])) 10159 { 10160 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10161 } 10162 else 10163 { 10164 $scheme = 'http://search.yahoo.com/mrss/category_schema'; 10165 } 10166 if (isset($category['attribs']['']['label'])) 10167 { 10168 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 10169 } 10170 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); 10171 } 10172 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category) 10173 { 10174 $term = null; 10175 $scheme = null; 10176 $label = null; 10177 if (isset($category['data'])) 10178 { 10179 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10180 } 10181 if (isset($category['attribs']['']['scheme'])) 10182 { 10183 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10184 } 10185 else 10186 { 10187 $scheme = 'http://search.yahoo.com/mrss/category_schema'; 10188 } 10189 if (isset($category['attribs']['']['label'])) 10190 { 10191 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 10192 } 10193 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); 10194 } 10195 foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category) 10196 { 10197 $term = null; 10198 $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd'; 10199 $label = null; 10200 if (isset($category['attribs']['']['text'])) 10201 { 10202 $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT); 10203 } 10204 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); 10205 10206 if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'])) 10207 { 10208 foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory) 10209 { 10210 if (isset($subcategory['attribs']['']['text'])) 10211 { 10212 $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT); 10213 } 10214 $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label)); 10215 } 10216 } 10217 } 10218 if (is_array($categories_parent)) 10219 { 10220 $categories_parent = array_values(array_unique($categories_parent)); 10221 } 10222 10223 // COPYRIGHT 10224 if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright')) 10225 { 10226 $copyright_url = null; 10227 $copyright_label = null; 10228 if (isset($copyright[0]['attribs']['']['url'])) 10229 { 10230 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); 10231 } 10232 if (isset($copyright[0]['data'])) 10233 { 10234 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10235 } 10236 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); 10237 } 10238 elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright')) 10239 { 10240 $copyright_url = null; 10241 $copyright_label = null; 10242 if (isset($copyright[0]['attribs']['']['url'])) 10243 { 10244 $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); 10245 } 10246 if (isset($copyright[0]['data'])) 10247 { 10248 $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10249 } 10250 $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); 10251 } 10252 10253 // CREDITS 10254 if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit')) 10255 { 10256 foreach ($credits as $credit) 10257 { 10258 $credit_role = null; 10259 $credit_scheme = null; 10260 $credit_name = null; 10261 if (isset($credit['attribs']['']['role'])) 10262 { 10263 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); 10264 } 10265 if (isset($credit['attribs']['']['scheme'])) 10266 { 10267 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10268 } 10269 else 10270 { 10271 $credit_scheme = 'urn:ebu'; 10272 } 10273 if (isset($credit['data'])) 10274 { 10275 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10276 } 10277 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); 10278 } 10279 } 10280 elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit')) 10281 { 10282 foreach ($credits as $credit) 10283 { 10284 $credit_role = null; 10285 $credit_scheme = null; 10286 $credit_name = null; 10287 if (isset($credit['attribs']['']['role'])) 10288 { 10289 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); 10290 } 10291 if (isset($credit['attribs']['']['scheme'])) 10292 { 10293 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10294 } 10295 else 10296 { 10297 $credit_scheme = 'urn:ebu'; 10298 } 10299 if (isset($credit['data'])) 10300 { 10301 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10302 } 10303 $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); 10304 } 10305 } 10306 if (is_array($credits_parent)) 10307 { 10308 $credits_parent = array_values(array_unique($credits_parent)); 10309 } 10310 10311 // DESCRIPTION 10312 if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description')) 10313 { 10314 if (isset($description_parent[0]['data'])) 10315 { 10316 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10317 } 10318 } 10319 elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description')) 10320 { 10321 if (isset($description_parent[0]['data'])) 10322 { 10323 $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10324 } 10325 } 10326 10327 // DURATION 10328 if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration')) 10329 { 10330 $seconds = null; 10331 $minutes = null; 10332 $hours = null; 10333 if (isset($duration_parent[0]['data'])) 10334 { 10335 $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 10336 if (sizeof($temp) > 0) 10337 { 10338 $seconds = (int) array_pop($temp); 10339 } 10340 if (sizeof($temp) > 0) 10341 { 10342 $minutes = (int) array_pop($temp); 10343 $seconds += $minutes * 60; 10344 } 10345 if (sizeof($temp) > 0) 10346 { 10347 $hours = (int) array_pop($temp); 10348 $seconds += $hours * 3600; 10349 } 10350 unset($temp); 10351 $duration_parent = $seconds; 10352 } 10353 } 10354 10355 // HASHES 10356 if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash')) 10357 { 10358 foreach ($hashes_iterator as $hash) 10359 { 10360 $value = null; 10361 $algo = null; 10362 if (isset($hash['data'])) 10363 { 10364 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10365 } 10366 if (isset($hash['attribs']['']['algo'])) 10367 { 10368 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); 10369 } 10370 else 10371 { 10372 $algo = 'md5'; 10373 } 10374 $hashes_parent[] = $algo.':'.$value; 10375 } 10376 } 10377 elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash')) 10378 { 10379 foreach ($hashes_iterator as $hash) 10380 { 10381 $value = null; 10382 $algo = null; 10383 if (isset($hash['data'])) 10384 { 10385 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10386 } 10387 if (isset($hash['attribs']['']['algo'])) 10388 { 10389 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); 10390 } 10391 else 10392 { 10393 $algo = 'md5'; 10394 } 10395 $hashes_parent[] = $algo.':'.$value; 10396 } 10397 } 10398 if (is_array($hashes_parent)) 10399 { 10400 $hashes_parent = array_values(array_unique($hashes_parent)); 10401 } 10402 10403 // KEYWORDS 10404 if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords')) 10405 { 10406 if (isset($keywords[0]['data'])) 10407 { 10408 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 10409 foreach ($temp as $word) 10410 { 10411 $keywords_parent[] = trim($word); 10412 } 10413 } 10414 unset($temp); 10415 } 10416 elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords')) 10417 { 10418 if (isset($keywords[0]['data'])) 10419 { 10420 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 10421 foreach ($temp as $word) 10422 { 10423 $keywords_parent[] = trim($word); 10424 } 10425 } 10426 unset($temp); 10427 } 10428 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords')) 10429 { 10430 if (isset($keywords[0]['data'])) 10431 { 10432 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 10433 foreach ($temp as $word) 10434 { 10435 $keywords_parent[] = trim($word); 10436 } 10437 } 10438 unset($temp); 10439 } 10440 elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords')) 10441 { 10442 if (isset($keywords[0]['data'])) 10443 { 10444 $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 10445 foreach ($temp as $word) 10446 { 10447 $keywords_parent[] = trim($word); 10448 } 10449 } 10450 unset($temp); 10451 } 10452 if (is_array($keywords_parent)) 10453 { 10454 $keywords_parent = array_values(array_unique($keywords_parent)); 10455 } 10456 10457 // PLAYER 10458 if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player')) 10459 { 10460 if (isset($player_parent[0]['attribs']['']['url'])) 10461 { 10462 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 10463 } 10464 } 10465 elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player')) 10466 { 10467 if (isset($player_parent[0]['attribs']['']['url'])) 10468 { 10469 $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 10470 } 10471 } 10472 10473 // RATINGS 10474 if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating')) 10475 { 10476 foreach ($ratings as $rating) 10477 { 10478 $rating_scheme = null; 10479 $rating_value = null; 10480 if (isset($rating['attribs']['']['scheme'])) 10481 { 10482 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10483 } 10484 else 10485 { 10486 $rating_scheme = 'urn:simple'; 10487 } 10488 if (isset($rating['data'])) 10489 { 10490 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10491 } 10492 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 10493 } 10494 } 10495 elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit')) 10496 { 10497 foreach ($ratings as $rating) 10498 { 10499 $rating_scheme = 'urn:itunes'; 10500 $rating_value = null; 10501 if (isset($rating['data'])) 10502 { 10503 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10504 } 10505 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 10506 } 10507 } 10508 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating')) 10509 { 10510 foreach ($ratings as $rating) 10511 { 10512 $rating_scheme = null; 10513 $rating_value = null; 10514 if (isset($rating['attribs']['']['scheme'])) 10515 { 10516 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10517 } 10518 else 10519 { 10520 $rating_scheme = 'urn:simple'; 10521 } 10522 if (isset($rating['data'])) 10523 { 10524 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10525 } 10526 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 10527 } 10528 } 10529 elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit')) 10530 { 10531 foreach ($ratings as $rating) 10532 { 10533 $rating_scheme = 'urn:itunes'; 10534 $rating_value = null; 10535 if (isset($rating['data'])) 10536 { 10537 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10538 } 10539 $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 10540 } 10541 } 10542 if (is_array($ratings_parent)) 10543 { 10544 $ratings_parent = array_values(array_unique($ratings_parent)); 10545 } 10546 10547 // RESTRICTIONS 10548 if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction')) 10549 { 10550 foreach ($restrictions as $restriction) 10551 { 10552 $restriction_relationship = null; 10553 $restriction_type = null; 10554 $restriction_value = null; 10555 if (isset($restriction['attribs']['']['relationship'])) 10556 { 10557 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); 10558 } 10559 if (isset($restriction['attribs']['']['type'])) 10560 { 10561 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10562 } 10563 if (isset($restriction['data'])) 10564 { 10565 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10566 } 10567 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 10568 } 10569 } 10570 elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block')) 10571 { 10572 foreach ($restrictions as $restriction) 10573 { 10574 $restriction_relationship = 'allow'; 10575 $restriction_type = null; 10576 $restriction_value = 'itunes'; 10577 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') 10578 { 10579 $restriction_relationship = 'deny'; 10580 } 10581 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 10582 } 10583 } 10584 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction')) 10585 { 10586 foreach ($restrictions as $restriction) 10587 { 10588 $restriction_relationship = null; 10589 $restriction_type = null; 10590 $restriction_value = null; 10591 if (isset($restriction['attribs']['']['relationship'])) 10592 { 10593 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); 10594 } 10595 if (isset($restriction['attribs']['']['type'])) 10596 { 10597 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10598 } 10599 if (isset($restriction['data'])) 10600 { 10601 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10602 } 10603 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 10604 } 10605 } 10606 elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block')) 10607 { 10608 foreach ($restrictions as $restriction) 10609 { 10610 $restriction_relationship = 'allow'; 10611 $restriction_type = null; 10612 $restriction_value = 'itunes'; 10613 if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes') 10614 { 10615 $restriction_relationship = 'deny'; 10616 } 10617 $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 10618 } 10619 } 10620 if (is_array($restrictions_parent)) 10621 { 10622 $restrictions_parent = array_values(array_unique($restrictions_parent)); 10623 } 10624 else 10625 { 10626 $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default')); 10627 } 10628 10629 // THUMBNAILS 10630 if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail')) 10631 { 10632 foreach ($thumbnails as $thumbnail) 10633 { 10634 if (isset($thumbnail['attribs']['']['url'])) 10635 { 10636 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 10637 } 10638 } 10639 } 10640 elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail')) 10641 { 10642 foreach ($thumbnails as $thumbnail) 10643 { 10644 if (isset($thumbnail['attribs']['']['url'])) 10645 { 10646 $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 10647 } 10648 } 10649 } 10650 10651 // TITLES 10652 if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title')) 10653 { 10654 if (isset($title_parent[0]['data'])) 10655 { 10656 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10657 } 10658 } 10659 elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title')) 10660 { 10661 if (isset($title_parent[0]['data'])) 10662 { 10663 $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10664 } 10665 } 10666 10667 // Clear the memory 10668 unset($parent); 10669 10670 // Attributes 10671 $bitrate = null; 10672 $channels = null; 10673 $duration = null; 10674 $expression = null; 10675 $framerate = null; 10676 $height = null; 10677 $javascript = null; 10678 $lang = null; 10679 $length = null; 10680 $medium = null; 10681 $samplingrate = null; 10682 $type = null; 10683 $url = null; 10684 $width = null; 10685 10686 // Elements 10687 $captions = null; 10688 $categories = null; 10689 $copyrights = null; 10690 $credits = null; 10691 $description = null; 10692 $hashes = null; 10693 $keywords = null; 10694 $player = null; 10695 $ratings = null; 10696 $restrictions = null; 10697 $thumbnails = null; 10698 $title = null; 10699 10700 // If we have media:group tags, loop through them. 10701 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group) 10702 { 10703 if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'])) 10704 { 10705 // If we have media:content tags, loop through them. 10706 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) 10707 { 10708 if (isset($content['attribs']['']['url'])) 10709 { 10710 // Attributes 10711 $bitrate = null; 10712 $channels = null; 10713 $duration = null; 10714 $expression = null; 10715 $framerate = null; 10716 $height = null; 10717 $javascript = null; 10718 $lang = null; 10719 $length = null; 10720 $medium = null; 10721 $samplingrate = null; 10722 $type = null; 10723 $url = null; 10724 $width = null; 10725 10726 // Elements 10727 $captions = null; 10728 $categories = null; 10729 $copyrights = null; 10730 $credits = null; 10731 $description = null; 10732 $hashes = null; 10733 $keywords = null; 10734 $player = null; 10735 $ratings = null; 10736 $restrictions = null; 10737 $thumbnails = null; 10738 $title = null; 10739 10740 // Start checking the attributes of media:content 10741 if (isset($content['attribs']['']['bitrate'])) 10742 { 10743 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); 10744 } 10745 if (isset($content['attribs']['']['channels'])) 10746 { 10747 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); 10748 } 10749 if (isset($content['attribs']['']['duration'])) 10750 { 10751 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); 10752 } 10753 else 10754 { 10755 $duration = $duration_parent; 10756 } 10757 if (isset($content['attribs']['']['expression'])) 10758 { 10759 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); 10760 } 10761 if (isset($content['attribs']['']['framerate'])) 10762 { 10763 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); 10764 } 10765 if (isset($content['attribs']['']['height'])) 10766 { 10767 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); 10768 } 10769 if (isset($content['attribs']['']['lang'])) 10770 { 10771 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 10772 } 10773 if (isset($content['attribs']['']['fileSize'])) 10774 { 10775 $length = ceil($content['attribs']['']['fileSize']); 10776 } 10777 if (isset($content['attribs']['']['medium'])) 10778 { 10779 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); 10780 } 10781 if (isset($content['attribs']['']['samplingrate'])) 10782 { 10783 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); 10784 } 10785 if (isset($content['attribs']['']['type'])) 10786 { 10787 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10788 } 10789 if (isset($content['attribs']['']['width'])) 10790 { 10791 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); 10792 } 10793 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 10794 10795 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel 10796 10797 // CAPTIONS 10798 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) 10799 { 10800 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) 10801 { 10802 $caption_type = null; 10803 $caption_lang = null; 10804 $caption_startTime = null; 10805 $caption_endTime = null; 10806 $caption_text = null; 10807 if (isset($caption['attribs']['']['type'])) 10808 { 10809 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10810 } 10811 if (isset($caption['attribs']['']['lang'])) 10812 { 10813 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 10814 } 10815 if (isset($caption['attribs']['']['start'])) 10816 { 10817 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); 10818 } 10819 if (isset($caption['attribs']['']['end'])) 10820 { 10821 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); 10822 } 10823 if (isset($caption['data'])) 10824 { 10825 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10826 } 10827 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); 10828 } 10829 if (is_array($captions)) 10830 { 10831 $captions = array_values(array_unique($captions)); 10832 } 10833 } 10834 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) 10835 { 10836 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) 10837 { 10838 $caption_type = null; 10839 $caption_lang = null; 10840 $caption_startTime = null; 10841 $caption_endTime = null; 10842 $caption_text = null; 10843 if (isset($caption['attribs']['']['type'])) 10844 { 10845 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 10846 } 10847 if (isset($caption['attribs']['']['lang'])) 10848 { 10849 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 10850 } 10851 if (isset($caption['attribs']['']['start'])) 10852 { 10853 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); 10854 } 10855 if (isset($caption['attribs']['']['end'])) 10856 { 10857 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); 10858 } 10859 if (isset($caption['data'])) 10860 { 10861 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10862 } 10863 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); 10864 } 10865 if (is_array($captions)) 10866 { 10867 $captions = array_values(array_unique($captions)); 10868 } 10869 } 10870 else 10871 { 10872 $captions = $captions_parent; 10873 } 10874 10875 // CATEGORIES 10876 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) 10877 { 10878 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) 10879 { 10880 $term = null; 10881 $scheme = null; 10882 $label = null; 10883 if (isset($category['data'])) 10884 { 10885 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10886 } 10887 if (isset($category['attribs']['']['scheme'])) 10888 { 10889 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10890 } 10891 else 10892 { 10893 $scheme = 'http://search.yahoo.com/mrss/category_schema'; 10894 } 10895 if (isset($category['attribs']['']['label'])) 10896 { 10897 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 10898 } 10899 $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); 10900 } 10901 } 10902 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) 10903 { 10904 foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) 10905 { 10906 $term = null; 10907 $scheme = null; 10908 $label = null; 10909 if (isset($category['data'])) 10910 { 10911 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10912 } 10913 if (isset($category['attribs']['']['scheme'])) 10914 { 10915 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10916 } 10917 else 10918 { 10919 $scheme = 'http://search.yahoo.com/mrss/category_schema'; 10920 } 10921 if (isset($category['attribs']['']['label'])) 10922 { 10923 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 10924 } 10925 $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); 10926 } 10927 } 10928 if (is_array($categories) && is_array($categories_parent)) 10929 { 10930 $categories = array_values(array_unique(array_merge($categories, $categories_parent))); 10931 } 10932 elseif (is_array($categories)) 10933 { 10934 $categories = array_values(array_unique($categories)); 10935 } 10936 elseif (is_array($categories_parent)) 10937 { 10938 $categories = array_values(array_unique($categories_parent)); 10939 } 10940 10941 // COPYRIGHTS 10942 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) 10943 { 10944 $copyright_url = null; 10945 $copyright_label = null; 10946 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) 10947 { 10948 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); 10949 } 10950 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) 10951 { 10952 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10953 } 10954 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); 10955 } 10956 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) 10957 { 10958 $copyright_url = null; 10959 $copyright_label = null; 10960 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) 10961 { 10962 $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); 10963 } 10964 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) 10965 { 10966 $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10967 } 10968 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); 10969 } 10970 else 10971 { 10972 $copyrights = $copyrights_parent; 10973 } 10974 10975 // CREDITS 10976 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) 10977 { 10978 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) 10979 { 10980 $credit_role = null; 10981 $credit_scheme = null; 10982 $credit_name = null; 10983 if (isset($credit['attribs']['']['role'])) 10984 { 10985 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); 10986 } 10987 if (isset($credit['attribs']['']['scheme'])) 10988 { 10989 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 10990 } 10991 else 10992 { 10993 $credit_scheme = 'urn:ebu'; 10994 } 10995 if (isset($credit['data'])) 10996 { 10997 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); 10998 } 10999 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); 11000 } 11001 if (is_array($credits)) 11002 { 11003 $credits = array_values(array_unique($credits)); 11004 } 11005 } 11006 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) 11007 { 11008 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) 11009 { 11010 $credit_role = null; 11011 $credit_scheme = null; 11012 $credit_name = null; 11013 if (isset($credit['attribs']['']['role'])) 11014 { 11015 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); 11016 } 11017 if (isset($credit['attribs']['']['scheme'])) 11018 { 11019 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 11020 } 11021 else 11022 { 11023 $credit_scheme = 'urn:ebu'; 11024 } 11025 if (isset($credit['data'])) 11026 { 11027 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11028 } 11029 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); 11030 } 11031 if (is_array($credits)) 11032 { 11033 $credits = array_values(array_unique($credits)); 11034 } 11035 } 11036 else 11037 { 11038 $credits = $credits_parent; 11039 } 11040 11041 // DESCRIPTION 11042 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) 11043 { 11044 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11045 } 11046 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) 11047 { 11048 $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11049 } 11050 else 11051 { 11052 $description = $description_parent; 11053 } 11054 11055 // HASHES 11056 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) 11057 { 11058 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) 11059 { 11060 $value = null; 11061 $algo = null; 11062 if (isset($hash['data'])) 11063 { 11064 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11065 } 11066 if (isset($hash['attribs']['']['algo'])) 11067 { 11068 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); 11069 } 11070 else 11071 { 11072 $algo = 'md5'; 11073 } 11074 $hashes[] = $algo.':'.$value; 11075 } 11076 if (is_array($hashes)) 11077 { 11078 $hashes = array_values(array_unique($hashes)); 11079 } 11080 } 11081 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) 11082 { 11083 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) 11084 { 11085 $value = null; 11086 $algo = null; 11087 if (isset($hash['data'])) 11088 { 11089 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11090 } 11091 if (isset($hash['attribs']['']['algo'])) 11092 { 11093 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); 11094 } 11095 else 11096 { 11097 $algo = 'md5'; 11098 } 11099 $hashes[] = $algo.':'.$value; 11100 } 11101 if (is_array($hashes)) 11102 { 11103 $hashes = array_values(array_unique($hashes)); 11104 } 11105 } 11106 else 11107 { 11108 $hashes = $hashes_parent; 11109 } 11110 11111 // KEYWORDS 11112 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) 11113 { 11114 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) 11115 { 11116 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 11117 foreach ($temp as $word) 11118 { 11119 $keywords[] = trim($word); 11120 } 11121 unset($temp); 11122 } 11123 if (is_array($keywords)) 11124 { 11125 $keywords = array_values(array_unique($keywords)); 11126 } 11127 } 11128 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) 11129 { 11130 if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) 11131 { 11132 $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 11133 foreach ($temp as $word) 11134 { 11135 $keywords[] = trim($word); 11136 } 11137 unset($temp); 11138 } 11139 if (is_array($keywords)) 11140 { 11141 $keywords = array_values(array_unique($keywords)); 11142 } 11143 } 11144 else 11145 { 11146 $keywords = $keywords_parent; 11147 } 11148 11149 // PLAYER 11150 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) 11151 { 11152 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11153 } 11154 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) 11155 { 11156 $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11157 } 11158 else 11159 { 11160 $player = $player_parent; 11161 } 11162 11163 // RATINGS 11164 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) 11165 { 11166 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) 11167 { 11168 $rating_scheme = null; 11169 $rating_value = null; 11170 if (isset($rating['attribs']['']['scheme'])) 11171 { 11172 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 11173 } 11174 else 11175 { 11176 $rating_scheme = 'urn:simple'; 11177 } 11178 if (isset($rating['data'])) 11179 { 11180 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11181 } 11182 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 11183 } 11184 if (is_array($ratings)) 11185 { 11186 $ratings = array_values(array_unique($ratings)); 11187 } 11188 } 11189 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) 11190 { 11191 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) 11192 { 11193 $rating_scheme = null; 11194 $rating_value = null; 11195 if (isset($rating['attribs']['']['scheme'])) 11196 { 11197 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 11198 } 11199 else 11200 { 11201 $rating_scheme = 'urn:simple'; 11202 } 11203 if (isset($rating['data'])) 11204 { 11205 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11206 } 11207 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 11208 } 11209 if (is_array($ratings)) 11210 { 11211 $ratings = array_values(array_unique($ratings)); 11212 } 11213 } 11214 else 11215 { 11216 $ratings = $ratings_parent; 11217 } 11218 11219 // RESTRICTIONS 11220 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) 11221 { 11222 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) 11223 { 11224 $restriction_relationship = null; 11225 $restriction_type = null; 11226 $restriction_value = null; 11227 if (isset($restriction['attribs']['']['relationship'])) 11228 { 11229 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); 11230 } 11231 if (isset($restriction['attribs']['']['type'])) 11232 { 11233 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11234 } 11235 if (isset($restriction['data'])) 11236 { 11237 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11238 } 11239 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 11240 } 11241 if (is_array($restrictions)) 11242 { 11243 $restrictions = array_values(array_unique($restrictions)); 11244 } 11245 } 11246 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) 11247 { 11248 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) 11249 { 11250 $restriction_relationship = null; 11251 $restriction_type = null; 11252 $restriction_value = null; 11253 if (isset($restriction['attribs']['']['relationship'])) 11254 { 11255 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); 11256 } 11257 if (isset($restriction['attribs']['']['type'])) 11258 { 11259 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11260 } 11261 if (isset($restriction['data'])) 11262 { 11263 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11264 } 11265 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 11266 } 11267 if (is_array($restrictions)) 11268 { 11269 $restrictions = array_values(array_unique($restrictions)); 11270 } 11271 } 11272 else 11273 { 11274 $restrictions = $restrictions_parent; 11275 } 11276 11277 // THUMBNAILS 11278 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) 11279 { 11280 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) 11281 { 11282 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11283 } 11284 if (is_array($thumbnails)) 11285 { 11286 $thumbnails = array_values(array_unique($thumbnails)); 11287 } 11288 } 11289 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) 11290 { 11291 foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) 11292 { 11293 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11294 } 11295 if (is_array($thumbnails)) 11296 { 11297 $thumbnails = array_values(array_unique($thumbnails)); 11298 } 11299 } 11300 else 11301 { 11302 $thumbnails = $thumbnails_parent; 11303 } 11304 11305 // TITLES 11306 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) 11307 { 11308 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11309 } 11310 elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) 11311 { 11312 $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11313 } 11314 else 11315 { 11316 $title = $title_parent; 11317 } 11318 11319 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width)); 11320 } 11321 } 11322 } 11323 } 11324 11325 // If we have standalone media:content tags, loop through them. 11326 if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'])) 11327 { 11328 foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content) 11329 { 11330 if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) 11331 { 11332 // Attributes 11333 $bitrate = null; 11334 $channels = null; 11335 $duration = null; 11336 $expression = null; 11337 $framerate = null; 11338 $height = null; 11339 $javascript = null; 11340 $lang = null; 11341 $length = null; 11342 $medium = null; 11343 $samplingrate = null; 11344 $type = null; 11345 $url = null; 11346 $width = null; 11347 11348 // Elements 11349 $captions = null; 11350 $categories = null; 11351 $copyrights = null; 11352 $credits = null; 11353 $description = null; 11354 $hashes = null; 11355 $keywords = null; 11356 $player = null; 11357 $ratings = null; 11358 $restrictions = null; 11359 $thumbnails = null; 11360 $title = null; 11361 11362 // Start checking the attributes of media:content 11363 if (isset($content['attribs']['']['bitrate'])) 11364 { 11365 $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT); 11366 } 11367 if (isset($content['attribs']['']['channels'])) 11368 { 11369 $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT); 11370 } 11371 if (isset($content['attribs']['']['duration'])) 11372 { 11373 $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT); 11374 } 11375 else 11376 { 11377 $duration = $duration_parent; 11378 } 11379 if (isset($content['attribs']['']['expression'])) 11380 { 11381 $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT); 11382 } 11383 if (isset($content['attribs']['']['framerate'])) 11384 { 11385 $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT); 11386 } 11387 if (isset($content['attribs']['']['height'])) 11388 { 11389 $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT); 11390 } 11391 if (isset($content['attribs']['']['lang'])) 11392 { 11393 $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 11394 } 11395 if (isset($content['attribs']['']['fileSize'])) 11396 { 11397 $length = ceil($content['attribs']['']['fileSize']); 11398 } 11399 if (isset($content['attribs']['']['medium'])) 11400 { 11401 $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT); 11402 } 11403 if (isset($content['attribs']['']['samplingrate'])) 11404 { 11405 $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT); 11406 } 11407 if (isset($content['attribs']['']['type'])) 11408 { 11409 $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11410 } 11411 if (isset($content['attribs']['']['width'])) 11412 { 11413 $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT); 11414 } 11415 if (isset($content['attribs']['']['url'])) 11416 { 11417 $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11418 } 11419 // Checking the other optional media: elements. Priority: media:content, media:group, item, channel 11420 11421 // CAPTIONS 11422 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'])) 11423 { 11424 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption) 11425 { 11426 $caption_type = null; 11427 $caption_lang = null; 11428 $caption_startTime = null; 11429 $caption_endTime = null; 11430 $caption_text = null; 11431 if (isset($caption['attribs']['']['type'])) 11432 { 11433 $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11434 } 11435 if (isset($caption['attribs']['']['lang'])) 11436 { 11437 $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT); 11438 } 11439 if (isset($caption['attribs']['']['start'])) 11440 { 11441 $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT); 11442 } 11443 if (isset($caption['attribs']['']['end'])) 11444 { 11445 $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT); 11446 } 11447 if (isset($caption['data'])) 11448 { 11449 $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11450 } 11451 $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text)); 11452 } 11453 if (is_array($captions)) 11454 { 11455 $captions = array_values(array_unique($captions)); 11456 } 11457 } 11458 else 11459 { 11460 $captions = $captions_parent; 11461 } 11462 11463 // CATEGORIES 11464 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'])) 11465 { 11466 foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category) 11467 { 11468 $term = null; 11469 $scheme = null; 11470 $label = null; 11471 if (isset($category['data'])) 11472 { 11473 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11474 } 11475 if (isset($category['attribs']['']['scheme'])) 11476 { 11477 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 11478 } 11479 else 11480 { 11481 $scheme = 'http://search.yahoo.com/mrss/category_schema'; 11482 } 11483 if (isset($category['attribs']['']['label'])) 11484 { 11485 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 11486 } 11487 $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); 11488 } 11489 } 11490 if (is_array($categories) && is_array($categories_parent)) 11491 { 11492 $categories = array_values(array_unique(array_merge($categories, $categories_parent))); 11493 } 11494 elseif (is_array($categories)) 11495 { 11496 $categories = array_values(array_unique($categories)); 11497 } 11498 elseif (is_array($categories_parent)) 11499 { 11500 $categories = array_values(array_unique($categories_parent)); 11501 } 11502 else 11503 { 11504 $categories = null; 11505 } 11506 11507 // COPYRIGHTS 11508 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'])) 11509 { 11510 $copyright_url = null; 11511 $copyright_label = null; 11512 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'])) 11513 { 11514 $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT); 11515 } 11516 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'])) 11517 { 11518 $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11519 } 11520 $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label)); 11521 } 11522 else 11523 { 11524 $copyrights = $copyrights_parent; 11525 } 11526 11527 // CREDITS 11528 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'])) 11529 { 11530 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit) 11531 { 11532 $credit_role = null; 11533 $credit_scheme = null; 11534 $credit_name = null; 11535 if (isset($credit['attribs']['']['role'])) 11536 { 11537 $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT); 11538 } 11539 if (isset($credit['attribs']['']['scheme'])) 11540 { 11541 $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 11542 } 11543 else 11544 { 11545 $credit_scheme = 'urn:ebu'; 11546 } 11547 if (isset($credit['data'])) 11548 { 11549 $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11550 } 11551 $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name)); 11552 } 11553 if (is_array($credits)) 11554 { 11555 $credits = array_values(array_unique($credits)); 11556 } 11557 } 11558 else 11559 { 11560 $credits = $credits_parent; 11561 } 11562 11563 // DESCRIPTION 11564 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'])) 11565 { 11566 $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11567 } 11568 else 11569 { 11570 $description = $description_parent; 11571 } 11572 11573 // HASHES 11574 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'])) 11575 { 11576 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash) 11577 { 11578 $value = null; 11579 $algo = null; 11580 if (isset($hash['data'])) 11581 { 11582 $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11583 } 11584 if (isset($hash['attribs']['']['algo'])) 11585 { 11586 $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT); 11587 } 11588 else 11589 { 11590 $algo = 'md5'; 11591 } 11592 $hashes[] = $algo.':'.$value; 11593 } 11594 if (is_array($hashes)) 11595 { 11596 $hashes = array_values(array_unique($hashes)); 11597 } 11598 } 11599 else 11600 { 11601 $hashes = $hashes_parent; 11602 } 11603 11604 // KEYWORDS 11605 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'])) 11606 { 11607 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'])) 11608 { 11609 $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)); 11610 foreach ($temp as $word) 11611 { 11612 $keywords[] = trim($word); 11613 } 11614 unset($temp); 11615 } 11616 if (is_array($keywords)) 11617 { 11618 $keywords = array_values(array_unique($keywords)); 11619 } 11620 } 11621 else 11622 { 11623 $keywords = $keywords_parent; 11624 } 11625 11626 // PLAYER 11627 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'])) 11628 { 11629 $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11630 } 11631 else 11632 { 11633 $player = $player_parent; 11634 } 11635 11636 // RATINGS 11637 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'])) 11638 { 11639 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating) 11640 { 11641 $rating_scheme = null; 11642 $rating_value = null; 11643 if (isset($rating['attribs']['']['scheme'])) 11644 { 11645 $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 11646 } 11647 else 11648 { 11649 $rating_scheme = 'urn:simple'; 11650 } 11651 if (isset($rating['data'])) 11652 { 11653 $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11654 } 11655 $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value)); 11656 } 11657 if (is_array($ratings)) 11658 { 11659 $ratings = array_values(array_unique($ratings)); 11660 } 11661 } 11662 else 11663 { 11664 $ratings = $ratings_parent; 11665 } 11666 11667 // RESTRICTIONS 11668 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'])) 11669 { 11670 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction) 11671 { 11672 $restriction_relationship = null; 11673 $restriction_type = null; 11674 $restriction_value = null; 11675 if (isset($restriction['attribs']['']['relationship'])) 11676 { 11677 $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT); 11678 } 11679 if (isset($restriction['attribs']['']['type'])) 11680 { 11681 $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11682 } 11683 if (isset($restriction['data'])) 11684 { 11685 $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11686 } 11687 $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value)); 11688 } 11689 if (is_array($restrictions)) 11690 { 11691 $restrictions = array_values(array_unique($restrictions)); 11692 } 11693 } 11694 else 11695 { 11696 $restrictions = $restrictions_parent; 11697 } 11698 11699 // THUMBNAILS 11700 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'])) 11701 { 11702 foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail) 11703 { 11704 $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI); 11705 } 11706 if (is_array($thumbnails)) 11707 { 11708 $thumbnails = array_values(array_unique($thumbnails)); 11709 } 11710 } 11711 else 11712 { 11713 $thumbnails = $thumbnails_parent; 11714 } 11715 11716 // TITLES 11717 if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'])) 11718 { 11719 $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 11720 } 11721 else 11722 { 11723 $title = $title_parent; 11724 } 11725 11726 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width)); 11727 } 11728 } 11729 } 11730 11731 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link) 11732 { 11733 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') 11734 { 11735 // Attributes 11736 $bitrate = null; 11737 $channels = null; 11738 $duration = null; 11739 $expression = null; 11740 $framerate = null; 11741 $height = null; 11742 $javascript = null; 11743 $lang = null; 11744 $length = null; 11745 $medium = null; 11746 $samplingrate = null; 11747 $type = null; 11748 $url = null; 11749 $width = null; 11750 11751 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 11752 if (isset($link['attribs']['']['type'])) 11753 { 11754 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11755 } 11756 if (isset($link['attribs']['']['length'])) 11757 { 11758 $length = ceil($link['attribs']['']['length']); 11759 } 11760 11761 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor 11762 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); 11763 } 11764 } 11765 11766 foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link) 11767 { 11768 if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure') 11769 { 11770 // Attributes 11771 $bitrate = null; 11772 $channels = null; 11773 $duration = null; 11774 $expression = null; 11775 $framerate = null; 11776 $height = null; 11777 $javascript = null; 11778 $lang = null; 11779 $length = null; 11780 $medium = null; 11781 $samplingrate = null; 11782 $type = null; 11783 $url = null; 11784 $width = null; 11785 11786 $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 11787 if (isset($link['attribs']['']['type'])) 11788 { 11789 $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11790 } 11791 if (isset($link['attribs']['']['length'])) 11792 { 11793 $length = ceil($link['attribs']['']['length']); 11794 } 11795 11796 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor 11797 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); 11798 } 11799 } 11800 11801 if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure')) 11802 { 11803 if (isset($enclosure[0]['attribs']['']['url'])) 11804 { 11805 // Attributes 11806 $bitrate = null; 11807 $channels = null; 11808 $duration = null; 11809 $expression = null; 11810 $framerate = null; 11811 $height = null; 11812 $javascript = null; 11813 $lang = null; 11814 $length = null; 11815 $medium = null; 11816 $samplingrate = null; 11817 $type = null; 11818 $url = null; 11819 $width = null; 11820 11821 $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0])); 11822 if (isset($enclosure[0]['attribs']['']['type'])) 11823 { 11824 $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT); 11825 } 11826 if (isset($enclosure[0]['attribs']['']['length'])) 11827 { 11828 $length = ceil($enclosure[0]['attribs']['']['length']); 11829 } 11830 11831 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor 11832 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); 11833 } 11834 } 11835 11836 if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width)) 11837 { 11838 // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor 11839 $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width)); 11840 } 11841 11842 $this->data['enclosures'] = array_values(array_unique($this->data['enclosures'])); 11843 } 11844 if (!empty($this->data['enclosures'])) 11845 { 11846 return $this->data['enclosures']; 11847 } 11848 else 11849 { 11850 return null; 11851 } 11852 } 11853 11854 /** 11855 * Get the latitude coordinates for the item 11856 * 11857 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications 11858 * 11859 * Uses `<geo:lat>` or `<georss:point>` 11860 * 11861 * @since 1.0 11862 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo 11863 * @link http://www.georss.org/ GeoRSS 11864 * @return string|null 11865 */ 11866 public function get_latitude() 11867 { 11868 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) 11869 { 11870 return (float) $return[0]['data']; 11871 } 11872 elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) 11873 { 11874 return (float) $match[1]; 11875 } 11876 else 11877 { 11878 return null; 11879 } 11880 } 11881 11882 /** 11883 * Get the longitude coordinates for the item 11884 * 11885 * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications 11886 * 11887 * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>` 11888 * 11889 * @since 1.0 11890 * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo 11891 * @link http://www.georss.org/ GeoRSS 11892 * @return string|null 11893 */ 11894 public function get_longitude() 11895 { 11896 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) 11897 { 11898 return (float) $return[0]['data']; 11899 } 11900 elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) 11901 { 11902 return (float) $return[0]['data']; 11903 } 11904 elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) 11905 { 11906 return (float) $match[2]; 11907 } 11908 else 11909 { 11910 return null; 11911 } 11912 } 11913 11914 /** 11915 * Get the `<atom:source>` for the item 11916 * 11917 * @since 1.1 11918 * @return SimplePie_Source|null 11919 */ 11920 public function get_source() 11921 { 11922 if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source')) 11923 { 11924 return $this->registry->create('Source', array($this, $return[0])); 11925 } 11926 else 11927 { 11928 return null; 11929 } 11930 } 11931 } 11932 11933 /** 11934 * Used for feed auto-discovery 11935 * 11936 * 11937 * This class can be overloaded with {@see SimplePie::set_locator_class()} 11938 * 11939 * @package SimplePie 11940 */ 11941 class SimplePie_Locator 11942 { 11943 var $useragent; 11944 var $timeout; 11945 var $file; 11946 var $local = array(); 11947 var $elsewhere = array(); 11948 var $cached_entities = array(); 11949 var $http_base; 11950 var $base; 11951 var $base_location = 0; 11952 var $checked_feeds = 0; 11953 var $max_checked_feeds = 10; 11954 protected $registry; 11955 11956 public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10) 11957 { 11958 $this->file = $file; 11959 $this->useragent = $useragent; 11960 $this->timeout = $timeout; 11961 $this->max_checked_feeds = $max_checked_feeds; 11962 11963 if (class_exists('DOMDocument')) 11964 { 11965 $this->dom = new DOMDocument(); 11966 11967 set_error_handler(array('SimplePie_Misc', 'silence_errors')); 11968 $this->dom->loadHTML($this->file->body); 11969 restore_error_handler(); 11970 } 11971 else 11972 { 11973 $this->dom = null; 11974 } 11975 } 11976 11977 public function set_registry(SimplePie_Registry $registry) 11978 { 11979 $this->registry = $registry; 11980 } 11981 11982 public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working) 11983 { 11984 if ($this->is_feed($this->file)) 11985 { 11986 return $this->file; 11987 } 11988 11989 if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) 11990 { 11991 $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file)); 11992 if ($sniffer->get_type() !== 'text/html') 11993 { 11994 return null; 11995 } 11996 } 11997 11998 if ($type & ~SIMPLEPIE_LOCATOR_NONE) 11999 { 12000 $this->get_base(); 12001 } 12002 12003 if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery()) 12004 { 12005 return $working[0]; 12006 } 12007 12008 if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links()) 12009 { 12010 if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local)) 12011 { 12012 return $working; 12013 } 12014 12015 if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local)) 12016 { 12017 return $working; 12018 } 12019 12020 if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere)) 12021 { 12022 return $working; 12023 } 12024 12025 if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere)) 12026 { 12027 return $working; 12028 } 12029 } 12030 return null; 12031 } 12032 12033 public function is_feed($file) 12034 { 12035 if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE) 12036 { 12037 $sniffer = $this->registry->create('Content_Type_Sniffer', array($file)); 12038 $sniffed = $sniffer->get_type(); 12039 if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) 12040 { 12041 return true; 12042 } 12043 else 12044 { 12045 return false; 12046 } 12047 } 12048 elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL) 12049 { 12050 return true; 12051 } 12052 else 12053 { 12054 return false; 12055 } 12056 } 12057 12058 public function get_base() 12059 { 12060 if ($this->dom === null) 12061 { 12062 throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); 12063 } 12064 $this->http_base = $this->file->url; 12065 $this->base = $this->http_base; 12066 $elements = $this->dom->getElementsByTagName('base'); 12067 foreach ($elements as $element) 12068 { 12069 if ($element->hasAttribute('href')) 12070 { 12071 $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base)); 12072 if ($base === false) 12073 { 12074 continue; 12075 } 12076 $this->base = $base; 12077 $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0; 12078 break; 12079 } 12080 } 12081 } 12082 12083 public function autodiscovery() 12084 { 12085 $done = array(); 12086 $feeds = array(); 12087 $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds)); 12088 $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds)); 12089 $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds)); 12090 12091 if (!empty($feeds)) 12092 { 12093 return array_values($feeds); 12094 } 12095 else 12096 { 12097 return null; 12098 } 12099 } 12100 12101 protected function search_elements_by_tag($name, &$done, $feeds) 12102 { 12103 if ($this->dom === null) 12104 { 12105 throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); 12106 } 12107 12108 $links = $this->dom->getElementsByTagName($name); 12109 foreach ($links as $link) 12110 { 12111 if ($this->checked_feeds === $this->max_checked_feeds) 12112 { 12113 break; 12114 } 12115 if ($link->hasAttribute('href') && $link->hasAttribute('rel')) 12116 { 12117 $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel'))))); 12118 $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1; 12119 12120 if ($this->base_location < $line) 12121 { 12122 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base)); 12123 } 12124 else 12125 { 12126 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base)); 12127 } 12128 if ($href === false) 12129 { 12130 continue; 12131 } 12132 12133 if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href])) 12134 { 12135 $this->checked_feeds++; 12136 $headers = array( 12137 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 12138 ); 12139 $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent)); 12140 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) 12141 { 12142 $feeds[$href] = $feed; 12143 } 12144 } 12145 $done[] = $href; 12146 } 12147 } 12148 12149 return $feeds; 12150 } 12151 12152 public function get_links() 12153 { 12154 if ($this->dom === null) 12155 { 12156 throw new SimplePie_Exception('DOMDocument not found, unable to use locator'); 12157 } 12158 12159 $links = $this->dom->getElementsByTagName('a'); 12160 foreach ($links as $link) 12161 { 12162 if ($link->hasAttribute('href')) 12163 { 12164 $href = trim($link->getAttribute('href')); 12165 $parsed = $this->registry->call('Misc', 'parse_url', array($href)); 12166 if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme'])) 12167 { 12168 if ($this->base_location < $link->getLineNo()) 12169 { 12170 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base)); 12171 } 12172 else 12173 { 12174 $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base)); 12175 } 12176 if ($href === false) 12177 { 12178 continue; 12179 } 12180 12181 $current = $this->registry->call('Misc', 'parse_url', array($this->file->url)); 12182 12183 if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority']) 12184 { 12185 $this->local[] = $href; 12186 } 12187 else 12188 { 12189 $this->elsewhere[] = $href; 12190 } 12191 } 12192 } 12193 } 12194 $this->local = array_unique($this->local); 12195 $this->elsewhere = array_unique($this->elsewhere); 12196 if (!empty($this->local) || !empty($this->elsewhere)) 12197 { 12198 return true; 12199 } 12200 return null; 12201 } 12202 12203 public function extension(&$array) 12204 { 12205 foreach ($array as $key => $value) 12206 { 12207 if ($this->checked_feeds === $this->max_checked_feeds) 12208 { 12209 break; 12210 } 12211 if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml'))) 12212 { 12213 $this->checked_feeds++; 12214 12215 $headers = array( 12216 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 12217 ); 12218 $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent)); 12219 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) 12220 { 12221 return $feed; 12222 } 12223 else 12224 { 12225 unset($array[$key]); 12226 } 12227 } 12228 } 12229 return null; 12230 } 12231 12232 public function body(&$array) 12233 { 12234 foreach ($array as $key => $value) 12235 { 12236 if ($this->checked_feeds === $this->max_checked_feeds) 12237 { 12238 break; 12239 } 12240 if (preg_match('/(rss|rdf|atom|xml)/i', $value)) 12241 { 12242 $this->checked_feeds++; 12243 $headers = array( 12244 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1', 12245 ); 12246 $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent)); 12247 if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed)) 12248 { 12249 return $feed; 12250 } 12251 else 12252 { 12253 unset($array[$key]); 12254 } 12255 } 12256 } 12257 return null; 12258 } 12259 } 12260 12261 /** 12262 * Miscellanous utilities 12263 * 12264 * @package SimplePie 12265 */ 12266 class SimplePie_Misc 12267 { 12268 public static function time_hms($seconds) 12269 { 12270 $time = ''; 12271 12272 $hours = floor($seconds / 3600); 12273 $remainder = $seconds % 3600; 12274 if ($hours > 0) 12275 { 12276 $time .= $hours.':'; 12277 } 12278 12279 $minutes = floor($remainder / 60); 12280 $seconds = $remainder % 60; 12281 if ($minutes < 10 && $hours > 0) 12282 { 12283 $minutes = '0' . $minutes; 12284 } 12285 if ($seconds < 10) 12286 { 12287 $seconds = '0' . $seconds; 12288 } 12289 12290 $time .= $minutes.':'; 12291 $time .= $seconds; 12292 12293 return $time; 12294 } 12295 12296 public static function absolutize_url($relative, $base) 12297 { 12298 $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative); 12299 if ($iri === false) 12300 { 12301 return false; 12302 } 12303 return $iri->get_uri(); 12304 } 12305 12306 /** 12307 * Get a HTML/XML element from a HTML string 12308 * 12309 * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!) 12310 * @param string $realname Element name (including namespace prefix if applicable) 12311 * @param string $string HTML document 12312 * @return array 12313 */ 12314 public static function get_element($realname, $string) 12315 { 12316 $return = array(); 12317 $name = preg_quote($realname, '/'); 12318 if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) 12319 { 12320 for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++) 12321 { 12322 $return[$i]['tag'] = $realname; 12323 $return[$i]['full'] = $matches[$i][0][0]; 12324 $return[$i]['offset'] = $matches[$i][0][1]; 12325 if (strlen($matches[$i][3][0]) <= 2) 12326 { 12327 $return[$i]['self_closing'] = true; 12328 } 12329 else 12330 { 12331 $return[$i]['self_closing'] = false; 12332 $return[$i]['content'] = $matches[$i][4][0]; 12333 } 12334 $return[$i]['attribs'] = array(); 12335 if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER)) 12336 { 12337 for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++) 12338 { 12339 if (count($attribs[$j]) === 2) 12340 { 12341 $attribs[$j][2] = $attribs[$j][1]; 12342 } 12343 $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); 12344 } 12345 } 12346 } 12347 } 12348 return $return; 12349 } 12350 12351 public static function element_implode($element) 12352 { 12353 $full = "<$element[tag]"; 12354 foreach ($element['attribs'] as $key => $value) 12355 { 12356 $key = strtolower($key); 12357 $full .= " $key=\"" . htmlspecialchars($value['data']) . '"'; 12358 } 12359 if ($element['self_closing']) 12360 { 12361 $full .= ' />'; 12362 } 12363 else 12364 { 12365 $full .= ">$element[content]</$element[tag]>"; 12366 } 12367 return $full; 12368 } 12369 12370 public static function error($message, $level, $file, $line) 12371 { 12372 if ((ini_get('error_reporting') & $level) > 0) 12373 { 12374 switch ($level) 12375 { 12376 case E_USER_ERROR: 12377 $note = 'PHP Error'; 12378 break; 12379 case E_USER_WARNING: 12380 $note = 'PHP Warning'; 12381 break; 12382 case E_USER_NOTICE: 12383 $note = 'PHP Notice'; 12384 break; 12385 default: 12386 $note = 'Unknown Error'; 12387 break; 12388 } 12389 12390 $log_error = true; 12391 if (!function_exists('error_log')) 12392 { 12393 $log_error = false; 12394 } 12395 12396 $log_file = @ini_get('error_log'); 12397 if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file)) 12398 { 12399 $log_error = false; 12400 } 12401 12402 if ($log_error) 12403 { 12404 @error_log("$note: $message in $file on line $line", 0); 12405 } 12406 } 12407 12408 return $message; 12409 } 12410 12411 public static function fix_protocol($url, $http = 1) 12412 { 12413 $url = SimplePie_Misc::normalize_url($url); 12414 $parsed = SimplePie_Misc::parse_url($url); 12415 if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https') 12416 { 12417 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http); 12418 } 12419 12420 if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url)) 12421 { 12422 return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http); 12423 } 12424 12425 if ($http === 2 && $parsed['scheme'] !== '') 12426 { 12427 return "feed:$url"; 12428 } 12429 elseif ($http === 3 && strtolower($parsed['scheme']) === 'http') 12430 { 12431 return substr_replace($url, 'podcast', 0, 4); 12432 } 12433 elseif ($http === 4 && strtolower($parsed['scheme']) === 'http') 12434 { 12435 return substr_replace($url, 'itpc', 0, 4); 12436 } 12437 else 12438 { 12439 return $url; 12440 } 12441 } 12442 12443 public static function parse_url($url) 12444 { 12445 $iri = new SimplePie_IRI($url); 12446 return array( 12447 'scheme' => (string) $iri->scheme, 12448 'authority' => (string) $iri->authority, 12449 'path' => (string) $iri->path, 12450 'query' => (string) $iri->query, 12451 'fragment' => (string) $iri->fragment 12452 ); 12453 } 12454 12455 public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '') 12456 { 12457 $iri = new SimplePie_IRI(''); 12458 $iri->scheme = $scheme; 12459 $iri->authority = $authority; 12460 $iri->path = $path; 12461 $iri->query = $query; 12462 $iri->fragment = $fragment; 12463 return $iri->get_uri(); 12464 } 12465 12466 public static function normalize_url($url) 12467 { 12468 $iri = new SimplePie_IRI($url); 12469 return $iri->get_uri(); 12470 } 12471 12472 public static function percent_encoding_normalization($match) 12473 { 12474 $integer = hexdec($match[1]); 12475 if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E) 12476 { 12477 return chr($integer); 12478 } 12479 else 12480 { 12481 return strtoupper($match[0]); 12482 } 12483 } 12484 12485 /** 12486 * Converts a Windows-1252 encoded string to a UTF-8 encoded string 12487 * 12488 * @static 12489 * @param string $string Windows-1252 encoded string 12490 * @return string UTF-8 encoded string 12491 */ 12492 public static function windows_1252_to_utf8($string) 12493 { 12494 static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF"); 12495 12496 return strtr($string, $convert_table); 12497 } 12498 12499 /** 12500 * Change a string from one encoding to another 12501 * 12502 * @param string $data Raw data in $input encoding 12503 * @param string $input Encoding of $data 12504 * @param string $output Encoding you want 12505 * @return string|boolean False if we can't convert it 12506 */ 12507 public static function change_encoding($data, $input, $output) 12508 { 12509 $input = SimplePie_Misc::encoding($input); 12510 $output = SimplePie_Misc::encoding($output); 12511 12512 // We fail to fail on non US-ASCII bytes 12513 if ($input === 'US-ASCII') 12514 { 12515 static $non_ascii_octects = ''; 12516 if (!$non_ascii_octects) 12517 { 12518 for ($i = 0x80; $i <= 0xFF; $i++) 12519 { 12520 $non_ascii_octects .= chr($i); 12521 } 12522 } 12523 $data = substr($data, 0, strcspn($data, $non_ascii_octects)); 12524 } 12525 12526 // This is first, as behaviour of this is completely predictable 12527 if ($input === 'windows-1252' && $output === 'UTF-8') 12528 { 12529 return SimplePie_Misc::windows_1252_to_utf8($data); 12530 } 12531 // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported). 12532 elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output))) 12533 { 12534 return $return; 12535 } 12536 // This is last, as behaviour of this varies with OS userland and PHP version 12537 elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output))) 12538 { 12539 return $return; 12540 } 12541 // If we can't do anything, just fail 12542 else 12543 { 12544 return false; 12545 } 12546 } 12547 12548 protected static function change_encoding_mbstring($data, $input, $output) 12549 { 12550 if ($input === 'windows-949') 12551 { 12552 $input = 'EUC-KR'; 12553 } 12554 if ($output === 'windows-949') 12555 { 12556 $output = 'EUC-KR'; 12557 } 12558 if ($input === 'Windows-31J') 12559 { 12560 $input = 'SJIS'; 12561 } 12562 if ($output === 'Windows-31J') 12563 { 12564 $output = 'SJIS'; 12565 } 12566 12567 // Check that the encoding is supported 12568 if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80") 12569 { 12570 return false; 12571 } 12572 if (!in_array($input, mb_list_encodings())) 12573 { 12574 return false; 12575 } 12576 12577 // Let's do some conversion 12578 if ($return = @mb_convert_encoding($data, $output, $input)) 12579 { 12580 return $return; 12581 } 12582 12583 return false; 12584 } 12585 12586 protected static function change_encoding_iconv($data, $input, $output) 12587 { 12588 return @iconv($input, $output, $data); 12589 } 12590 12591 /** 12592 * Normalize an encoding name 12593 * 12594 * This is automatically generated by create.php 12595 * 12596 * To generate it, run `php create.php` on the command line, and copy the 12597 * output to replace this function. 12598 * 12599 * @param string $charset Character set to standardise 12600 * @return string Standardised name 12601 */ 12602 public static function encoding($charset) 12603 { 12604 // Normalization from UTS #22 12605 switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset))) 12606 { 12607 case 'adobestandardencoding': 12608 case 'csadobestandardencoding': 12609 return 'Adobe-Standard-Encoding'; 12610 12611 case 'adobesymbolencoding': 12612 case 'cshppsmath': 12613 return 'Adobe-Symbol-Encoding'; 12614 12615 case 'ami1251': 12616 case 'amiga1251': 12617 return 'Amiga-1251'; 12618 12619 case 'ansix31101983': 12620 case 'csat5001983': 12621 case 'csiso99naplps': 12622 case 'isoir99': 12623 case 'naplps': 12624 return 'ANSI_X3.110-1983'; 12625 12626 case 'arabic7': 12627 case 'asmo449': 12628 case 'csiso89asmo449': 12629 case 'iso9036': 12630 case 'isoir89': 12631 return 'ASMO_449'; 12632 12633 case 'big5': 12634 case 'csbig5': 12635 return 'Big5'; 12636 12637 case 'big5hkscs': 12638 return 'Big5-HKSCS'; 12639 12640 case 'bocu1': 12641 case 'csbocu1': 12642 return 'BOCU-1'; 12643 12644 case 'brf': 12645 case 'csbrf': 12646 return 'BRF'; 12647 12648 case 'bs4730': 12649 case 'csiso4unitedkingdom': 12650 case 'gb': 12651 case 'iso646gb': 12652 case 'isoir4': 12653 case 'uk': 12654 return 'BS_4730'; 12655 12656 case 'bsviewdata': 12657 case 'csiso47bsviewdata': 12658 case 'isoir47': 12659 return 'BS_viewdata'; 12660 12661 case 'cesu8': 12662 case 'cscesu8': 12663 return 'CESU-8'; 12664 12665 case 'ca': 12666 case 'csa71': 12667 case 'csaz243419851': 12668 case 'csiso121canadian1': 12669 case 'iso646ca': 12670 case 'isoir121': 12671 return 'CSA_Z243.4-1985-1'; 12672 12673 case 'csa72': 12674 case 'csaz243419852': 12675 case 'csiso122canadian2': 12676 case 'iso646ca2': 12677 case 'isoir122': 12678 return 'CSA_Z243.4-1985-2'; 12679 12680 case 'csaz24341985gr': 12681 case 'csiso123csaz24341985gr': 12682 case 'isoir123': 12683 return 'CSA_Z243.4-1985-gr'; 12684 12685 case 'csiso139csn369103': 12686 case 'csn369103': 12687 case 'isoir139': 12688 return 'CSN_369103'; 12689 12690 case 'csdecmcs': 12691 case 'dec': 12692 case 'decmcs': 12693 return 'DEC-MCS'; 12694 12695 case 'csiso21german': 12696 case 'de': 12697 case 'din66003': 12698 case 'iso646de': 12699 case 'isoir21': 12700 return 'DIN_66003'; 12701 12702 case 'csdkus': 12703 case 'dkus': 12704 return 'dk-us'; 12705 12706 case 'csiso646danish': 12707 case 'dk': 12708 case 'ds2089': 12709 case 'iso646dk': 12710 return 'DS_2089'; 12711 12712 case 'csibmebcdicatde': 12713 case 'ebcdicatde': 12714 return 'EBCDIC-AT-DE'; 12715 12716 case 'csebcdicatdea': 12717 case 'ebcdicatdea': 12718 return 'EBCDIC-AT-DE-A'; 12719 12720 case 'csebcdiccafr': 12721 case 'ebcdiccafr': 12722 return 'EBCDIC-CA-FR'; 12723 12724 case 'csebcdicdkno': 12725 case 'ebcdicdkno': 12726 return 'EBCDIC-DK-NO'; 12727 12728 case 'csebcdicdknoa': 12729 case 'ebcdicdknoa': 12730 return 'EBCDIC-DK-NO-A'; 12731 12732 case 'csebcdices': 12733 case 'ebcdices': 12734 return 'EBCDIC-ES'; 12735 12736 case 'csebcdicesa': 12737 case 'ebcdicesa': 12738 return 'EBCDIC-ES-A'; 12739 12740 case 'csebcdicess': 12741 case 'ebcdicess': 12742 return 'EBCDIC-ES-S'; 12743 12744 case 'csebcdicfise': 12745 case 'ebcdicfise': 12746 return 'EBCDIC-FI-SE'; 12747 12748 case 'csebcdicfisea': 12749 case 'ebcdicfisea': 12750 return 'EBCDIC-FI-SE-A'; 12751 12752 case 'csebcdicfr': 12753 case 'ebcdicfr': 12754 return 'EBCDIC-FR'; 12755 12756 case 'csebcdicit': 12757 case 'ebcdicit': 12758 return 'EBCDIC-IT'; 12759 12760 case 'csebcdicpt': 12761 case 'ebcdicpt': 12762 return 'EBCDIC-PT'; 12763 12764 case 'csebcdicuk': 12765 case 'ebcdicuk': 12766 return 'EBCDIC-UK'; 12767 12768 case 'csebcdicus': 12769 case 'ebcdicus': 12770 return 'EBCDIC-US'; 12771 12772 case 'csiso111ecmacyrillic': 12773 case 'ecmacyrillic': 12774 case 'isoir111': 12775 case 'koi8e': 12776 return 'ECMA-cyrillic'; 12777 12778 case 'csiso17spanish': 12779 case 'es': 12780 case 'iso646es': 12781 case 'isoir17': 12782 return 'ES'; 12783 12784 case 'csiso85spanish2': 12785 case 'es2': 12786 case 'iso646es2': 12787 case 'isoir85': 12788 return 'ES2'; 12789 12790 case 'cseucpkdfmtjapanese': 12791 case 'eucjp': 12792 case 'extendedunixcodepackedformatforjapanese': 12793 return 'EUC-JP'; 12794 12795 case 'cseucfixwidjapanese': 12796 case 'extendedunixcodefixedwidthforjapanese': 12797 return 'Extended_UNIX_Code_Fixed_Width_for_Japanese'; 12798 12799 case 'gb18030': 12800 return 'GB18030'; 12801 12802 case 'chinese': 12803 case 'cp936': 12804 case 'csgb2312': 12805 case 'csiso58gb231280': 12806 case 'gb2312': 12807 case 'gb231280': 12808 case 'gbk': 12809 case 'isoir58': 12810 case 'ms936': 12811 case 'windows936': 12812 return 'GBK'; 12813 12814 case 'cn': 12815 case 'csiso57gb1988': 12816 case 'gb198880': 12817 case 'iso646cn': 12818 case 'isoir57': 12819 return 'GB_1988-80'; 12820 12821 case 'csiso153gost1976874': 12822 case 'gost1976874': 12823 case 'isoir153': 12824 case 'stsev35888': 12825 return 'GOST_19768-74'; 12826 12827 case 'csiso150': 12828 case 'csiso150greekccitt': 12829 case 'greekccitt': 12830 case 'isoir150': 12831 return 'greek-ccitt'; 12832 12833 case 'csiso88greek7': 12834 case 'greek7': 12835 case 'isoir88': 12836 return 'greek7'; 12837 12838 case 'csiso18greek7old': 12839 case 'greek7old': 12840 case 'isoir18': 12841 return 'greek7-old'; 12842 12843 case 'cshpdesktop': 12844 case 'hpdesktop': 12845 return 'HP-DeskTop'; 12846 12847 case 'cshplegal': 12848 case 'hplegal': 12849 return 'HP-Legal'; 12850 12851 case 'cshpmath8': 12852 case 'hpmath8': 12853 return 'HP-Math8'; 12854 12855 case 'cshppifont': 12856 case 'hppifont': 12857 return 'HP-Pi-font'; 12858 12859 case 'cshproman8': 12860 case 'hproman8': 12861 case 'r8': 12862 case 'roman8': 12863 return 'hp-roman8'; 12864 12865 case 'hzgb2312': 12866 return 'HZ-GB-2312'; 12867 12868 case 'csibmsymbols': 12869 case 'ibmsymbols': 12870 return 'IBM-Symbols'; 12871 12872 case 'csibmthai': 12873 case 'ibmthai': 12874 return 'IBM-Thai'; 12875 12876 case 'cp37': 12877 case 'csibm37': 12878 case 'ebcdiccpca': 12879 case 'ebcdiccpnl': 12880 case 'ebcdiccpus': 12881 case 'ebcdiccpwt': 12882 case 'ibm37': 12883 return 'IBM037'; 12884 12885 case 'cp38': 12886 case 'csibm38': 12887 case 'ebcdicint': 12888 case 'ibm38': 12889 return 'IBM038'; 12890 12891 case 'cp273': 12892 case 'csibm273': 12893 case 'ibm273': 12894 return 'IBM273'; 12895 12896 case 'cp274': 12897 case 'csibm274': 12898 case 'ebcdicbe': 12899 case 'ibm274': 12900 return 'IBM274'; 12901 12902 case 'cp275': 12903 case 'csibm275': 12904 case 'ebcdicbr': 12905 case 'ibm275': 12906 return 'IBM275'; 12907 12908 case 'csibm277': 12909 case 'ebcdiccpdk': 12910 case 'ebcdiccpno': 12911 case 'ibm277': 12912 return 'IBM277'; 12913 12914 case 'cp278': 12915 case 'csibm278': 12916 case 'ebcdiccpfi': 12917 case 'ebcdiccpse': 12918 case 'ibm278': 12919 return 'IBM278'; 12920 12921 case 'cp280': 12922 case 'csibm280': 12923 case 'ebcdiccpit': 12924 case 'ibm280': 12925 return 'IBM280'; 12926 12927 case 'cp281': 12928 case 'csibm281': 12929 case 'ebcdicjpe': 12930 case 'ibm281': 12931 return 'IBM281'; 12932 12933 case 'cp284': 12934 case 'csibm284': 12935 case 'ebcdiccpes': 12936 case 'ibm284': 12937 return 'IBM284'; 12938 12939 case 'cp285': 12940 case 'csibm285': 12941 case 'ebcdiccpgb': 12942 case 'ibm285': 12943 return 'IBM285'; 12944 12945 case 'cp290': 12946 case 'csibm290': 12947 case 'ebcdicjpkana': 12948 case 'ibm290': 12949 return 'IBM290'; 12950 12951 case 'cp297': 12952 case 'csibm297': 12953 case 'ebcdiccpfr': 12954 case 'ibm297': 12955 return 'IBM297'; 12956 12957 case 'cp420': 12958 case 'csibm420': 12959 case 'ebcdiccpar1': 12960 case 'ibm420': 12961 return 'IBM420'; 12962 12963 case 'cp423': 12964 case 'csibm423': 12965 case 'ebcdiccpgr': 12966 case 'ibm423': 12967 return 'IBM423'; 12968 12969 case 'cp424': 12970 case 'csibm424': 12971 case 'ebcdiccphe': 12972 case 'ibm424': 12973 return 'IBM424'; 12974 12975 case '437': 12976 case 'cp437': 12977 case 'cspc8codepage437': 12978 case 'ibm437': 12979 return 'IBM437'; 12980 12981 case 'cp500': 12982 case 'csibm500': 12983 case 'ebcdiccpbe': 12984 case 'ebcdiccpch': 12985 case 'ibm500': 12986 return 'IBM500'; 12987 12988 case 'cp775': 12989 case 'cspc775baltic': 12990 case 'ibm775': 12991 return 'IBM775'; 12992 12993 case '850': 12994 case 'cp850': 12995 case 'cspc850multilingual': 12996 case 'ibm850': 12997 return 'IBM850'; 12998 12999 case '851': 13000 case 'cp851': 13001 case 'csibm851': 13002 case 'ibm851': 13003 return 'IBM851'; 13004 13005 case '852': 13006 case 'cp852': 13007 case 'cspcp852': 13008 case 'ibm852': 13009 return 'IBM852'; 13010 13011 case '855': 13012 case 'cp855': 13013 case 'csibm855': 13014 case 'ibm855': 13015 return 'IBM855'; 13016 13017 case '857': 13018 case 'cp857': 13019 case 'csibm857': 13020 case 'ibm857': 13021 return 'IBM857'; 13022 13023 case 'ccsid858': 13024 case 'cp858': 13025 case 'ibm858': 13026 case 'pcmultilingual850euro': 13027 return 'IBM00858'; 13028 13029 case '860': 13030 case 'cp860': 13031 case 'csibm860': 13032 case 'ibm860': 13033 return 'IBM860'; 13034 13035 case '861': 13036 case 'cp861': 13037 case 'cpis': 13038 case 'csibm861': 13039 case 'ibm861': 13040 return 'IBM861'; 13041 13042 case '862': 13043 case 'cp862': 13044 case 'cspc862latinhebrew': 13045 case 'ibm862': 13046 return 'IBM862'; 13047 13048 case '863': 13049 case 'cp863': 13050 case 'csibm863': 13051 case 'ibm863': 13052 return 'IBM863'; 13053 13054 case 'cp864': 13055 case 'csibm864': 13056 case 'ibm864': 13057 return 'IBM864'; 13058 13059 case '865': 13060 case 'cp865': 13061 case 'csibm865': 13062 case 'ibm865': 13063 return 'IBM865'; 13064 13065 case '866': 13066 case 'cp866': 13067 case 'csibm866': 13068 case 'ibm866': 13069 return 'IBM866'; 13070 13071 case 'cp868': 13072 case 'cpar': 13073 case 'csibm868': 13074 case 'ibm868': 13075 return 'IBM868'; 13076 13077 case '869': 13078 case 'cp869': 13079 case 'cpgr': 13080 case 'csibm869': 13081 case 'ibm869': 13082 return 'IBM869'; 13083 13084 case 'cp870': 13085 case 'csibm870': 13086 case 'ebcdiccproece': 13087 case 'ebcdiccpyu': 13088 case 'ibm870': 13089 return 'IBM870'; 13090 13091 case 'cp871': 13092 case 'csibm871': 13093 case 'ebcdiccpis': 13094 case 'ibm871': 13095 return 'IBM871'; 13096 13097 case 'cp880': 13098 case 'csibm880': 13099 case 'ebcdiccyrillic': 13100 case 'ibm880': 13101 return 'IBM880'; 13102 13103 case 'cp891': 13104 case 'csibm891': 13105 case 'ibm891': 13106 return 'IBM891'; 13107 13108 case 'cp903': 13109 case 'csibm903': 13110 case 'ibm903': 13111 return 'IBM903'; 13112 13113 case '904': 13114 case 'cp904': 13115 case 'csibbm904': 13116 case 'ibm904': 13117 return 'IBM904'; 13118 13119 case 'cp905': 13120 case 'csibm905': 13121 case 'ebcdiccptr': 13122 case 'ibm905': 13123 return 'IBM905'; 13124 13125 case 'cp918': 13126 case 'csibm918': 13127 case 'ebcdiccpar2': 13128 case 'ibm918': 13129 return 'IBM918'; 13130 13131 case 'ccsid924': 13132 case 'cp924': 13133 case 'ebcdiclatin9euro': 13134 case 'ibm924': 13135 return 'IBM00924'; 13136 13137 case 'cp1026': 13138 case 'csibm1026': 13139 case 'ibm1026': 13140 return 'IBM1026'; 13141 13142 case 'ibm1047': 13143 return 'IBM1047'; 13144 13145 case 'ccsid1140': 13146 case 'cp1140': 13147 case 'ebcdicus37euro': 13148 case 'ibm1140': 13149 return 'IBM01140'; 13150 13151 case 'ccsid1141': 13152 case 'cp1141': 13153 case 'ebcdicde273euro': 13154 case 'ibm1141': 13155 return 'IBM01141'; 13156 13157 case 'ccsid1142': 13158 case 'cp1142': 13159 case 'ebcdicdk277euro': 13160 case 'ebcdicno277euro': 13161 case 'ibm1142': 13162 return 'IBM01142'; 13163 13164 case 'ccsid1143': 13165 case 'cp1143': 13166 case 'ebcdicfi278euro': 13167 case 'ebcdicse278euro': 13168 case 'ibm1143': 13169 return 'IBM01143'; 13170 13171 case 'ccsid1144': 13172 case 'cp1144': 13173 case 'ebcdicit280euro': 13174 case 'ibm1144': 13175 return 'IBM01144'; 13176 13177 case 'ccsid1145': 13178 case 'cp1145': 13179 case 'ebcdices284euro': 13180 case 'ibm1145': 13181 return 'IBM01145'; 13182 13183 case 'ccsid1146': 13184 case 'cp1146': 13185 case 'ebcdicgb285euro': 13186 case 'ibm1146': 13187 return 'IBM01146'; 13188 13189 case 'ccsid1147': 13190 case 'cp1147': 13191 case 'ebcdicfr297euro': 13192 case 'ibm1147': 13193 return 'IBM01147'; 13194 13195 case 'ccsid1148': 13196 case 'cp1148': 13197 case 'ebcdicinternational500euro': 13198 case 'ibm1148': 13199 return 'IBM01148'; 13200 13201 case 'ccsid1149': 13202 case 'cp1149': 13203 case 'ebcdicis871euro': 13204 case 'ibm1149': 13205 return 'IBM01149'; 13206 13207 case 'csiso143iecp271': 13208 case 'iecp271': 13209 case 'isoir143': 13210 return 'IEC_P27-1'; 13211 13212 case 'csiso49inis': 13213 case 'inis': 13214 case 'isoir49': 13215 return 'INIS'; 13216 13217 case 'csiso50inis8': 13218 case 'inis8': 13219 case 'isoir50': 13220 return 'INIS-8'; 13221 13222 case 'csiso51iniscyrillic': 13223 case 'iniscyrillic': 13224 case 'isoir51': 13225 return 'INIS-cyrillic'; 13226 13227 case 'csinvariant': 13228 case 'invariant': 13229 return 'INVARIANT'; 13230 13231 case 'iso2022cn': 13232 return 'ISO-2022-CN'; 13233 13234 case 'iso2022cnext': 13235 return 'ISO-2022-CN-EXT'; 13236 13237 case 'csiso2022jp': 13238 case 'iso2022jp': 13239 return 'ISO-2022-JP'; 13240 13241 case 'csiso2022jp2': 13242 case 'iso2022jp2': 13243 return 'ISO-2022-JP-2'; 13244 13245 case 'csiso2022kr': 13246 case 'iso2022kr': 13247 return 'ISO-2022-KR'; 13248 13249 case 'cswindows30latin1': 13250 case 'iso88591windows30latin1': 13251 return 'ISO-8859-1-Windows-3.0-Latin-1'; 13252 13253 case 'cswindows31latin1': 13254 case 'iso88591windows31latin1': 13255 return 'ISO-8859-1-Windows-3.1-Latin-1'; 13256 13257 case 'csisolatin2': 13258 case 'iso88592': 13259 case 'iso885921987': 13260 case 'isoir101': 13261 case 'l2': 13262 case 'latin2': 13263 return 'ISO-8859-2'; 13264 13265 case 'cswindows31latin2': 13266 case 'iso88592windowslatin2': 13267 return 'ISO-8859-2-Windows-Latin-2'; 13268 13269 case 'csisolatin3': 13270 case 'iso88593': 13271 case 'iso885931988': 13272 case 'isoir109': 13273 case 'l3': 13274 case 'latin3': 13275 return 'ISO-8859-3'; 13276 13277 case 'csisolatin4': 13278 case 'iso88594': 13279 case 'iso885941988': 13280 case 'isoir110': 13281 case 'l4': 13282 case 'latin4': 13283 return 'ISO-8859-4'; 13284 13285 case 'csisolatincyrillic': 13286 case 'cyrillic': 13287 case 'iso88595': 13288 case 'iso885951988': 13289 case 'isoir144': 13290 return 'ISO-8859-5'; 13291 13292 case 'arabic': 13293 case 'asmo708': 13294 case 'csisolatinarabic': 13295 case 'ecma114': 13296 case 'iso88596': 13297 case 'iso885961987': 13298 case 'isoir127': 13299 return 'ISO-8859-6'; 13300 13301 case 'csiso88596e': 13302 case 'iso88596e': 13303 return 'ISO-8859-6-E'; 13304 13305 case 'csiso88596i': 13306 case 'iso88596i': 13307 return 'ISO-8859-6-I'; 13308 13309 case 'csisolatingreek': 13310 case 'ecma118': 13311 case 'elot928': 13312 case 'greek': 13313 case 'greek8': 13314 case 'iso88597': 13315 case 'iso885971987': 13316 case 'isoir126': 13317 return 'ISO-8859-7'; 13318 13319 case 'csisolatinhebrew': 13320 case 'hebrew': 13321 case 'iso88598': 13322 case 'iso885981988': 13323 case 'isoir138': 13324 return 'ISO-8859-8'; 13325 13326 case 'csiso88598e': 13327 case 'iso88598e': 13328 return 'ISO-8859-8-E'; 13329 13330 case 'csiso88598i': 13331 case 'iso88598i': 13332 return 'ISO-8859-8-I'; 13333 13334 case 'cswindows31latin5': 13335 case 'iso88599windowslatin5': 13336 return 'ISO-8859-9-Windows-Latin-5'; 13337 13338 case 'csisolatin6': 13339 case 'iso885910': 13340 case 'iso8859101992': 13341 case 'isoir157': 13342 case 'l6': 13343 case 'latin6': 13344 return 'ISO-8859-10'; 13345 13346 case 'iso885913': 13347 return 'ISO-8859-13'; 13348 13349 case 'iso885914': 13350 case 'iso8859141998': 13351 case 'isoceltic': 13352 case 'isoir199': 13353 case 'l8': 13354 case 'latin8': 13355 return 'ISO-8859-14'; 13356 13357 case 'iso885915': 13358 case 'latin9': 13359 return 'ISO-8859-15'; 13360 13361 case 'iso885916': 13362 case 'iso8859162001': 13363 case 'isoir226': 13364 case 'l10': 13365 case 'latin10': 13366 return 'ISO-8859-16'; 13367 13368 case 'iso10646j1': 13369 return 'ISO-10646-J-1'; 13370 13371 case 'csunicode': 13372 case 'iso10646ucs2': 13373 return 'ISO-10646-UCS-2'; 13374 13375 case 'csucs4': 13376 case 'iso10646ucs4': 13377 return 'ISO-10646-UCS-4'; 13378 13379 case 'csunicodeascii': 13380 case 'iso10646ucsbasic': 13381 return 'ISO-10646-UCS-Basic'; 13382 13383 case 'csunicodelatin1': 13384 case 'iso10646': 13385 case 'iso10646unicodelatin1': 13386 return 'ISO-10646-Unicode-Latin1'; 13387 13388 case 'csiso10646utf1': 13389 case 'iso10646utf1': 13390 return 'ISO-10646-UTF-1'; 13391 13392 case 'csiso115481': 13393 case 'iso115481': 13394 case 'isotr115481': 13395 return 'ISO-11548-1'; 13396 13397 case 'csiso90': 13398 case 'isoir90': 13399 return 'iso-ir-90'; 13400 13401 case 'csunicodeibm1261': 13402 case 'isounicodeibm1261': 13403 return 'ISO-Unicode-IBM-1261'; 13404 13405 case 'csunicodeibm1264': 13406 case 'isounicodeibm1264': 13407 return 'ISO-Unicode-IBM-1264'; 13408 13409 case 'csunicodeibm1265': 13410 case 'isounicodeibm1265': 13411 return 'ISO-Unicode-IBM-1265'; 13412 13413 case 'csunicodeibm1268': 13414 case 'isounicodeibm1268': 13415 return 'ISO-Unicode-IBM-1268'; 13416 13417 case 'csunicodeibm1276': 13418 case 'isounicodeibm1276': 13419 return 'ISO-Unicode-IBM-1276'; 13420 13421 case 'csiso646basic1983': 13422 case 'iso646basic1983': 13423 case 'ref': 13424 return 'ISO_646.basic:1983'; 13425 13426 case 'csiso2intlrefversion': 13427 case 'irv': 13428 case 'iso646irv1983': 13429 case 'isoir2': 13430 return 'ISO_646.irv:1983'; 13431 13432 case 'csiso2033': 13433 case 'e13b': 13434 case 'iso20331983': 13435 case 'isoir98': 13436 return 'ISO_2033-1983'; 13437 13438 case 'csiso5427cyrillic': 13439 case 'iso5427': 13440 case 'isoir37': 13441 return 'ISO_5427'; 13442 13443 case 'iso5427cyrillic1981': 13444 case 'iso54271981': 13445 case 'isoir54': 13446 return 'ISO_5427:1981'; 13447 13448 case 'csiso5428greek': 13449 case 'iso54281980': 13450 case 'isoir55': 13451 return 'ISO_5428:1980'; 13452 13453 case 'csiso6937add': 13454 case 'iso6937225': 13455 case 'isoir152': 13456 return 'ISO_6937-2-25'; 13457 13458 case 'csisotextcomm': 13459 case 'iso69372add': 13460 case 'isoir142': 13461 return 'ISO_6937-2-add'; 13462 13463 case 'csiso8859supp': 13464 case 'iso8859supp': 13465 case 'isoir154': 13466 case 'latin125': 13467 return 'ISO_8859-supp'; 13468 13469 case 'csiso10367box': 13470 case 'iso10367box': 13471 case 'isoir155': 13472 return 'ISO_10367-box'; 13473 13474 case 'csiso15italian': 13475 case 'iso646it': 13476 case 'isoir15': 13477 case 'it': 13478 return 'IT'; 13479 13480 case 'csiso13jisc6220jp': 13481 case 'isoir13': 13482 case 'jisc62201969': 13483 case 'jisc62201969jp': 13484 case 'katakana': 13485 case 'x2017': 13486 return 'JIS_C6220-1969-jp'; 13487 13488 case 'csiso14jisc6220ro': 13489 case 'iso646jp': 13490 case 'isoir14': 13491 case 'jisc62201969ro': 13492 case 'jp': 13493 return 'JIS_C6220-1969-ro'; 13494 13495 case 'csiso42jisc62261978': 13496 case 'isoir42': 13497 case 'jisc62261978': 13498 return 'JIS_C6226-1978'; 13499 13500 case 'csiso87jisx208': 13501 case 'isoir87': 13502 case 'jisc62261983': 13503 case 'jisx2081983': 13504 case 'x208': 13505 return 'JIS_C6226-1983'; 13506 13507 case 'csiso91jisc62291984a': 13508 case 'isoir91': 13509 case 'jisc62291984a': 13510 case 'jpocra': 13511 return 'JIS_C6229-1984-a'; 13512 13513 case 'csiso92jisc62991984b': 13514 case 'iso646jpocrb': 13515 case 'isoir92': 13516 case 'jisc62291984b': 13517 case 'jpocrb': 13518 return 'JIS_C6229-1984-b'; 13519 13520 case 'csiso93jis62291984badd': 13521 case 'isoir93': 13522 case 'jisc62291984badd': 13523 case 'jpocrbadd': 13524 return 'JIS_C6229-1984-b-add'; 13525 13526 case 'csiso94jis62291984hand': 13527 case 'isoir94': 13528 case 'jisc62291984hand': 13529 case 'jpocrhand': 13530 return 'JIS_C6229-1984-hand'; 13531 13532 case 'csiso95jis62291984handadd': 13533 case 'isoir95': 13534 case 'jisc62291984handadd': 13535 case 'jpocrhandadd': 13536 return 'JIS_C6229-1984-hand-add'; 13537 13538 case 'csiso96jisc62291984kana': 13539 case 'isoir96': 13540 case 'jisc62291984kana': 13541 return 'JIS_C6229-1984-kana'; 13542 13543 case 'csjisencoding': 13544 case 'jisencoding': 13545 return 'JIS_Encoding'; 13546 13547 case 'cshalfwidthkatakana': 13548 case 'jisx201': 13549 case 'x201': 13550 return 'JIS_X0201'; 13551 13552 case 'csiso159jisx2121990': 13553 case 'isoir159': 13554 case 'jisx2121990': 13555 case 'x212': 13556 return 'JIS_X0212-1990'; 13557 13558 case 'csiso141jusib1002': 13559 case 'iso646yu': 13560 case 'isoir141': 13561 case 'js': 13562 case 'jusib1002': 13563 case 'yu': 13564 return 'JUS_I.B1.002'; 13565 13566 case 'csiso147macedonian': 13567 case 'isoir147': 13568 case 'jusib1003mac': 13569 case 'macedonian': 13570 return 'JUS_I.B1.003-mac'; 13571 13572 case 'csiso146serbian': 13573 case 'isoir146': 13574 case 'jusib1003serb': 13575 case 'serbian': 13576 return 'JUS_I.B1.003-serb'; 13577 13578 case 'koi7switched': 13579 return 'KOI7-switched'; 13580 13581 case 'cskoi8r': 13582 case 'koi8r': 13583 return 'KOI8-R'; 13584 13585 case 'koi8u': 13586 return 'KOI8-U'; 13587 13588 case 'csksc5636': 13589 case 'iso646kr': 13590 case 'ksc5636': 13591 return 'KSC5636'; 13592 13593 case 'cskz1048': 13594 case 'kz1048': 13595 case 'rk1048': 13596 case 'strk10482002': 13597 return 'KZ-1048'; 13598 13599 case 'csiso19latingreek': 13600 case 'isoir19': 13601 case 'latingreek': 13602 return 'latin-greek'; 13603 13604 case 'csiso27latingreek1': 13605 case 'isoir27': 13606 case 'latingreek1': 13607 return 'Latin-greek-1'; 13608 13609 case 'csiso158lap': 13610 case 'isoir158': 13611 case 'lap': 13612 case 'latinlap': 13613 return 'latin-lap'; 13614 13615 case 'csmacintosh': 13616 case 'mac': 13617 case 'macintosh': 13618 return 'macintosh'; 13619 13620 case 'csmicrosoftpublishing': 13621 case 'microsoftpublishing': 13622 return 'Microsoft-Publishing'; 13623 13624 case 'csmnem': 13625 case 'mnem': 13626 return 'MNEM'; 13627 13628 case 'csmnemonic': 13629 case 'mnemonic': 13630 return 'MNEMONIC'; 13631 13632 case 'csiso86hungarian': 13633 case 'hu': 13634 case 'iso646hu': 13635 case 'isoir86': 13636 case 'msz77953': 13637 return 'MSZ_7795.3'; 13638 13639 case 'csnatsdano': 13640 case 'isoir91': 13641 case 'natsdano': 13642 return 'NATS-DANO'; 13643 13644 case 'csnatsdanoadd': 13645 case 'isoir92': 13646 case 'natsdanoadd': 13647 return 'NATS-DANO-ADD'; 13648 13649 case 'csnatssefi': 13650 case 'isoir81': 13651 case 'natssefi': 13652 return 'NATS-SEFI'; 13653 13654 case 'csnatssefiadd': 13655 case 'isoir82': 13656 case 'natssefiadd': 13657 return 'NATS-SEFI-ADD'; 13658 13659 case 'csiso151cuba': 13660 case 'cuba': 13661 case 'iso646cu': 13662 case 'isoir151': 13663 case 'ncnc1081': 13664 return 'NC_NC00-10:81'; 13665 13666 case 'csiso69french': 13667 case 'fr': 13668 case 'iso646fr': 13669 case 'isoir69': 13670 case 'nfz62010': 13671 return 'NF_Z_62-010'; 13672 13673 case 'csiso25french': 13674 case 'iso646fr1': 13675 case 'isoir25': 13676 case 'nfz620101973': 13677 return 'NF_Z_62-010_(1973)'; 13678 13679 case 'csiso60danishnorwegian': 13680 case 'csiso60norwegian1': 13681 case 'iso646no': 13682 case 'isoir60': 13683 case 'no': 13684 case 'ns45511': 13685 return 'NS_4551-1'; 13686 13687 case 'csiso61norwegian2': 13688 case 'iso646no2': 13689 case 'isoir61': 13690 case 'no2': 13691 case 'ns45512': 13692 return 'NS_4551-2'; 13693 13694 case 'osdebcdicdf3irv': 13695 return 'OSD_EBCDIC_DF03_IRV'; 13696 13697 case 'osdebcdicdf41': 13698 return 'OSD_EBCDIC_DF04_1'; 13699 13700 case 'osdebcdicdf415': 13701 return 'OSD_EBCDIC_DF04_15'; 13702 13703 case 'cspc8danishnorwegian': 13704 case 'pc8danishnorwegian': 13705 return 'PC8-Danish-Norwegian'; 13706 13707 case 'cspc8turkish': 13708 case 'pc8turkish': 13709 return 'PC8-Turkish'; 13710 13711 case 'csiso16portuguese': 13712 case 'iso646pt': 13713 case 'isoir16': 13714 case 'pt': 13715 return 'PT'; 13716 13717 case 'csiso84portuguese2': 13718 case 'iso646pt2': 13719 case 'isoir84': 13720 case 'pt2': 13721 return 'PT2'; 13722 13723 case 'cp154': 13724 case 'csptcp154': 13725 case 'cyrillicasian': 13726 case 'pt154': 13727 case 'ptcp154': 13728 return 'PTCP154'; 13729 13730 case 'scsu': 13731 return 'SCSU'; 13732 13733 case 'csiso10swedish': 13734 case 'fi': 13735 case 'iso646fi': 13736 case 'iso646se': 13737 case 'isoir10': 13738 case 'se': 13739 case 'sen850200b': 13740 return 'SEN_850200_B'; 13741 13742 case 'csiso11swedishfornames': 13743 case 'iso646se2': 13744 case 'isoir11': 13745 case 'se2': 13746 case 'sen850200c': 13747 return 'SEN_850200_C'; 13748 13749 case 'csiso102t617bit': 13750 case 'isoir102': 13751 case 't617bit': 13752 return 'T.61-7bit'; 13753 13754 case 'csiso103t618bit': 13755 case 'isoir103': 13756 case 't61': 13757 case 't618bit': 13758 return 'T.61-8bit'; 13759 13760 case 'csiso128t101g2': 13761 case 'isoir128': 13762 case 't101g2': 13763 return 'T.101-G2'; 13764 13765 case 'cstscii': 13766 case 'tscii': 13767 return 'TSCII'; 13768 13769 case 'csunicode11': 13770 case 'unicode11': 13771 return 'UNICODE-1-1'; 13772 13773 case 'csunicode11utf7': 13774 case 'unicode11utf7': 13775 return 'UNICODE-1-1-UTF-7'; 13776 13777 case 'csunknown8bit': 13778 case 'unknown8bit': 13779 return 'UNKNOWN-8BIT'; 13780 13781 case 'ansix341968': 13782 case 'ansix341986': 13783 case 'ascii': 13784 case 'cp367': 13785 case 'csascii': 13786 case 'ibm367': 13787 case 'iso646irv1991': 13788 case 'iso646us': 13789 case 'isoir6': 13790 case 'us': 13791 case 'usascii': 13792 return 'US-ASCII'; 13793 13794 case 'csusdk': 13795 case 'usdk': 13796 return 'us-dk'; 13797 13798 case 'utf7': 13799 return 'UTF-7'; 13800 13801 case 'utf8': 13802 return 'UTF-8'; 13803 13804 case 'utf16': 13805 return 'UTF-16'; 13806 13807 case 'utf16be': 13808 return 'UTF-16BE'; 13809 13810 case 'utf16le': 13811 return 'UTF-16LE'; 13812 13813 case 'utf32': 13814 return 'UTF-32'; 13815 13816 case 'utf32be': 13817 return 'UTF-32BE'; 13818 13819 case 'utf32le': 13820 return 'UTF-32LE'; 13821 13822 case 'csventurainternational': 13823 case 'venturainternational': 13824 return 'Ventura-International'; 13825 13826 case 'csventuramath': 13827 case 'venturamath': 13828 return 'Ventura-Math'; 13829 13830 case 'csventuraus': 13831 case 'venturaus': 13832 return 'Ventura-US'; 13833 13834 case 'csiso70videotexsupp1': 13835 case 'isoir70': 13836 case 'videotexsuppl': 13837 return 'videotex-suppl'; 13838 13839 case 'csviqr': 13840 case 'viqr': 13841 return 'VIQR'; 13842 13843 case 'csviscii': 13844 case 'viscii': 13845 return 'VISCII'; 13846 13847 case 'csshiftjis': 13848 case 'cswindows31j': 13849 case 'mskanji': 13850 case 'shiftjis': 13851 case 'windows31j': 13852 return 'Windows-31J'; 13853 13854 case 'iso885911': 13855 case 'tis620': 13856 return 'windows-874'; 13857 13858 case 'cseuckr': 13859 case 'csksc56011987': 13860 case 'euckr': 13861 case 'isoir149': 13862 case 'korean': 13863 case 'ksc5601': 13864 case 'ksc56011987': 13865 case 'ksc56011989': 13866 case 'windows949': 13867 return 'windows-949'; 13868 13869 case 'windows1250': 13870 return 'windows-1250'; 13871 13872 case 'windows1251': 13873 return 'windows-1251'; 13874 13875 case 'cp819': 13876 case 'csisolatin1': 13877 case 'ibm819': 13878 case 'iso88591': 13879 case 'iso885911987': 13880 case 'isoir100': 13881 case 'l1': 13882 case 'latin1': 13883 case 'windows1252': 13884 return 'windows-1252'; 13885 13886 case 'windows1253': 13887 return 'windows-1253'; 13888 13889 case 'csisolatin5': 13890 case 'iso88599': 13891 case 'iso885991989': 13892 case 'isoir148': 13893 case 'l5': 13894 case 'latin5': 13895 case 'windows1254': 13896 return 'windows-1254'; 13897 13898 case 'windows1255': 13899 return 'windows-1255'; 13900 13901 case 'windows1256': 13902 return 'windows-1256'; 13903 13904 case 'windows1257': 13905 return 'windows-1257'; 13906 13907 case 'windows1258': 13908 return 'windows-1258'; 13909 13910 default: 13911 return $charset; 13912 } 13913 } 13914 13915 public static function get_curl_version() 13916 { 13917 if (is_array($curl = curl_version())) 13918 { 13919 $curl = $curl['version']; 13920 } 13921 elseif (substr($curl, 0, 5) === 'curl/') 13922 { 13923 $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5)); 13924 } 13925 elseif (substr($curl, 0, 8) === 'libcurl/') 13926 { 13927 $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8)); 13928 } 13929 else 13930 { 13931 $curl = 0; 13932 } 13933 return $curl; 13934 } 13935 13936 /** 13937 * Strip HTML comments 13938 * 13939 * @param string $data Data to strip comments from 13940 * @return string Comment stripped string 13941 */ 13942 public static function strip_comments($data) 13943 { 13944 $output = ''; 13945 while (($start = strpos($data, '<!--')) !== false) 13946 { 13947 $output .= substr($data, 0, $start); 13948 if (($end = strpos($data, '-->', $start)) !== false) 13949 { 13950 $data = substr_replace($data, '', 0, $end + 3); 13951 } 13952 else 13953 { 13954 $data = ''; 13955 } 13956 } 13957 return $output . $data; 13958 } 13959 13960 public static function parse_date($dt) 13961 { 13962 $parser = SimplePie_Parse_Date::get(); 13963 return $parser->parse($dt); 13964 } 13965 13966 /** 13967 * Decode HTML entities 13968 * 13969 * @deprecated Use DOMDocument instead 13970 * @param string $data Input data 13971 * @return string Output data 13972 */ 13973 public static function entities_decode($data) 13974 { 13975 $decoder = new SimplePie_Decode_HTML_Entities($data); 13976 return $decoder->parse(); 13977 } 13978 13979 /** 13980 * Remove RFC822 comments 13981 * 13982 * @param string $data Data to strip comments from 13983 * @return string Comment stripped string 13984 */ 13985 public static function uncomment_rfc822($string) 13986 { 13987 $string = (string) $string; 13988 $position = 0; 13989 $length = strlen($string); 13990 $depth = 0; 13991 13992 $output = ''; 13993 13994 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) 13995 { 13996 $output .= substr($string, $position, $pos - $position); 13997 $position = $pos + 1; 13998 if ($string[$pos - 1] !== '\\') 13999 { 14000 $depth++; 14001 while ($depth && $position < $length) 14002 { 14003 $position += strcspn($string, '()', $position); 14004 if ($string[$position - 1] === '\\') 14005 { 14006 $position++; 14007 continue; 14008 } 14009 elseif (isset($string[$position])) 14010 { 14011 switch ($string[$position]) 14012 { 14013 case '(': 14014 $depth++; 14015 break; 14016 14017 case ')': 14018 $depth--; 14019 break; 14020 } 14021 $position++; 14022 } 14023 else 14024 { 14025 break; 14026 } 14027 } 14028 } 14029 else 14030 { 14031 $output .= '('; 14032 } 14033 } 14034 $output .= substr($string, $position); 14035 14036 return $output; 14037 } 14038 14039 public static function parse_mime($mime) 14040 { 14041 if (($pos = strpos($mime, ';')) === false) 14042 { 14043 return trim($mime); 14044 } 14045 else 14046 { 14047 return trim(substr($mime, 0, $pos)); 14048 } 14049 } 14050 14051 public static function atom_03_construct_type($attribs) 14052 { 14053 if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64')) 14054 { 14055 $mode = SIMPLEPIE_CONSTRUCT_BASE64; 14056 } 14057 else 14058 { 14059 $mode = SIMPLEPIE_CONSTRUCT_NONE; 14060 } 14061 if (isset($attribs['']['type'])) 14062 { 14063 switch (strtolower(trim($attribs['']['type']))) 14064 { 14065 case 'text': 14066 case 'text/plain': 14067 return SIMPLEPIE_CONSTRUCT_TEXT | $mode; 14068 14069 case 'html': 14070 case 'text/html': 14071 return SIMPLEPIE_CONSTRUCT_HTML | $mode; 14072 14073 case 'xhtml': 14074 case 'application/xhtml+xml': 14075 return SIMPLEPIE_CONSTRUCT_XHTML | $mode; 14076 14077 default: 14078 return SIMPLEPIE_CONSTRUCT_NONE | $mode; 14079 } 14080 } 14081 else 14082 { 14083 return SIMPLEPIE_CONSTRUCT_TEXT | $mode; 14084 } 14085 } 14086 14087 public static function atom_10_construct_type($attribs) 14088 { 14089 if (isset($attribs['']['type'])) 14090 { 14091 switch (strtolower(trim($attribs['']['type']))) 14092 { 14093 case 'text': 14094 return SIMPLEPIE_CONSTRUCT_TEXT; 14095 14096 case 'html': 14097 return SIMPLEPIE_CONSTRUCT_HTML; 14098 14099 case 'xhtml': 14100 return SIMPLEPIE_CONSTRUCT_XHTML; 14101 14102 default: 14103 return SIMPLEPIE_CONSTRUCT_NONE; 14104 } 14105 } 14106 return SIMPLEPIE_CONSTRUCT_TEXT; 14107 } 14108 14109 public static function atom_10_content_construct_type($attribs) 14110 { 14111 if (isset($attribs['']['type'])) 14112 { 14113 $type = strtolower(trim($attribs['']['type'])); 14114 switch ($type) 14115 { 14116 case 'text': 14117 return SIMPLEPIE_CONSTRUCT_TEXT; 14118 14119 case 'html': 14120 return SIMPLEPIE_CONSTRUCT_HTML; 14121 14122 case 'xhtml': 14123 return SIMPLEPIE_CONSTRUCT_XHTML; 14124 } 14125 if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/') 14126 { 14127 return SIMPLEPIE_CONSTRUCT_NONE; 14128 } 14129 else 14130 { 14131 return SIMPLEPIE_CONSTRUCT_BASE64; 14132 } 14133 } 14134 else 14135 { 14136 return SIMPLEPIE_CONSTRUCT_TEXT; 14137 } 14138 } 14139 14140 public static function is_isegment_nz_nc($string) 14141 { 14142 return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string); 14143 } 14144 14145 public static function space_seperated_tokens($string) 14146 { 14147 $space_characters = "\x20\x09\x0A\x0B\x0C\x0D"; 14148 $string_length = strlen($string); 14149 14150 $position = strspn($string, $space_characters); 14151 $tokens = array(); 14152 14153 while ($position < $string_length) 14154 { 14155 $len = strcspn($string, $space_characters, $position); 14156 $tokens[] = substr($string, $position, $len); 14157 $position += $len; 14158 $position += strspn($string, $space_characters, $position); 14159 } 14160 14161 return $tokens; 14162 } 14163 14164 /** 14165 * Converts a unicode codepoint to a UTF-8 character 14166 * 14167 * @static 14168 * @param int $codepoint Unicode codepoint 14169 * @return string UTF-8 character 14170 */ 14171 public static function codepoint_to_utf8($codepoint) 14172 { 14173 $codepoint = (int) $codepoint; 14174 if ($codepoint < 0) 14175 { 14176 return false; 14177 } 14178 else if ($codepoint <= 0x7f) 14179 { 14180 return chr($codepoint); 14181 } 14182 else if ($codepoint <= 0x7ff) 14183 { 14184 return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f)); 14185 } 14186 else if ($codepoint <= 0xffff) 14187 { 14188 return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); 14189 } 14190 else if ($codepoint <= 0x10ffff) 14191 { 14192 return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f)); 14193 } 14194 else 14195 { 14196 // U+FFFD REPLACEMENT CHARACTER 14197 return "\xEF\xBF\xBD"; 14198 } 14199 } 14200 14201 /** 14202 * Similar to parse_str() 14203 * 14204 * Returns an associative array of name/value pairs, where the value is an 14205 * array of values that have used the same name 14206 * 14207 * @static 14208 * @param string $str The input string. 14209 * @return array 14210 */ 14211 public static function parse_str($str) 14212 { 14213 $return = array(); 14214 $str = explode('&', $str); 14215 14216 foreach ($str as $section) 14217 { 14218 if (strpos($section, '=') !== false) 14219 { 14220 list($name, $value) = explode('=', $section, 2); 14221 $return[urldecode($name)][] = urldecode($value); 14222 } 14223 else 14224 { 14225 $return[urldecode($section)][] = null; 14226 } 14227 } 14228 14229 return $return; 14230 } 14231 14232 /** 14233 * Detect XML encoding, as per XML 1.0 Appendix F.1 14234 * 14235 * @todo Add support for EBCDIC 14236 * @param string $data XML data 14237 * @param SimplePie_Registry $registry Class registry 14238 * @return array Possible encodings 14239 */ 14240 public static function xml_encoding($data, $registry) 14241 { 14242 // UTF-32 Big Endian BOM 14243 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") 14244 { 14245 $encoding[] = 'UTF-32BE'; 14246 } 14247 // UTF-32 Little Endian BOM 14248 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") 14249 { 14250 $encoding[] = 'UTF-32LE'; 14251 } 14252 // UTF-16 Big Endian BOM 14253 elseif (substr($data, 0, 2) === "\xFE\xFF") 14254 { 14255 $encoding[] = 'UTF-16BE'; 14256 } 14257 // UTF-16 Little Endian BOM 14258 elseif (substr($data, 0, 2) === "\xFF\xFE") 14259 { 14260 $encoding[] = 'UTF-16LE'; 14261 } 14262 // UTF-8 BOM 14263 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") 14264 { 14265 $encoding[] = 'UTF-8'; 14266 } 14267 // UTF-32 Big Endian Without BOM 14268 elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C") 14269 { 14270 if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E")) 14271 { 14272 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'))); 14273 if ($parser->parse()) 14274 { 14275 $encoding[] = $parser->encoding; 14276 } 14277 } 14278 $encoding[] = 'UTF-32BE'; 14279 } 14280 // UTF-32 Little Endian Without BOM 14281 elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00") 14282 { 14283 if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00")) 14284 { 14285 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'))); 14286 if ($parser->parse()) 14287 { 14288 $encoding[] = $parser->encoding; 14289 } 14290 } 14291 $encoding[] = 'UTF-32LE'; 14292 } 14293 // UTF-16 Big Endian Without BOM 14294 elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C") 14295 { 14296 if ($pos = strpos($data, "\x00\x3F\x00\x3E")) 14297 { 14298 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'))); 14299 if ($parser->parse()) 14300 { 14301 $encoding[] = $parser->encoding; 14302 } 14303 } 14304 $encoding[] = 'UTF-16BE'; 14305 } 14306 // UTF-16 Little Endian Without BOM 14307 elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00") 14308 { 14309 if ($pos = strpos($data, "\x3F\x00\x3E\x00")) 14310 { 14311 $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'))); 14312 if ($parser->parse()) 14313 { 14314 $encoding[] = $parser->encoding; 14315 } 14316 } 14317 $encoding[] = 'UTF-16LE'; 14318 } 14319 // US-ASCII (or superset) 14320 elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C") 14321 { 14322 if ($pos = strpos($data, "\x3F\x3E")) 14323 { 14324 $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5))); 14325 if ($parser->parse()) 14326 { 14327 $encoding[] = $parser->encoding; 14328 } 14329 } 14330 $encoding[] = 'UTF-8'; 14331 } 14332 // Fallback to UTF-8 14333 else 14334 { 14335 $encoding[] = 'UTF-8'; 14336 } 14337 return $encoding; 14338 } 14339 14340 public static function output_javascript() 14341 { 14342 if (function_exists('ob_gzhandler')) 14343 { 14344 ob_start('ob_gzhandler'); 14345 } 14346 header('Content-type: text/javascript; charset: UTF-8'); 14347 header('Cache-Control: must-revalidate'); 14348 header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days 14349 ?> 14350 function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) { 14351 if (placeholder != '') { 14352 document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); 14353 } 14354 else { 14355 document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>'); 14356 } 14357 } 14358 14359 function embed_flash(bgcolor, width, height, link, loop, type) { 14360 document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>'); 14361 } 14362 14363 function embed_flv(width, height, link, placeholder, loop, player) { 14364 document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>'); 14365 } 14366 14367 function embed_wmedia(width, height, link) { 14368 document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>'); 14369 } 14370 <?php 14371 } 14372 14373 /** 14374 * Get the SimplePie build timestamp 14375 * 14376 * Uses the git index if it exists, otherwise uses the modification time 14377 * of the newest file. 14378 */ 14379 public static function get_build() 14380 { 14381 $root = dirname(dirname(__FILE__)); 14382 if (file_exists($root . '/.git/index')) 14383 { 14384 return filemtime($root . '/.git/index'); 14385 } 14386 elseif (file_exists($root . '/SimplePie')) 14387 { 14388 $time = 0; 14389 foreach (glob($root . '/SimplePie/*.php') as $file) 14390 { 14391 if (($mtime = filemtime($file)) > $time) 14392 { 14393 $time = $mtime; 14394 } 14395 } 14396 return $time; 14397 } 14398 elseif (file_exists(dirname(__FILE__) . '/Core.php')) 14399 { 14400 return filemtime(dirname(__FILE__) . '/Core.php'); 14401 } 14402 else 14403 { 14404 return filemtime(__FILE__); 14405 } 14406 } 14407 14408 /** 14409 * Format debugging information 14410 */ 14411 public static function debug(&$sp) 14412 { 14413 $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n"; 14414 $info .= 'PHP ' . PHP_VERSION . "\n"; 14415 if ($sp->error() !== null) 14416 { 14417 $info .= 'Error occurred: ' . $sp->error() . "\n"; 14418 } 14419 else 14420 { 14421 $info .= "No error found.\n"; 14422 } 14423 $info .= "Extensions:\n"; 14424 $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml'); 14425 foreach ($extensions as $ext) 14426 { 14427 if (extension_loaded($ext)) 14428 { 14429 $info .= " $ext loaded\n"; 14430 switch ($ext) 14431 { 14432 case 'pcre': 14433 $info .= ' Version ' . PCRE_VERSION . "\n"; 14434 break; 14435 case 'curl': 14436 $version = curl_version(); 14437 $info .= ' Version ' . $version['version'] . "\n"; 14438 break; 14439 case 'mbstring': 14440 $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n"; 14441 break; 14442 case 'iconv': 14443 $info .= ' Version ' . ICONV_VERSION . "\n"; 14444 break; 14445 case 'xml': 14446 $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n"; 14447 break; 14448 } 14449 } 14450 else 14451 { 14452 $info .= " $ext not loaded\n"; 14453 } 14454 } 14455 return $info; 14456 } 14457 14458 public static function silence_errors($num, $str) 14459 { 14460 // No-op 14461 } 14462 } 14463 14464 /** 14465 * Class to validate and to work with IPv6 addresses. 14466 * 14467 * @package SimplePie 14468 * @subpackage HTTP 14469 * @copyright 2003-2005 The PHP Group 14470 * @license http://www.opensource.org/licenses/bsd-license.php 14471 * @link http://pear.php.net/package/Net_IPv6 14472 * @author Alexander Merz <alexander.merz@web.de> 14473 * @author elfrink at introweb dot nl 14474 * @author Josh Peck <jmp at joshpeck dot org> 14475 * @author Geoffrey Sneddon <geoffers@gmail.com> 14476 */ 14477 class SimplePie_Net_IPv6 14478 { 14479 /** 14480 * Uncompresses an IPv6 address 14481 * 14482 * RFC 4291 allows you to compress concecutive zero pieces in an address to 14483 * '::'. This method expects a valid IPv6 address and expands the '::' to 14484 * the required number of zero pieces. 14485 * 14486 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 14487 * ::1 -> 0:0:0:0:0:0:0:1 14488 * 14489 * @author Alexander Merz <alexander.merz@web.de> 14490 * @author elfrink at introweb dot nl 14491 * @author Josh Peck <jmp at joshpeck dot org> 14492 * @copyright 2003-2005 The PHP Group 14493 * @license http://www.opensource.org/licenses/bsd-license.php 14494 * @param string $ip An IPv6 address 14495 * @return string The uncompressed IPv6 address 14496 */ 14497 public static function uncompress($ip) 14498 { 14499 $c1 = -1; 14500 $c2 = -1; 14501 if (substr_count($ip, '::') === 1) 14502 { 14503 list($ip1, $ip2) = explode('::', $ip); 14504 if ($ip1 === '') 14505 { 14506 $c1 = -1; 14507 } 14508 else 14509 { 14510 $c1 = substr_count($ip1, ':'); 14511 } 14512 if ($ip2 === '') 14513 { 14514 $c2 = -1; 14515 } 14516 else 14517 { 14518 $c2 = substr_count($ip2, ':'); 14519 } 14520 if (strpos($ip2, '.') !== false) 14521 { 14522 $c2++; 14523 } 14524 // :: 14525 if ($c1 === -1 && $c2 === -1) 14526 { 14527 $ip = '0:0:0:0:0:0:0:0'; 14528 } 14529 // ::xxx 14530 else if ($c1 === -1) 14531 { 14532 $fill = str_repeat('0:', 7 - $c2); 14533 $ip = str_replace('::', $fill, $ip); 14534 } 14535 // xxx:: 14536 else if ($c2 === -1) 14537 { 14538 $fill = str_repeat(':0', 7 - $c1); 14539 $ip = str_replace('::', $fill, $ip); 14540 } 14541 // xxx::xxx 14542 else 14543 { 14544 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); 14545 $ip = str_replace('::', $fill, $ip); 14546 } 14547 } 14548 return $ip; 14549 } 14550 14551 /** 14552 * Compresses an IPv6 address 14553 * 14554 * RFC 4291 allows you to compress concecutive zero pieces in an address to 14555 * '::'. This method expects a valid IPv6 address and compresses consecutive 14556 * zero pieces to '::'. 14557 * 14558 * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 14559 * 0:0:0:0:0:0:0:1 -> ::1 14560 * 14561 * @see uncompress() 14562 * @param string $ip An IPv6 address 14563 * @return string The compressed IPv6 address 14564 */ 14565 public static function compress($ip) 14566 { 14567 // Prepare the IP to be compressed 14568 $ip = self::uncompress($ip); 14569 $ip_parts = self::split_v6_v4($ip); 14570 14571 // Replace all leading zeros 14572 $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]); 14573 14574 // Find bunches of zeros 14575 if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) 14576 { 14577 $max = 0; 14578 $pos = null; 14579 foreach ($matches[0] as $match) 14580 { 14581 if (strlen($match[0]) > $max) 14582 { 14583 $max = strlen($match[0]); 14584 $pos = $match[1]; 14585 } 14586 } 14587 14588 $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max); 14589 } 14590 14591 if ($ip_parts[1] !== '') 14592 { 14593 return implode(':', $ip_parts); 14594 } 14595 else 14596 { 14597 return $ip_parts[0]; 14598 } 14599 } 14600 14601 /** 14602 * Splits an IPv6 address into the IPv6 and IPv4 representation parts 14603 * 14604 * RFC 4291 allows you to represent the last two parts of an IPv6 address 14605 * using the standard IPv4 representation 14606 * 14607 * Example: 0:0:0:0:0:0:13.1.68.3 14608 * 0:0:0:0:0:FFFF:129.144.52.38 14609 * 14610 * @param string $ip An IPv6 address 14611 * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part 14612 */ 14613 private static function split_v6_v4($ip) 14614 { 14615 if (strpos($ip, '.') !== false) 14616 { 14617 $pos = strrpos($ip, ':'); 14618 $ipv6_part = substr($ip, 0, $pos); 14619 $ipv4_part = substr($ip, $pos + 1); 14620 return array($ipv6_part, $ipv4_part); 14621 } 14622 else 14623 { 14624 return array($ip, ''); 14625 } 14626 } 14627 14628 /** 14629 * Checks an IPv6 address 14630 * 14631 * Checks if the given IP is a valid IPv6 address 14632 * 14633 * @param string $ip An IPv6 address 14634 * @return bool true if $ip is a valid IPv6 address 14635 */ 14636 public static function check_ipv6($ip) 14637 { 14638 $ip = self::uncompress($ip); 14639 list($ipv6, $ipv4) = self::split_v6_v4($ip); 14640 $ipv6 = explode(':', $ipv6); 14641 $ipv4 = explode('.', $ipv4); 14642 if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) 14643 { 14644 foreach ($ipv6 as $ipv6_part) 14645 { 14646 // The section can't be empty 14647 if ($ipv6_part === '') 14648 return false; 14649 14650 // Nor can it be over four characters 14651 if (strlen($ipv6_part) > 4) 14652 return false; 14653 14654 // Remove leading zeros (this is safe because of the above) 14655 $ipv6_part = ltrim($ipv6_part, '0'); 14656 if ($ipv6_part === '') 14657 $ipv6_part = '0'; 14658 14659 // Check the value is valid 14660 $value = hexdec($ipv6_part); 14661 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) 14662 return false; 14663 } 14664 if (count($ipv4) === 4) 14665 { 14666 foreach ($ipv4 as $ipv4_part) 14667 { 14668 $value = (int) $ipv4_part; 14669 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) 14670 return false; 14671 } 14672 } 14673 return true; 14674 } 14675 else 14676 { 14677 return false; 14678 } 14679 } 14680 14681 /** 14682 * Checks if the given IP is a valid IPv6 address 14683 * 14684 * @codeCoverageIgnore 14685 * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead 14686 * @see check_ipv6 14687 * @param string $ip An IPv6 address 14688 * @return bool true if $ip is a valid IPv6 address 14689 */ 14690 public static function checkIPv6($ip) 14691 { 14692 return self::check_ipv6($ip); 14693 } 14694 } 14695 14696 /** 14697 * Date Parser 14698 * 14699 * @package SimplePie 14700 * @subpackage Parsing 14701 */ 14702 class SimplePie_Parse_Date 14703 { 14704 /** 14705 * Input data 14706 * 14707 * @access protected 14708 * @var string 14709 */ 14710 var $date; 14711 14712 /** 14713 * List of days, calendar day name => ordinal day number in the week 14714 * 14715 * @access protected 14716 * @var array 14717 */ 14718 var $day = array( 14719 // English 14720 'mon' => 1, 14721 'monday' => 1, 14722 'tue' => 2, 14723 'tuesday' => 2, 14724 'wed' => 3, 14725 'wednesday' => 3, 14726 'thu' => 4, 14727 'thursday' => 4, 14728 'fri' => 5, 14729 'friday' => 5, 14730 'sat' => 6, 14731 'saturday' => 6, 14732 'sun' => 7, 14733 'sunday' => 7, 14734 // Dutch 14735 'maandag' => 1, 14736 'dinsdag' => 2, 14737 'woensdag' => 3, 14738 'donderdag' => 4, 14739 'vrijdag' => 5, 14740 'zaterdag' => 6, 14741 'zondag' => 7, 14742 // French 14743 'lundi' => 1, 14744 'mardi' => 2, 14745 'mercredi' => 3, 14746 'jeudi' => 4, 14747 'vendredi' => 5, 14748 'samedi' => 6, 14749 'dimanche' => 7, 14750 // German 14751 'montag' => 1, 14752 'dienstag' => 2, 14753 'mittwoch' => 3, 14754 'donnerstag' => 4, 14755 'freitag' => 5, 14756 'samstag' => 6, 14757 'sonnabend' => 6, 14758 'sonntag' => 7, 14759 // Italian 14760 'lunedì' => 1, 14761 'martedì' => 2, 14762 'mercoledì' => 3, 14763 'giovedì' => 4, 14764 'venerdì' => 5, 14765 'sabato' => 6, 14766 'domenica' => 7, 14767 // Spanish 14768 'lunes' => 1, 14769 'martes' => 2, 14770 'miércoles' => 3, 14771 'jueves' => 4, 14772 'viernes' => 5, 14773 'sábado' => 6, 14774 'domingo' => 7, 14775 // Finnish 14776 'maanantai' => 1, 14777 'tiistai' => 2, 14778 'keskiviikko' => 3, 14779 'torstai' => 4, 14780 'perjantai' => 5, 14781 'lauantai' => 6, 14782 'sunnuntai' => 7, 14783 // Hungarian 14784 'hétfő' => 1, 14785 'kedd' => 2, 14786 'szerda' => 3, 14787 'csütörtok' => 4, 14788 'péntek' => 5, 14789 'szombat' => 6, 14790 'vasárnap' => 7, 14791 // Greek 14792 'Δευ' => 1, 14793 'Τρι' => 2, 14794 'Τετ' => 3, 14795 'Πεμ' => 4, 14796 'Παρ' => 5, 14797 'Σαβ' => 6, 14798 'Κυρ' => 7, 14799 ); 14800 14801 /** 14802 * List of months, calendar month name => calendar month number 14803 * 14804 * @access protected 14805 * @var array 14806 */ 14807 var $month = array( 14808 // English 14809 'jan' => 1, 14810 'january' => 1, 14811 'feb' => 2, 14812 'february' => 2, 14813 'mar' => 3, 14814 'march' => 3, 14815 'apr' => 4, 14816 'april' => 4, 14817 'may' => 5, 14818 // No long form of May 14819 'jun' => 6, 14820 'june' => 6, 14821 'jul' => 7, 14822 'july' => 7, 14823 'aug' => 8, 14824 'august' => 8, 14825 'sep' => 9, 14826 'september' => 8, 14827 'oct' => 10, 14828 'october' => 10, 14829 'nov' => 11, 14830 'november' => 11, 14831 'dec' => 12, 14832 'december' => 12, 14833 // Dutch 14834 'januari' => 1, 14835 'februari' => 2, 14836 'maart' => 3, 14837 'april' => 4, 14838 'mei' => 5, 14839 'juni' => 6, 14840 'juli' => 7, 14841 'augustus' => 8, 14842 'september' => 9, 14843 'oktober' => 10, 14844 'november' => 11, 14845 'december' => 12, 14846 // French 14847 'janvier' => 1, 14848 'février' => 2, 14849 'mars' => 3, 14850 'avril' => 4, 14851 'mai' => 5, 14852 'juin' => 6, 14853 'juillet' => 7, 14854 'août' => 8, 14855 'septembre' => 9, 14856 'octobre' => 10, 14857 'novembre' => 11, 14858 'décembre' => 12, 14859 // German 14860 'januar' => 1, 14861 'februar' => 2, 14862 'märz' => 3, 14863 'april' => 4, 14864 'mai' => 5, 14865 'juni' => 6, 14866 'juli' => 7, 14867 'august' => 8, 14868 'september' => 9, 14869 'oktober' => 10, 14870 'november' => 11, 14871 'dezember' => 12, 14872 // Italian 14873 'gennaio' => 1, 14874 'febbraio' => 2, 14875 'marzo' => 3, 14876 'aprile' => 4, 14877 'maggio' => 5, 14878 'giugno' => 6, 14879 'luglio' => 7, 14880 'agosto' => 8, 14881 'settembre' => 9, 14882 'ottobre' => 10, 14883 'novembre' => 11, 14884 'dicembre' => 12, 14885 // Spanish 14886 'enero' => 1, 14887 'febrero' => 2, 14888 'marzo' => 3, 14889 'abril' => 4, 14890 'mayo' => 5, 14891 'junio' => 6, 14892 'julio' => 7, 14893 'agosto' => 8, 14894 'septiembre' => 9, 14895 'setiembre' => 9, 14896 'octubre' => 10, 14897 'noviembre' => 11, 14898 'diciembre' => 12, 14899 // Finnish 14900 'tammikuu' => 1, 14901 'helmikuu' => 2, 14902 'maaliskuu' => 3, 14903 'huhtikuu' => 4, 14904 'toukokuu' => 5, 14905 'kesäkuu' => 6, 14906 'heinäkuu' => 7, 14907 'elokuu' => 8, 14908 'suuskuu' => 9, 14909 'lokakuu' => 10, 14910 'marras' => 11, 14911 'joulukuu' => 12, 14912 // Hungarian 14913 'január' => 1, 14914 'február' => 2, 14915 'március' => 3, 14916 'április' => 4, 14917 'május' => 5, 14918 'június' => 6, 14919 'július' => 7, 14920 'augusztus' => 8, 14921 'szeptember' => 9, 14922 'október' => 10, 14923 'november' => 11, 14924 'december' => 12, 14925 // Greek 14926 'Ιαν' => 1, 14927 'Φεβ' => 2, 14928 'Μάώ' => 3, 14929 'Μαώ' => 3, 14930 'Απρ' => 4, 14931 'Μάι' => 5, 14932 'Μαϊ' => 5, 14933 'Μαι' => 5, 14934 'Ιούν' => 6, 14935 'Ιον' => 6, 14936 'Ιούλ' => 7, 14937 'Ιολ' => 7, 14938 'Αύγ' => 8, 14939 'Αυγ' => 8, 14940 'Σεπ' => 9, 14941 'Οκτ' => 10, 14942 'Νοέ' => 11, 14943 'Δεκ' => 12, 14944 ); 14945 14946 /** 14947 * List of timezones, abbreviation => offset from UTC 14948 * 14949 * @access protected 14950 * @var array 14951 */ 14952 var $timezone = array( 14953 'ACDT' => 37800, 14954 'ACIT' => 28800, 14955 'ACST' => 34200, 14956 'ACT' => -18000, 14957 'ACWDT' => 35100, 14958 'ACWST' => 31500, 14959 'AEDT' => 39600, 14960 'AEST' => 36000, 14961 'AFT' => 16200, 14962 'AKDT' => -28800, 14963 'AKST' => -32400, 14964 'AMDT' => 18000, 14965 'AMT' => -14400, 14966 'ANAST' => 46800, 14967 'ANAT' => 43200, 14968 'ART' => -10800, 14969 'AZOST' => -3600, 14970 'AZST' => 18000, 14971 'AZT' => 14400, 14972 'BIOT' => 21600, 14973 'BIT' => -43200, 14974 'BOT' => -14400, 14975 'BRST' => -7200, 14976 'BRT' => -10800, 14977 'BST' => 3600, 14978 'BTT' => 21600, 14979 'CAST' => 18000, 14980 'CAT' => 7200, 14981 'CCT' => 23400, 14982 'CDT' => -18000, 14983 'CEDT' => 7200, 14984 'CET' => 3600, 14985 'CGST' => -7200, 14986 'CGT' => -10800, 14987 'CHADT' => 49500, 14988 'CHAST' => 45900, 14989 'CIST' => -28800, 14990 'CKT' => -36000, 14991 'CLDT' => -10800, 14992 'CLST' => -14400, 14993 'COT' => -18000, 14994 'CST' => -21600, 14995 'CVT' => -3600, 14996 'CXT' => 25200, 14997 'DAVT' => 25200, 14998 'DTAT' => 36000, 14999 'EADT' => -18000, 15000 'EAST' => -21600, 15001 'EAT' => 10800, 15002 'ECT' => -18000, 15003 'EDT' => -14400, 15004 'EEST' => 10800, 15005 'EET' => 7200, 15006 'EGT' => -3600, 15007 'EKST' => 21600, 15008 'EST' => -18000, 15009 'FJT' => 43200, 15010 'FKDT' => -10800, 15011 'FKST' => -14400, 15012 'FNT' => -7200, 15013 'GALT' => -21600, 15014 'GEDT' => 14400, 15015 'GEST' => 10800, 15016 'GFT' => -10800, 15017 'GILT' => 43200, 15018 'GIT' => -32400, 15019 'GST' => 14400, 15020 'GST' => -7200, 15021 'GYT' => -14400, 15022 'HAA' => -10800, 15023 'HAC' => -18000, 15024 'HADT' => -32400, 15025 'HAE' => -14400, 15026 'HAP' => -25200, 15027 'HAR' => -21600, 15028 'HAST' => -36000, 15029 'HAT' => -9000, 15030 'HAY' => -28800, 15031 'HKST' => 28800, 15032 'HMT' => 18000, 15033 'HNA' => -14400, 15034 'HNC' => -21600, 15035 'HNE' => -18000, 15036 'HNP' => -28800, 15037 'HNR' => -25200, 15038 'HNT' => -12600, 15039 'HNY' => -32400, 15040 'IRDT' => 16200, 15041 'IRKST' => 32400, 15042 'IRKT' => 28800, 15043 'IRST' => 12600, 15044 'JFDT' => -10800, 15045 'JFST' => -14400, 15046 'JST' => 32400, 15047 'KGST' => 21600, 15048 'KGT' => 18000, 15049 'KOST' => 39600, 15050 'KOVST' => 28800, 15051 'KOVT' => 25200, 15052 'KRAST' => 28800, 15053 'KRAT' => 25200, 15054 'KST' => 32400, 15055 'LHDT' => 39600, 15056 'LHST' => 37800, 15057 'LINT' => 50400, 15058 'LKT' => 21600, 15059 'MAGST' => 43200, 15060 'MAGT' => 39600, 15061 'MAWT' => 21600, 15062 'MDT' => -21600, 15063 'MESZ' => 7200, 15064 'MEZ' => 3600, 15065 'MHT' => 43200, 15066 'MIT' => -34200, 15067 'MNST' => 32400, 15068 'MSDT' => 14400, 15069 'MSST' => 10800, 15070 'MST' => -25200, 15071 'MUT' => 14400, 15072 'MVT' => 18000, 15073 'MYT' => 28800, 15074 'NCT' => 39600, 15075 'NDT' => -9000, 15076 'NFT' => 41400, 15077 'NMIT' => 36000, 15078 'NOVST' => 25200, 15079 'NOVT' => 21600, 15080 'NPT' => 20700, 15081 'NRT' => 43200, 15082 'NST' => -12600, 15083 'NUT' => -39600, 15084 'NZDT' => 46800, 15085 'NZST' => 43200, 15086 'OMSST' => 25200, 15087 'OMST' => 21600, 15088 'PDT' => -25200, 15089 'PET' => -18000, 15090 'PETST' => 46800, 15091 'PETT' => 43200, 15092 'PGT' => 36000, 15093 'PHOT' => 46800, 15094 'PHT' => 28800, 15095 'PKT' => 18000, 15096 'PMDT' => -7200, 15097 'PMST' => -10800, 15098 'PONT' => 39600, 15099 'PST' => -28800, 15100 'PWT' => 32400, 15101 'PYST' => -10800, 15102 'PYT' => -14400, 15103 'RET' => 14400, 15104 'ROTT' => -10800, 15105 'SAMST' => 18000, 15106 'SAMT' => 14400, 15107 'SAST' => 7200, 15108 'SBT' => 39600, 15109 'SCDT' => 46800, 15110 'SCST' => 43200, 15111 'SCT' => 14400, 15112 'SEST' => 3600, 15113 'SGT' => 28800, 15114 'SIT' => 28800, 15115 'SRT' => -10800, 15116 'SST' => -39600, 15117 'SYST' => 10800, 15118 'SYT' => 7200, 15119 'TFT' => 18000, 15120 'THAT' => -36000, 15121 'TJT' => 18000, 15122 'TKT' => -36000, 15123 'TMT' => 18000, 15124 'TOT' => 46800, 15125 'TPT' => 32400, 15126 'TRUT' => 36000, 15127 'TVT' => 43200, 15128 'TWT' => 28800, 15129 'UYST' => -7200, 15130 'UYT' => -10800, 15131 'UZT' => 18000, 15132 'VET' => -14400, 15133 'VLAST' => 39600, 15134 'VLAT' => 36000, 15135 'VOST' => 21600, 15136 'VUT' => 39600, 15137 'WAST' => 7200, 15138 'WAT' => 3600, 15139 'WDT' => 32400, 15140 'WEST' => 3600, 15141 'WFT' => 43200, 15142 'WIB' => 25200, 15143 'WIT' => 32400, 15144 'WITA' => 28800, 15145 'WKST' => 18000, 15146 'WST' => 28800, 15147 'YAKST' => 36000, 15148 'YAKT' => 32400, 15149 'YAPT' => 36000, 15150 'YEKST' => 21600, 15151 'YEKT' => 18000, 15152 ); 15153 15154 /** 15155 * Cached PCRE for SimplePie_Parse_Date::$day 15156 * 15157 * @access protected 15158 * @var string 15159 */ 15160 var $day_pcre; 15161 15162 /** 15163 * Cached PCRE for SimplePie_Parse_Date::$month 15164 * 15165 * @access protected 15166 * @var string 15167 */ 15168 var $month_pcre; 15169 15170 /** 15171 * Array of user-added callback methods 15172 * 15173 * @access private 15174 * @var array 15175 */ 15176 var $built_in = array(); 15177 15178 /** 15179 * Array of user-added callback methods 15180 * 15181 * @access private 15182 * @var array 15183 */ 15184 var $user = array(); 15185 15186 /** 15187 * Create new SimplePie_Parse_Date object, and set self::day_pcre, 15188 * self::month_pcre, and self::built_in 15189 * 15190 * @access private 15191 */ 15192 public function __construct() 15193 { 15194 $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')'; 15195 $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')'; 15196 15197 static $cache; 15198 if (!isset($cache[get_class($this)])) 15199 { 15200 $all_methods = get_class_methods($this); 15201 15202 foreach ($all_methods as $method) 15203 { 15204 if (strtolower(substr($method, 0, 5)) === 'date_') 15205 { 15206 $cache[get_class($this)][] = $method; 15207 } 15208 } 15209 } 15210 15211 foreach ($cache[get_class($this)] as $method) 15212 { 15213 $this->built_in[] = $method; 15214 } 15215 } 15216 15217 /** 15218 * Get the object 15219 * 15220 * @access public 15221 */ 15222 public static function get() 15223 { 15224 static $object; 15225 if (!$object) 15226 { 15227 $object = new SimplePie_Parse_Date; 15228 } 15229 return $object; 15230 } 15231 15232 /** 15233 * Parse a date 15234 * 15235 * @final 15236 * @access public 15237 * @param string $date Date to parse 15238 * @return int Timestamp corresponding to date string, or false on failure 15239 */ 15240 public function parse($date) 15241 { 15242 foreach ($this->user as $method) 15243 { 15244 if (($returned = call_user_func($method, $date)) !== false) 15245 { 15246 return $returned; 15247 } 15248 } 15249 15250 foreach ($this->built_in as $method) 15251 { 15252 if (($returned = call_user_func(array($this, $method), $date)) !== false) 15253 { 15254 return $returned; 15255 } 15256 } 15257 15258 return false; 15259 } 15260 15261 /** 15262 * Add a callback method to parse a date 15263 * 15264 * @final 15265 * @access public 15266 * @param callback $callback 15267 */ 15268 public function add_callback($callback) 15269 { 15270 if (is_callable($callback)) 15271 { 15272 $this->user[] = $callback; 15273 } 15274 else 15275 { 15276 trigger_error('User-supplied function must be a valid callback', E_USER_WARNING); 15277 } 15278 } 15279 15280 /** 15281 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as 15282 * well as allowing any of upper or lower case "T", horizontal tabs, or 15283 * spaces to be used as the time seperator (including more than one)) 15284 * 15285 * @access protected 15286 * @return int Timestamp 15287 */ 15288 public function date_w3cdtf($date) 15289 { 15290 static $pcre; 15291 if (!$pcre) 15292 { 15293 $year = '([0-9]{4})'; 15294 $month = $day = $hour = $minute = $second = '([0-9]{2})'; 15295 $decimal = '([0-9]*)'; 15296 $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))'; 15297 $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/'; 15298 } 15299 if (preg_match($pcre, $date, $match)) 15300 { 15301 /* 15302 Capturing subpatterns: 15303 1: Year 15304 2: Month 15305 3: Day 15306 4: Hour 15307 5: Minute 15308 6: Second 15309 7: Decimal fraction of a second 15310 8: Zulu 15311 9: Timezone ± 15312 10: Timezone hours 15313 11: Timezone minutes 15314 */ 15315 15316 // Fill in empty matches 15317 for ($i = count($match); $i <= 3; $i++) 15318 { 15319 $match[$i] = '1'; 15320 } 15321 15322 for ($i = count($match); $i <= 7; $i++) 15323 { 15324 $match[$i] = '0'; 15325 } 15326 15327 // Numeric timezone 15328 if (isset($match[9]) && $match[9] !== '') 15329 { 15330 $timezone = $match[10] * 3600; 15331 $timezone += $match[11] * 60; 15332 if ($match[9] === '-') 15333 { 15334 $timezone = 0 - $timezone; 15335 } 15336 } 15337 else 15338 { 15339 $timezone = 0; 15340 } 15341 15342 // Convert the number of seconds to an integer, taking decimals into account 15343 $second = round($match[6] + $match[7] / pow(10, strlen($match[7]))); 15344 15345 return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone; 15346 } 15347 else 15348 { 15349 return false; 15350 } 15351 } 15352 15353 /** 15354 * Remove RFC822 comments 15355 * 15356 * @access protected 15357 * @param string $data Data to strip comments from 15358 * @return string Comment stripped string 15359 */ 15360 public function remove_rfc2822_comments($string) 15361 { 15362 $string = (string) $string; 15363 $position = 0; 15364 $length = strlen($string); 15365 $depth = 0; 15366 15367 $output = ''; 15368 15369 while ($position < $length && ($pos = strpos($string, '(', $position)) !== false) 15370 { 15371 $output .= substr($string, $position, $pos - $position); 15372 $position = $pos + 1; 15373 if ($string[$pos - 1] !== '\\') 15374 { 15375 $depth++; 15376 while ($depth && $position < $length) 15377 { 15378 $position += strcspn($string, '()', $position); 15379 if ($string[$position - 1] === '\\') 15380 { 15381 $position++; 15382 continue; 15383 } 15384 elseif (isset($string[$position])) 15385 { 15386 switch ($string[$position]) 15387 { 15388 case '(': 15389 $depth++; 15390 break; 15391 15392 case ')': 15393 $depth--; 15394 break; 15395 } 15396 $position++; 15397 } 15398 else 15399 { 15400 break; 15401 } 15402 } 15403 } 15404 else 15405 { 15406 $output .= '('; 15407 } 15408 } 15409 $output .= substr($string, $position); 15410 15411 return $output; 15412 } 15413 15414 /** 15415 * Parse RFC2822's date format 15416 * 15417 * @access protected 15418 * @return int Timestamp 15419 */ 15420 public function date_rfc2822($date) 15421 { 15422 static $pcre; 15423 if (!$pcre) 15424 { 15425 $wsp = '[\x09\x20]'; 15426 $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)'; 15427 $optional_fws = $fws . '?'; 15428 $day_name = $this->day_pcre; 15429 $month = $this->month_pcre; 15430 $day = '([0-9]{1,2})'; 15431 $hour = $minute = $second = '([0-9]{2})'; 15432 $year = '([0-9]{2,4})'; 15433 $num_zone = '([+\-])([0-9]{2})([0-9]{2})'; 15434 $character_zone = '([A-Z]{1,5})'; 15435 $zone = '(?:' . $num_zone . '|' . $character_zone . ')'; 15436 $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i'; 15437 } 15438 if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match)) 15439 { 15440 /* 15441 Capturing subpatterns: 15442 1: Day name 15443 2: Day 15444 3: Month 15445 4: Year 15446 5: Hour 15447 6: Minute 15448 7: Second 15449 8: Timezone ± 15450 9: Timezone hours 15451 10: Timezone minutes 15452 11: Alphabetic timezone 15453 */ 15454 15455 // Find the month number 15456 $month = $this->month[strtolower($match[3])]; 15457 15458 // Numeric timezone 15459 if ($match[8] !== '') 15460 { 15461 $timezone = $match[9] * 3600; 15462 $timezone += $match[10] * 60; 15463 if ($match[8] === '-') 15464 { 15465 $timezone = 0 - $timezone; 15466 } 15467 } 15468 // Character timezone 15469 elseif (isset($this->timezone[strtoupper($match[11])])) 15470 { 15471 $timezone = $this->timezone[strtoupper($match[11])]; 15472 } 15473 // Assume everything else to be -0000 15474 else 15475 { 15476 $timezone = 0; 15477 } 15478 15479 // Deal with 2/3 digit years 15480 if ($match[4] < 50) 15481 { 15482 $match[4] += 2000; 15483 } 15484 elseif ($match[4] < 1000) 15485 { 15486 $match[4] += 1900; 15487 } 15488 15489 // Second is optional, if it is empty set it to zero 15490 if ($match[7] !== '') 15491 { 15492 $second = $match[7]; 15493 } 15494 else 15495 { 15496 $second = 0; 15497 } 15498 15499 return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone; 15500 } 15501 else 15502 { 15503 return false; 15504 } 15505 } 15506 15507 /** 15508 * Parse RFC850's date format 15509 * 15510 * @access protected 15511 * @return int Timestamp 15512 */ 15513 public function date_rfc850($date) 15514 { 15515 static $pcre; 15516 if (!$pcre) 15517 { 15518 $space = '[\x09\x20]+'; 15519 $day_name = $this->day_pcre; 15520 $month = $this->month_pcre; 15521 $day = '([0-9]{1,2})'; 15522 $year = $hour = $minute = $second = '([0-9]{2})'; 15523 $zone = '([A-Z]{1,5})'; 15524 $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i'; 15525 } 15526 if (preg_match($pcre, $date, $match)) 15527 { 15528 /* 15529 Capturing subpatterns: 15530 1: Day name 15531 2: Day 15532 3: Month 15533 4: Year 15534 5: Hour 15535 6: Minute 15536 7: Second 15537 8: Timezone 15538 */ 15539 15540 // Month 15541 $month = $this->month[strtolower($match[3])]; 15542 15543 // Character timezone 15544 if (isset($this->timezone[strtoupper($match[8])])) 15545 { 15546 $timezone = $this->timezone[strtoupper($match[8])]; 15547 } 15548 // Assume everything else to be -0000 15549 else 15550 { 15551 $timezone = 0; 15552 } 15553 15554 // Deal with 2 digit year 15555 if ($match[4] < 50) 15556 { 15557 $match[4] += 2000; 15558 } 15559 else 15560 { 15561 $match[4] += 1900; 15562 } 15563 15564 return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone; 15565 } 15566 else 15567 { 15568 return false; 15569 } 15570 } 15571 15572 /** 15573 * Parse C99's asctime()'s date format 15574 * 15575 * @access protected 15576 * @return int Timestamp 15577 */ 15578 public function date_asctime($date) 15579 { 15580 static $pcre; 15581 if (!$pcre) 15582 { 15583 $space = '[\x09\x20]+'; 15584 $wday_name = $this->day_pcre; 15585 $mon_name = $this->month_pcre; 15586 $day = '([0-9]{1,2})'; 15587 $hour = $sec = $min = '([0-9]{2})'; 15588 $year = '([0-9]{4})'; 15589 $terminator = '\x0A?\x00?'; 15590 $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i'; 15591 } 15592 if (preg_match($pcre, $date, $match)) 15593 { 15594 /* 15595 Capturing subpatterns: 15596 1: Day name 15597 2: Month 15598 3: Day 15599 4: Hour 15600 5: Minute 15601 6: Second 15602 7: Year 15603 */ 15604 15605 $month = $this->month[strtolower($match[2])]; 15606 return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]); 15607 } 15608 else 15609 { 15610 return false; 15611 } 15612 } 15613 15614 /** 15615 * Parse dates using strtotime() 15616 * 15617 * @access protected 15618 * @return int Timestamp 15619 */ 15620 public function date_strtotime($date) 15621 { 15622 $strtotime = strtotime($date); 15623 if ($strtotime === -1 || $strtotime === false) 15624 { 15625 return false; 15626 } 15627 else 15628 { 15629 return $strtotime; 15630 } 15631 } 15632 } 15633 15634 /** 15635 * Parses XML into something sane 15636 * 15637 * 15638 * This class can be overloaded with {@see SimplePie::set_parser_class()} 15639 * 15640 * @package SimplePie 15641 * @subpackage Parsing 15642 */ 15643 class SimplePie_Parser 15644 { 15645 var $error_code; 15646 var $error_string; 15647 var $current_line; 15648 var $current_column; 15649 var $current_byte; 15650 var $separator = ' '; 15651 var $namespace = array(''); 15652 var $element = array(''); 15653 var $xml_base = array(''); 15654 var $xml_base_explicit = array(false); 15655 var $xml_lang = array(''); 15656 var $data = array(); 15657 var $datas = array(array()); 15658 var $current_xhtml_construct = -1; 15659 var $encoding; 15660 protected $registry; 15661 15662 public function set_registry(SimplePie_Registry $registry) 15663 { 15664 $this->registry = $registry; 15665 } 15666 15667 public function parse(&$data, $encoding) 15668 { 15669 // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character 15670 if (strtoupper($encoding) === 'US-ASCII') 15671 { 15672 $this->encoding = 'UTF-8'; 15673 } 15674 else 15675 { 15676 $this->encoding = $encoding; 15677 } 15678 15679 // Strip BOM: 15680 // UTF-32 Big Endian BOM 15681 if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") 15682 { 15683 $data = substr($data, 4); 15684 } 15685 // UTF-32 Little Endian BOM 15686 elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00") 15687 { 15688 $data = substr($data, 4); 15689 } 15690 // UTF-16 Big Endian BOM 15691 elseif (substr($data, 0, 2) === "\xFE\xFF") 15692 { 15693 $data = substr($data, 2); 15694 } 15695 // UTF-16 Little Endian BOM 15696 elseif (substr($data, 0, 2) === "\xFF\xFE") 15697 { 15698 $data = substr($data, 2); 15699 } 15700 // UTF-8 BOM 15701 elseif (substr($data, 0, 3) === "\xEF\xBB\xBF") 15702 { 15703 $data = substr($data, 3); 15704 } 15705 15706 if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false) 15707 { 15708 $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5))); 15709 if ($declaration->parse()) 15710 { 15711 $data = substr($data, $pos + 2); 15712 $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data; 15713 } 15714 else 15715 { 15716 $this->error_string = 'SimplePie bug! Please report this!'; 15717 return false; 15718 } 15719 } 15720 15721 $return = true; 15722 15723 static $xml_is_sane = null; 15724 if ($xml_is_sane === null) 15725 { 15726 $parser_check = xml_parser_create(); 15727 xml_parse_into_struct($parser_check, '<foo>&</foo>', $values); 15728 xml_parser_free($parser_check); 15729 $xml_is_sane = isset($values[0]['value']); 15730 } 15731 15732 // Create the parser 15733 if ($xml_is_sane) 15734 { 15735 $xml = xml_parser_create_ns($this->encoding, $this->separator); 15736 xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1); 15737 xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0); 15738 xml_set_object($xml, $this); 15739 xml_set_character_data_handler($xml, 'cdata'); 15740 xml_set_element_handler($xml, 'tag_open', 'tag_close'); 15741 15742 // Parse! 15743 if (!xml_parse($xml, $data, true)) 15744 { 15745 $this->error_code = xml_get_error_code($xml); 15746 $this->error_string = xml_error_string($this->error_code); 15747 $return = false; 15748 } 15749 $this->current_line = xml_get_current_line_number($xml); 15750 $this->current_column = xml_get_current_column_number($xml); 15751 $this->current_byte = xml_get_current_byte_index($xml); 15752 xml_parser_free($xml); 15753 return $return; 15754 } 15755 else 15756 { 15757 libxml_clear_errors(); 15758 $xml = new XMLReader(); 15759 $xml->xml($data); 15760 while (@$xml->read()) 15761 { 15762 switch ($xml->nodeType) 15763 { 15764 15765 case constant('XMLReader::END_ELEMENT'): 15766 if ($xml->namespaceURI !== '') 15767 { 15768 $tagName = $xml->namespaceURI . $this->separator . $xml->localName; 15769 } 15770 else 15771 { 15772 $tagName = $xml->localName; 15773 } 15774 $this->tag_close(null, $tagName); 15775 break; 15776 case constant('XMLReader::ELEMENT'): 15777 $empty = $xml->isEmptyElement; 15778 if ($xml->namespaceURI !== '') 15779 { 15780 $tagName = $xml->namespaceURI . $this->separator . $xml->localName; 15781 } 15782 else 15783 { 15784 $tagName = $xml->localName; 15785 } 15786 $attributes = array(); 15787 while ($xml->moveToNextAttribute()) 15788 { 15789 if ($xml->namespaceURI !== '') 15790 { 15791 $attrName = $xml->namespaceURI . $this->separator . $xml->localName; 15792 } 15793 else 15794 { 15795 $attrName = $xml->localName; 15796 } 15797 $attributes[$attrName] = $xml->value; 15798 } 15799 $this->tag_open(null, $tagName, $attributes); 15800 if ($empty) 15801 { 15802 $this->tag_close(null, $tagName); 15803 } 15804 break; 15805 case constant('XMLReader::TEXT'): 15806 15807 case constant('XMLReader::CDATA'): 15808 $this->cdata(null, $xml->value); 15809 break; 15810 } 15811 } 15812 if ($error = libxml_get_last_error()) 15813 { 15814 $this->error_code = $error->code; 15815 $this->error_string = $error->message; 15816 $this->current_line = $error->line; 15817 $this->current_column = $error->column; 15818 return false; 15819 } 15820 else 15821 { 15822 return true; 15823 } 15824 } 15825 } 15826 15827 public function get_error_code() 15828 { 15829 return $this->error_code; 15830 } 15831 15832 public function get_error_string() 15833 { 15834 return $this->error_string; 15835 } 15836 15837 public function get_current_line() 15838 { 15839 return $this->current_line; 15840 } 15841 15842 public function get_current_column() 15843 { 15844 return $this->current_column; 15845 } 15846 15847 public function get_current_byte() 15848 { 15849 return $this->current_byte; 15850 } 15851 15852 public function get_data() 15853 { 15854 return $this->data; 15855 } 15856 15857 public function tag_open($parser, $tag, $attributes) 15858 { 15859 list($this->namespace[], $this->element[]) = $this->split_ns($tag); 15860 15861 $attribs = array(); 15862 foreach ($attributes as $name => $value) 15863 { 15864 list($attrib_namespace, $attribute) = $this->split_ns($name); 15865 $attribs[$attrib_namespace][$attribute] = $value; 15866 } 15867 15868 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base'])) 15869 { 15870 $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base))); 15871 if ($base !== false) 15872 { 15873 $this->xml_base[] = $base; 15874 $this->xml_base_explicit[] = true; 15875 } 15876 } 15877 else 15878 { 15879 $this->xml_base[] = end($this->xml_base); 15880 $this->xml_base_explicit[] = end($this->xml_base_explicit); 15881 } 15882 15883 if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang'])) 15884 { 15885 $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang']; 15886 } 15887 else 15888 { 15889 $this->xml_lang[] = end($this->xml_lang); 15890 } 15891 15892 if ($this->current_xhtml_construct >= 0) 15893 { 15894 $this->current_xhtml_construct++; 15895 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML) 15896 { 15897 $this->data['data'] .= '<' . end($this->element); 15898 if (isset($attribs[''])) 15899 { 15900 foreach ($attribs[''] as $name => $value) 15901 { 15902 $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"'; 15903 } 15904 } 15905 $this->data['data'] .= '>'; 15906 } 15907 } 15908 else 15909 { 15910 $this->datas[] =& $this->data; 15911 $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][]; 15912 $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang)); 15913 if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml') 15914 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml') 15915 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title'))) 15916 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title'))) 15917 || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title')))) 15918 { 15919 $this->current_xhtml_construct = 0; 15920 } 15921 } 15922 } 15923 15924 public function cdata($parser, $cdata) 15925 { 15926 if ($this->current_xhtml_construct >= 0) 15927 { 15928 $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding); 15929 } 15930 else 15931 { 15932 $this->data['data'] .= $cdata; 15933 } 15934 } 15935 15936 public function tag_close($parser, $tag) 15937 { 15938 if ($this->current_xhtml_construct >= 0) 15939 { 15940 $this->current_xhtml_construct--; 15941 if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'))) 15942 { 15943 $this->data['data'] .= '</' . end($this->element) . '>'; 15944 } 15945 } 15946 if ($this->current_xhtml_construct === -1) 15947 { 15948 $this->data =& $this->datas[count($this->datas) - 1]; 15949 array_pop($this->datas); 15950 } 15951 15952 array_pop($this->element); 15953 array_pop($this->namespace); 15954 array_pop($this->xml_base); 15955 array_pop($this->xml_base_explicit); 15956 array_pop($this->xml_lang); 15957 } 15958 15959 public function split_ns($string) 15960 { 15961 static $cache = array(); 15962 if (!isset($cache[$string])) 15963 { 15964 if ($pos = strpos($string, $this->separator)) 15965 { 15966 static $separator_length; 15967 if (!$separator_length) 15968 { 15969 $separator_length = strlen($this->separator); 15970 } 15971 $namespace = substr($string, 0, $pos); 15972 $local_name = substr($string, $pos + $separator_length); 15973 if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES) 15974 { 15975 $namespace = SIMPLEPIE_NAMESPACE_ITUNES; 15976 } 15977 15978 // Normalize the Media RSS namespaces 15979 if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG || 15980 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 || 15981 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 || 15982 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 || 15983 $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 ) 15984 { 15985 $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS; 15986 } 15987 $cache[$string] = array($namespace, $local_name); 15988 } 15989 else 15990 { 15991 $cache[$string] = array('', $string); 15992 } 15993 } 15994 return $cache[$string]; 15995 } 15996 } 15997 15998 /** 15999 * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively 16000 * 16001 * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()} 16002 * 16003 * This class can be overloaded with {@see SimplePie::set_rating_class()} 16004 * 16005 * @package SimplePie 16006 * @subpackage API 16007 */ 16008 class SimplePie_Rating 16009 { 16010 /** 16011 * Rating scheme 16012 * 16013 * @var string 16014 * @see get_scheme() 16015 */ 16016 var $scheme; 16017 16018 /** 16019 * Rating value 16020 * 16021 * @var string 16022 * @see get_value() 16023 */ 16024 var $value; 16025 16026 /** 16027 * Constructor, used to input the data 16028 * 16029 * For documentation on all the parameters, see the corresponding 16030 * properties and their accessors 16031 */ 16032 public function __construct($scheme = null, $value = null) 16033 { 16034 $this->scheme = $scheme; 16035 $this->value = $value; 16036 } 16037 16038 /** 16039 * String-ified version 16040 * 16041 * @return string 16042 */ 16043 public function __toString() 16044 { 16045 // There is no $this->data here 16046 return md5(serialize($this)); 16047 } 16048 16049 /** 16050 * Get the organizational scheme for the rating 16051 * 16052 * @return string|null 16053 */ 16054 public function get_scheme() 16055 { 16056 if ($this->scheme !== null) 16057 { 16058 return $this->scheme; 16059 } 16060 else 16061 { 16062 return null; 16063 } 16064 } 16065 16066 /** 16067 * Get the value of the rating 16068 * 16069 * @return string|null 16070 */ 16071 public function get_value() 16072 { 16073 if ($this->value !== null) 16074 { 16075 return $this->value; 16076 } 16077 else 16078 { 16079 return null; 16080 } 16081 } 16082 } 16083 16084 /** 16085 * Handles creating objects and calling methods 16086 * 16087 * Access this via {@see SimplePie::get_registry()} 16088 * 16089 * @package SimplePie 16090 */ 16091 class SimplePie_Registry 16092 { 16093 /** 16094 * Default class mapping 16095 * 16096 * Overriding classes *must* subclass these. 16097 * 16098 * @var array 16099 */ 16100 protected $default = array( 16101 'Cache' => 'SimplePie_Cache', 16102 'Locator' => 'SimplePie_Locator', 16103 'Parser' => 'SimplePie_Parser', 16104 'File' => 'SimplePie_File', 16105 'Sanitize' => 'SimplePie_Sanitize', 16106 'Item' => 'SimplePie_Item', 16107 'Author' => 'SimplePie_Author', 16108 'Category' => 'SimplePie_Category', 16109 'Enclosure' => 'SimplePie_Enclosure', 16110 'Caption' => 'SimplePie_Caption', 16111 'Copyright' => 'SimplePie_Copyright', 16112 'Credit' => 'SimplePie_Credit', 16113 'Rating' => 'SimplePie_Rating', 16114 'Restriction' => 'SimplePie_Restriction', 16115 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer', 16116 'Source' => 'SimplePie_Source', 16117 'Misc' => 'SimplePie_Misc', 16118 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser', 16119 'Parse_Date' => 'SimplePie_Parse_Date', 16120 ); 16121 16122 /** 16123 * Class mapping 16124 * 16125 * @see register() 16126 * @var array 16127 */ 16128 protected $classes = array(); 16129 16130 /** 16131 * Legacy classes 16132 * 16133 * @see register() 16134 * @var array 16135 */ 16136 protected $legacy = array(); 16137 16138 /** 16139 * Constructor 16140 * 16141 * No-op 16142 */ 16143 public function __construct() { } 16144 16145 /** 16146 * Register a class 16147 * 16148 * @param string $type See {@see $default} for names 16149 * @param string $class Class name, must subclass the corresponding default 16150 * @param bool $legacy Whether to enable legacy support for this class 16151 * @return bool Successfulness 16152 */ 16153 public function register($type, $class, $legacy = false) 16154 { 16155 if (!is_subclass_of($class, $this->default[$type])) 16156 { 16157 return false; 16158 } 16159 16160 $this->classes[$type] = $class; 16161 16162 if ($legacy) 16163 { 16164 $this->legacy[] = $class; 16165 } 16166 16167 return true; 16168 } 16169 16170 /** 16171 * Get the class registered for a type 16172 * 16173 * Where possible, use {@see create()} or {@see call()} instead 16174 * 16175 * @param string $type 16176 * @return string|null 16177 */ 16178 public function get_class($type) 16179 { 16180 if (!empty($this->classes[$type])) 16181 { 16182 return $this->classes[$type]; 16183 } 16184 if (!empty($this->default[$type])) 16185 { 16186 return $this->default[$type]; 16187 } 16188 16189 return null; 16190 } 16191 16192 /** 16193 * Create a new instance of a given type 16194 * 16195 * @param string $type 16196 * @param array $parameters Parameters to pass to the constructor 16197 * @return object Instance of class 16198 */ 16199 public function &create($type, $parameters = array()) 16200 { 16201 $class = $this->get_class($type); 16202 16203 if (in_array($class, $this->legacy)) 16204 { 16205 switch ($type) 16206 { 16207 case 'locator': 16208 // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class 16209 // Specified: file, timeout, useragent, max_checked_feeds 16210 $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer')); 16211 array_splice($parameters, 3, 1, $replacement); 16212 break; 16213 } 16214 } 16215 16216 if (!method_exists($class, '__construct')) 16217 { 16218 $instance = new $class; 16219 } 16220 else 16221 { 16222 $reflector = new ReflectionClass($class); 16223 $instance = $reflector->newInstanceArgs($parameters); 16224 } 16225 16226 if (method_exists($instance, 'set_registry')) 16227 { 16228 $instance->set_registry($this); 16229 } 16230 return $instance; 16231 } 16232 16233 /** 16234 * Call a static method for a type 16235 * 16236 * @param string $type 16237 * @param string $method 16238 * @param array $parameters 16239 * @return mixed 16240 */ 16241 public function &call($type, $method, $parameters = array()) 16242 { 16243 $class = $this->get_class($type); 16244 16245 if (in_array($class, $this->legacy)) 16246 { 16247 switch ($type) 16248 { 16249 case 'Cache': 16250 // For backwards compatibility with old non-static 16251 // Cache::create() methods 16252 if ($method === 'get_handler') 16253 { 16254 $result = @call_user_func_array(array($class, 'create'), $parameters); 16255 return $result; 16256 } 16257 break; 16258 } 16259 } 16260 16261 $result = call_user_func_array(array($class, $method), $parameters); 16262 return $result; 16263 } 16264 } 16265 16266 /** 16267 * Handles `<media:restriction>` as defined in Media RSS 16268 * 16269 * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()} 16270 * 16271 * This class can be overloaded with {@see SimplePie::set_restriction_class()} 16272 * 16273 * @package SimplePie 16274 * @subpackage API 16275 */ 16276 class SimplePie_Restriction 16277 { 16278 /** 16279 * Relationship ('allow'/'deny') 16280 * 16281 * @var string 16282 * @see get_relationship() 16283 */ 16284 var $relationship; 16285 16286 /** 16287 * Type of restriction 16288 * 16289 * @var string 16290 * @see get_type() 16291 */ 16292 var $type; 16293 16294 /** 16295 * Restricted values 16296 * 16297 * @var string 16298 * @see get_value() 16299 */ 16300 var $value; 16301 16302 /** 16303 * Constructor, used to input the data 16304 * 16305 * For documentation on all the parameters, see the corresponding 16306 * properties and their accessors 16307 */ 16308 public function __construct($relationship = null, $type = null, $value = null) 16309 { 16310 $this->relationship = $relationship; 16311 $this->type = $type; 16312 $this->value = $value; 16313 } 16314 16315 /** 16316 * String-ified version 16317 * 16318 * @return string 16319 */ 16320 public function __toString() 16321 { 16322 // There is no $this->data here 16323 return md5(serialize($this)); 16324 } 16325 16326 /** 16327 * Get the relationship 16328 * 16329 * @return string|null Either 'allow' or 'deny' 16330 */ 16331 public function get_relationship() 16332 { 16333 if ($this->relationship !== null) 16334 { 16335 return $this->relationship; 16336 } 16337 else 16338 { 16339 return null; 16340 } 16341 } 16342 16343 /** 16344 * Get the type 16345 * 16346 * @return string|null 16347 */ 16348 public function get_type() 16349 { 16350 if ($this->type !== null) 16351 { 16352 return $this->type; 16353 } 16354 else 16355 { 16356 return null; 16357 } 16358 } 16359 16360 /** 16361 * Get the list of restricted things 16362 * 16363 * @return string|null 16364 */ 16365 public function get_value() 16366 { 16367 if ($this->value !== null) 16368 { 16369 return $this->value; 16370 } 16371 else 16372 { 16373 return null; 16374 } 16375 } 16376 } 16377 16378 /** 16379 * Used for data cleanup and post-processing 16380 * 16381 * 16382 * This class can be overloaded with {@see SimplePie::set_sanitize_class()} 16383 * 16384 * @package SimplePie 16385 * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags 16386 */ 16387 class SimplePie_Sanitize 16388 { 16389 // Private vars 16390 var $base; 16391 16392 // Options 16393 var $remove_div = true; 16394 var $image_handler = ''; 16395 var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'); 16396 var $encode_instead_of_strip = false; 16397 var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); 16398 var $strip_comments = false; 16399 var $output_encoding = 'UTF-8'; 16400 var $enable_cache = true; 16401 var $cache_location = './cache'; 16402 var $cache_name_function = 'md5'; 16403 var $timeout = 10; 16404 var $useragent = ''; 16405 var $force_fsockopen = false; 16406 var $replace_url_attributes = null; 16407 16408 public function __construct() 16409 { 16410 // Set defaults 16411 $this->set_url_replacements(null); 16412 } 16413 16414 public function remove_div($enable = true) 16415 { 16416 $this->remove_div = (bool) $enable; 16417 } 16418 16419 public function set_image_handler($page = false) 16420 { 16421 if ($page) 16422 { 16423 $this->image_handler = (string) $page; 16424 } 16425 else 16426 { 16427 $this->image_handler = false; 16428 } 16429 } 16430 16431 public function set_registry(SimplePie_Registry $registry) 16432 { 16433 $this->registry = $registry; 16434 } 16435 16436 public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache') 16437 { 16438 if (isset($enable_cache)) 16439 { 16440 $this->enable_cache = (bool) $enable_cache; 16441 } 16442 16443 if ($cache_location) 16444 { 16445 $this->cache_location = (string) $cache_location; 16446 } 16447 16448 if ($cache_name_function) 16449 { 16450 $this->cache_name_function = (string) $cache_name_function; 16451 } 16452 } 16453 16454 public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false) 16455 { 16456 if ($timeout) 16457 { 16458 $this->timeout = (string) $timeout; 16459 } 16460 16461 if ($useragent) 16462 { 16463 $this->useragent = (string) $useragent; 16464 } 16465 16466 if ($force_fsockopen) 16467 { 16468 $this->force_fsockopen = (string) $force_fsockopen; 16469 } 16470 } 16471 16472 public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style')) 16473 { 16474 if ($tags) 16475 { 16476 if (is_array($tags)) 16477 { 16478 $this->strip_htmltags = $tags; 16479 } 16480 else 16481 { 16482 $this->strip_htmltags = explode(',', $tags); 16483 } 16484 } 16485 else 16486 { 16487 $this->strip_htmltags = false; 16488 } 16489 } 16490 16491 public function encode_instead_of_strip($encode = false) 16492 { 16493 $this->encode_instead_of_strip = (bool) $encode; 16494 } 16495 16496 public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc')) 16497 { 16498 if ($attribs) 16499 { 16500 if (is_array($attribs)) 16501 { 16502 $this->strip_attributes = $attribs; 16503 } 16504 else 16505 { 16506 $this->strip_attributes = explode(',', $attribs); 16507 } 16508 } 16509 else 16510 { 16511 $this->strip_attributes = false; 16512 } 16513 } 16514 16515 public function strip_comments($strip = false) 16516 { 16517 $this->strip_comments = (bool) $strip; 16518 } 16519 16520 public function set_output_encoding($encoding = 'UTF-8') 16521 { 16522 $this->output_encoding = (string) $encoding; 16523 } 16524 16525 /** 16526 * Set element/attribute key/value pairs of HTML attributes 16527 * containing URLs that need to be resolved relative to the feed 16528 * 16529 * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite, 16530 * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite, 16531 * |q|@cite 16532 * 16533 * @since 1.0 16534 * @param array|null $element_attribute Element/attribute key/value pairs, null for default 16535 */ 16536 public function set_url_replacements($element_attribute = null) 16537 { 16538 if ($element_attribute === null) 16539 { 16540 $element_attribute = array( 16541 'a' => 'href', 16542 'area' => 'href', 16543 'blockquote' => 'cite', 16544 'del' => 'cite', 16545 'form' => 'action', 16546 'img' => array( 16547 'longdesc', 16548 'src' 16549 ), 16550 'input' => 'src', 16551 'ins' => 'cite', 16552 'q' => 'cite' 16553 ); 16554 } 16555 $this->replace_url_attributes = (array) $element_attribute; 16556 } 16557 16558 public function sanitize($data, $type, $base = '') 16559 { 16560 $data = trim($data); 16561 if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI) 16562 { 16563 if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML) 16564 { 16565 if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) 16566 { 16567 $type |= SIMPLEPIE_CONSTRUCT_HTML; 16568 } 16569 else 16570 { 16571 $type |= SIMPLEPIE_CONSTRUCT_TEXT; 16572 } 16573 } 16574 16575 if ($type & SIMPLEPIE_CONSTRUCT_BASE64) 16576 { 16577 $data = base64_decode($data); 16578 } 16579 16580 if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML)) 16581 { 16582 if (!class_exists('DOMDocument')) 16583 { 16584 $this->registry->call('Misc', 'error', array('DOMDocument not found, unable to use sanitizer', E_USER_WARNING, __FILE__, __LINE__)); 16585 return ''; 16586 } 16587 $document = new DOMDocument(); 16588 $document->encoding = 'UTF-8'; 16589 $data = $this->preprocess($data, $type); 16590 16591 set_error_handler(array('SimplePie_Misc', 'silence_errors')); 16592 $document->loadHTML($data); 16593 restore_error_handler(); 16594 16595 // Strip comments 16596 if ($this->strip_comments) 16597 { 16598 $xpath = new DOMXPath($document); 16599 $comments = $xpath->query('//comment()'); 16600 16601 foreach ($comments as $comment) 16602 { 16603 $comment->parentNode->removeChild($comment); 16604 } 16605 } 16606 16607 // Strip out HTML tags and attributes that might cause various security problems. 16608 // Based on recommendations by Mark Pilgrim at: 16609 // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely 16610 if ($this->strip_htmltags) 16611 { 16612 foreach ($this->strip_htmltags as $tag) 16613 { 16614 $this->strip_tag($tag, $document, $type); 16615 } 16616 } 16617 16618 if ($this->strip_attributes) 16619 { 16620 foreach ($this->strip_attributes as $attrib) 16621 { 16622 $this->strip_attr($attrib, $document); 16623 } 16624 } 16625 16626 // Replace relative URLs 16627 $this->base = $base; 16628 foreach ($this->replace_url_attributes as $element => $attributes) 16629 { 16630 $this->replace_urls($document, $element, $attributes); 16631 } 16632 16633 // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags. 16634 if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache) 16635 { 16636 $images = $document->getElementsByTagName('img'); 16637 foreach ($images as $img) 16638 { 16639 if ($img->hasAttribute('src')) 16640 { 16641 $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src')); 16642 $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi')); 16643 16644 if ($cache->load()) 16645 { 16646 $img->setAttribute('src', $this->image_handler . $image_url); 16647 } 16648 else 16649 { 16650 $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen)); 16651 $headers = $file->headers; 16652 16653 if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300))) 16654 { 16655 if ($cache->save(array('headers' => $file->headers, 'body' => $file->body))) 16656 { 16657 $img->setAttribute('src', $this->image_handler . $image_url); 16658 } 16659 else 16660 { 16661 trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING); 16662 } 16663 } 16664 } 16665 } 16666 } 16667 } 16668 16669 // Remove the DOCTYPE 16670 // Seems to cause segfaulting if we don't do this 16671 if ($document->firstChild instanceof DOMDocumentType) 16672 { 16673 $document->removeChild($document->firstChild); 16674 } 16675 16676 // Move everything from the body to the root 16677 $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0); 16678 $document->replaceChild($real_body, $document->firstChild); 16679 16680 // Finally, convert to a HTML string 16681 $data = trim($document->saveHTML()); 16682 16683 if ($this->remove_div) 16684 { 16685 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data); 16686 $data = preg_replace('/<\/div>$/', '', $data); 16687 } 16688 else 16689 { 16690 $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data); 16691 } 16692 } 16693 16694 if ($type & SIMPLEPIE_CONSTRUCT_IRI) 16695 { 16696 $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base)); 16697 if ($absolute !== false) 16698 { 16699 $data = $absolute; 16700 } 16701 } 16702 16703 if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI)) 16704 { 16705 $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8'); 16706 } 16707 16708 if ($this->output_encoding !== 'UTF-8') 16709 { 16710 $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding)); 16711 } 16712 } 16713 return $data; 16714 } 16715 16716 protected function preprocess($html, $type) 16717 { 16718 $ret = ''; 16719 if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML) 16720 { 16721 // Atom XHTML constructs are wrapped with a div by default 16722 // Note: No protection if $html contains a stray </div>! 16723 $html = '<div>' . $html . '</div>'; 16724 $ret .= '<!DOCTYPE html>'; 16725 $content_type = 'text/html'; 16726 } 16727 else 16728 { 16729 $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; 16730 $content_type = 'application/xhtml+xml'; 16731 } 16732 16733 $ret .= '<html><head>'; 16734 $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />'; 16735 $ret .= '</head><body>' . $html . '</body></html>'; 16736 return $ret; 16737 } 16738 16739 public function replace_urls($document, $tag, $attributes) 16740 { 16741 if (!is_array($attributes)) 16742 { 16743 $attributes = array($attributes); 16744 } 16745 16746 if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags)) 16747 { 16748 $elements = $document->getElementsByTagName($tag); 16749 foreach ($elements as $element) 16750 { 16751 foreach ($attributes as $attribute) 16752 { 16753 if ($element->hasAttribute($attribute)) 16754 { 16755 $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base)); 16756 if ($value !== false) 16757 { 16758 $element->setAttribute($attribute, $value); 16759 } 16760 } 16761 } 16762 } 16763 } 16764 } 16765 16766 public function do_strip_htmltags($match) 16767 { 16768 if ($this->encode_instead_of_strip) 16769 { 16770 if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) 16771 { 16772 $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8'); 16773 $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8'); 16774 return "<$match[1]$match[2]>$match[3]</$match[1]>"; 16775 } 16776 else 16777 { 16778 return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8'); 16779 } 16780 } 16781 elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style'))) 16782 { 16783 return $match[4]; 16784 } 16785 else 16786 { 16787 return ''; 16788 } 16789 } 16790 16791 protected function strip_tag($tag, $document, $type) 16792 { 16793 $xpath = new DOMXPath($document); 16794 $elements = $xpath->query('body//' . $tag); 16795 if ($this->encode_instead_of_strip) 16796 { 16797 foreach ($elements as $element) 16798 { 16799 $fragment = $document->createDocumentFragment(); 16800 16801 // For elements which aren't script or style, include the tag itself 16802 if (!in_array($tag, array('script', 'style'))) 16803 { 16804 $text = '<' . $tag; 16805 if ($element->hasAttributes()) 16806 { 16807 $attrs = array(); 16808 foreach ($element->attributes as $name => $attr) 16809 { 16810 $value = $attr->value; 16811 16812 // In XHTML, empty values should never exist, so we repeat the value 16813 if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML)) 16814 { 16815 $value = $name; 16816 } 16817 // For HTML, empty is fine 16818 elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML)) 16819 { 16820 $attrs[] = $name; 16821 continue; 16822 } 16823 16824 // Standard attribute text 16825 $attrs[] = $name . '="' . $attr->value . '"'; 16826 } 16827 $text .= ' ' . implode(' ', $attrs); 16828 } 16829 $text .= '>'; 16830 $fragment->appendChild(new DOMText($text)); 16831 } 16832 16833 $number = $element->childNodes->length; 16834 for ($i = $number; $i > 0; $i--) 16835 { 16836 $child = $element->childNodes->item(0); 16837 $fragment->appendChild($child); 16838 } 16839 16840 if (!in_array($tag, array('script', 'style'))) 16841 { 16842 $fragment->appendChild(new DOMText('</' . $tag . '>')); 16843 } 16844 16845 $element->parentNode->replaceChild($fragment, $element); 16846 } 16847 16848 return; 16849 } 16850 elseif (in_array($tag, array('script', 'style'))) 16851 { 16852 foreach ($elements as $element) 16853 { 16854 $element->parentNode->removeChild($element); 16855 } 16856 16857 return; 16858 } 16859 else 16860 { 16861 foreach ($elements as $element) 16862 { 16863 $fragment = $document->createDocumentFragment(); 16864 $number = $element->childNodes->length; 16865 for ($i = $number; $i > 0; $i--) 16866 { 16867 $child = $element->childNodes->item(0); 16868 $fragment->appendChild($child); 16869 } 16870 16871 $element->parentNode->replaceChild($fragment, $element); 16872 } 16873 } 16874 } 16875 16876 protected function strip_attr($attrib, $document) 16877 { 16878 $xpath = new DOMXPath($document); 16879 $elements = $xpath->query('//*[@' . $attrib . ']'); 16880 16881 foreach ($elements as $element) 16882 { 16883 $element->removeAttribute($attrib); 16884 } 16885 } 16886 } 16887 16888 /** 16889 * Handles `<atom:source>` 16890 * 16891 * Used by {@see SimplePie_Item::get_source()} 16892 * 16893 * This class can be overloaded with {@see SimplePie::set_source_class()} 16894 * 16895 * @package SimplePie 16896 * @subpackage API 16897 */ 16898 class SimplePie_Source 16899 { 16900 var $item; 16901 var $data = array(); 16902 protected $registry; 16903 16904 public function __construct($item, $data) 16905 { 16906 $this->item = $item; 16907 $this->data = $data; 16908 } 16909 16910 public function set_registry(SimplePie_Registry $registry) 16911 { 16912 $this->registry = $registry; 16913 } 16914 16915 public function __toString() 16916 { 16917 return md5(serialize($this->data)); 16918 } 16919 16920 public function get_source_tags($namespace, $tag) 16921 { 16922 if (isset($this->data['child'][$namespace][$tag])) 16923 { 16924 return $this->data['child'][$namespace][$tag]; 16925 } 16926 else 16927 { 16928 return null; 16929 } 16930 } 16931 16932 public function get_base($element = array()) 16933 { 16934 return $this->item->get_base($element); 16935 } 16936 16937 public function sanitize($data, $type, $base = '') 16938 { 16939 return $this->item->sanitize($data, $type, $base); 16940 } 16941 16942 public function get_item() 16943 { 16944 return $this->item; 16945 } 16946 16947 public function get_title() 16948 { 16949 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title')) 16950 { 16951 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 16952 } 16953 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title')) 16954 { 16955 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 16956 } 16957 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title')) 16958 { 16959 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 16960 } 16961 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title')) 16962 { 16963 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 16964 } 16965 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title')) 16966 { 16967 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 16968 } 16969 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title')) 16970 { 16971 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 16972 } 16973 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title')) 16974 { 16975 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 16976 } 16977 else 16978 { 16979 return null; 16980 } 16981 } 16982 16983 public function get_category($key = 0) 16984 { 16985 $categories = $this->get_categories(); 16986 if (isset($categories[$key])) 16987 { 16988 return $categories[$key]; 16989 } 16990 else 16991 { 16992 return null; 16993 } 16994 } 16995 16996 public function get_categories() 16997 { 16998 $categories = array(); 16999 17000 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category) 17001 { 17002 $term = null; 17003 $scheme = null; 17004 $label = null; 17005 if (isset($category['attribs']['']['term'])) 17006 { 17007 $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT); 17008 } 17009 if (isset($category['attribs']['']['scheme'])) 17010 { 17011 $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT); 17012 } 17013 if (isset($category['attribs']['']['label'])) 17014 { 17015 $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT); 17016 } 17017 $categories[] = $this->registry->create('Category', array($term, $scheme, $label)); 17018 } 17019 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category) 17020 { 17021 // This is really the label, but keep this as the term also for BC. 17022 // Label will also work on retrieving because that falls back to term. 17023 $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17024 if (isset($category['attribs']['']['domain'])) 17025 { 17026 $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT); 17027 } 17028 else 17029 { 17030 $scheme = null; 17031 } 17032 $categories[] = $this->registry->create('Category', array($term, $scheme, null)); 17033 } 17034 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category) 17035 { 17036 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 17037 } 17038 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category) 17039 { 17040 $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 17041 } 17042 17043 if (!empty($categories)) 17044 { 17045 return array_unique($categories); 17046 } 17047 else 17048 { 17049 return null; 17050 } 17051 } 17052 17053 public function get_author($key = 0) 17054 { 17055 $authors = $this->get_authors(); 17056 if (isset($authors[$key])) 17057 { 17058 return $authors[$key]; 17059 } 17060 else 17061 { 17062 return null; 17063 } 17064 } 17065 17066 public function get_authors() 17067 { 17068 $authors = array(); 17069 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author) 17070 { 17071 $name = null; 17072 $uri = null; 17073 $email = null; 17074 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) 17075 { 17076 $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17077 } 17078 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) 17079 { 17080 $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); 17081 } 17082 if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) 17083 { 17084 $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17085 } 17086 if ($name !== null || $email !== null || $uri !== null) 17087 { 17088 $authors[] = $this->registry->create('Author', array($name, $uri, $email)); 17089 } 17090 } 17091 if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author')) 17092 { 17093 $name = null; 17094 $url = null; 17095 $email = null; 17096 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) 17097 { 17098 $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17099 } 17100 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) 17101 { 17102 $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); 17103 } 17104 if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) 17105 { 17106 $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17107 } 17108 if ($name !== null || $email !== null || $url !== null) 17109 { 17110 $authors[] = $this->registry->create('Author', array($name, $url, $email)); 17111 } 17112 } 17113 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author) 17114 { 17115 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 17116 } 17117 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author) 17118 { 17119 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 17120 } 17121 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author) 17122 { 17123 $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null)); 17124 } 17125 17126 if (!empty($authors)) 17127 { 17128 return array_unique($authors); 17129 } 17130 else 17131 { 17132 return null; 17133 } 17134 } 17135 17136 public function get_contributor($key = 0) 17137 { 17138 $contributors = $this->get_contributors(); 17139 if (isset($contributors[$key])) 17140 { 17141 return $contributors[$key]; 17142 } 17143 else 17144 { 17145 return null; 17146 } 17147 } 17148 17149 public function get_contributors() 17150 { 17151 $contributors = array(); 17152 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor) 17153 { 17154 $name = null; 17155 $uri = null; 17156 $email = null; 17157 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])) 17158 { 17159 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17160 } 17161 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])) 17162 { 17163 $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0])); 17164 } 17165 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'])) 17166 { 17167 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17168 } 17169 if ($name !== null || $email !== null || $uri !== null) 17170 { 17171 $contributors[] = $this->registry->create('Author', array($name, $uri, $email)); 17172 } 17173 } 17174 foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor) 17175 { 17176 $name = null; 17177 $url = null; 17178 $email = null; 17179 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'])) 17180 { 17181 $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17182 } 17183 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'])) 17184 { 17185 $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0])); 17186 } 17187 if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'])) 17188 { 17189 $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17190 } 17191 if ($name !== null || $email !== null || $url !== null) 17192 { 17193 $contributors[] = $this->registry->create('Author', array($name, $url, $email)); 17194 } 17195 } 17196 17197 if (!empty($contributors)) 17198 { 17199 return array_unique($contributors); 17200 } 17201 else 17202 { 17203 return null; 17204 } 17205 } 17206 17207 public function get_link($key = 0, $rel = 'alternate') 17208 { 17209 $links = $this->get_links($rel); 17210 if (isset($links[$key])) 17211 { 17212 return $links[$key]; 17213 } 17214 else 17215 { 17216 return null; 17217 } 17218 } 17219 17220 /** 17221 * Added for parity between the parent-level and the item/entry-level. 17222 */ 17223 public function get_permalink() 17224 { 17225 return $this->get_link(0); 17226 } 17227 17228 public function get_links($rel = 'alternate') 17229 { 17230 if (!isset($this->data['links'])) 17231 { 17232 $this->data['links'] = array(); 17233 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link')) 17234 { 17235 foreach ($links as $link) 17236 { 17237 if (isset($link['attribs']['']['href'])) 17238 { 17239 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; 17240 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 17241 } 17242 } 17243 } 17244 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link')) 17245 { 17246 foreach ($links as $link) 17247 { 17248 if (isset($link['attribs']['']['href'])) 17249 { 17250 $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate'; 17251 $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link)); 17252 17253 } 17254 } 17255 } 17256 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link')) 17257 { 17258 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 17259 } 17260 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link')) 17261 { 17262 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 17263 } 17264 if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link')) 17265 { 17266 $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0])); 17267 } 17268 17269 $keys = array_keys($this->data['links']); 17270 foreach ($keys as $key) 17271 { 17272 if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key))) 17273 { 17274 if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key])) 17275 { 17276 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]); 17277 $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]; 17278 } 17279 else 17280 { 17281 $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key]; 17282 } 17283 } 17284 elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY) 17285 { 17286 $this->data['links'][substr($key, 41)] =& $this->data['links'][$key]; 17287 } 17288 $this->data['links'][$key] = array_unique($this->data['links'][$key]); 17289 } 17290 } 17291 17292 if (isset($this->data['links'][$rel])) 17293 { 17294 return $this->data['links'][$rel]; 17295 } 17296 else 17297 { 17298 return null; 17299 } 17300 } 17301 17302 public function get_description() 17303 { 17304 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle')) 17305 { 17306 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 17307 } 17308 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline')) 17309 { 17310 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 17311 } 17312 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description')) 17313 { 17314 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 17315 } 17316 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description')) 17317 { 17318 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 17319 } 17320 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description')) 17321 { 17322 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0])); 17323 } 17324 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description')) 17325 { 17326 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17327 } 17328 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description')) 17329 { 17330 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17331 } 17332 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary')) 17333 { 17334 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 17335 } 17336 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle')) 17337 { 17338 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0])); 17339 } 17340 else 17341 { 17342 return null; 17343 } 17344 } 17345 17346 public function get_copyright() 17347 { 17348 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights')) 17349 { 17350 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 17351 } 17352 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright')) 17353 { 17354 return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0])); 17355 } 17356 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright')) 17357 { 17358 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17359 } 17360 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights')) 17361 { 17362 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17363 } 17364 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights')) 17365 { 17366 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17367 } 17368 else 17369 { 17370 return null; 17371 } 17372 } 17373 17374 public function get_language() 17375 { 17376 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language')) 17377 { 17378 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17379 } 17380 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language')) 17381 { 17382 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17383 } 17384 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language')) 17385 { 17386 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT); 17387 } 17388 elseif (isset($this->data['xml_lang'])) 17389 { 17390 return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT); 17391 } 17392 else 17393 { 17394 return null; 17395 } 17396 } 17397 17398 public function get_latitude() 17399 { 17400 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat')) 17401 { 17402 return (float) $return[0]['data']; 17403 } 17404 elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) 17405 { 17406 return (float) $match[1]; 17407 } 17408 else 17409 { 17410 return null; 17411 } 17412 } 17413 17414 public function get_longitude() 17415 { 17416 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long')) 17417 { 17418 return (float) $return[0]['data']; 17419 } 17420 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon')) 17421 { 17422 return (float) $return[0]['data']; 17423 } 17424 elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match)) 17425 { 17426 return (float) $match[2]; 17427 } 17428 else 17429 { 17430 return null; 17431 } 17432 } 17433 17434 public function get_image_url() 17435 { 17436 if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image')) 17437 { 17438 return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI); 17439 } 17440 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo')) 17441 { 17442 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 17443 } 17444 elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon')) 17445 { 17446 return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0])); 17447 } 17448 else 17449 { 17450 return null; 17451 } 17452 } 17453 } 17454 17455 /** 17456 * Parses the XML Declaration 17457 * 17458 * @package SimplePie 17459 * @subpackage Parsing 17460 */ 17461 class SimplePie_XML_Declaration_Parser 17462 { 17463 /** 17464 * XML Version 17465 * 17466 * @access public 17467 * @var string 17468 */ 17469 var $version = '1.0'; 17470 17471 /** 17472 * Encoding 17473 * 17474 * @access public 17475 * @var string 17476 */ 17477 var $encoding = 'UTF-8'; 17478 17479 /** 17480 * Standalone 17481 * 17482 * @access public 17483 * @var bool 17484 */ 17485 var $standalone = false; 17486 17487 /** 17488 * Current state of the state machine 17489 * 17490 * @access private 17491 * @var string 17492 */ 17493 var $state = 'before_version_name'; 17494 17495 /** 17496 * Input data 17497 * 17498 * @access private 17499 * @var string 17500 */ 17501 var $data = ''; 17502 17503 /** 17504 * Input data length (to avoid calling strlen() everytime this is needed) 17505 * 17506 * @access private 17507 * @var int 17508 */ 17509 var $data_length = 0; 17510 17511 /** 17512 * Current position of the pointer 17513 * 17514 * @var int 17515 * @access private 17516 */ 17517 var $position = 0; 17518 17519 /** 17520 * Create an instance of the class with the input data 17521 * 17522 * @access public 17523 * @param string $data Input data 17524 */ 17525 public function __construct($data) 17526 { 17527 $this->data = $data; 17528 $this->data_length = strlen($this->data); 17529 } 17530 17531 /** 17532 * Parse the input data 17533 * 17534 * @access public 17535 * @return bool true on success, false on failure 17536 */ 17537 public function parse() 17538 { 17539 while ($this->state && $this->state !== 'emit' && $this->has_data()) 17540 { 17541 $state = $this->state; 17542 $this->$state(); 17543 } 17544 $this->data = ''; 17545 if ($this->state === 'emit') 17546 { 17547 return true; 17548 } 17549 else 17550 { 17551 $this->version = ''; 17552 $this->encoding = ''; 17553 $this->standalone = ''; 17554 return false; 17555 } 17556 } 17557 17558 /** 17559 * Check whether there is data beyond the pointer 17560 * 17561 * @access private 17562 * @return bool true if there is further data, false if not 17563 */ 17564 public function has_data() 17565 { 17566 return (bool) ($this->position < $this->data_length); 17567 } 17568 17569 /** 17570 * Advance past any whitespace 17571 * 17572 * @return int Number of whitespace characters passed 17573 */ 17574 public function skip_whitespace() 17575 { 17576 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); 17577 $this->position += $whitespace; 17578 return $whitespace; 17579 } 17580 17581 /** 17582 * Read value 17583 */ 17584 public function get_value() 17585 { 17586 $quote = substr($this->data, $this->position, 1); 17587 if ($quote === '"' || $quote === "'") 17588 { 17589 $this->position++; 17590 $len = strcspn($this->data, $quote, $this->position); 17591 if ($this->has_data()) 17592 { 17593 $value = substr($this->data, $this->position, $len); 17594 $this->position += $len + 1; 17595 return $value; 17596 } 17597 } 17598 return false; 17599 } 17600 17601 public function before_version_name() 17602 { 17603 if ($this->skip_whitespace()) 17604 { 17605 $this->state = 'version_name'; 17606 } 17607 else 17608 { 17609 $this->state = false; 17610 } 17611 } 17612 17613 public function version_name() 17614 { 17615 if (substr($this->data, $this->position, 7) === 'version') 17616 { 17617 $this->position += 7; 17618 $this->skip_whitespace(); 17619 $this->state = 'version_equals'; 17620 } 17621 else 17622 { 17623 $this->state = false; 17624 } 17625 } 17626 17627 public function version_equals() 17628 { 17629 if (substr($this->data, $this->position, 1) === '=') 17630 { 17631 $this->position++; 17632 $this->skip_whitespace(); 17633 $this->state = 'version_value'; 17634 } 17635 else 17636 { 17637 $this->state = false; 17638 } 17639 } 17640 17641 public function version_value() 17642 { 17643 if ($this->version = $this->get_value()) 17644 { 17645 $this->skip_whitespace(); 17646 if ($this->has_data()) 17647 { 17648 $this->state = 'encoding_name'; 17649 } 17650 else 17651 { 17652 $this->state = 'emit'; 17653 } 17654 } 17655 else 17656 { 17657 $this->state = false; 17658 } 17659 } 17660 17661 public function encoding_name() 17662 { 17663 if (substr($this->data, $this->position, 8) === 'encoding') 17664 { 17665 $this->position += 8; 17666 $this->skip_whitespace(); 17667 $this->state = 'encoding_equals'; 17668 } 17669 else 17670 { 17671 $this->state = 'standalone_name'; 17672 } 17673 } 17674 17675 public function encoding_equals() 17676 { 17677 if (substr($this->data, $this->position, 1) === '=') 17678 { 17679 $this->position++; 17680 $this->skip_whitespace(); 17681 $this->state = 'encoding_value'; 17682 } 17683 else 17684 { 17685 $this->state = false; 17686 } 17687 } 17688 17689 public function encoding_value() 17690 { 17691 if ($this->encoding = $this->get_value()) 17692 { 17693 $this->skip_whitespace(); 17694 if ($this->has_data()) 17695 { 17696 $this->state = 'standalone_name'; 17697 } 17698 else 17699 { 17700 $this->state = 'emit'; 17701 } 17702 } 17703 else 17704 { 17705 $this->state = false; 17706 } 17707 } 17708 17709 public function standalone_name() 17710 { 17711 if (substr($this->data, $this->position, 10) === 'standalone') 17712 { 17713 $this->position += 10; 17714 $this->skip_whitespace(); 17715 $this->state = 'standalone_equals'; 17716 } 17717 else 17718 { 17719 $this->state = false; 17720 } 17721 } 17722 17723 public function standalone_equals() 17724 { 17725 if (substr($this->data, $this->position, 1) === '=') 17726 { 17727 $this->position++; 17728 $this->skip_whitespace(); 17729 $this->state = 'standalone_value'; 17730 } 17731 else 17732 { 17733 $this->state = false; 17734 } 17735 } 17736 17737 public function standalone_value() 17738 { 17739 if ($standalone = $this->get_value()) 17740 { 17741 switch ($standalone) 17742 { 17743 case 'yes': 17744 $this->standalone = true; 17745 break; 17746 17747 case 'no': 17748 $this->standalone = false; 17749 break; 17750 17751 default: 17752 $this->state = false; 17753 return; 17754 } 17755 17756 $this->skip_whitespace(); 17757 if ($this->has_data()) 17758 { 17759 $this->state = false; 17760 } 17761 else 17762 { 17763 $this->state = 'emit'; 17764 } 17765 } 17766 else 17767 { 17768 $this->state = false; 17769 } 17770 } 17771 } 17772
title
Description
Body
title
Description
Body
title
Description
Body
title
Body